diff --git a/doc/opengl-mapping.dox b/doc/opengl-mapping.dox index 7c82f8f40..dae5de8ee 100644 --- a/doc/opengl-mapping.dox +++ b/doc/opengl-mapping.dox @@ -247,7 +247,7 @@ OpenGL function | Matching API @fn_gl{ValidateProgramPipeline} | | @fn_gl{VertexAttrib} | not supported (@ref opengl-unsupported "details") @fn_gl{VertexAttribBinding} | | -@fn_gl{VertexAttribDivisor} | | +@fn_gl{VertexAttribDivisor}, \n @fn_gl_extension{VertexArrayVertexAttribDivisor,EXT,direct_state_access} | @ref Mesh::addVertexBufferInstanced() @fn_gl{VertexAttribFormat} | | @fn_gl{VertexAttribPointer}, \n @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access} | @ref Mesh::addVertexBuffer() @fn_gl{VertexBindingDivisor} | | diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index cc16ada03..bfd5ea51e 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -107,7 +107,7 @@ following: %Extension | Status -------------------------------------------- | ------ -@extension{ARB,instanced_arrays} | | +@extension{ARB,instanced_arrays} | done @extension{ARB,blend_func_extended} | missing limit query @extension{ARB,explicit_attrib_location} | done (shading language only) @extension{ARB,occlusion_query2} | done @@ -243,7 +243,7 @@ supported. -------------------------------------------- | ------ @es_extension{ANGLE,framebuffer_blit} | done @es_extension{ANGLE,framebuffer_multisample} | done -@es_extension{ANGLE,instanced_arrays} | missing vertex attrib divisor +@es_extension{ANGLE,instanced_arrays} | done @es_extension{ANGLE,depth_texture} | done @es_extension{APPLE,framebuffer_multisample} | done (ES 3.0 subset) @es_extension{APPLE,texture_max_level} | done @@ -257,6 +257,7 @@ supported. @es_extension{EXT,texture_rg} | done @es_extension{EXT,texture_storage} | done @es_extension{EXT,map_buffer_range} | done +@es_extension{EXT,instanced_arrays} | done @es_extension2{EXT,draw_instanced,draw_instanced} | done @es_extension{NV,draw_buffers} | done @es_extension{NV,fbo_color_attachments} | done @@ -264,6 +265,7 @@ supported. @es_extension{NV,draw_instanced} | done @es_extension{NV,framebuffer_blit} | done @es_extension{NV,framebuffer_multisample} | done +@es_extension{NV,instanced_arrays} | done @es_extension{NV,shadow_samplers_array} | done (shading language only) @es_extension{NV,shadow_samplers_cube} | done (shading language only) @es_extension{OES,depth24} | done diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index c8847bc3d..e835284ae 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -226,6 +226,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,EXT,texture_rg), _extension(GL,EXT,texture_storage), _extension(GL,EXT,map_buffer_range), + _extension(GL,EXT,instanced_arrays), _extension(GL,EXT,draw_instanced), _extension(GL,NV,draw_buffers), _extension(GL,NV,fbo_color_attachments), @@ -233,6 +234,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,NV,draw_instanced), _extension(GL,NV,framebuffer_blit), _extension(GL,NV,framebuffer_multisample), + _extension(GL,NV,instanced_arrays), _extension(GL,NV,shadow_samplers_array), _extension(GL,NV,shadow_samplers_cube), _extension(GL,OES,depth24), diff --git a/src/Magnum/Extensions.h b/src/Magnum/Extensions.h index c41039c9f..dc4dc0cab 100644 --- a/src/Magnum/Extensions.h +++ b/src/Magnum/Extensions.h @@ -255,6 +255,7 @@ namespace GL { #endif _extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150 #ifdef MAGNUM_TARGET_GLES2 + _extension(GL,EXT,instanced_arrays, GLES200, GLES300) // #156 _extension(GL,EXT,draw_instanced, GLES200, GLES300) // #157 #endif #ifndef MAGNUM_TARGET_GLES2 @@ -276,6 +277,7 @@ namespace GL { _extension(GL,NV,draw_instanced, GLES200, GLES300) // #141 _extension(GL,NV,framebuffer_blit, GLES200, GLES300) // #142 _extension(GL,NV,framebuffer_multisample, GLES200, GLES300) // #143 + _extension(GL,NV,instanced_arrays, GLES200, GLES300) // #145 _extension(GL,NV,shadow_samplers_array, GLES200, GLES300) // #146 _extension(GL,NV,shadow_samplers_cube, GLES200, GLES300) // #147 #endif diff --git a/src/Magnum/Implementation/MeshState.cpp b/src/Magnum/Implementation/MeshState.cpp index b7946673f..66d56fb57 100644 --- a/src/Magnum/Implementation/MeshState.cpp +++ b/src/Magnum/Implementation/MeshState.cpp @@ -117,6 +117,24 @@ MeshState::MeshState(Context& context, std::vector& extensions): cu drawArraysInstancedImplementation = nullptr; drawElementsInstancedImplementation = nullptr; } + + /* Instanced arrays implementation on ES2 */ + if(context.isExtensionSupported()) { + /* Extension added above */ + + vertexAttribDivisorImplementation = &Mesh::vertexAttribDivisorImplementationANGLE; + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::EXT::instanced_arrays::string()); + + vertexAttribDivisorImplementation = &Mesh::vertexAttribDivisorImplementationEXT; + + } else if(context.isExtensionSupported()) { + extensions.push_back(Extensions::GL::NV::instanced_arrays::string()); + + vertexAttribDivisorImplementation = &Mesh::vertexAttribDivisorImplementationNV; + + } else vertexAttribDivisorImplementation = nullptr; #endif } diff --git a/src/Magnum/Implementation/MeshState.h b/src/Magnum/Implementation/MeshState.h index f91dd4e5c..2c39037fc 100644 --- a/src/Magnum/Implementation/MeshState.h +++ b/src/Magnum/Implementation/MeshState.h @@ -44,6 +44,9 @@ struct MeshState { void(Mesh::*attributeLPointerImplementation)(const Mesh::LongAttribute&); #endif #endif + #ifdef MAGNUM_TARGET_GLES2 + void(Mesh::*vertexAttribDivisorImplementation)(GLuint, GLuint); + #endif void(Mesh::*bindIndexBufferImplementation)(Buffer&); void(Mesh::*bindImplementation)(); void(Mesh::*unbindImplementation)(); diff --git a/src/Magnum/Implementation/setupDriverWorkarounds.cpp b/src/Magnum/Implementation/setupDriverWorkarounds.cpp index 08f311c96..e909bf48f 100644 --- a/src/Magnum/Implementation/setupDriverWorkarounds.cpp +++ b/src/Magnum/Implementation/setupDriverWorkarounds.cpp @@ -77,6 +77,7 @@ void Context::setupDriverWorkarounds() { #endif _setRequiredVersion(GL::EXT::texture_storage, None); _setRequiredVersion(GL::EXT::map_buffer_range, None); + _setRequiredVersion(GL::EXT::instanced_arrays, None); _setRequiredVersion(GL::EXT::draw_instanced, None); _setRequiredVersion(GL::NV::draw_buffers, None); _setRequiredVersion(GL::NV::fbo_color_attachments, None); // ?? @@ -84,6 +85,7 @@ void Context::setupDriverWorkarounds() { _setRequiredVersion(GL::NV::draw_instanced, None); _setRequiredVersion(GL::NV::framebuffer_blit, None); _setRequiredVersion(GL::NV::framebuffer_multisample, None); + _setRequiredVersion(GL::NV::instanced_arrays, None); _setRequiredVersion(GL::OES::texture_3D, None); _setRequiredVersion(GL::OES::vertex_array_object, None); #endif diff --git a/src/Magnum/Mesh.cpp b/src/Magnum/Mesh.cpp index 1c9ee808d..219b004ff 100644 --- a/src/Magnum/Mesh.cpp +++ b/src/Magnum/Mesh.cpp @@ -348,6 +348,7 @@ void Mesh::attributePointerImplementationVAO(const Attribute& attribute) { void Mesh::attributePointerImplementationDSA(const Attribute& attribute) { glEnableVertexArrayAttribEXT(_id, attribute.location); glVertexArrayVertexAttribOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.offset); + if(attribute.divisor) glVertexArrayVertexAttribDivisorEXT(_id, attribute.location, attribute.divisor); } #endif @@ -355,6 +356,13 @@ void Mesh::vertexAttribPointer(const Attribute& attribute) { glEnableVertexAttribArray(attribute.location); attribute.buffer->bind(Buffer::Target::Array); glVertexAttribPointer(attribute.location, attribute.size, attribute.type, attribute.normalized, attribute.stride, reinterpret_cast(attribute.offset)); + if(attribute.divisor) { + #ifndef MAGNUM_TARGET_GLES2 + glVertexAttribDivisor(attribute.location, attribute.divisor); + #else + (this->*Context::current()->state().mesh->vertexAttribDivisorImplementation)(attribute.location, attribute.divisor); + #endif + } } #ifndef MAGNUM_TARGET_GLES2 @@ -375,6 +383,7 @@ void Mesh::attributePointerImplementationVAO(const IntegerAttribute& attribute) void Mesh::attributePointerImplementationDSA(const IntegerAttribute& attribute) { glEnableVertexArrayAttribEXT(_id, attribute.location); glVertexArrayVertexAttribIOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); + if(attribute.divisor) glVertexArrayVertexAttribDivisorEXT(_id, attribute.location, attribute.divisor); } #endif @@ -382,6 +391,7 @@ void Mesh::vertexAttribPointer(const IntegerAttribute& attribute) { glEnableVertexAttribArray(attribute.location); attribute.buffer->bind(Buffer::Target::Array); glVertexAttribIPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); + if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor); } #endif @@ -402,12 +412,37 @@ void Mesh::attributePointerImplementationVAO(const LongAttribute& attribute) { void Mesh::attributePointerImplementationDSA(const LongAttribute& attribute) { glEnableVertexArrayAttribEXT(_id, attribute.location); glVertexArrayVertexAttribLOffsetEXT(_id, attribute.buffer->id(), attribute.location, attribute.size, attribute.type, attribute.stride, attribute.offset); + if(attribute.divisor) glVertexArrayVertexAttribDivisorEXT(_id, attribute.location, attribute.divisor); } void Mesh::vertexAttribPointer(const LongAttribute& attribute) { glEnableVertexAttribArray(attribute.location); attribute.buffer->bind(Buffer::Target::Array); glVertexAttribLPointer(attribute.location, attribute.size, attribute.type, attribute.stride, reinterpret_cast(attribute.offset)); + if(attribute.divisor) glVertexAttribDivisor(attribute.location, attribute.divisor); +} +#endif + +#ifdef MAGNUM_TARGET_GLES2 +void Mesh::vertexAttribDivisorImplementationANGLE(const GLuint index, const GLuint divisor) { + //glVertexAttribDivisorANGLE(index, divisor); + CORRADE_INTERNAL_ASSERT(false); + static_cast(index); + static_cast(divisor); +} + +void Mesh::vertexAttribDivisorImplementationEXT(const GLuint index, const GLuint divisor) { + //glVertexAttribDivisorEXT(index, divisor); + CORRADE_INTERNAL_ASSERT(false); + static_cast(index); + static_cast(divisor); +} + +void Mesh::vertexAttribDivisorImplementationNV(const GLuint index, const GLuint divisor) { + //glVertexAttribDivisorNV(index, divisor); + CORRADE_INTERNAL_ASSERT(false); + static_cast(index); + static_cast(divisor); } #endif diff --git a/src/Magnum/Mesh.h b/src/Magnum/Mesh.h index 81788c55e..50c5d7d3b 100644 --- a/src/Magnum/Mesh.h +++ b/src/Magnum/Mesh.h @@ -669,7 +669,34 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { * if @extension{APPLE,vertex_array_object} is available */ template inline Mesh& addVertexBuffer(Buffer& buffer, GLintptr offset, const T&... attributes) { - addVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), attributes...); + addVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), 0, attributes...); + return *this; + } + + /** + * @brief Add instanced vertex buffer + * @return Reference to self (for method chaining) + * + * Similar to the above function, the @p divisor parameter specifies + * number of instances that will pass until new data are fetched from + * the buffer. Setting it to `0` is equivalent to calling + * @ref addVertexBuffer(). + * @see @ref maxVertexAttributes(), @ref setPrimitive(), + * @ref setCount(), @ref setInstanceCount(), @ref setBaseInstance(), + * @fn_gl{BindVertexArray}, @fn_gl{EnableVertexAttribArray}, + * @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer}, + * @fn_gl{VertexAttribDivisor} or + * @fn_gl_extension{EnableVertexArrayAttrib,EXT,direct_state_access}, + * @fn_gl_extension{VertexArrayVertexAttribOffset,EXT,direct_state_access}, + * @fn_gl_extension{VertexArrayVertexAttribDivisor,EXT,direct_state_access} + * if @extension{APPLE,vertex_array_object} is available + * @requires_gl33 %Extension @extension{ARB,instanced_arrays} + * @requires_gles30 %Extension @es_extension{ANGLE,instanced_arrays}, + * @es_extension{EXT,instanced_arrays} or + * @es_extension{NV,instanced_arrays} in OpenGL ES 2.0. + */ + template inline Mesh& addVertexBufferInstanced(Buffer& buffer, UnsignedInt divisor, GLintptr offset, const T&... attributes) { + addVertexBufferInternal(buffer, offset, strideOfInterleaved(attributes...), divisor, attributes...); return *this; } @@ -773,6 +800,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { bool normalized; GLintptr offset; GLsizei stride; + GLuint divisor; }; #ifndef MAGNUM_TARGET_GLES2 @@ -783,6 +811,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLenum type; GLintptr offset; GLsizei stride; + GLuint divisor; }; #ifndef MAGNUM_TARGET_GLES @@ -793,6 +822,7 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLenum type; GLintptr offset; GLsizei stride; + GLuint divisor; }; #endif #endif @@ -808,19 +838,19 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { static GLsizei strideOfInterleaved() { return 0; } /* Adding interleaved vertex attributes */ - template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { - addVertexAttribute(buffer, attribute, offset, stride); + template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLuint divisor, const AbstractShaderProgram::Attribute& attribute, const U&... attributes) { + addVertexAttribute(buffer, attribute, offset, stride, divisor); /* Add size of this attribute to offset for next attribute */ - addVertexBufferInternal(buffer, offset+attribute.vectorSize()*AbstractShaderProgram::Attribute::VectorCount, stride, attributes...); + addVertexBufferInternal(buffer, offset+attribute.vectorSize()*AbstractShaderProgram::Attribute::VectorCount, stride, divisor, attributes...); } - template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLintptr gap, const T&... attributes) { + template void addVertexBufferInternal(Buffer& buffer, GLintptr offset, GLsizei stride, GLuint divisor, GLintptr gap, const T&... attributes) { /* Add the gap to offset for next attribute */ - addVertexBufferInternal(buffer, offset+gap, stride, attributes...); + addVertexBufferInternal(buffer, offset+gap, stride, divisor, attributes...); } - void addVertexBufferInternal(Buffer&, GLsizei, GLintptr) {} + void addVertexBufferInternal(Buffer&, GLsizei, GLuint, GLintptr) {} - template void addVertexAttribute(typename std::enable_if::ScalarType, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template void addVertexAttribute(typename std::enable_if::ScalarType, Float>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride, GLuint divisor) { for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute::VectorCount; ++i) attributePointerInternal(Attribute{ &buffer, @@ -829,24 +859,26 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLenum(attribute.dataType()), bool(attribute.dataOptions() & AbstractShaderProgram::Attribute::DataOption::Normalized), GLintptr(offset+i*attribute.vectorSize()), - stride + stride, + divisor }); } #ifndef MAGNUM_TARGET_GLES2 - template void addVertexAttribute(typename std::enable_if::ScalarType>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template void addVertexAttribute(typename std::enable_if::ScalarType>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride, GLuint divisor) { attributePointerInternal(IntegerAttribute{ &buffer, location, GLint(attribute.components()), GLenum(attribute.dataType()), offset, - stride + stride, + divisor }); } #ifndef MAGNUM_TARGET_GLES - template void addVertexAttribute(typename std::enable_if::ScalarType, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template void addVertexAttribute(typename std::enable_if::ScalarType, Double>::value, Buffer&>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride, GLuint divisor) { for(UnsignedInt i = 0; i != AbstractShaderProgram::Attribute::VectorCount; ++i) attributePointerInternal(LongAttribute{ &buffer, @@ -854,7 +886,8 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { GLint(attribute.components()), GLenum(attribute.dataType()), GLintptr(offset+i*attribute.vectorSize()), - stride + stride, + divisor }); } #endif @@ -902,6 +935,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject { void MAGNUM_LOCAL vertexAttribPointer(const LongAttribute& attribute); #endif + #ifdef MAGNUM_TARGET_GLES2 + void MAGNUM_LOCAL vertexAttribDivisorImplementationANGLE(GLuint index, GLuint divisor); + void MAGNUM_LOCAL vertexAttribDivisorImplementationEXT(GLuint index, GLuint divisor); + void MAGNUM_LOCAL vertexAttribDivisorImplementationNV(GLuint index, GLuint divisor); + #endif + void MAGNUM_LOCAL bindIndexBufferImplementationDefault(Buffer&); void MAGNUM_LOCAL bindIndexBufferImplementationVAO(Buffer& buffer); diff --git a/src/Magnum/Test/MeshGLTest.cpp b/src/Magnum/Test/MeshGLTest.cpp index 28f9bde6b..3248676fb 100644 --- a/src/Magnum/Test/MeshGLTest.cpp +++ b/src/Magnum/Test/MeshGLTest.cpp @@ -118,6 +118,14 @@ class MeshGLTest: public AbstractOpenGLTester { void setInstanceCountBaseVertex(); void setInstanceCountBaseVertexBaseInstance(); #endif + + void addVertexBufferInstancedFloat(); + #ifndef MAGNUM_TARGET_GLES2 + void addVertexBufferInstancedInteger(); + #endif + #ifndef MAGNUM_TARGET_GLES + void addVertexBufferInstancedDouble(); + #endif }; MeshGLTest::MeshGLTest() { @@ -191,7 +199,15 @@ MeshGLTest::MeshGLTest() { &MeshGLTest::setInstanceCountBaseInstance, &MeshGLTest::setInstanceCountBaseInstanceIndexed, &MeshGLTest::setInstanceCountBaseVertex, - &MeshGLTest::setInstanceCountBaseVertexBaseInstance + &MeshGLTest::setInstanceCountBaseVertexBaseInstance, + #endif + + &MeshGLTest::addVertexBufferInstancedFloat, + #ifndef MAGNUM_TARGET_GLES2 + &MeshGLTest::addVertexBufferInstancedInteger, + #endif + #ifndef MAGNUM_TARGET_GLES + &MeshGLTest::addVertexBufferInstancedDouble #endif }); } @@ -1538,6 +1554,121 @@ void MeshGLTest::setInstanceCountBaseVertexBaseInstance() { } #endif +void MeshGLTest::addVertexBufferInstancedFloat() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::instanced_arrays::string() + std::string(" is not available.")); + #elif defined(MAGNUM_TARGET_GLES2) + if(!Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported()) + CORRADE_SKIP("Required instancing extension is not available."); + if(!Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported() && !Context::current()->isExtensionSupported()) + CORRADE_SKIP("Required drawing extension is not available."); + #endif + + typedef AbstractShaderProgram::Attribute<0, Float> Attribute; + + const Float data[] = { + 0.0f, /* Offset */ + /* Base vertex is ignored for instanced arrays */ + -0.7f, /* First instance */ + 0.3f, /* Second instance */ + Math::normalize(96) /* Third instance */ + }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBufferInstanced(buffer, 1, 4, Attribute{}); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(FloatShader("float", "vec4(valueInterpolated, 0.0, 0.0, 0.0)"), + #ifndef MAGNUM_TARGET_GLES2 + RenderbufferFormat::RGBA8, + #else + RenderbufferFormat::RGBA4, + #endif + mesh).get(ColorFormat::RGBA, ColorType::UnsignedByte); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 96); +} + +#ifndef MAGNUM_TARGET_GLES2 +void MeshGLTest::addVertexBufferInstancedInteger() { + #ifndef MAGNUM_TARGET_GLES + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::instanced_arrays::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::gpu_shader4::string() + std::string(" is not available.")); + #endif + + typedef AbstractShaderProgram::Attribute<0, UnsignedInt> Attribute; + + constexpr UnsignedInt data[] = { + 0, /* Offset */ + /* Base vertex is ignored for instanced arrays */ + 157, /* First instance */ + 25, /* Second instance */ + 35681 /* Third instance */ + }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBufferInstanced(buffer, 1, 4, Attribute{}); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(IntegerShader("uint"), RenderbufferFormat::R32UI, mesh) + .get(ColorFormat::RedInteger, ColorType::UnsignedInt); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 35681); +} +#endif + +#ifndef MAGNUM_TARGET_GLES +void MeshGLTest::addVertexBufferInstancedDouble() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::instanced_arrays::string() + std::string(" is not available.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::ARB::vertex_attrib_64bit::string() + std::string(" is not available.")); + + typedef AbstractShaderProgram::Attribute<0, Double> Attribute; + + const Double data[] = { + 0.0, /* Offset */ + /* Base vertex is ignored for instanced arrays */ + -0.7, /* First instance */ + 0.3, /* Second instance */ + Math::normalize(45828) /* Third instance */ + }; + Buffer buffer; + buffer.setData(data, BufferUsage::StaticDraw); + + Mesh mesh; + mesh.setInstanceCount(3) + .addVertexBufferInstanced(buffer, 1, 8, Attribute{}); + + MAGNUM_VERIFY_NO_ERROR(); + + const auto value = Checker(DoubleShader("double", "float", "vec4(value, 0.0, 0.0, 0.0)"), + RenderbufferFormat::R16, mesh).get(ColorFormat::Red, ColorType::UnsignedShort); + + MAGNUM_VERIFY_NO_ERROR(); + CORRADE_COMPARE(value, 45828); +} +#endif + }} CORRADE_TEST_MAIN(Magnum::Test::MeshGLTest)