diff --git a/doc/changelog.dox b/doc/changelog.dox index 90eafbebc..ad9f3c3a8 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -62,14 +62,14 @@ See also: @webgl_extension{WEBGL,debug_renderer_info} and @webgl_extension{WEBGL,debug_shaders} extensions, no implementation done yet -- Recognizing ANGLE GLES and WebGL multi-draw extensions and using them in - @ref GL::AbstractShaderProgram::draw(Containers::ArrayView>): - - @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) - - @webgl_extension{WEBGL,multi_draw} -- The following extensions are recognized but not used yet: - - @m_class{m-doc-external} [ANGLE_base_vertex_base_instance](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_base_vertex_base_instance.txt) +- Recognizing ANGLE GLES and WebGL base vertex, base instance and multi-draw + extensions and using them in @ref GL::AbstractShaderProgram::draw(Mesh&) + and @ref GL::AbstractShaderProgram::draw(Containers::ArrayView>): - @gl_extension{EXT,draw_elements_base_vertex} - @gl_extension{OES,draw_elements_base_vertex} + - @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) + - @m_class{m-doc-external} [ANGLE_base_vertex_base_instance](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_base_vertex_base_instance.txt) + - @webgl_extension{WEBGL,multi_draw} - @webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} - @webgl_extension{WEBGL,multi_draw_instanced_base_vertex_base_instance} - Added a @ref GL::AbstractTexture::target() getter to simplify interaction diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 050e80605..9c8ce2efa 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -450,7 +450,7 @@ Extension | Status @gl_extension2{ANGLE,texture_compression_dxt3,ANGLE_texture_compression_dxt} | done @gl_extension2{ANGLE,texture_compression_dxt5,ANGLE_texture_compression_dxt} | done @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) (unlisted) | done -@m_class{m-doc-external} [ANGLE_base_vertex_base_instance](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_base_vertex_base_instance.txt) (unlisted) | | +@m_class{m-doc-external} [ANGLE_base_vertex_base_instance](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_base_vertex_base_instance.txt) (unlisted) | done except instanced multi-draw @gl_extension{APPLE,texture_format_BGRA8888} | done @gl_extension{APPLE,clip_distance} | done @gl_extension{ARM,shader_framebuffer_fetch} | missing renderer setup and limit query @@ -472,7 +472,7 @@ Extension | Status @gl_extension{EXT,texture_compression_s3tc} | done @gl_extension{EXT,pvrtc_sRGB} | done @gl_extension{EXT,shader_integer_mix} | done (shading language only) -@gl_extension{EXT,draw_elements_base_vertex} | | +@gl_extension{EXT,draw_elements_base_vertex} | done @gl_extension{EXT,texture_norm16} | done @gl_extension{EXT,texture_sRGB_R8} | done @gl_extension{EXT,texture_sRGB_RG8} | done @@ -500,7 +500,7 @@ Extension | Status @gl_extension{OES,stencil1} | done @gl_extension{OES,stencil4} | done @gl_extension{OES,texture_float_linear} | done -@gl_extension{OES,draw_elements_base_vertex} | | +@gl_extension{OES,draw_elements_base_vertex} | done @gl_extension{OVR,multiview} | | @gl_extension{OVR,multiview2} | | @@ -573,8 +573,8 @@ Extension | Status @webgl_extension{WEBGL,compressed_texture_s3tc_srgb} | done @webgl_extension{WEBGL,multi_draw} | done @webgl_extension{WEBGL,blend_equation_advanced_coherent} | done -@webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} | | -@webgl_extension{WEBGL,multi_draw_instanced_base_vertex_base_instance} | | +@webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} | done +@webgl_extension{WEBGL,multi_draw_instanced_base_vertex_base_instance} | done except instanced multi-draw @section opengl-unsupported Unsupported OpenGL features diff --git a/src/Magnum/GL/AbstractShaderProgram.cpp b/src/Magnum/GL/AbstractShaderProgram.cpp index e426d43ed..065fc7dad 100644 --- a/src/Magnum/GL/AbstractShaderProgram.cpp +++ b/src/Magnum/GL/AbstractShaderProgram.cpp @@ -358,10 +358,8 @@ void AbstractShaderProgram::draw(Mesh& mesh) { use(); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 mesh.drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._baseInstance, mesh._indexOffset, mesh._indexStart, mesh._indexEnd); - #elif !defined(MAGNUM_TARGET_GLES2) - mesh.drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._indexOffset, mesh._indexStart, mesh._indexEnd); #else mesh.drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._indexOffset); #endif @@ -375,10 +373,8 @@ void AbstractShaderProgram::draw(MeshView& mesh) { use(); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 mesh._original->drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._baseInstance, mesh._indexOffset, mesh._indexStart, mesh._indexEnd); - #elif !defined(MAGNUM_TARGET_GLES2) - mesh._original->drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._indexOffset, mesh._indexStart, mesh._indexEnd); #else mesh._original->drawInternal(mesh._count, mesh._baseVertex, mesh._instanceCount, mesh._indexOffset); #endif diff --git a/src/Magnum/GL/AbstractShaderProgram.h b/src/Magnum/GL/AbstractShaderProgram.h index b62f58ec1..07cb01f77 100644 --- a/src/Magnum/GL/AbstractShaderProgram.h +++ b/src/Magnum/GL/AbstractShaderProgram.h @@ -863,8 +863,14 @@ class MAGNUM_GL_EXPORT AbstractShaderProgram: public AbstractObject { * @requires_gl32 Extension @gl_extension{ARB,draw_elements_base_vertex} * if the mesh is indexed and @ref MeshView::baseVertex() is not * `0` - * @requires_gl Specifying base vertex for indexed meshes is not - * available in OpenGL ES or WebGL. + * @requires_es_extension OpenGL ES 3.0 and extension + * @gl_extension{OES,draw_elements_base_vertex} or + * @gl_extension{EXT,draw_elements_base_vertex} if the mesh is + * indexed and @ref MeshView::baseVertex() is not `0` + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{WEBGL,multi_draw_instanced_base_vertex_base_instance} + * if the mesh is indexed and @ref MeshView::baseVertex() is not + * `0` */ void draw(Containers::ArrayView> meshes); diff --git a/src/Magnum/GL/Implementation/MeshState.cpp b/src/Magnum/GL/Implementation/MeshState.cpp index eef00a734..1f5075893 100644 --- a/src/Magnum/GL/Implementation/MeshState.cpp +++ b/src/Magnum/GL/Implementation/MeshState.cpp @@ -107,6 +107,102 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector()) { + extensions.push_back(Extensions::EXT::draw_elements_base_vertex::string()); + + drawElementsBaseVertexImplementation = glDrawElementsBaseVertexEXT; + #ifndef MAGNUM_TARGET_GLES2 + drawRangeElementsBaseVertexImplementation = glDrawRangeElementsBaseVertexEXT; + drawElementsInstancedBaseVertexImplementation = glDrawElementsInstancedBaseVertexEXT; + #endif + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::OES::draw_elements_base_vertex::string()); + + drawElementsBaseVertexImplementation = glDrawElementsBaseVertexOES; + #ifndef MAGNUM_TARGET_GLES2 + drawRangeElementsBaseVertexImplementation = glDrawRangeElementsBaseVertexOES; + drawElementsInstancedBaseVertexImplementation = glDrawElementsInstancedBaseVertexOES; + #endif + } else + #else + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string()); + + /* The WEBGL extension uses the same entrypoints as the ANGLE extension + it was based on, however we wrap it to supply trivial instance count + because there's no non-instanced variant. Only available since + 1.39.15: https://github.com/emscripten-core/emscripten/pull/11054 */ + #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 13915 + drawElementsBaseVertexImplementation = Mesh::drawElementsBaseVertexImplementationANGLE; + drawRangeElementsBaseVertexImplementation = Mesh::drawRangeElementsBaseVertexImplementationANGLE; + drawElementsInstancedBaseVertexImplementation = Mesh::drawElementsInstancedBaseVertexImplementationANGLE; + #else + /* In Context::setupDriverWorkarounds() we make sure the extension is + not even advertised, so this shouldn't be reached. */ + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + #endif + } else + #endif + { + drawElementsBaseVertexImplementation = Mesh::drawElementsBaseVertexImplementationAssert; + #ifndef MAGNUM_TARGET_GLES2 + drawRangeElementsBaseVertexImplementation = Mesh::drawRangeElementsBaseVertexImplementationAssert; + drawElementsInstancedBaseVertexImplementation = Mesh::drawElementsInstancedBaseVertexImplementationAssert; + #endif + } + #endif + + /* Base instance draws on ES3 and WebGL2 */ + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) + #ifndef MAGNUM_TARGET_WEBGL + #ifndef MAGNUM_TARGET_GLES2 + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::ANGLE::base_vertex_base_instance::string()); + + drawArraysInstancedBaseInstanceImplementation = glDrawArraysInstancedBaseInstanceANGLE; + /* This variant isn't in the ext, emulated using + glDrawElementsInstancedBaseVertexBaseInstanceANGLE */ + drawElementsInstancedBaseInstanceImplementation = Mesh::drawElementsInstancedBaseInstanceImplementationANGLE; + drawElementsInstancedBaseVertexBaseInstanceImplementation = glDrawElementsInstancedBaseVertexBaseInstanceANGLE; + } else + #endif + #else + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string()); + + /* The WEBGL extension uses the same entrypoints as the ANGLE extension + it was based on. Only available since 1.39.15: + https://github.com/emscripten-core/emscripten/pull/11054 */ + #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 13915 + drawArraysInstancedBaseInstanceImplementation = glDrawArraysInstancedBaseInstanceANGLE; + /* This variant isn't in the ext, emulated using + glDrawElementsInstancedBaseVertexBaseInstanceANGLE */ + drawElementsInstancedBaseInstanceImplementation = Mesh::drawElementsInstancedBaseInstanceImplementationANGLE; + drawElementsInstancedBaseVertexBaseInstanceImplementation = glDrawElementsInstancedBaseVertexBaseInstanceANGLE; + #else + /* In Context::setupDriverWorkarounds() we make sure the extension is + not even advertised, so this shouldn't be reached. */ + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + #endif + } else + #endif + { + drawArraysInstancedBaseInstanceImplementation = Mesh::drawArraysInstancedBaseInstanceImplementationAssert; + drawElementsInstancedBaseInstanceImplementation = Mesh::drawElementsInstancedBaseInstanceImplementationAssert; + drawElementsInstancedBaseVertexBaseInstanceImplementation = Mesh::drawElementsInstancedBaseVertexBaseInstanceImplementationAssert; + } + #endif + #ifdef MAGNUM_TARGET_GLES /* Multi draw implementation on ES. Because there's a lot of dispatch logic involved, the multiDrawImplementationDefault then has internal @@ -149,6 +245,44 @@ MeshState::MeshState(Context& context, ContextState& contextState, std::vector()) { + extensions.push_back(Extensions::EXT::draw_elements_base_vertex::string()); + + multiDrawElementsBaseVertexImplementation = glMultiDrawElementsBaseVertexEXT; + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::OES::draw_elements_base_vertex::string()); + + /* Yes, it's really EXT, the same as with + EXT_draw_elements_base_vertex. I have no idea why the two + extensions exist and why it isn't just one. */ + multiDrawElementsBaseVertexImplementation = glMultiDrawElementsBaseVertexEXT; + } else + #else + if(context.isExtensionSupported()) { + extensions.push_back(Extensions::WEBGL::multi_draw_instanced_base_vertex_base_instance::string()); + + /* The WEBGL extension uses the same entrypoints as the ANGLE + extension it was based on, however we wrap it and supply trivial + instance counts because there's no non-instanced variant. Only + available since 2.0.5: https://github.com/emscripten-core/emscripten/pull/12282 */ + #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 20005 + multiDrawElementsBaseVertexImplementation = MeshView::multiDrawElementsBaseVertexImplementationANGLE; + #else + /* In Context::setupDriverWorkarounds() we make sure the extension + is not even advertised, so this shouldn't be reached. */ + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + #endif + } else + #endif + { + multiDrawElementsBaseVertexImplementation = MeshView::multiDrawElementsBaseVertexImplementationAssert; + } + #endif + multiDrawImplementation = &MeshView::multiDrawImplementationDefault; } else multiDrawImplementation = &MeshView::multiDrawImplementationFallback; diff --git a/src/Magnum/GL/Implementation/MeshState.h b/src/Magnum/GL/Implementation/MeshState.h index 3e5c441dc..30a6034f0 100644 --- a/src/Magnum/GL/Implementation/MeshState.h +++ b/src/Magnum/GL/Implementation/MeshState.h @@ -53,15 +53,37 @@ struct MeshState { void(Mesh::*bindImplementation)(); void(Mesh::*unbindImplementation)(); + #ifdef MAGNUM_TARGET_GLES + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + void(APIENTRY *drawElementsBaseVertexImplementation)(GLenum, GLsizei, GLenum, const void*, GLint); + #endif + #ifndef MAGNUM_TARGET_GLES2 + void(APIENTRY *drawRangeElementsBaseVertexImplementation)(GLenum, GLuint, GLuint, GLsizei, GLenum, const void*, GLint); + #endif + #endif + #ifdef MAGNUM_TARGET_GLES2 void(APIENTRY *drawArraysInstancedImplementation)(GLenum, GLint, GLsizei, GLsizei); + #endif + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) + void(APIENTRY *drawArraysInstancedBaseInstanceImplementation)(GLenum, GLint, GLsizei, GLsizei, GLuint); + #endif + #ifdef MAGNUM_TARGET_GLES2 void(APIENTRY *drawElementsInstancedImplementation)(GLenum, GLsizei, GLenum, const void*, GLsizei); #endif + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_GLES2) + void(APIENTRY *drawElementsInstancedBaseVertexImplementation)(GLenum, GLsizei, GLenum, const void*, GLsizei, GLint); + void(APIENTRY *drawElementsInstancedBaseInstanceImplementation)(GLenum, GLsizei, GLenum, const void*, GLsizei, GLuint); + void(APIENTRY *drawElementsInstancedBaseVertexBaseInstanceImplementation)(GLenum, GLsizei, GLenum, const void*, GLsizei, GLint, GLuint); + #endif #ifdef MAGNUM_TARGET_GLES void(*multiDrawImplementation)(Containers::ArrayView>); void(APIENTRY *multiDrawArraysImplementation)(GLenum, const GLint*, const GLsizei*, GLsizei); void(APIENTRY *multiDrawElementsImplementation)(GLenum, const GLsizei*, GLenum, const void* const*, GLsizei); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + void(APIENTRY *multiDrawElementsBaseVertexImplementation)(GLenum, const GLsizei*, GLenum, const void* const*, GLsizei, const GLint*); + #endif #endif void(*bindVAOImplementation)(GLuint); diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index 25f9e311b..6d06c3749 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -547,6 +547,18 @@ void Context::setupDriverWorkarounds() { #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ < 20000 _setRequiredVersion(WEBGL::multi_draw, None); #endif + #ifndef MAGNUM_TARGET_GLES2 + /* WEBGL_multi_draw_instanced_base_vertex_base_instance only since + Emscripten 2.0.5: https://github.com/emscripten-core/emscripten/pull/12282 */ + #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ < 20005 + _setRequiredVersion(WEBGL::multi_draw_instanced_base_vertex_base_instance, None); + #endif + /* WEBGL_draw_instanced_base_vertex_base_instance only since Emscripten + 1.39.15: https://github.com/emscripten-core/emscripten/pull/11054 */ + #if __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ < 13915 + _setRequiredVersion(WEBGL::draw_instanced_base_vertex_base_instance, None); + #endif + #endif #endif #undef _setRequiredVersion diff --git a/src/Magnum/GL/Mesh.cpp b/src/Magnum/GL/Mesh.cpp index c3340be0f..3fa160a1f 100644 --- a/src/Magnum/GL/Mesh.cpp +++ b/src/Magnum/GL/Mesh.cpp @@ -401,10 +401,8 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, const GLintptr offset, const MeshInde return *this; } -#ifndef MAGNUM_TARGET_GLES +#ifndef MAGNUM_TARGET_GLES2 void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, UnsignedInt baseInstance, GLintptr indexOffset, Int indexStart, Int indexEnd) -#elif !defined(MAGNUM_TARGET_GLES2) -void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset, Int indexStart, Int indexEnd) #else void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset) #endif @@ -421,15 +419,30 @@ void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr i /* Indexed mesh with base vertex */ } else if(baseVertex) { - #ifndef MAGNUM_TARGET_GLES + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + #ifndef MAGNUM_TARGET_GLES2 /* Indexed mesh with specified range */ if(indexEnd) { - glDrawRangeElementsBaseVertex(GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast(indexOffset), baseVertex); + #ifndef MAGNUM_TARGET_GLES + glDrawRangeElementsBaseVertex + #else + state.drawRangeElementsBaseVertexImplementation + #endif + (GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast(indexOffset), baseVertex); /* Indexed mesh */ - } else glDrawElementsBaseVertex(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), baseVertex); + } else + #endif + { + #ifndef MAGNUM_TARGET_GLES + glDrawElementsBaseVertex + #else + state.drawElementsBaseVertexImplementation + #endif + (GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), baseVertex); + } #else - CORRADE_ASSERT_UNREACHABLE("GL::Mesh::draw(): desktop OpenGL is required for base vertex specification in indexed meshes", ); + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): indexed mesh draw with base vertex specification possible only since WebGL 2.0", ); #endif /* Indexed mesh */ @@ -457,10 +470,15 @@ void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr i } else { /* Non-indexed mesh */ if(!_indexBuffer.id()) { - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 /* Non-indexed mesh with base instance */ if(baseInstance) { - glDrawArraysInstancedBaseInstance(GLenum(_primitive), baseVertex, count, instanceCount, baseInstance); + #ifndef MAGNUM_TARGET_GLES + glDrawArraysInstancedBaseInstance + #else + state.drawArraysInstancedBaseInstanceImplementation + #endif + (GLenum(_primitive), baseVertex, count, instanceCount, baseInstance); /* Non-indexed mesh */ } else @@ -476,28 +494,40 @@ void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr i /* Indexed mesh with base vertex */ } else if(baseVertex) { - #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 /* Indexed mesh with base vertex and base instance */ if(baseInstance) { - glDrawElementsInstancedBaseVertexBaseInstance(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseVertex, baseInstance); + #ifndef MAGNUM_TARGET_GLES + glDrawElementsInstancedBaseVertexBaseInstance + #else + state.drawElementsInstancedBaseVertexBaseInstanceImplementation + #endif + (GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseVertex, baseInstance); /* Indexed mesh with base vertex */ - } else - #endif - { - glDrawElementsInstancedBaseVertex(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseVertex); + } else { + #ifndef MAGNUM_TARGET_GLES + glDrawElementsInstancedBaseVertex + #else + state.drawElementsInstancedBaseVertexImplementation + #endif + (GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseVertex); } #else - CORRADE_ASSERT_UNREACHABLE("GL::Mesh::draw(): OpenGL ES 3.2 or desktop GL is required for base vertex specification in indexed meshes", ); + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): instanced indexed mesh draw with base vertex specification possible only since OpenGL ES 3.0", ); #endif /* Indexed mesh */ } else { - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 /* Indexed mesh with base instance */ if(baseInstance) { - glDrawElementsInstancedBaseInstance(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseInstance); + #ifndef MAGNUM_TARGET_GLES + glDrawElementsInstancedBaseInstance + #else + state.drawElementsInstancedBaseInstanceImplementation + #endif + (GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast(indexOffset), instanceCount, baseInstance); /* Instanced mesh */ } else @@ -873,4 +903,58 @@ void Mesh::unbindImplementationDefault() { void Mesh::unbindImplementationVAO() {} +#ifdef MAGNUM_TARGET_GLES +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) +#if defined(MAGNUM_TARGET_WEBGL) && __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_patch__ >= 13915 +void Mesh::drawElementsBaseVertexImplementationANGLE(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint baseVertex) { + glDrawElementsInstancedBaseVertexBaseInstanceANGLE(mode, count, type, indices, 1, baseVertex, 0); +} +#endif + +void Mesh::drawElementsBaseVertexImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLint) { + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): no extension available for indexed mesh draw with base vertex specification", ); +} +#endif + +#ifndef MAGNUM_TARGET_GLES2 +#if defined(MAGNUM_TARGET_WEBGL) && __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_patch__ >= 13915 +void Mesh::drawRangeElementsBaseVertexImplementationANGLE(const GLenum mode, GLuint, GLuint, GLsizei count, GLenum type, const void* indices, GLint baseVertex) { + glDrawElementsInstancedBaseVertexBaseInstanceANGLE(mode, count, type, indices, 1, baseVertex, 0); +} +#endif + +void Mesh::drawRangeElementsBaseVertexImplementationAssert(GLenum, GLuint, GLuint, GLsizei, GLenum, const void*, GLint) { + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): no extension available for indexed mesh draw with base vertex specification", ); +} + +void Mesh::drawArraysInstancedBaseInstanceImplementationAssert(GLenum, GLint, GLsizei, GLsizei, GLuint) { + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): no extension available for instanced mesh draw with base instance specification", ); +} + +#if !defined(MAGNUM_TARGET_WEBGL) || __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_patch__ >= 13915 +void Mesh::drawElementsInstancedBaseInstanceImplementationANGLE(const GLenum mode, const GLsizei count, const GLenum type, const void* const indices, const GLsizei instanceCount, const GLuint baseInstance) { + glDrawElementsInstancedBaseVertexBaseInstanceANGLE(mode, count, type, indices, instanceCount, 0, baseInstance); +} +#endif + +void Mesh::drawElementsInstancedBaseInstanceImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLsizei, GLuint) { + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): no extension available for instanced indexed mesh draw with base instance specification", ); +} + +void Mesh::drawElementsInstancedBaseVertexBaseInstanceImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLsizei, GLint, GLuint) { + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): no extension available for instanced indexed mesh draw with base vertex and base instance specification", ); +} + +#if defined(MAGNUM_TARGET_WEBGL) && __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_patch__ >= 13915 +void Mesh::drawElementsInstancedBaseVertexImplementationANGLE(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instanceCount, GLint baseVertex) { + glDrawElementsInstancedBaseVertexBaseInstanceANGLE(mode, count, type, indices, instanceCount, baseVertex, 0); +} +#endif + +void Mesh::drawElementsInstancedBaseVertexImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLsizei, GLint) { + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): no extension available for instanced indexed mesh draw with base vertex specification", ); +} +#endif +#endif + }} diff --git a/src/Magnum/GL/Mesh.h b/src/Magnum/GL/Mesh.h index a2c25d402..a60395167 100644 --- a/src/Magnum/GL/Mesh.h +++ b/src/Magnum/GL/Mesh.h @@ -608,8 +608,12 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { * @see @ref setCount(), @ref setBaseInstance() * @requires_gl32 Extension @gl_extension{ARB,draw_elements_base_vertex} * for indexed meshes - * @requires_gles32 Base vertex cannot be specified for indexed meshes - * in OpenGL ES 3.1 or WebGL. + * @requires_gles32 Extension @gl_extension{OES,draw_elements_base_vertex} + * or @gl_extension{EXT,draw_elements_base_vertex} for indexed + * meshes on OpenGL ES 3.1 and older + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} + * for indexed meshes */ Mesh& setBaseVertex(Int baseVertex) { _baseVertex = baseVertex; @@ -647,7 +651,7 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { return *this; } - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 /** @brief Base instance */ UnsignedInt baseInstance() const { return _baseInstance; } @@ -659,8 +663,10 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { * Default is @cpp 0 @ce. * @see @ref setInstanceCount(), @ref setBaseVertex() * @requires_gl42 Extension @gl_extension{ARB,base_instance} - * @requires_gl Base instance cannot be specified in OpenGL ES or - * WebGL. + * @requires_es_extension OpenGL ES 3.1 and extension + * @m_class{m-doc-external} [ANGLE_base_vertex_base_instance](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_base_vertex_base_instance.txt) + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} */ Mesh& setBaseInstance(UnsignedInt baseInstance) { _baseInstance = baseInstance; @@ -1068,10 +1074,8 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { void MAGNUM_GL_LOCAL bindVAO(); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 void drawInternal(Int count, Int baseVertex, Int instanceCount, UnsignedInt baseInstance, GLintptr indexOffset, Int indexStart, Int indexEnd); - #elif !defined(MAGNUM_TARGET_GLES2) - void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset, Int indexStart, Int indexEnd); #else void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset); #endif @@ -1133,6 +1137,36 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { void MAGNUM_GL_LOCAL unbindImplementationDefault(); void MAGNUM_GL_LOCAL unbindImplementationVAO(); + #ifdef MAGNUM_TARGET_GLES + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + #if defined(MAGNUM_TARGET_WEBGL) && __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 13915 + static void MAGNUM_GL_LOCAL drawElementsBaseVertexImplementationANGLE(GLenum mode, GLsizei count, GLenum type, const void* indices, GLint baseVertex); + #endif + static void MAGNUM_GL_LOCAL drawElementsBaseVertexImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLint); + #endif + + #ifndef MAGNUM_TARGET_GLES2 + #if defined(MAGNUM_TARGET_WEBGL) && __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 13915 + static void MAGNUM_GL_LOCAL drawRangeElementsBaseVertexImplementationANGLE(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices, GLint baseVertex); + #endif + static void MAGNUM_GL_LOCAL drawRangeElementsBaseVertexImplementationAssert(GLenum, GLuint, GLuint, GLsizei, GLenum, const void*, GLint); + + static void MAGNUM_GL_LOCAL drawArraysInstancedBaseInstanceImplementationAssert(GLenum, GLint, GLsizei, GLsizei, GLuint); + + #if !defined(MAGNUM_TARGET_WEBGL) || __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 13915 + static void MAGNUM_GL_LOCAL drawElementsInstancedBaseInstanceImplementationANGLE(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instanceCount, GLuint baseInstance); + #endif + static void MAGNUM_GL_LOCAL drawElementsInstancedBaseInstanceImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLsizei, GLuint); + + static void MAGNUM_GL_LOCAL drawElementsInstancedBaseVertexBaseInstanceImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLsizei, GLint, GLuint); + + #if defined(MAGNUM_TARGET_WEBGL) && __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 13915 + static void MAGNUM_GL_LOCAL drawElementsInstancedBaseVertexImplementationANGLE(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instanceCount, GLint baseVertex); + #endif + static void MAGNUM_GL_LOCAL drawElementsInstancedBaseVertexImplementationAssert(GLenum, GLsizei, GLenum, const void*, GLsizei, GLint); + #endif + #endif + /* _id, _primitive, _flags set from constructors */ GLuint _id; MeshPrimitive _primitive; @@ -1144,10 +1178,8 @@ class MAGNUM_GL_EXPORT Mesh: public AbstractObject { object is constructed using NoCreate). Also fits in the gap. */ bool _constructed{}; Int _count{}, _baseVertex{}, _instanceCount{1}; - #ifndef MAGNUM_TARGET_GLES - UnsignedInt _baseInstance{}; - #endif #ifndef MAGNUM_TARGET_GLES2 + UnsignedInt _baseInstance{}; UnsignedInt _indexStart{}, _indexEnd{}; #endif GLintptr _indexOffset{}; diff --git a/src/Magnum/GL/MeshView.cpp b/src/Magnum/GL/MeshView.cpp index 0dddaff5c..1b16ce9d2 100644 --- a/src/Magnum/GL/MeshView.cpp +++ b/src/Magnum/GL/MeshView.cpp @@ -26,6 +26,7 @@ #include "MeshView.h" #include +#include #include #include "Magnum/GL/AbstractShaderProgram.h" @@ -95,24 +96,16 @@ void MeshView::multiDrawImplementationDefault(Containers::ArrayView baseVertex{meshes.size()}; /* Gather the parameters */ - #ifndef MAGNUM_TARGET_GLES bool hasBaseVertex = false; - #endif std::size_t i = 0; for(MeshView& mesh: meshes) { - CORRADE_ASSERT(mesh._instanceCount == 1, "GL::MeshView::draw(): cannot draw multiple instanced meshes", ); + CORRADE_ASSERT(mesh._instanceCount == 1, "GL::AbstractShaderProgram::draw(): cannot draw multiple instanced meshes", ); count[i] = mesh._count; indices[i] = reinterpret_cast(mesh._indexOffset); baseVertex[i] = mesh._baseVertex; - if(mesh._baseVertex) { - #ifndef MAGNUM_TARGET_GLES - hasBaseVertex = true; - #else - CORRADE_ASSERT(!original._indexBuffer.id(), "GL::MeshView::draw(): desktop OpenGL is required for base vertex specification in indexed meshes", ); - #endif - } + if(mesh._baseVertex) hasBaseVertex = true; ++i; } @@ -131,14 +124,20 @@ void MeshView::multiDrawImplementationDefault(Containers::ArrayView= 20005 +void MeshView::multiDrawElementsBaseVertexImplementationANGLE(const GLenum mode, const GLsizei* const count, const GLenum type, const void* const* const indices, const GLsizei drawCount, const GLint* const baseVertex) { + /** @todo merge with the allocation in multiDrawImplementationDefault */ + Containers::ArrayView instanceCount; + Containers::ArrayView baseInstance; + Containers::ArrayTuple data{ + {Containers::NoInit, std::size_t(drawCount), instanceCount}, + {Containers::ValueInit, std::size_t(drawCount), baseInstance}, + }; + for(GLsizei& i: instanceCount) i = 1; + + glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE(mode, count, type, indices, instanceCount, baseVertex, baseInstance, drawCount); +} +#endif + +void MeshView::multiDrawElementsBaseVertexImplementationAssert(GLenum, const GLsizei*, GLenum, const void* const*, GLsizei, const GLint*) { + CORRADE_ASSERT_UNREACHABLE("GL::AbstractShaderProgram::draw(): no extension available for indexed mesh multi-draw with base vertex specification", ); +} +#endif + }} diff --git a/src/Magnum/GL/MeshView.h b/src/Magnum/GL/MeshView.h index 1ba06a250..7f1bfa5c4 100644 --- a/src/Magnum/GL/MeshView.h +++ b/src/Magnum/GL/MeshView.h @@ -134,8 +134,12 @@ class MAGNUM_GL_EXPORT MeshView { * @cpp 0 @ce. * @requires_gl32 Extension @gl_extension{ARB,draw_elements_base_vertex} * for indexed meshes - * @requires_gles32 Base vertex cannot be specified for indexed meshes - * in OpenGL ES 3.1 or WebGL. + * @requires_es_extension Extension @gl_extension{OES,draw_elements_base_vertex} + * or @gl_extension{EXT,draw_elements_base_vertex} for indexed + * meshes on OpenGL ES 3.1 and older + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} + * for indexed meshes */ MeshView& setBaseVertex(Int baseVertex) { _baseVertex = baseVertex; @@ -201,7 +205,7 @@ class MAGNUM_GL_EXPORT MeshView { return *this; } - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 /** @brief Base instance */ UnsignedInt baseInstance() const { return _baseInstance; } @@ -212,8 +216,10 @@ class MAGNUM_GL_EXPORT MeshView { * Ignored when calling @ref AbstractShaderProgram::drawTransformFeedback(). * Default is @cpp 0 @ce. * @requires_gl42 Extension @gl_extension{ARB,base_instance} - * @requires_gl Base instance cannot be specified in OpenGL ES or - * WebGL. + * @requires_es_extension OpenGL ES 3.1 and extension + * @m_class{m-doc-external} [ANGLE_base_vertex_base_instance](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_base_vertex_base_instance.txt) + * @requires_webgl_extension WebGL 2.0 and extension + * @webgl_extension{WEBGL,draw_instanced_base_vertex_base_instance} */ MeshView& setBaseInstance(UnsignedInt baseInstance) { _baseInstance = baseInstance; @@ -262,11 +268,18 @@ class MAGNUM_GL_EXPORT MeshView { static MAGNUM_GL_LOCAL void multiDrawImplementationFallback(Containers::ArrayView> meshes); #endif + #ifdef MAGNUM_TARGET_GLES + #if defined(MAGNUM_TARGET_WEBGL) && !defined(MAGNUM_TARGET_GLES2) && __EMSCRIPTEN_major__*10000 + __EMSCRIPTEN_minor__*100 + __EMSCRIPTEN_tiny__ >= 20005 + static MAGNUM_GL_LOCAL void multiDrawElementsBaseVertexImplementationANGLE(GLenum mode, const GLsizei* count, GLenum type, const void* const* indices, GLsizei drawCount, const GLint* baseVertex); + #endif + static MAGNUM_GL_LOCAL void multiDrawElementsBaseVertexImplementationAssert(GLenum, const GLsizei*, GLenum, const void* const*, GLsizei, const GLint*); + #endif + Containers::Reference _original; bool _countSet{}; Int _count{}, _baseVertex{}, _instanceCount{1}; - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 UnsignedInt _baseInstance{}; #endif GLintptr _indexOffset{}; diff --git a/src/Magnum/GL/Test/MeshGLTest.cpp b/src/Magnum/GL/Test/MeshGLTest.cpp index 2bba4708b..97dfee031 100644 --- a/src/Magnum/GL/Test/MeshGLTest.cpp +++ b/src/Magnum/GL/Test/MeshGLTest.cpp @@ -137,16 +137,38 @@ struct MeshGLTest: OpenGLTester { void unbindVAOBeforeEnteringExternalSection(); void bindScratchVaoWhenEnteringExternalSection(); - #ifndef MAGNUM_TARGET_GLES + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void setBaseVertex(); #endif + #ifdef MAGNUM_TARGET_GLES + void setBaseVertexNoExtensionAvailable(); + void setBaseVertexRangeNoExtensionAvailable(); + #endif void setInstanceCount(); - void setInstanceCountIndexed(); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 void setInstanceCountBaseInstance(); - void setInstanceCountBaseInstanceIndexed(); - void setInstanceCountBaseVertex(); - void setInstanceCountBaseVertexBaseInstance(); + #ifdef MAGNUM_TARGET_GLES + void setInstanceCountBaseInstanceNoExtensionAvailable(); + #endif + #endif + void setInstanceCountIndexed(); + #ifndef MAGNUM_TARGET_GLES2 + void setInstanceCountIndexedBaseInstance(); + #ifdef MAGNUM_TARGET_GLES + void setInstanceCountIndexedBaseInstanceNoExtensionAvailable(); + #endif + #endif + #ifndef MAGNUM_TARGET_GLES2 + void setInstanceCountIndexedBaseVertex(); + #endif + #ifdef MAGNUM_TARGET_GLES + void setInstanceCountIndexedBaseVertexNoExtensionAvailable(); + #endif + #ifndef MAGNUM_TARGET_GLES2 + void setInstanceCountIndexedBaseVertexBaseInstance(); + #ifdef MAGNUM_TARGET_GLES + void setInstanceCountIndexedBaseVertexBaseInstanceNoExtensionAvailable(); + #endif #endif void addVertexBufferInstancedFloat(); @@ -160,9 +182,13 @@ struct MeshGLTest: OpenGLTester { void multiDraw(); void multiDrawIndexed(); - #ifndef MAGNUM_TARGET_GLES + void multiDrawInstanced(); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void multiDrawBaseVertex(); #endif + #ifdef MAGNUM_TARGET_GLES + void multiDrawBaseVertexNoExtensionAvailable(); + #endif }; MeshGLTest::MeshGLTest() { @@ -259,16 +285,38 @@ MeshGLTest::MeshGLTest() { &MeshGLTest::unbindVAOBeforeEnteringExternalSection, &MeshGLTest::bindScratchVaoWhenEnteringExternalSection, - #ifndef MAGNUM_TARGET_GLES + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) &MeshGLTest::setBaseVertex, #endif + #ifdef MAGNUM_TARGET_GLES + &MeshGLTest::setBaseVertexNoExtensionAvailable, + &MeshGLTest::setBaseVertexRangeNoExtensionAvailable, + #endif &MeshGLTest::setInstanceCount, - &MeshGLTest::setInstanceCountIndexed, - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 &MeshGLTest::setInstanceCountBaseInstance, - &MeshGLTest::setInstanceCountBaseInstanceIndexed, - &MeshGLTest::setInstanceCountBaseVertex, - &MeshGLTest::setInstanceCountBaseVertexBaseInstance, + #ifdef MAGNUM_TARGET_GLES + &MeshGLTest::setInstanceCountBaseInstanceNoExtensionAvailable, + #endif + #endif + &MeshGLTest::setInstanceCountIndexed, + #ifndef MAGNUM_TARGET_GLES2 + &MeshGLTest::setInstanceCountIndexedBaseInstance, + #ifdef MAGNUM_TARGET_GLES + &MeshGLTest::setInstanceCountIndexedBaseInstanceNoExtensionAvailable, + #endif + #endif + #ifndef MAGNUM_TARGET_GLES2 + &MeshGLTest::setInstanceCountIndexedBaseVertex, + #endif + #ifdef MAGNUM_TARGET_GLES + &MeshGLTest::setInstanceCountIndexedBaseVertexNoExtensionAvailable, + #endif + #ifndef MAGNUM_TARGET_GLES2 + &MeshGLTest::setInstanceCountIndexedBaseVertexBaseInstance, + #ifdef MAGNUM_TARGET_GLES + &MeshGLTest::setInstanceCountIndexedBaseVertexBaseInstanceNoExtensionAvailable, + #endif #endif &MeshGLTest::addVertexBufferInstancedFloat, @@ -282,8 +330,12 @@ MeshGLTest::MeshGLTest() { &MeshGLTest::multiDraw, &MeshGLTest::multiDrawIndexed, - #ifndef MAGNUM_TARGET_GLES - &MeshGLTest::multiDrawBaseVertex + &MeshGLTest::multiDrawInstanced, + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + &MeshGLTest::multiDrawBaseVertex, + #endif + #ifdef MAGNUM_TARGET_GLES + &MeshGLTest::multiDrawBaseVertexNoExtensionAvailable #endif }); } @@ -1966,7 +2018,6 @@ const Float indexedVertexData[] = { 1.0f, -0.5f }; -#ifndef MAGNUM_TARGET_GLES const Float indexedVertexDataBaseVertex[] = { 0.0f, 0.0f, /* Offset */ @@ -1995,7 +2046,6 @@ const Float indexedVertexDataBaseVertex[] = { 0.4f, 0.0f, -0.9f, 1.0f, -0.5f }; -#endif #ifndef MAGNUM_TARGET_GLES2 constexpr Color4ub indexedResult{64 + 15 + 97, 17 + 164 + 28, 56 + 17, 255}; @@ -2485,10 +2535,19 @@ void MeshGLTest::bindScratchVaoWhenEnteringExternalSection() { #endif } -#ifndef MAGNUM_TARGET_GLES +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void MeshGLTest::setBaseVertex() { + #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::draw_elements_base_vertex::string() + std::string(" is not available.")); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!Context::current().isExtensionSupported() && + !Context::current().isExtensionSupported()) + CORRADE_SKIP(std::string{"Neither "} + Extensions::OES::draw_elements_base_vertex::string() + " nor " + Extensions::EXT::draw_elements_base_vertex::string() + " is available."); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is not available."}); + #endif Buffer vertices; vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); @@ -2513,6 +2572,72 @@ void MeshGLTest::setBaseVertex() { } #endif +#ifdef MAGNUM_TARGET_GLES +void MeshGLTest::setBaseVertexNoExtensionAvailable() { + #ifndef MAGNUM_TARGET_WEBGL + if(Context::current().isVersionSupported(Version::GLES320)) + CORRADE_SKIP("OpenGL ES 3.2 is available."); + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::draw_elements_base_vertex::string() + std::string{" is available."}); + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::OES::draw_elements_base_vertex::string() + std::string{" is available."}); + #elif !defined(MAGNUM_TARGET_GLES2) + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is available."}); + #endif + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices{Buffer::TargetHint::ElementArray}; + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setCount(3) + .setBaseVertex(1) + .setIndexBuffer(indices, 0, MeshIndexType::UnsignedShort); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw(mesh); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): no extension available for indexed mesh draw with base vertex specification\n"); + #else + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): indexed mesh draw with base vertex specification possible only since WebGL 2.0\n"); + #endif +} + +void MeshGLTest::setBaseVertexRangeNoExtensionAvailable() { + #ifndef MAGNUM_TARGET_WEBGL + if(Context::current().isVersionSupported(Version::GLES320)) + CORRADE_SKIP("OpenGL ES 3.2 is available."); + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::draw_elements_base_vertex::string() + std::string{" is available."}); + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::OES::draw_elements_base_vertex::string() + std::string{" is available."}); + #elif !defined(MAGNUM_TARGET_GLES2) + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is available."}); + #endif + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices{Buffer::TargetHint::ElementArray}; + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setCount(3) + .setBaseVertex(1) + .setIndexBuffer(indices, 0, MeshIndexType::UnsignedShort, 0, 2); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw(mesh); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): no extension available for indexed mesh draw with base vertex specification\n"); + #else + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): indexed mesh draw with base vertex specification possible only since WebGL 2.0\n"); + #endif +} +#endif + void MeshGLTest::setInstanceCount() { /* Verbatim copy of addVertexBufferFloat() with added extension check and setInstanceCount() call. It would just render three times the same @@ -2561,6 +2686,71 @@ void MeshGLTest::setInstanceCount() { CORRADE_COMPARE(value, 96); } +#ifndef MAGNUM_TARGET_GLES2 +void MeshGLTest::setInstanceCountBaseInstance() { + /* Verbatim copy of setInstanceCount() with additional extension check and + setBaseInstance() call. It would just render three times the same + value. I'm too lazy to invent proper test case, so I'll just check that + it didn't generate any error and rendered something */ + + #ifndef MAGNUM_TARGET_GLES + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ARB::base_instance::string() + std::string(" is not available.")); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ANGLE::base_vertex_base_instance::string() + std::string{" is not available."}); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is not available."}); + #endif + + typedef Attribute<0, Float> Attribute; + + const Float data[] = { 0.0f, -0.7f, Math::unpack(96) }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setBaseVertex(1) + .setInstanceCount(3) + .setBaseInstance(72) + .addVertexBuffer(buffer, 4, Attribute()); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + const auto value = Checker(FloatShader("float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"), + RenderbufferFormat::RGBA8, + mesh).get(PixelFormat::RGBA, PixelType::UnsignedByte); + + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE(value, 96); +} + +#ifdef MAGNUM_TARGET_GLES +void MeshGLTest::setInstanceCountBaseInstanceNoExtensionAvailable() { + #ifndef MAGNUM_TARGET_WEBGL + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ANGLE::base_vertex_base_instance::string() + std::string{" is available."}); + #else + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is available."}); + #endif + + Mesh mesh; + mesh.setCount(3) + .setInstanceCount(2) + .setBaseInstance(1); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw(mesh); + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): no extension available for instanced mesh draw with base instance specification\n"); +} +#endif +#endif + void MeshGLTest::setInstanceCountIndexed() { /* Verbatim copy of setIndexBuffer() with added extension check and setInstanceCount() call. It would just render three times the same @@ -2611,50 +2801,25 @@ void MeshGLTest::setInstanceCountIndexed() { CORRADE_COMPARE(value, indexedResult); } -#ifndef MAGNUM_TARGET_GLES -void MeshGLTest::setInstanceCountBaseInstance() { - /* Verbatim copy of setInstanceCount() with additional extension check and - setBaseInstance() call. It would just render three times the same - value. I'm too lazy to invent proper test case, so I'll just check that - it didn't generate any error and rendered something */ - - if(!Context::current().isExtensionSupported()) - CORRADE_SKIP(Extensions::ARB::draw_instanced::string() + std::string(" is not available.")); - if(!Context::current().isExtensionSupported()) - CORRADE_SKIP(Extensions::ARB::base_instance::string() + std::string(" is not available.")); - - typedef Attribute<0, Float> Attribute; - - const Float data[] = { 0.0f, -0.7f, Math::unpack(96) }; - Buffer buffer; - buffer.setData(data, BufferUsage::StaticDraw); - - Mesh mesh; - mesh.setBaseVertex(1) - .setInstanceCount(3) - .setBaseInstance(72) - .addVertexBuffer(buffer, 4, Attribute()); - - MAGNUM_VERIFY_NO_GL_ERROR(); - - const auto value = Checker(FloatShader("float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"), - RenderbufferFormat::RGBA8, - mesh).get(PixelFormat::RGBA, PixelType::UnsignedByte); - - MAGNUM_VERIFY_NO_GL_ERROR(); - CORRADE_COMPARE(value, 96); -} - -void MeshGLTest::setInstanceCountBaseInstanceIndexed() { +#ifndef MAGNUM_TARGET_GLES2 +void MeshGLTest::setInstanceCountIndexedBaseInstance() { /* Verbatim copy of setInstanceCountIndexed() with additional extension check and setBaseInstance() call. It would just render three times the same value. I'm too lazy to invent proper test case, so I'll just check that it didn't generate any error and rendered something */ + #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::draw_instanced::string() + std::string(" is not available.")); if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::base_instance::string() + std::string(" is not available.")); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ANGLE::base_vertex_base_instance::string() + std::string{" is not available."}); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is not available."}); + #endif Buffer vertices; vertices.setData(indexedVertexData, BufferUsage::StaticDraw); @@ -2679,16 +2844,54 @@ void MeshGLTest::setInstanceCountBaseInstanceIndexed() { CORRADE_COMPARE(value, indexedResult); } -void MeshGLTest::setInstanceCountBaseVertex() { +#ifdef MAGNUM_TARGET_GLES +void MeshGLTest::setInstanceCountIndexedBaseInstanceNoExtensionAvailable() { + #ifndef MAGNUM_TARGET_WEBGL + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ANGLE::base_vertex_base_instance::string() + std::string{" is available."}); + #else + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is available."}); + #endif + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices{Buffer::TargetHint::ElementArray}; + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setCount(3) + .setInstanceCount(2) + .setBaseInstance(1) + .setIndexBuffer(indices, 0, MeshIndexType::UnsignedShort); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw(mesh); + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): no extension available for instanced indexed mesh draw with base instance specification\n"); +} +#endif +#endif + +#ifndef MAGNUM_TARGET_GLES2 +void MeshGLTest::setInstanceCountIndexedBaseVertex() { /* Verbatim copy of setBaseVertex() with additional extension check and setInstanceCount() call. It would just render three times the same value. I'm too lazy to invent proper test case, so I'll just check that it didn't generate any error and rendered something */ + #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::draw_instanced::string() + std::string(" is not available.")); if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::draw_elements_base_vertex::string() + std::string(" is not available.")); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!Context::current().isExtensionSupported() && + !Context::current().isExtensionSupported()) + CORRADE_SKIP(std::string{"Neither "} + Extensions::OES::draw_elements_base_vertex::string() + " nor " + Extensions::EXT::draw_elements_base_vertex::string() + " is available."); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is not available."}); + #endif Buffer vertices; vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); @@ -2712,19 +2915,66 @@ void MeshGLTest::setInstanceCountBaseVertex() { MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE(value, indexedResult); } +#endif + +#ifdef MAGNUM_TARGET_GLES +void MeshGLTest::setInstanceCountIndexedBaseVertexNoExtensionAvailable() { + #ifndef MAGNUM_TARGET_GLES2 + #ifndef MAGNUM_TARGET_WEBGL + if(Context::current().isVersionSupported(Version::GLES320)) + CORRADE_SKIP("OpenGL ES 3.2 is available."); + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::draw_elements_base_vertex::string() + std::string{" is available."}); + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::OES::draw_elements_base_vertex::string() + std::string{" is available."}); + #else + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is available."}); + #endif + #endif -void MeshGLTest::setInstanceCountBaseVertexBaseInstance() { + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices{Buffer::TargetHint::ElementArray}; + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setCount(3) + .setInstanceCount(2) + .setBaseVertex(1) + .setIndexBuffer(indices, 0, MeshIndexType::UnsignedShort); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw(mesh); + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): no extension available for instanced indexed mesh draw with base vertex specification\n"); + #else + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): instanced indexed mesh draw with base vertex specification possible only since OpenGL ES 3.0\n"); + #endif +} +#endif + +#ifndef MAGNUM_TARGET_GLES2 +void MeshGLTest::setInstanceCountIndexedBaseVertexBaseInstance() { /* Verbatim copy of setInstanceCountBaseVertex() with added extension check and setBaseInstance() call. It would just render three times the same value. I'm too lazy to invent proper test case, so I'll just check that it didn't generate any error and rendered something */ + #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::draw_instanced::string() + std::string(" is not available.")); if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::draw_elements_base_vertex::string() + std::string(" is not available.")); if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::base_instance::string() + std::string(" is not available.")); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ANGLE::base_vertex_base_instance::string() + std::string{" is not available."}); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is not available."}); + #endif Buffer vertices; vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); @@ -2749,6 +2999,38 @@ void MeshGLTest::setInstanceCountBaseVertexBaseInstance() { MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE(value, indexedResult); } + +#ifdef MAGNUM_TARGET_GLES +void MeshGLTest::setInstanceCountIndexedBaseVertexBaseInstanceNoExtensionAvailable() { + #ifndef MAGNUM_TARGET_WEBGL + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::ANGLE::base_vertex_base_instance::string() + std::string{" is available."}); + #else + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::draw_instanced_base_vertex_base_instance::string() + std::string{" is available."}); + #endif + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices{Buffer::TargetHint::ElementArray}; + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setCount(3) + .setInstanceCount(2) + .setBaseVertex(1) + .setBaseInstance(1) + .setIndexBuffer(indices, 0, MeshIndexType::UnsignedShort); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw(mesh); + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): no extension available for instanced indexed mesh draw with base vertex and base instance specification\n"); + #else + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): instanced indexed mesh draw with base vertex specification possible only since OpenGL 3.0\n"); + #endif +} +#endif #endif void MeshGLTest::addVertexBufferInstancedFloat() { @@ -3079,10 +3361,31 @@ void MeshGLTest::multiDrawIndexed() { CORRADE_COMPARE(value, indexedResult); } -#ifndef MAGNUM_TARGET_GLES +void MeshGLTest::multiDrawInstanced() { + Mesh mesh; + MeshView view{mesh}; + view.setCount(3) + .setInstanceCount(2); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw({view, view}); + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): cannot draw multiple instanced meshes\n"); +} + +#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) void MeshGLTest::multiDrawBaseVertex() { + #ifndef MAGNUM_TARGET_GLES if(!Context::current().isExtensionSupported()) CORRADE_SKIP(Extensions::ARB::draw_elements_base_vertex::string() + std::string(" is not available.")); + #elif !defined(MAGNUM_TARGET_WEBGL) + if(!Context::current().isExtensionSupported() && + !Context::current().isExtensionSupported()) + CORRADE_SKIP(std::string{"Neither "} + Extensions::OES::draw_elements_base_vertex::string() + " nor " + Extensions::EXT::draw_elements_base_vertex::string() + " is available."); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::multi_draw_instanced_base_vertex_base_instance::string() + std::string{" is not available."}); + #endif Buffer vertices; vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw); @@ -3106,6 +3409,53 @@ void MeshGLTest::multiDrawBaseVertex() { } #endif +#ifdef MAGNUM_TARGET_GLES +void MeshGLTest::multiDrawBaseVertexNoExtensionAvailable() { + #ifdef MAGNUM_TARGET_GLES + /* If the multidraw extensions aren't available, we can't test this assert, + only the assert in the fallback path, which is already tested above. */ + #ifndef MAGNUM_TARGET_WEBGL + if(!Context::current().isExtensionSupported() && + !Context::current().isExtensionSupported()) + CORRADE_SKIP(std::string{"Neither "} + Extensions::EXT::multi_draw_arrays::string() + " nor " + Extensions::ANGLE::multi_draw::string() + " is available."); + #else + if(!Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::multi_draw::string() + std::string{" is not available."}); + #endif + #endif + + #ifndef MAGNUM_TARGET_WEBGL + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::EXT::draw_elements_base_vertex::string() + std::string{" is available."}); + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::OES::draw_elements_base_vertex::string() + std::string{" is available."}); + #elif !defined(MAGNUM_TARGET_GLES2) + if(Context::current().isExtensionSupported()) + CORRADE_SKIP(Extensions::WEBGL::multi_draw_instanced_base_vertex_base_instance::string() + std::string{" is available."}); + #endif + + constexpr UnsignedShort indexData[] = { 2, 1, 0 }; + Buffer indices{Buffer::TargetHint::ElementArray}; + indices.setData(indexData, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setIndexBuffer(indices, 0, MeshIndexType::UnsignedShort); + + MeshView view{mesh}; + view.setCount(3) + .setBaseVertex(1); + + std::ostringstream out; + Error redirectError{&out}; + MultipleShader{}.draw({view, view}); + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): no extension available for indexed mesh multi-draw with base vertex specification\n"); + #else + CORRADE_COMPARE(out.str(), "GL::AbstractShaderProgram::draw(): indexed mesh multi-draw with base vertex specification possible only since WebGL 2.0\n"); + #endif +} +#endif + }}}} CORRADE_TEST_MAIN(Magnum::GL::Test::MeshGLTest)