diff --git a/include/bgfx.h b/include/bgfx.h index 51fe931f..df0be6c3 100644 --- a/include/bgfx.h +++ b/include/bgfx.h @@ -1409,6 +1409,9 @@ namespace bgfx /// void setBuffer(uint8_t _stage, DynamicVertexBufferHandle _handle, Access::Enum _access); + /// + void setBuffer(uint8_t _stage, DrawIndirectBufferHandle _handle, Access::Enum _access); + /// void setImage(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint8_t _mip, Access::Enum _access, TextureFormat::Enum _format = TextureFormat::Count); diff --git a/src/glimports.h b/src/glimports.h index ed91ea0a..3fe2527f 100644 --- a/src/glimports.h +++ b/src/glimports.h @@ -146,6 +146,8 @@ typedef GLint (GL_APIENTRYP PFNGLGETUNIFORMLOCATIONPROC) (GLuint progra typedef void (GL_APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); typedef void (GL_APIENTRYP PFNGLLINKPROGRAMPROC) (GLuint program); typedef void (GL_APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers); +typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); +typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); typedef void (GL_APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label); typedef void (GL_APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); @@ -266,7 +268,7 @@ GL_IMPORT______(false, PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVert GL_IMPORT______(true, PFNGLDISPATCHCOMPUTEPROC, glDispatchCompute); GL_IMPORT______(true, PFNGLDISPATCHCOMPUTEINDIRECTPROC, glDispatchComputeIndirect); GL_IMPORT______(false, PFNGLDRAWARRAYSPROC, glDrawArrays); -GL_IMPORT______(true, PFNGLDRAWARRAYSINDIRECTPROC, glDrawArraysInderect); +GL_IMPORT______(true, PFNGLDRAWARRAYSINDIRECTPROC, glDrawArraysIndirect); GL_IMPORT______(true, PFNGLDRAWARRAYSINSTANCEDPROC, glDrawArraysInstanced); GL_IMPORT______(true, PFNGLDRAWBUFFERPROC, glDrawBuffer); GL_IMPORT______(true, PFNGLDRAWBUFFERSPROC, glDrawBuffers); @@ -317,6 +319,8 @@ GL_IMPORT______(false, PFNGLGETUNIFORMLOCATIONPROC, glGetUniformL GL_IMPORT______(true, PFNGLINVALIDATEFRAMEBUFFERPROC, glInvalidateFramebuffer); GL_IMPORT______(false, PFNGLLINKPROGRAMPROC, glLinkProgram); GL_IMPORT______(true, PFNGLMEMORYBARRIERPROC, glMemoryBarrier); +GL_IMPORT______(true, PFNGLMULTIDRAWARRAYSINDIRECTPROC, glMultiDrawArraysIndirect); +GL_IMPORT______(true, PFNGLMULTIDRAWELEMENTSINDIRECTPROC, glMultiDrawElementsIndirect); GL_IMPORT______(true, PFNGLOBJECTLABELPROC, glObjectLabel); GL_IMPORT______(true, PFNGLOBJECTPTRLABELPROC, glObjectPtrLabel); GL_IMPORT______(false, PFNGLPIXELSTOREIPROC, glPixelStorei); @@ -395,6 +399,9 @@ GL_IMPORT_ARB__(true, PFNGLDRAWBUFFERSPROC, glDrawBuffers GL_IMPORT_ARB__(true, PFNGLINVALIDATEFRAMEBUFFERPROC, glInvalidateFramebuffer); +GL_IMPORT_ARB__(true, PFNGLMULTIDRAWARRAYSINDIRECTPROC, glMultiDrawArraysIndirect); +GL_IMPORT_ARB__(true, PFNGLMULTIDRAWELEMENTSINDIRECTPROC, glMultiDrawElementsIndirect); + GL_IMPORT_EXT__(true, PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer); GL_IMPORT_EXT__(true, PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers); GL_IMPORT_EXT__(true, PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers); @@ -443,8 +450,10 @@ GL_IMPORT_EXT__(true, PFNGLPUSHGROUPMARKEREXTPROC, glPushGroupMa GL_IMPORT_EXT__(true, PFNGLPOPGROUPMARKEREXTPROC, glPopGroupMarker); GL_IMPORT_EXT__(true, PFNGLOBJECTLABELPROC, glObjectLabel); -GL_IMPORT_EXT__(true, PFNGLDRAWARRAYSINDIRECTPROC, glDrawArraysInderect); +GL_IMPORT_EXT__(true, PFNGLDRAWARRAYSINDIRECTPROC, glDrawArraysIndirect); GL_IMPORT_EXT__(true, PFNGLDRAWELEMENTSINDIRECTPROC, glDrawElementsIndirect); +GL_IMPORT_EXT__(true, PFNGLMULTIDRAWARRAYSINDIRECTPROC, glMultiDrawArraysIndirect); +GL_IMPORT_EXT__(true, PFNGLMULTIDRAWELEMENTSINDIRECTPROC, glMultiDrawElementsIndirect); GL_IMPORT_OES__(true, PFNGLGETPROGRAMBINARYPROC, glGetProgramBinary); GL_IMPORT_OES__(true, PFNGLPROGRAMBINARYPROC, glProgramBinary); diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 45736de7..f5634399 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -813,6 +813,26 @@ namespace bgfx { namespace gl { } + static void GL_APIENTRY stubMultiDrawArraysIndirect(GLenum _mode, const void* _indirect, GLsizei _drawcount, GLsizei _stride) + { + const uint8_t* args = (const uint8_t*)_indirect; + for (GLsizei ii = 0; ii < _drawcount; ++ii) + { + GL_CHECK(glDrawArraysIndirect(_mode, (void*)args) ); + args += _stride; + } + } + + static void GL_APIENTRY stubMultiDrawElementsIndirect(GLenum _mode, GLenum _type, const void* _indirect, GLsizei _drawcount, GLsizei _stride) + { + const uint8_t* args = (const uint8_t*)_indirect; + for (GLsizei ii = 0; ii < _drawcount; ++ii) + { + GL_CHECK(glDrawElementsIndirect(_mode, _type, (void*)args) ); + args += _stride; + } + } + typedef void (*PostSwapBuffersFn)(uint32_t _width, uint32_t _height); static const char* getGLString(GLenum _name) @@ -1401,8 +1421,18 @@ namespace bgfx { namespace gl || s_extension[Extension::EXT_multi_draw_indirect].m_supported ; + if (drawIndirectSupported) + { + if (NULL == glMultiDrawArraysIndirect + || NULL == glMultiDrawElementsIndirect) + { + glMultiDrawArraysIndirect = stubMultiDrawArraysIndirect; + glMultiDrawElementsIndirect = stubMultiDrawElementsIndirect; + } + } + g_caps.supported |= drawIndirectSupported - ? 0 //BGFX_CAPS_DRAW_INDIRECT + ? BGFX_CAPS_DRAW_INDIRECT : 0 ; @@ -1688,9 +1718,9 @@ namespace bgfx { namespace gl { } - void createVertexBuffer(VertexBufferHandle _handle, Memory* _mem, VertexDeclHandle _declHandle, uint8_t /*_flags*/) BX_OVERRIDE + void createVertexBuffer(VertexBufferHandle _handle, Memory* _mem, VertexDeclHandle _declHandle, uint8_t _flags) BX_OVERRIDE { - m_vertexBuffers[_handle.idx].create(_mem->size, _mem->data, _declHandle); + m_vertexBuffers[_handle.idx].create(_mem->size, _mem->data, _declHandle, _flags); } void destroyVertexBuffer(VertexBufferHandle _handle) BX_OVERRIDE @@ -1713,10 +1743,10 @@ namespace bgfx { namespace gl m_indexBuffers[_handle.idx].destroy(); } - void createDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _size, uint8_t /*_flags*/) BX_OVERRIDE + void createDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _size, uint8_t _flags) BX_OVERRIDE { VertexDeclHandle decl = BGFX_INVALID_HANDLE; - m_vertexBuffers[_handle.idx].create(_size, NULL, decl); + m_vertexBuffers[_handle.idx].create(_size, NULL, decl, _flags); } void updateDynamicVertexBuffer(VertexBufferHandle _handle, uint32_t _offset, uint32_t _size, Memory* _mem) BX_OVERRIDE @@ -5376,61 +5406,104 @@ namespace bgfx { namespace gl numVertices = vb.m_size/vertexDecl.m_stride; } - uint32_t numIndices = 0; + uint32_t numIndices = 0; uint32_t numPrimsSubmitted = 0; - uint32_t numInstances = 0; - uint32_t numPrimsRendered = 0; + uint32_t numInstances = 0; + uint32_t numPrimsRendered = 0; + uint32_t numDrawIndirect = 0; - if (isValid(draw.m_indexBuffer) ) + if (isValid(draw.m_drawIndirectBuffer) ) { - const IndexBufferGL& ib = m_indexBuffers[draw.m_indexBuffer.idx]; - const bool hasIndex16 = 0 == (ib.m_flags & BGFX_BUFFER_INDEX32); - const GLenum indexFormat = hasIndex16 - ? GL_UNSIGNED_SHORT - : GL_UNSIGNED_INT - ; - - if (UINT32_MAX == draw.m_numIndices) + const VertexBufferGL& vb = m_vertexBuffers[draw.m_drawIndirectBuffer.idx]; + if (currentState.m_drawIndirectBuffer.idx != draw.m_drawIndirectBuffer.idx) { - const uint32_t indexSize = hasIndex16 ? 2 : 4; - numIndices = ib.m_size/indexSize; - numPrimsSubmitted = numIndices/prim.m_div - prim.m_sub; - numInstances = draw.m_numInstances; - numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; - - GL_CHECK(glDrawElementsInstanced(prim.m_type - , numIndices - , indexFormat - , (void*)0 - , draw.m_numInstances - ) ); + currentState.m_drawIndirectBuffer = draw.m_drawIndirectBuffer; + GL_CHECK(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vb.m_id) ); } - else if (prim.m_min <= draw.m_numIndices) - { - numIndices = draw.m_numIndices; - numPrimsSubmitted = numIndices/prim.m_div - prim.m_sub; - numInstances = draw.m_numInstances; - numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; - GL_CHECK(glDrawElementsInstanced(prim.m_type - , numIndices - , indexFormat - , (void*)(uintptr_t)(draw.m_startIndex*2) - , draw.m_numInstances - ) ); + if (isValid(draw.m_indexBuffer) ) + { + const IndexBufferGL& ib = m_indexBuffers[draw.m_indexBuffer.idx]; + const bool hasIndex16 = 0 == (ib.m_flags & BGFX_BUFFER_INDEX32); + const GLenum indexFormat = hasIndex16 + ? GL_UNSIGNED_SHORT + : GL_UNSIGNED_INT + ; + + const uint32_t commandSize = 5 * sizeof(uint32_t); + numDrawIndirect = UINT16_MAX == draw.m_numDrawIndirect ? vb.m_size/commandSize : draw.m_numDrawIndirect; + + uint32_t args = draw.m_startDrawIndirect * commandSize; + GL_CHECK(glMultiDrawElementsIndirect(prim.m_type, indexFormat, (void*)args, numDrawIndirect, commandSize) ); + } + else + { + const uint32_t commandSize = 4 * sizeof(uint32_t); + numDrawIndirect = UINT16_MAX == draw.m_numDrawIndirect ? vb.m_size/commandSize : draw.m_numDrawIndirect; + + uint32_t args = draw.m_startDrawIndirect * commandSize; + GL_CHECK(glMultiDrawArraysIndirect(prim.m_type, (void*)args, numDrawIndirect, commandSize) ); } } else { - numPrimsSubmitted = numVertices/prim.m_div - prim.m_sub; - numInstances = draw.m_numInstances; - numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + if (isValid(currentState.m_drawIndirectBuffer) ) + { + currentState.m_drawIndirectBuffer.idx = invalidHandle; + GL_CHECK(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0) ); + } - GL_CHECK(glDrawArraysInstanced(prim.m_type - , 0 - , numVertices - , draw.m_numInstances - ) ); + if (isValid(draw.m_indexBuffer) ) + { + const IndexBufferGL& ib = m_indexBuffers[draw.m_indexBuffer.idx]; + const bool hasIndex16 = 0 == (ib.m_flags & BGFX_BUFFER_INDEX32); + const GLenum indexFormat = hasIndex16 + ? GL_UNSIGNED_SHORT + : GL_UNSIGNED_INT + ; + + if (UINT32_MAX == draw.m_numIndices) + { + const uint32_t indexSize = hasIndex16 ? 2 : 4; + numIndices = ib.m_size/indexSize; + numPrimsSubmitted = numIndices/prim.m_div - prim.m_sub; + numInstances = draw.m_numInstances; + numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + + GL_CHECK(glDrawElementsInstanced(prim.m_type + , numIndices + , indexFormat + , (void*)0 + , draw.m_numInstances + ) ); + } + else if (prim.m_min <= draw.m_numIndices) + { + numIndices = draw.m_numIndices; + numPrimsSubmitted = numIndices/prim.m_div - prim.m_sub; + numInstances = draw.m_numInstances; + numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + + GL_CHECK(glDrawElementsInstanced(prim.m_type + , numIndices + , indexFormat + , (void*)(uintptr_t)(draw.m_startIndex*2) + , draw.m_numInstances + ) ); + } + } + else + { + numPrimsSubmitted = numVertices/prim.m_div - prim.m_sub; + numInstances = draw.m_numInstances; + numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + + GL_CHECK(glDrawArraysInstanced(prim.m_type + , 0 + , numVertices + , draw.m_numInstances + ) ); + } } statsNumPrimsSubmitted[primIndex] += numPrimsSubmitted; diff --git a/src/renderer_gl.h b/src/renderer_gl.h index 97c14350..fb9066a4 100644 --- a/src/renderer_gl.h +++ b/src/renderer_gl.h @@ -868,32 +868,35 @@ namespace bgfx { namespace gl struct VertexBufferGL { - void create(uint32_t _size, void* _data, VertexDeclHandle _declHandle) + void create(uint32_t _size, void* _data, VertexDeclHandle _declHandle, uint8_t _flags) { m_size = _size; m_decl = _declHandle; + const bool drawIndirect = 0 != (_flags & BGFX_BUFFER_DRAW_INDIRECT); + + m_target = drawIndirect ? GL_DRAW_INDIRECT_BUFFER : GL_ARRAY_BUFFER; GL_CHECK(glGenBuffers(1, &m_id) ); BX_CHECK(0 != m_id, "Failed to generate buffer id."); - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id) ); - GL_CHECK(glBufferData(GL_ARRAY_BUFFER + GL_CHECK(glBindBuffer(m_target, m_id) ); + GL_CHECK(glBufferData(m_target , _size , _data , (NULL==_data) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW ) ); - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0) ); + GL_CHECK(glBindBuffer(m_target, 0) ); } void update(uint32_t _offset, uint32_t _size, void* _data) { BX_CHECK(0 != m_id, "Updating invalid vertex buffer."); - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id) ); - GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER + GL_CHECK(glBindBuffer(m_target, m_id) ); + GL_CHECK(glBufferSubData(m_target , _offset , _size , _data ) ); - GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0) ); + GL_CHECK(glBindBuffer(m_target, 0) ); } void destroy(); @@ -904,6 +907,7 @@ namespace bgfx { namespace gl } GLuint m_id; + GLenum m_target; uint32_t m_size; VertexDeclHandle m_decl; VaoCacheRef m_vcref;