Browse Source

Support for instanced mesh drawing and base instance.

On desktop GL this is provided by ARB_draw_instanced (GL 3.1). Base
instance is available only on desktop GL (4.2, ARB_base_instance). In
ES2 the instanced functionality is provided by three (!) different
extensions (ANGLE_instanced_arrays, EXT_draw_instanced,
NV_draw_instanced), the proper implementation is chosen on context
creation based on what extension is available. Though we don't have
extension loader for ES yet, thus all these extensions are disabled and
the implementation has assertion in it.

Added blind test which tests only that something has been drawn and no
errors were emitted, but not whether the right command is used. I'll
probably need to check this later, because the Mesh::draw() behemoth is
going slightly out of hand :)
pull/54/head
Vladimír Vondruš 12 years ago
parent
commit
20df20de0f
  1. 3
      doc/opengl-mapping.dox
  2. 9
      doc/opengl-support.dox
  3. 3
      src/Magnum/Context.cpp
  4. 5
      src/Magnum/Extensions.h
  5. 26
      src/Magnum/Implementation/MeshState.cpp
  6. 5
      src/Magnum/Implementation/MeshState.h
  7. 3
      src/Magnum/Implementation/setupDriverWorkarounds.cpp
  8. 201
      src/Magnum/Mesh.cpp
  9. 103
      src/Magnum/Mesh.h
  10. 16
      src/Magnum/MeshView.cpp
  11. 48
      src/Magnum/MeshView.h
  12. 239
      src/Magnum/Test/MeshGLTest.cpp

3
doc/opengl-mapping.dox

@ -103,9 +103,8 @@ OpenGL function | Matching API
@fn_gl{DetachShader} | | @fn_gl{DetachShader} | |
@fn_gl{DispatchCompute} | | @fn_gl{DispatchCompute} | |
@fn_gl{DispatchComputeIndirect} | | @fn_gl{DispatchComputeIndirect} | |
@fn_gl{DrawArrays}, \n @fn_gl{DrawElements}, \n @fn_gl{DrawRangeElements}, \n @fn_gl{DrawElementsBaseVertex}, \n @fn_gl{DrawRangeElementsBaseVertex} | @ref Mesh::draw(), \n @ref MeshView::draw() @fn_gl{DrawArrays}, \n @fn_gl{DrawArraysInstanced}, \n @fn_gl{DrawArraysInstancedBaseInstance}, \n @fn_gl{DrawElements}, \n @fn_gl{DrawRangeElements}, \n @fn_gl{DrawElementsBaseVertex}, \n @fn_gl{DrawRangeElementsBaseVertex}, \n @fn_gl{DrawElementsInstanced}, \n @fn_gl{DrawElementsInstancedBaseInstance}, \n @fn_gl{DrawElementsInstancedBaseVertex}, \n @fn_gl{DrawElementsInstancedBaseVertexBaseInstance} | @ref Mesh::draw(), \n @ref MeshView::draw()
@fn_gl{DrawArraysIndirect}, \n @fn_gl{DrawElementsIndirect}, \n @fn_gl{MultiDrawArraysIndirect}, \n @fn_gl{MultiDrawElementsIndirect} | | @fn_gl{DrawArraysIndirect}, \n @fn_gl{DrawElementsIndirect}, \n @fn_gl{MultiDrawArraysIndirect}, \n @fn_gl{MultiDrawElementsIndirect} | |
@fn_gl{DrawArraysInstanced}, \n @fn_gl{DrawArraysInstancedBaseInstance}, \n @fn_gl{DrawElementsInstanced}, \n @fn_gl{DrawElementsInstancedBaseInstance}, \n @fn_gl{DrawElementsInstancedBaseVertex}, \n @fn_gl{DrawElementsInstancedBaseVertexBaseInstance} | |
@fn_gl{DrawBuffer}, \n @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access}, \n @fn_gl{DrawBuffers}, \n @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} | @ref DefaultFramebuffer::mapForDraw(), \n @ref Framebuffer::mapForDraw() @fn_gl{DrawBuffer}, \n @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access}, \n @fn_gl{DrawBuffers}, \n @fn_gl_extension{FramebufferDrawBuffers,EXT,direct_state_access} | @ref DefaultFramebuffer::mapForDraw(), \n @ref Framebuffer::mapForDraw()
@fn_gl{DrawTransformFeedback}, \n @fn_gl{DrawTransformFeedbackInstanced}, \n @fn_gl{DrawTransformFeedbackStream}, \n @fn_gl{DrawTransformFeedbackStreamInstanced} | | @fn_gl{DrawTransformFeedback}, \n @fn_gl{DrawTransformFeedbackInstanced}, \n @fn_gl{DrawTransformFeedbackStream}, \n @fn_gl{DrawTransformFeedbackStreamInstanced} | |
@fn_gl{Enable}, `glDisable()` | @ref Renderer::setFeature() @fn_gl{Enable}, `glDisable()` | @ref Renderer::setFeature()

9
doc/opengl-support.dox

