GL: Added draw indirect support.

This commit is contained in:
Branimir Karadžić 2015-04-30 18:06:41 -07:00
parent 5c6854c684
commit b04af680ad
4 changed files with 147 additions and 58 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;