@ -82,7 +82,7 @@ following:
%Extension | Status %Extension | Status
-------------------------------------------- | ------ -------------------------------------------- | ------
@extension{ARB,texture_rectangle} | done @extension{ARB,texture_rectangle} | done
@extension{ARB,draw_instanced} | | @extension{ARB,draw_instanced} | done
@extension{ARB,texture_buffer_object} | done @extension{ARB,texture_buffer_object} | done
@extension{ARB,uniform_buffer_object} | | @extension{ARB,uniform_buffer_object} | |
@extension{ARB,copy_buffer} | done @extension{ARB,copy_buffer} | done
@ -95,7 +95,7 @@ following:
-------------------------------------------- | ------ -------------------------------------------- | ------
@extension{ARB,geometry_shader4} | missing layered attachments @extension{ARB,geometry_shader4} | missing layered attachments
@extension{ARB,depth_clamp} | done @extension{ARB,depth_clamp} | done
@extension{ARB,draw_elements_base_vertex} | | @extension{ARB,draw_elements_base_vertex} | missing `Multi*` command
@extension{ARB,fragment_coord_conventions} | done (shading language only) @extension{ARB,fragment_coord_conventions} | done (shading language only)
@extension{ARB,provoking_vertex} | done @extension{ARB,provoking_vertex} | done
@extension{ARB,seamless_cube_map} | done @extension{ARB,seamless_cube_map} | done
@ -152,7 +152,7 @@ following:
%Extension | Status %Extension | Status
-------------------------------------------- | ------ -------------------------------------------- | ------
@extension{ARB,texture_compression_bptc} | done @extension{ARB,texture_compression_bptc} | done
@extension{ARB,base_instance} | | @extension{ARB,base_instance} | done
@extension{ARB,shading_language_420pack} | done (shading language only) @extension{ARB,shading_language_420pack} | done (shading language only)
@extension{ARB,transform_feedback_instanced} | | @extension{ARB,transform_feedback_instanced} | |
@extension{ARB,compressed_texture_pixel_storage} | | @extension{ARB,compressed_texture_pixel_storage} | |
@ -243,6 +243,7 @@ supported.
-------------------------------------------- | ------ -------------------------------------------- | ------
@es_extension{ANGLE,framebuffer_blit} | done @es_extension{ANGLE,framebuffer_blit} | done
@es_extension{ANGLE,framebuffer_multisample} | done @es_extension{ANGLE,framebuffer_multisample} | done
@es_extension{ANGLE,instanced_arrays} | missing vertex attrib divisor
@es_extension{ANGLE,depth_texture} | done @es_extension{ANGLE,depth_texture} | done
@es_extension{APPLE,framebuffer_multisample} | done (ES 3.0 subset) @es_extension{APPLE,framebuffer_multisample} | done (ES 3.0 subset)
@es_extension{APPLE,texture_max_level} | done @es_extension{APPLE,texture_max_level} | done
@ -256,9 +257,11 @@ supported.
@es_extension{EXT,texture_rg} | done @es_extension{EXT,texture_rg} | done
@es_extension{EXT,texture_storage} | done @es_extension{EXT,texture_storage} | done
@es_extension{EXT,map_buffer_range} | done @es_extension{EXT,map_buffer_range} | done
@es_extension2{EXT,draw_instanced,draw_instanced} | done
@es_extension{NV,draw_buffers} | done @es_extension{NV,draw_buffers} | done
@es_extension{NV,fbo_color_attachments} | done @es_extension{NV,fbo_color_attachments} | done
@es_extension{NV,read_buffer} | done @es_extension{NV,read_buffer} | done
@es_extension{NV,draw_instanced} | done
@es_extension{NV,framebuffer_blit} | done @es_extension{NV,framebuffer_blit} | done
@es_extension{NV,framebuffer_multisample} | done @es_extension{NV,framebuffer_multisample} | done
@es_extension{NV,shadow_samplers_array} | done (shading language only) @es_extension{NV,shadow_samplers_array} | done (shading language only)

3
src/Magnum/Context.cpp

@ -212,6 +212,7 @@ const std::vector<Extension>& Extension::extensions(Version version) {
static const std::vector<Extension> extensionsES300{ static const std::vector<Extension> extensionsES300{
_extension(GL,ANGLE,framebuffer_blit), _extension(GL,ANGLE,framebuffer_blit),
_extension(GL,ANGLE,framebuffer_multisample), _extension(GL,ANGLE,framebuffer_multisample),
_extension(GL,ANGLE,instanced_arrays),
_extension(GL,ANGLE,depth_texture), _extension(GL,ANGLE,depth_texture),
_extension(GL,APPLE,framebuffer_multisample), _extension(GL,APPLE,framebuffer_multisample),
_extension(GL,APPLE,texture_max_level), _extension(GL,APPLE,texture_max_level),
@ -225,9 +226,11 @@ const std::vector<Extension>& Extension::extensions(Version version) {
_extension(GL,EXT,texture_rg), _extension(GL,EXT,texture_rg),
_extension(GL,EXT,texture_storage), _extension(GL,EXT,texture_storage),
_extension(GL,EXT,map_buffer_range), _extension(GL,EXT,map_buffer_range),
_extension(GL,EXT,draw_instanced),
_extension(GL,NV,draw_buffers), _extension(GL,NV,draw_buffers),
_extension(GL,NV,fbo_color_attachments), _extension(GL,NV,fbo_color_attachments),
_extension(GL,NV,read_buffer), _extension(GL,NV,read_buffer),
_extension(GL,NV,draw_instanced),
_extension(GL,NV,framebuffer_blit), _extension(GL,NV,framebuffer_blit),
_extension(GL,NV,framebuffer_multisample), _extension(GL,NV,framebuffer_multisample),
_extension(GL,NV,shadow_samplers_array), _extension(GL,NV,shadow_samplers_array),

5
src/Magnum/Extensions.h

@ -205,6 +205,7 @@ namespace GL {
#ifdef MAGNUM_TARGET_GLES2 #ifdef MAGNUM_TARGET_GLES2
_extension(GL,ANGLE,framebuffer_blit, GLES200, GLES300) // #83 _extension(GL,ANGLE,framebuffer_blit, GLES200, GLES300) // #83
_extension(GL,ANGLE,framebuffer_multisample, GLES200, GLES300) // #84 _extension(GL,ANGLE,framebuffer_multisample, GLES200, GLES300) // #84
_extension(GL,ANGLE,instanced_arrays, GLES200, GLES300) // #109
_extension(GL,ANGLE,depth_texture, GLES200, GLES300) // #138 _extension(GL,ANGLE,depth_texture, GLES200, GLES300) // #138
#endif #endif
} namespace APPLE { } namespace APPLE {
@ -253,6 +254,9 @@ namespace GL {
_extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121 _extension(GL,EXT,map_buffer_range, GLES200, GLES300) // #121
#endif #endif
_extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150 _extension(GL,EXT,disjoint_timer_query, GLES200, None) // #150
#ifdef MAGNUM_TARGET_GLES2
_extension(GL,EXT,draw_instanced, GLES200, GLES300) // #157
#endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_extension(GL,EXT,shader_integer_mix, GLES300, None) // #161 _extension(GL,EXT,shader_integer_mix, GLES300, None) // #161
#endif #endif
@ -269,6 +273,7 @@ namespace GL {
_extension(GL,NV,read_stencil, GLES200, None) // #94 _extension(GL,NV,read_stencil, GLES200, None) // #94
_extension(GL,NV,read_depth_stencil, GLES200, None) // #94 _extension(GL,NV,read_depth_stencil, GLES200, None) // #94
#ifdef MAGNUM_TARGET_GLES2 #ifdef MAGNUM_TARGET_GLES2
_extension(GL,NV,draw_instanced, GLES200, GLES300) // #141
_extension(GL,NV,framebuffer_blit, GLES200, GLES300) // #142 _extension(GL,NV,framebuffer_blit, GLES200, GLES300) // #142
_extension(GL,NV,framebuffer_multisample, GLES200, GLES300) // #143 _extension(GL,NV,framebuffer_multisample, GLES200, GLES300) // #143
_extension(GL,NV,shadow_samplers_array, GLES200, GLES300) // #146 _extension(GL,NV,shadow_samplers_array, GLES200, GLES300) // #146

26
src/Magnum/Implementation/MeshState.cpp

@ -92,6 +92,32 @@ MeshState::MeshState(Context& context, std::vector<std::string>& extensions): cu
unbindImplementation = &Mesh::unbindImplementationDefault; unbindImplementation = &Mesh::unbindImplementationDefault;
} }
#endif #endif
#ifdef MAGNUM_TARGET_GLES2
/* Instanced draw ímplementation on ES2 */
if(context.isExtensionSupported<Extensions::GL::ANGLE::instanced_arrays>()) {
extensions.push_back(Extensions::GL::ANGLE::instanced_arrays::string());
drawArraysInstancedImplementation = &Mesh::drawArraysInstancedImplementationANGLE;
drawElementsInstancedImplementation = &Mesh::drawElementsInstancedImplementationANGLE;
} else if(context.isExtensionSupported<Extensions::GL::EXT::draw_instanced>()) {
extensions.push_back(Extensions::GL::EXT::draw_instanced::string());
drawArraysInstancedImplementation = &Mesh::drawArraysInstancedImplementationEXT;
drawElementsInstancedImplementation = &Mesh::drawElementsInstancedImplementationEXT;
} else if(context.isExtensionSupported<Extensions::GL::NV::draw_instanced>()) {
extensions.push_back(Extensions::GL::NV::draw_instanced::string());
drawArraysInstancedImplementation = &Mesh::drawArraysInstancedImplementationNV;
drawElementsInstancedImplementation = &Mesh::drawElementsInstancedImplementationNV;
} else {
drawArraysInstancedImplementation = nullptr;
drawElementsInstancedImplementation = nullptr;
}
#endif
} }
}} }}

5
src/Magnum/Implementation/MeshState.h

@ -48,6 +48,11 @@ struct MeshState {
void(Mesh::*bindImplementation)(); void(Mesh::*bindImplementation)();
void(Mesh::*unbindImplementation)(); void(Mesh::*unbindImplementation)();
#ifdef MAGNUM_TARGET_GLES2
void(Mesh::*drawArraysInstancedImplementation)(GLint, GLsizei, GLsizei);
void(Mesh::*drawElementsInstancedImplementation)(GLsizei, GLintptr, GLsizei);
#endif
GLuint currentVAO; GLuint currentVAO;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
GLint maxElementsIndices, maxElementsVertices; GLint maxElementsIndices, maxElementsVertices;

3
src/Magnum/Implementation/setupDriverWorkarounds.cpp

@ -68,6 +68,7 @@ void Context::setupDriverWorkarounds() {
#ifdef MAGNUM_TARGET_GLES2 #ifdef MAGNUM_TARGET_GLES2
_setRequiredVersion(GL::ANGLE::framebuffer_blit, None); _setRequiredVersion(GL::ANGLE::framebuffer_blit, None);
_setRequiredVersion(GL::ANGLE::framebuffer_multisample, None); _setRequiredVersion(GL::ANGLE::framebuffer_multisample, None);
_setRequiredVersion(GL::ANGLE::instanced_arrays, None);
_setRequiredVersion(GL::APPLE::framebuffer_multisample, None); _setRequiredVersion(GL::APPLE::framebuffer_multisample, None);
_setRequiredVersion(GL::EXT::discard_framebuffer, None); _setRequiredVersion(GL::EXT::discard_framebuffer, None);
_setRequiredVersion(GL::EXT::blend_minmax, None); _setRequiredVersion(GL::EXT::blend_minmax, None);
@ -76,9 +77,11 @@ void Context::setupDriverWorkarounds() {
#endif #endif
_setRequiredVersion(GL::EXT::texture_storage, None); _setRequiredVersion(GL::EXT::texture_storage, None);
_setRequiredVersion(GL::EXT::map_buffer_range, None); _setRequiredVersion(GL::EXT::map_buffer_range, None);
_setRequiredVersion(GL::EXT::draw_instanced, None);
_setRequiredVersion(GL::NV::draw_buffers, None); _setRequiredVersion(GL::NV::draw_buffers, None);
_setRequiredVersion(GL::NV::fbo_color_attachments, None); // ?? _setRequiredVersion(GL::NV::fbo_color_attachments, None); // ??
_setRequiredVersion(GL::NV::read_buffer, None); _setRequiredVersion(GL::NV::read_buffer, None);
_setRequiredVersion(GL::NV::draw_instanced, None);
_setRequiredVersion(GL::NV::framebuffer_blit, None); _setRequiredVersion(GL::NV::framebuffer_blit, None);
_setRequiredVersion(GL::NV::framebuffer_multisample, None); _setRequiredVersion(GL::NV::framebuffer_multisample, None);
_setRequiredVersion(GL::OES::texture_3D, None); _setRequiredVersion(GL::OES::texture_3D, None);

201
src/Magnum/Mesh.cpp

@ -72,11 +72,14 @@ std::size_t Mesh::indexSize(IndexType type) {
CORRADE_ASSERT_UNREACHABLE(); CORRADE_ASSERT_UNREACHABLE();
} }
Mesh::Mesh(MeshPrimitive primitive): _primitive(primitive), _count(0), _baseVertex(0) Mesh::Mesh(MeshPrimitive primitive): _primitive(primitive), _count(0), _baseVertex(0), _instanceCount{1},
#ifndef MAGNUM_TARGET_GLES
_baseInstance{0},
#endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
, _indexStart(0), _indexEnd(0) _indexStart(0), _indexEnd(0),
#endif #endif
, _indexOffset(0), _indexType(IndexType::UnsignedInt), _indexBuffer(nullptr) _indexOffset(0), _indexType(IndexType::UnsignedInt), _indexBuffer(nullptr)
{ {
(this->*Context::current()->state().mesh->createImplementation)(); (this->*Context::current()->state().mesh->createImplementation)();
} }
@ -92,11 +95,14 @@ Mesh::~Mesh() {
(this->*Context::current()->state().mesh->destroyImplementation)(); (this->*Context::current()->state().mesh->destroyImplementation)();
} }
Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), _count(other._count), _baseVertex{other._baseVertex} Mesh::Mesh(Mesh&& other) noexcept: _id(other._id), _primitive(other._primitive), _count(other._count), _baseVertex{other._baseVertex}, _instanceCount{other._instanceCount},
#ifndef MAGNUM_TARGET_GLES
_baseInstance{other._baseInstance},
#endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
, _indexStart(other._indexStart), _indexEnd(other._indexEnd) _indexStart(other._indexStart), _indexEnd(other._indexEnd),
#endif #endif
, _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes)) _indexOffset(other._indexOffset), _indexType(other._indexType), _indexBuffer(other._indexBuffer), _attributes(std::move(other._attributes))
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
, _integerAttributes(std::move(other._integerAttributes)) , _integerAttributes(std::move(other._integerAttributes))
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
@ -112,6 +118,10 @@ Mesh& Mesh::operator=(Mesh&& other) noexcept {
std::swap(_primitive, other._primitive); std::swap(_primitive, other._primitive);
std::swap(_count, other._count); std::swap(_count, other._count);
std::swap(_baseVertex, other._baseVertex); std::swap(_baseVertex, other._baseVertex);
std::swap(_instanceCount, other._instanceCount);
#ifndef MAGNUM_TARGET_GLES
std::swap(_baseInstance, other._baseInstance);
#endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
std::swap(_indexStart, other._indexStart); std::swap(_indexStart, other._indexStart);
std::swap(_indexEnd, other._indexEnd); std::swap(_indexEnd, other._indexEnd);
@ -167,50 +177,111 @@ Mesh& Mesh::setIndexBuffer(Buffer& buffer, GLintptr offset, IndexType type, Unsi
return *this; return *this;
} }
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
void Mesh::drawInternal(Int count, Int baseVertex, GLintptr indexOffset, Int indexStart, Int indexEnd) 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 #else
void Mesh::drawInternal(Int count, Int baseVertex, GLintptr indexOffset) void Mesh::drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset)
#endif #endif
{ {
/* Nothing to draw */
if(!count) return;
(this->*Context::current()->state().mesh->bindImplementation)();
/* Non-indexed mesh */ const Implementation::MeshState& state = *Context::current()->state().mesh;
if(!_indexBuffer) {
glDrawArrays(GLenum(_primitive), baseVertex, count);
/* Indexed mesh with base vertex */ /* Nothing to draw */
} else if(baseVertex) { if(!count || !instanceCount) return;
#ifndef MAGNUM_TARGET_GLES
/* Indexed mesh with specified range */ (this->*state.bindImplementation)();
if(indexEnd) {
glDrawRangeElementsBaseVertex(GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), baseVertex); /* Non-instanced mesh */
if(instanceCount == 1) {
/* Indexed mesh without specified range */ /* Non-indexed mesh */
} else glDrawElementsBaseVertex(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), baseVertex); if(!_indexBuffer) {
#else glDrawArrays(GLenum(_primitive), baseVertex, count);
CORRADE_ASSERT(false, "Mesh::draw(): desktop OpenGL is required for base vertex specification in indexed meshes", );
#endif /* Indexed mesh with base vertex */
} else if(baseVertex) {
#ifndef MAGNUM_TARGET_GLES
/* Indexed mesh with specified range */
if(indexEnd) {
glDrawRangeElementsBaseVertex(GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), baseVertex);
/* Indexed mesh */
} else glDrawElementsBaseVertex(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), baseVertex);
#else
CORRADE_ASSERT(false, "Mesh::draw(): desktop OpenGL is required for base vertex specification in indexed meshes", );
#endif
/* Indexed mesh */
} else {
#ifndef MAGNUM_TARGET_GLES2
/* Indexed mesh with specified range */
if(indexEnd) {
glDrawRangeElements(GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset));
/* Indexed mesh */
} else
#endif
{
glDrawElements(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset));
}
}
/* Indexed mesh without base vertex */ /* Instanced mesh */
} else { } else {
/* Indexed mesh with specified range */ /* Non-indexed mesh */
#ifndef MAGNUM_TARGET_GLES2 if(!_indexBuffer) {
if(indexEnd) { #ifndef MAGNUM_TARGET_GLES
glDrawRangeElements(GLenum(_primitive), indexStart, indexEnd, count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset)); /* Non-indexed mesh with base instance */
if(baseInstance) {
/* Indexed mesh without specified range */ glDrawArraysInstancedBaseInstance(GLenum(_primitive), baseVertex, count, instanceCount, baseInstance);
} else
#endif /* Non-indexed mesh */
{ } else
glDrawElements(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset)); #endif
{
#ifndef MAGNUM_TARGET_GLES2
glDrawArraysInstanced(GLenum(_primitive), baseVertex, count, instanceCount);
#else
(this->*state.drawArraysInstancedImplementation)(baseVertex, count, instanceCount);
#endif
}
/* Indexed mesh with base vertex */
} else if(baseVertex) {
#ifndef MAGNUM_TARGET_GLES
/* Indexed mesh with base vertex and base instance */
if(baseInstance)
glDrawElementsInstancedBaseVertexBaseInstance(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), instanceCount, baseVertex, baseInstance);
/* Indexed mesh with base vertex */
else
glDrawElementsInstancedBaseVertex(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), instanceCount, baseVertex);
#else
CORRADE_ASSERT(false, "Mesh::draw(): desktop OpenGL is required for base vertex specification in indexed meshes", );
#endif
/* Indexed mesh */
} else {
#ifndef MAGNUM_TARGET_GLES
/* Indexed mesh with base instance */
if(baseInstance) {
glDrawElementsInstancedBaseInstance(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), instanceCount, baseInstance);
/* Instanced mesh */
} else
#endif
{
#ifndef MAGNUM_TARGET_GLES2
glDrawElementsInstanced(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), instanceCount);
#else
(this->*state.drawElementsInstancedImplementation)(count, indexOffset, instanceCount);
#endif
}
} }
} }
(this->*Context::current()->state().mesh->unbindImplementation)(); (this->*state.unbindImplementation)();
} }
void Mesh::bindVAO(GLuint vao) { void Mesh::bindVAO(GLuint vao) {
@ -400,6 +471,56 @@ void Mesh::unbindImplementationDefault() {
void Mesh::unbindImplementationVAO() {} void Mesh::unbindImplementationVAO() {}
#ifdef MAGNUM_TARGET_GLES2
void Mesh::drawArraysInstancedImplementationANGLE(const GLint baseVertex, const GLsizei count, const GLsizei instanceCount) {
//glDrawArraysInstancedANGLE(GLenum(_primitive), baseVertex, count, instanceCount);
CORRADE_INTERNAL_ASSERT(false);
static_cast<void>(baseVertex);
static_cast<void>(count);
static_cast<void>(instanceCount);
}
void Mesh::drawArraysInstancedImplementationEXT(const GLint baseVertex, const GLsizei count, const GLsizei instanceCount) {
//glDrawArraysInstancedEXT(GLenum(_primitive), baseVertex, count, instanceCount);
CORRADE_INTERNAL_ASSERT(false);
static_cast<void>(baseVertex);
static_cast<void>(count);
static_cast<void>(instanceCount);
}
void Mesh::drawArraysInstancedImplementationNV(const GLint baseVertex, const GLsizei count, const GLsizei instanceCount) {
//glDrawArraysInstancedNV(GLenum(_primitive), baseVertex, count, instanceCount);
CORRADE_INTERNAL_ASSERT(false);
static_cast<void>(baseVertex);
static_cast<void>(count);
static_cast<void>(instanceCount);
}
void Mesh::drawElementsInstancedImplementationANGLE(const GLsizei count, const GLintptr indexOffset, const GLsizei instanceCount) {
//glDrawElementsInstancedANGLE(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), instanceCount);
CORRADE_INTERNAL_ASSERT(false);
static_cast<void>(count);
static_cast<void>(indexOffset);
static_cast<void>(instanceCount);
}
void Mesh::drawElementsInstancedImplementationEXT(const GLsizei count, const GLintptr indexOffset, const GLsizei instanceCount) {
//glDrawElementsInstancedEXT(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), instanceCount);
CORRADE_INTERNAL_ASSERT(false);
static_cast<void>(count);
static_cast<void>(indexOffset);
static_cast<void>(instanceCount);
}
void Mesh::drawElementsInstancedImplementationNV(const GLsizei count, const GLintptr indexOffset, const GLsizei instanceCount) {
//glDrawElementsInstancedNV(GLenum(_primitive), count, GLenum(_indexType), reinterpret_cast<GLvoid*>(indexOffset), instanceCount);
CORRADE_INTERNAL_ASSERT(false);
static_cast<void>(count);
static_cast<void>(indexOffset);
static_cast<void>(instanceCount);
}
#endif
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
Debug operator<<(Debug debug, MeshPrimitive value) { Debug operator<<(Debug debug, MeshPrimitive value) {
switch(value) { switch(value) {

103
src/Magnum/Mesh.h

@ -143,8 +143,8 @@ that they are available for whole mesh lifetime. On the other hand it allows
you to use one buffer for more meshes (each mesh for example configured for you to use one buffer for more meshes (each mesh for example configured for
different usage) or store data for more meshes in one buffer. different usage) or store data for more meshes in one buffer.
If vertex/index count is zero, the mesh is empty and no draw commands are If vertex/index count or instance count is zero, the mesh is empty and no draw
issued when calling @ref draw(). commands are issued when calling @ref draw().
@subsection Mesh-configuration-examples Example mesh configuration @subsection Mesh-configuration-examples Example mesh configuration
@ -331,8 +331,6 @@ calls to @fn_gl{BindBuffer} and @fn_gl{BindVertexArray}. See documentation of
If index range is specified in @ref setIndexBuffer(), range-based version of If index range is specified in @ref setIndexBuffer(), range-based version of
drawing commands are used on desktop OpenGL and OpenGL ES 3.0. See also drawing commands are used on desktop OpenGL and OpenGL ES 3.0. See also
@ref draw() for more information. @ref draw() for more information.
@todo Redo in a way that allows glMultiDrawArrays, glDrawArraysInstanced etc.
*/ */
class MAGNUM_EXPORT Mesh: public AbstractObject { class MAGNUM_EXPORT Mesh: public AbstractObject {
friend class MeshView; friend class MeshView;
@ -567,6 +565,44 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
CORRADE_DEPRECATED("use setCount() instead") Mesh& setIndexCount(Int count) { return setCount(count); } CORRADE_DEPRECATED("use setCount() instead") Mesh& setIndexCount(Int count) { return setCount(count); }
#endif #endif
/** @brief Instance count */
Int instanceCount() const { return _instanceCount; }
/**
* @brief Set instance count
* @return Reference to self (for method chaining)
*
* If set to `1`, non-instanced draw commands are issued when calling
* @ref draw(). If set to `0`, no draw commands are issued altogether.
* Default is `1`.
* @requires_gl31 %Extension @extension{ARB,draw_instanced}
* @requires_gles30 %Extension @es_extension{ANGLE,instanced_arrays},
* @es_extension2{EXT,draw_instanced,draw_instanced} or
* @es_extension{NV,draw_instanced} in OpenGL ES 2.0.
*/
Mesh& setInstanceCount(Int count) {
_instanceCount = count;
return *this;
}
#ifndef MAGNUM_TARGET_GLES
/** @brief Base instance */
UnsignedInt baseInstance() const { return _baseInstance; }
/**
* @brief Set base instance
* @return Reference to self (for method chaining)
*
* Default is `0`.
* @requires_gl42 %Extension @extension{ARB,base_instance}
* @requires_gl Base instance cannot be specified in OpenGL ES.
*/
Mesh& setBaseInstance(UnsignedInt baseInstance) {
_baseInstance = baseInstance;
return *this;
}
#endif
/** /**
* @brief Add buffer with (interleaved) vertex attributes for use with given shader * @brief Add buffer with (interleaved) vertex attributes for use with given shader
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
@ -680,23 +716,31 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* @param shader Shader to use for drawing * @param shader Shader to use for drawing
* *
* Expects that the shader is compatible with this mesh and is fully * Expects that the shader is compatible with this mesh and is fully
* set up. See also * set up. If vertex/index count or instance count is `0`, no draw
* commands are issued. See also
* @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation" * @ref AbstractShaderProgram-rendering-workflow "AbstractShaderProgram documentation"
* for more information. * for more information.
* @see @fn_gl{UseProgram}, @fn_gl{EnableVertexAttribArray}, * @see @ref setCount(), @ref setInstanceCount(), @fn_gl{UseProgram},
* @fn_gl{BindBuffer}, @fn_gl{VertexAttribPointer}, * @fn_gl{EnableVertexAttribArray}, @fn_gl{BindBuffer},
* @fn_gl{DisableVertexAttribArray} or @fn_gl{BindVertexArray} (if * @fn_gl{VertexAttribPointer}, @fn_gl{DisableVertexAttribArray}
* @extension{APPLE,vertex_array_object} is available), @fn_gl{DrawArrays} * or @fn_gl{BindVertexArray} (if @extension{APPLE,vertex_array_object}
* or @fn_gl{DrawElements}/@fn_gl{DrawRangeElements}/ * is available), @fn_gl{DrawArrays}/@fn_gl{DrawArraysInstanced}/
* @fn_gl{DrawElementsBaseVertex}/@fn_gl{DrawRangeElementsBaseVertex} * @fn_gl{DrawArraysInstancedBaseInstance} or @fn_gl{DrawElements}/
* @fn_gl{DrawRangeElements}/@fn_gl{DrawElementsBaseVertex}/
* @fn_gl{DrawRangeElementsBaseVertex}/@fn_gl{DrawElementsInstanced}/
* @fn_gl{DrawElementsInstancedBaseInstance}/
* @fn_gl{DrawElementsInstancedBaseVertex}/
* @fn_gl{DrawElementsInstancedBaseVertexBaseInstance}
*/ */
void draw(AbstractShaderProgram& shader) { void draw(AbstractShaderProgram& shader) {
shader.use(); shader.use();
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
drawInternal(_count, _baseVertex, _indexOffset, _indexStart, _indexEnd); drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd);
#elif !defined(MAGNUM_TARGET_GLES2)
drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd);
#else #else
drawInternal(_count, _baseVertex, _indexOffset); drawInternal(_count, _baseVertex, _instanceCount, _indexOffset);
#endif #endif
} }
@ -709,10 +753,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
* instead. * instead.
*/ */
CORRADE_DEPRECATED("use draw(AbstractShaderProgram&) instead") void draw() { CORRADE_DEPRECATED("use draw(AbstractShaderProgram&) instead") void draw() {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
drawInternal(_count, _baseVertex, _indexOffset, _indexStart, _indexEnd); drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd);
#elif !defined(MAGNUM_TARGET_GLES2)
drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd);
#else #else
drawInternal(_count, _baseVertex, _indexOffset); drawInternal(_count, _baseVertex, _instanceCount, _indexOffset);
#endif #endif
} }
#endif #endif
@ -832,10 +878,12 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
#endif #endif
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
void drawInternal(Int count, Int baseVertex, GLintptr indexOffset, Int indexStart, Int indexEnd); 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 #else
void drawInternal(Int count, Int baseVertex, GLintptr indexOffset); void drawInternal(Int count, Int baseVertex, Int instanceCount, GLintptr indexOffset);
#endif #endif
void MAGNUM_LOCAL createImplementationDefault(); void MAGNUM_LOCAL createImplementationDefault();
@ -873,9 +921,22 @@ class MAGNUM_EXPORT Mesh: public AbstractObject {
void MAGNUM_LOCAL unbindImplementationDefault(); void MAGNUM_LOCAL unbindImplementationDefault();
void MAGNUM_LOCAL unbindImplementationVAO(); void MAGNUM_LOCAL unbindImplementationVAO();
#ifdef MAGNUM_TARGET_GLES2
void MAGNUM_LOCAL drawArraysInstancedImplementationANGLE(GLint baseVertex, GLsizei count, GLsizei instanceCount);
void MAGNUM_LOCAL drawArraysInstancedImplementationEXT(GLint baseVertex, GLsizei count, GLsizei instanceCount);
void MAGNUM_LOCAL drawArraysInstancedImplementationNV(GLint baseVertex, GLsizei count, GLsizei instanceCount);
void MAGNUM_LOCAL drawElementsInstancedImplementationANGLE(GLsizei count, GLintptr indexOffset, GLsizei instanceCount);
void MAGNUM_LOCAL drawElementsInstancedImplementationEXT(GLsizei count, GLintptr indexOffset, GLsizei instanceCount);
void MAGNUM_LOCAL drawElementsInstancedImplementationNV(GLsizei count, GLintptr indexOffset, GLsizei instanceCount);
#endif
GLuint _id; GLuint _id;
MeshPrimitive _primitive; MeshPrimitive _primitive;
Int _count, _baseVertex; Int _count, _baseVertex, _instanceCount;
#ifndef MAGNUM_TARGET_GLES
UnsignedInt _baseInstance;
#endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UnsignedInt _indexStart, _indexEnd; UnsignedInt _indexStart, _indexEnd;
#endif #endif

16
src/Magnum/MeshView.cpp

@ -37,19 +37,23 @@ MeshView& MeshView::setIndexRange(Int first) {
void MeshView::draw(AbstractShaderProgram& shader) { void MeshView::draw(AbstractShaderProgram& shader) {
shader.use(); shader.use();
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
_original->drawInternal(_count, _baseVertex, _indexOffset, _indexStart, _indexEnd); _original->drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd);
#elif !defined(MAGNUM_TARGET_GLES2)
_original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd);
#else #else
_original->drawInternal(_count, _baseVertex, _indexOffset); _original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset);
#endif #endif
} }
#ifdef MAGNUM_BUILD_DEPRECATED #ifdef MAGNUM_BUILD_DEPRECATED
void MeshView::draw() { void MeshView::draw() {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES
_original->drawInternal(_count, _baseVertex, _indexOffset, _indexStart, _indexEnd); _original->drawInternal(_count, _baseVertex, _instanceCount, _baseInstance, _indexOffset, _indexStart, _indexEnd);
#elif !defined(MAGNUM_TARGET_GLES2)
_original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset, _indexStart, _indexEnd);
#else #else
_original->drawInternal(_count, _baseVertex, _indexOffset); _original->drawInternal(_count, _baseVertex, _instanceCount, _indexOffset);
#endif #endif
} }
#endif #endif

48
src/Magnum/MeshView.h

@ -172,6 +172,42 @@ class MAGNUM_EXPORT MeshView {
} }
#endif #endif
/** @brief Instance count */
Int instanceCount() const { return _instanceCount; }
/**
* @brief Set instance count
* @return Reference to self (for method chaining)
*
* Default is `1`.
* @requires_gl31 %Extension @extension{ARB,draw_instanced}
* @requires_gles30 %Extension @es_extension{ANGLE,instanced_arrays},
* @es_extension2{EXT,draw_instanced,draw_instanced} or
* @es_extension{NV,draw_instanced} in OpenGL ES 2.0.
*/
MeshView& setInstanceCount(Int count) {
_instanceCount = count;
return *this;
}
#ifndef MAGNUM_TARGET_GLES
/** @brief Base instance */
UnsignedInt baseInstance() const { return _baseInstance; }
/**
* @brief Set base instance
* @return Reference to self (for method chaining)
*
* Default is `0`.
* @requires_gl42 %Extension @extension{ARB,base_instance}
* @requires_gl Base instance cannot be specified in OpenGL ES.
*/
MeshView& setBaseInstance(UnsignedInt baseInstance) {
_baseInstance = baseInstance;
return *this;
}
#endif
/** /**
* @brief Draw the mesh * @brief Draw the mesh
* *
@ -192,14 +228,21 @@ class MAGNUM_EXPORT MeshView {
private: private:
Mesh* _original; Mesh* _original;
Int _count, _baseVertex; Int _count, _baseVertex, _instanceCount;
#ifndef MAGNUM_TARGET_GLES
UnsignedInt _baseInstance;
#endif
GLintptr _indexOffset; GLintptr _indexOffset;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
UnsignedInt _indexStart, _indexEnd; UnsignedInt _indexStart, _indexEnd;
#endif #endif
}; };
inline MeshView::MeshView(Mesh& original): _original(&original), _count(0), _baseVertex(0), _indexOffset(0) inline MeshView::MeshView(Mesh& original): _original(&original), _count(0), _baseVertex(0), _instanceCount{1},
#ifndef MAGNUM_TARGET_GLES
_baseInstance{0},
#endif
_indexOffset(0)
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
, _indexStart(0), _indexEnd(0) , _indexStart(0), _indexEnd(0)
#endif #endif
@ -217,7 +260,6 @@ inline MeshView& MeshView::setIndexRange(Int first, UnsignedInt start, UnsignedI
return *this; return *this;
} }
} }
#endif #endif

239
src/Magnum/Test/MeshGLTest.cpp

@ -110,6 +110,14 @@ class MeshGLTest: public AbstractOpenGLTester {
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
void setBaseVertex(); void setBaseVertex();
#endif #endif
void setInstanceCount();
void setInstanceCountIndexed();
#ifndef MAGNUM_TARGET_GLES
void setInstanceCountBaseInstance();
void setInstanceCountBaseInstanceIndexed();
void setInstanceCountBaseVertex();
void setInstanceCountBaseVertexBaseInstance();
#endif
}; };
MeshGLTest::MeshGLTest() { MeshGLTest::MeshGLTest() {
@ -175,7 +183,15 @@ MeshGLTest::MeshGLTest() {
&MeshGLTest::setIndexBufferUnsignedInt, &MeshGLTest::setIndexBufferUnsignedInt,
#ifndef MAGNUM_TARGET_GLES #ifndef MAGNUM_TARGET_GLES
&MeshGLTest::setBaseVertex &MeshGLTest::setBaseVertex,
#endif
&MeshGLTest::setInstanceCount,
&MeshGLTest::setInstanceCountIndexed,
#ifndef MAGNUM_TARGET_GLES
&MeshGLTest::setInstanceCountBaseInstance,
&MeshGLTest::setInstanceCountBaseInstanceIndexed,
&MeshGLTest::setInstanceCountBaseVertex,
&MeshGLTest::setInstanceCountBaseVertexBaseInstance
#endif #endif
}); });
} }
@ -409,6 +425,10 @@ Checker::Checker(AbstractShaderProgram&& shader, RenderbufferFormat format, Mesh
MeshView(mesh) MeshView(mesh)
.setCount(1) .setCount(1)
.setBaseVertex(1) .setBaseVertex(1)
.setInstanceCount(mesh.instanceCount())
#ifndef MAGNUM_TARGET_GLES
.setBaseInstance(mesh.baseInstance())
#endif
.draw(shader); .draw(shader);
} }
@ -1195,6 +1215,10 @@ IndexChecker::IndexChecker(Mesh& mesh): framebuffer({{}, Vector2i(1)}) {
MeshView(mesh) MeshView(mesh)
.setCount(1) .setCount(1)
.setBaseVertex(mesh.baseVertex()) .setBaseVertex(mesh.baseVertex())
.setInstanceCount(mesh.instanceCount())
#ifndef MAGNUM_TARGET_GLES
.setBaseInstance(mesh.baseInstance())
#endif
.setIndexRange(1) .setIndexRange(1)
.draw(MultipleShader{}); .draw(MultipleShader{});
} }
@ -1301,6 +1325,219 @@ void MeshGLTest::setBaseVertex() {
} }
#endif #endif
void MeshGLTest::setInstanceCount() {
/* Verbatim copy of addVertexBufferFloat() with added 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<Extensions::GL::ARB::draw_instanced>())
CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available."));
#elif defined(MAGNUM_TARGET_GLES2)
if(!Context::current()->isExtensionSupported<Extensions::GL::ANGLE::instanced_arrays>() && !Context::current()->isExtensionSupported<Extensions::GL::EXT::draw_instanced>() && !Context::current()->isExtensionSupported<Extensions::GL::NV::draw_instanced>())
CORRADE_SKIP("Required extension is not available.");
#endif
typedef AbstractShaderProgram::Attribute<0, Float> Attribute;
const Float data[] = { 0.0f, -0.7f, Math::normalize<Float, UnsignedByte>(96) };
Buffer buffer;
buffer.setData(data, BufferUsage::StaticDraw);
Mesh mesh;
mesh.setInstanceCount(3)
.addVertexBuffer(buffer, 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<UnsignedByte>(ColorFormat::RGBA, ColorType::UnsignedByte);
MAGNUM_VERIFY_NO_ERROR();
CORRADE_COMPARE(value, 96);
}
void MeshGLTest::setInstanceCountIndexed() {
/* Verbatim copy of setIndexBuffer() with added 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<Extensions::GL::ARB::draw_instanced>())
CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available."));
#elif defined(MAGNUM_TARGET_GLES2)
if(!Context::current()->isExtensionSupported<Extensions::GL::ANGLE::instanced_arrays>() && !Context::current()->isExtensionSupported<Extensions::GL::EXT::draw_instanced>() && !Context::current()->isExtensionSupported<Extensions::GL::NV::draw_instanced>())
CORRADE_SKIP("Required extension is not available.");
#endif
Buffer vertices;
vertices.setData(indexedVertexData, BufferUsage::StaticDraw);
constexpr UnsignedShort indexData[] = { 2, 1, 0 };
Buffer indices(Buffer::Target::ElementArray);
indices.setData(indexData, BufferUsage::StaticDraw);
Mesh mesh;
mesh.setInstanceCount(3)
.addVertexBuffer(vertices, 1*4, MultipleShader::Position(),
MultipleShader::Normal(), MultipleShader::TextureCoordinates())
.setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort);
MAGNUM_VERIFY_NO_ERROR();
const auto value = IndexChecker(mesh).get();
MAGNUM_VERIFY_NO_ERROR();
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<Extensions::GL::ARB::draw_instanced>())
CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available."));
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::base_instance>())
CORRADE_SKIP(Extensions::GL::ARB::base_instance::string() + std::string(" is not available."));
typedef AbstractShaderProgram::Attribute<0, Float> Attribute;
const Float data[] = { 0.0f, -0.7f, Math::normalize<Float, UnsignedByte>(96) };
Buffer buffer;
buffer.setData(data, BufferUsage::StaticDraw);
Mesh mesh;
mesh.setInstanceCount(3)
.setBaseInstance(72)
.addVertexBuffer(buffer, 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<UnsignedByte>(ColorFormat::RGBA, ColorType::UnsignedByte);
MAGNUM_VERIFY_NO_ERROR();
CORRADE_COMPARE(value, 96);
}
void MeshGLTest::setInstanceCountBaseInstanceIndexed() {
/* 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 */
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::draw_instanced>())
CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available."));
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::base_instance>())
CORRADE_SKIP(Extensions::GL::ARB::base_instance::string() + std::string(" is not available."));
Buffer vertices;
vertices.setData(indexedVertexData, BufferUsage::StaticDraw);
constexpr UnsignedShort indexData[] = { 2, 1, 0 };
Buffer indices(Buffer::Target::ElementArray);
indices.setData(indexData, BufferUsage::StaticDraw);
Mesh mesh;
mesh.setInstanceCount(3)
.setBaseInstance(72)
.addVertexBuffer(vertices, 1*4, MultipleShader::Position(),
MultipleShader::Normal(), MultipleShader::TextureCoordinates())
.setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort);
MAGNUM_VERIFY_NO_ERROR();
const auto value = IndexChecker(mesh).get();
MAGNUM_VERIFY_NO_ERROR();
CORRADE_COMPARE(value, indexedResult);
}
void MeshGLTest::setInstanceCountBaseVertex() {
/* 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 */
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::draw_instanced>())
CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available."));
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::draw_elements_base_vertex>())
CORRADE_SKIP(Extensions::GL::ARB::draw_elements_base_vertex::string() + std::string(" is not available."));
Buffer vertices;
vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw);
constexpr UnsignedShort indexData[] = { 2, 1, 0 };
Buffer indices(Buffer::Target::ElementArray);
indices.setData(indexData, BufferUsage::StaticDraw);
Mesh mesh;
mesh.setBaseVertex(2)
.setInstanceCount(3)
.addVertexBuffer(vertices, 2*4, MultipleShader::Position(),
MultipleShader::Normal(), MultipleShader::TextureCoordinates())
.setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort);
MAGNUM_VERIFY_NO_ERROR();
const auto value = IndexChecker(mesh).get();
MAGNUM_VERIFY_NO_ERROR();
CORRADE_COMPARE(value, indexedResult);
}
void MeshGLTest::setInstanceCountBaseVertexBaseInstance() {
/* 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 */
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::draw_instanced>())
CORRADE_SKIP(Extensions::GL::ARB::draw_instanced::string() + std::string(" is not available."));
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::draw_elements_base_vertex>())
CORRADE_SKIP(Extensions::GL::ARB::draw_elements_base_vertex::string() + std::string(" is not available."));
if(!Context::current()->isExtensionSupported<Extensions::GL::ARB::base_instance>())
CORRADE_SKIP(Extensions::GL::ARB::base_instance::string() + std::string(" is not available."));
Buffer vertices;
vertices.setData(indexedVertexDataBaseVertex, BufferUsage::StaticDraw);
constexpr UnsignedShort indexData[] = { 2, 1, 0 };
Buffer indices(Buffer::Target::ElementArray);
indices.setData(indexData, BufferUsage::StaticDraw);
Mesh mesh;
mesh.setBaseVertex(2)
.setInstanceCount(3)
.setBaseInstance(72)
.addVertexBuffer(vertices, 2*4, MultipleShader::Position(),
MultipleShader::Normal(), MultipleShader::TextureCoordinates())
.setIndexBuffer(indices, 2, Mesh::IndexType::UnsignedShort);
MAGNUM_VERIFY_NO_ERROR();
const auto value = IndexChecker(mesh).get();
MAGNUM_VERIFY_NO_ERROR();
CORRADE_COMPARE(value, indexedResult);
}
#endif
}} }}
CORRADE_TEST_MAIN(Magnum::Test::MeshGLTest) CORRADE_TEST_MAIN(Magnum::Test::MeshGLTest)

Loading…
Cancel
Save