diff --git a/include/bgfx.h b/include/bgfx.h index f8a80bcd..b5ed64b3 100644 --- a/include/bgfx.h +++ b/include/bgfx.h @@ -206,6 +206,7 @@ namespace bgfx static const uint16_t invalidHandle = UINT16_MAX; + BGFX_HANDLE(DrawIndirectBufferHandle); BGFX_HANDLE(DynamicIndexBufferHandle); BGFX_HANDLE(DynamicVertexBufferHandle); BGFX_HANDLE(FrameBufferHandle); @@ -869,6 +870,12 @@ namespace bgfx /// const InstanceDataBuffer* allocInstanceDataBuffer(uint32_t _num, uint16_t _stride); + /// + DrawIndirectBufferHandle createDrawIndirectBuffer(uint32_t _num); + + /// + void destroyDrawIndirectBuffer(DrawIndirectBufferHandle _handle); + /// Create shader from memory buffer. ShaderHandle createShader(const Memory* _mem); @@ -1333,6 +1340,9 @@ namespace bgfx /// Set instance data buffer for draw primitive. void setInstanceDataBuffer(DynamicVertexBufferHandle _handle, uint32_t _startVertex, uint32_t _num); + /// + void setDrawIndirectBuffer(DrawIndirectBufferHandle _handle, uint16_t _start = 0, uint16_t _num = UINT16_MAX); + /// Set program for draw primitive. void setProgram(ProgramHandle _handle); diff --git a/include/bgfxdefines.h b/include/bgfxdefines.h index 58a4aacd..07310f6c 100644 --- a/include/bgfxdefines.h +++ b/include/bgfxdefines.h @@ -224,8 +224,9 @@ #define BGFX_BUFFER_NONE UINT8_C(0x00) #define BGFX_BUFFER_COMPUTE_READ UINT8_C(0x01) #define BGFX_BUFFER_COMPUTE_WRITE UINT8_C(0x02) -#define BGFX_BUFFER_ALLOW_RESIZE UINT8_C(0x04) -#define BGFX_BUFFER_INDEX32 UINT8_C(0x08) +#define BGFX_BUFFER_DRAW_INDIRECT UINT8_C(0x04) +#define BGFX_BUFFER_ALLOW_RESIZE UINT8_C(0x08) +#define BGFX_BUFFER_INDEX32 UINT8_C(0x10) #define BGFX_BUFFER_COMPUTE_READ_WRITE (BGFX_BUFFER_COMPUTE_READ | BGFX_BUFFER_COMPUTE_WRITE) /// @@ -319,6 +320,7 @@ #define BGFX_CAPS_SWAP_CHAIN UINT64_C(0x0000000000000400) #define BGFX_CAPS_HMD UINT64_C(0x0000000000000800) #define BGFX_CAPS_INDEX32 UINT64_C(0x0000000000001000) +#define BGFX_CAPS_DRAW_INDIRECT UINT64_C(0x0000000000002000) /// #define BGFX_CAPS_FORMAT_TEXTURE_NONE UINT8_C(0x00) diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 6bbae9e4..43d334f1 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -837,6 +837,7 @@ namespace bgfx CAPS_FLAGS(BGFX_CAPS_SWAP_CHAIN), CAPS_FLAGS(BGFX_CAPS_HMD), CAPS_FLAGS(BGFX_CAPS_INDEX32), + CAPS_FLAGS(BGFX_CAPS_DRAW_INDIRECT), #undef CAPS_FLAGS }; @@ -2308,6 +2309,18 @@ again: return s_ctx->allocInstanceDataBuffer(_num, _stride); } + DrawIndirectBufferHandle createDrawIndirectBuffer(uint32_t _num) + { + BGFX_CHECK_MAIN_THREAD(); + return s_ctx->createDrawIndirectBuffer(_num); + } + + void destroyDrawIndirectBuffer(DrawIndirectBufferHandle _handle) + { + BGFX_CHECK_MAIN_THREAD(); + s_ctx->destroyDrawIndirectBuffer(_handle); + } + ShaderHandle createShader(const Memory* _mem) { BGFX_CHECK_MAIN_THREAD(); @@ -2909,6 +2922,12 @@ again: s_ctx->setInstanceDataBuffer(_handle, _startVertex, _num); } + void setDrawIndirectBuffer(DrawIndirectBufferHandle _handle, uint16_t _start, uint16_t _num) + { + BGFX_CHECK_MAIN_THREAD(); + s_ctx->setDrawIndirectBuffer(_handle, _start, _num); + } + void setProgram(ProgramHandle _handle) { BGFX_CHECK_MAIN_THREAD(); @@ -2957,6 +2976,12 @@ again: s_ctx->setBuffer(_stage, _handle, _access); } + void setBuffer(uint8_t _stage, DrawIndirectBufferHandle _handle, Access::Enum _access) + { + BGFX_CHECK_MAIN_THREAD(); + s_ctx->setBuffer(_stage, _handle, _access); + } + void setImage(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint8_t _mip, Access::Enum _access, TextureFormat::Enum _format) { BGFX_CHECK_MAIN_THREAD(); diff --git a/src/bgfx_p.h b/src/bgfx_p.h index 1a6b199a..ff1632c7 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -1072,6 +1072,8 @@ namespace bgfx m_instanceDataOffset = 0; m_instanceDataStride = 0; m_numInstances = 1; + m_startDrawIndirect = 0; + m_numDrawIndirect = UINT16_MAX; m_num = 1; m_flags = BGFX_SUBMIT_EYE_FIRST; m_scissor = UINT16_MAX; @@ -1079,6 +1081,7 @@ namespace bgfx m_vertexDecl.idx = invalidHandle; m_indexBuffer.idx = invalidHandle; m_instanceDataBuffer.idx = invalidHandle; + m_drawIndirectBuffer.idx = invalidHandle; for (uint32_t ii = 0; ii < BGFX_CONFIG_MAX_TEXTURE_SAMPLERS; ++ii) { @@ -1100,6 +1103,8 @@ namespace bgfx uint32_t m_instanceDataOffset; uint16_t m_instanceDataStride; uint16_t m_numInstances; + uint16_t m_startDrawIndirect; + uint16_t m_numDrawIndirect; uint16_t m_num; uint16_t m_scissor; uint8_t m_submitFlags; @@ -1108,6 +1113,7 @@ namespace bgfx VertexDeclHandle m_vertexDecl; IndexBufferHandle m_indexBuffer; VertexBufferHandle m_instanceDataBuffer; + DrawIndirectBufferHandle m_drawIndirectBuffer; }; struct RenderCompute @@ -1381,6 +1387,13 @@ namespace bgfx m_draw.m_instanceDataBuffer = _handle; } + void setDrawIndirectBuffer(DrawIndirectBufferHandle _handle, uint16_t _start, uint16_t _num) + { + m_draw.m_startDrawIndirect = _start; + m_draw.m_numDrawIndirect = _num; + m_draw.m_drawIndirectBuffer = _handle; + } + void setProgram(ProgramHandle _handle) { m_key.m_program = _handle.idx; @@ -2496,6 +2509,36 @@ namespace bgfx return idb; } + DrawIndirectBufferHandle createDrawIndirectBuffer(uint32_t _num) + { + BX_UNUSED(_num); + DrawIndirectBufferHandle handle = { m_vertexBufferHandle.alloc() }; + + BX_WARN(isValid(handle), "Failed to allocate draw indirect buffer handle."); + if (isValid(handle) ) + { + uint32_t size = _num * sizeof(uint32_t) * 5; + uint8_t flags = BGFX_BUFFER_DRAW_INDIRECT; + + CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::CreateDynamicVertexBuffer); + cmdbuf.write(handle); + cmdbuf.write(size); + cmdbuf.write(flags); + } + + return handle; + } + + void destroyDrawIndirectBuffer(DrawIndirectBufferHandle _handle) + { + VertexBufferHandle handle = { _handle.idx }; + BGFX_CHECK_HANDLE("destroyDrawIndirectBuffer", m_vertexBufferHandle, handle); + + CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::DestroyDynamicVertexBuffer); + cmdbuf.write(handle); + m_submit->free(handle); + } + BGFX_API_FUNC(ShaderHandle createShader(const Memory* _mem) ) { bx::MemoryReader reader(_mem->data, _mem->size); @@ -3256,6 +3299,12 @@ namespace bgfx ); } + BGFX_API_FUNC(void setDrawIndirectBuffer(DrawIndirectBufferHandle _handle, uint16_t _start, uint16_t _num) ) + { + BGFX_CHECK_HANDLE("setDrawIndirectBuffer", m_vertexBufferHandle, _handle); + m_submit->setDrawIndirectBuffer(_handle, _start, _num); + } + BGFX_API_FUNC(void setProgram(ProgramHandle _handle) ) { BGFX_CHECK_HANDLE("setProgram", m_programHandle, _handle); @@ -3315,6 +3364,13 @@ namespace bgfx m_submit->setBuffer(_stage, dvb.m_handle, _access); } + BGFX_API_FUNC(void setBuffer(uint8_t _stage, DrawIndirectBufferHandle _handle, Access::Enum _access) ) + { + BGFX_CHECK_HANDLE("setBuffer", m_vertexBufferHandle, _handle); + VertexBufferHandle handle = { _handle.idx }; + m_submit->setBuffer(_stage, handle, _access); + } + BGFX_API_FUNC(void setImage(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint8_t _mip, Access::Enum _access, TextureFormat::Enum _format) ) { _format = TextureFormat::Count == _format ? TextureFormat::Enum(m_textureRef[_handle.idx].m_format) : _format; diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index 5cee953d..1034ae9b 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -449,6 +449,7 @@ namespace bgfx { namespace d3d11 , m_numWindows(0) , m_device(NULL) , m_deviceCtx(NULL) + , m_infoQueue(NULL) , m_backBufferColor(NULL) , m_backBufferDepthStencil(NULL) , m_currentColor(NULL) @@ -640,6 +641,8 @@ namespace bgfx { namespace d3d11 continue; } + // Enable debug flags. + flags |= (BX_ENABLED(BGFX_CONFIG_DEBUG) ? D3D11_CREATE_DEVICE_DEBUG : 0); ++ii; } @@ -785,14 +788,13 @@ BX_PRAGMA_DIAGNOSTIC_POP(); #if !defined(__MINGW32__) if (BX_ENABLED(BGFX_CONFIG_DEBUG) ) { - ID3D11InfoQueue* infoQueue; - hr = m_device->QueryInterface(IID_ID3D11InfoQueue, (void**)&infoQueue); + hr = m_device->QueryInterface(IID_ID3D11InfoQueue, (void**)&m_infoQueue); if (SUCCEEDED(hr) ) { - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, false); + m_infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); + m_infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, false); + m_infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, false); D3D11_INFO_QUEUE_FILTER filter; memset(&filter, 0, sizeof(filter) ); @@ -804,9 +806,9 @@ BX_PRAGMA_DIAGNOSTIC_POP(); }; filter.DenyList.NumCategories = BX_COUNTOF(catlist); filter.DenyList.pCategoryList = catlist; - infoQueue->PushStorageFilter(&filter); + m_infoQueue->PushStorageFilter(&filter); - DX_RELEASE(infoQueue, 3); + DX_RELEASE(m_infoQueue, 3); } else { @@ -829,6 +831,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); | (getIntelExtensions(m_device) ? BGFX_CAPS_FRAGMENT_ORDERING : 0) | BGFX_CAPS_SWAP_CHAIN | (m_ovr.isInitialized() ? BGFX_CAPS_HMD : 0) + | BGFX_CAPS_DRAW_INDIRECT ); if (m_featureLevel <= D3D_FEATURE_LEVEL_9_2) @@ -998,6 +1001,12 @@ BX_PRAGMA_DIAGNOSTIC_POP(); mbstowcs(s_viewNameW[ii], name, BGFX_CONFIG_MAX_VIEW_NAME_RESERVED); } + if (BX_ENABLED(BGFX_CONFIG_DEBUG) + && NULL != m_infoQueue) + { + m_infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); + } + updateMsaa(); postReset(); } @@ -2540,6 +2549,8 @@ BX_PRAGMA_DIAGNOSTIC_POP(); ID3D11Device* m_device; ID3D11DeviceContext* m_deviceCtx; + ID3D11InfoQueue* m_infoQueue; + ID3D11RenderTargetView* m_backBufferColor; ID3D11DepthStencilView* m_backBufferDepthStencil; ID3D11RenderTargetView* m_currentColor; @@ -2620,8 +2631,9 @@ BX_PRAGMA_DIAGNOSTIC_POP(); m_size = _size; m_flags = _flags; - const bool needUav = 0 != (_flags & BGFX_BUFFER_COMPUTE_WRITE); + const bool needUav = 0 != (_flags & (BGFX_BUFFER_COMPUTE_WRITE|BGFX_BUFFER_DRAW_INDIRECT) ); const bool needSrv = 0 != (_flags & BGFX_BUFFER_COMPUTE_READ); + const bool drawIndirect = 0 != (_flags & BGFX_BUFFER_DRAW_INDIRECT); m_dynamic = NULL == _data && !needUav; D3D11_BUFFER_DESC desc; @@ -2631,7 +2643,9 @@ BX_PRAGMA_DIAGNOSTIC_POP(); | (needUav ? D3D11_BIND_UNORDERED_ACCESS : 0) | (needSrv ? D3D11_BIND_SHADER_RESOURCE : 0) ; - desc.MiscFlags = 0; + desc.MiscFlags = 0 + | (drawIndirect ? D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS : 0) + ; desc.StructureByteStride = 0; const DXGI_FORMAT indexFormat = 0 == (_flags & BGFX_BUFFER_INDEX32) @@ -2654,7 +2668,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); DX_CHECK(device->CreateBuffer(&desc , NULL , &m_ptr - )); + ) ); D3D11_UNORDERED_ACCESS_VIEW_DESC uavd; uavd.Format = format; @@ -2665,7 +2679,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); DX_CHECK(device->CreateUnorderedAccessView(m_ptr , &uavd , &m_uav - )); + ) ); } else if (m_dynamic) { @@ -2675,7 +2689,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); DX_CHECK(device->CreateBuffer(&desc , NULL , &m_ptr - )); + ) ); } else { @@ -2690,7 +2704,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); DX_CHECK(device->CreateBuffer(&desc , &srd , &m_ptr - )); + ) ); } if (needSrv) @@ -2703,7 +2717,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); DX_CHECK(device->CreateShaderResourceView(m_ptr , &srvd , &m_srv - )); + ) ); } } @@ -3441,6 +3455,7 @@ BX_PRAGMA_DIAGNOSTIC_POP(); uint32_t statsNumPrimsSubmitted[BX_COUNTOF(s_primInfo)] = {}; uint32_t statsNumPrimsRendered[BX_COUNTOF(s_primInfo)] = {}; uint32_t statsNumInstances[BX_COUNTOF(s_primInfo)] = {}; + uint32_t statsNumDrawIndirect[BX_COUNTOF(s_primInfo)] = {}; uint32_t statsNumIndices = 0; uint32_t statsKeyType[2] = {}; @@ -3982,90 +3997,132 @@ BX_PRAGMA_DIAGNOSTIC_POP(); 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) ) { - if (UINT32_MAX == draw.m_numIndices) + if (isValid(draw.m_indexBuffer) ) { - const IndexBufferD3D11& ib = m_indexBuffers[draw.m_indexBuffer.idx]; - const uint32_t indexSize = 0 == (ib.m_flags & BGFX_BUFFER_INDEX32) ? 2 : 4; - numIndices = ib.m_size/indexSize; - numPrimsSubmitted = numIndices/prim.m_div - prim.m_sub; - numInstances = draw.m_numInstances; - numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + const VertexBufferD3D11& vb = m_vertexBuffers[draw.m_drawIndirectBuffer.idx]; + ID3D11Buffer* ptr = vb.m_ptr; - if (numInstances > 1) + 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; + for (uint32_t ii = 0; ii < numDrawIndirect; ++ii) { - deviceCtx->DrawIndexedInstanced(numIndices - , draw.m_numInstances - , 0 - , draw.m_startVertex - , 0 - ); - } - else - { - deviceCtx->DrawIndexed(numIndices - , 0 - , draw.m_startVertex + deviceCtx->DrawIndexedInstancedIndirect(ptr + , args ); + args += commandSize; } } - else if (prim.m_min <= draw.m_numIndices) + else { - numIndices = draw.m_numIndices; - numPrimsSubmitted = numIndices/prim.m_div - prim.m_sub; - numInstances = draw.m_numInstances; - numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + const VertexBufferD3D11& vb = m_vertexBuffers[draw.m_drawIndirectBuffer.idx]; + ID3D11Buffer* ptr = vb.m_ptr; - if (numInstances > 1) + 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; + for (uint32_t ii = 0; ii < numDrawIndirect; ++ii) { - deviceCtx->DrawIndexedInstanced(numIndices - , draw.m_numInstances - , draw.m_startIndex - , draw.m_startVertex - , 0 - ); - } - else - { - deviceCtx->DrawIndexed(numIndices - , draw.m_startIndex - , draw.m_startVertex + deviceCtx->DrawInstancedIndirect(ptr + , args ); + args += commandSize; } } } else { - numPrimsSubmitted = numVertices/prim.m_div - prim.m_sub; - numInstances = draw.m_numInstances; - numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; - - if (numInstances > 1) + if (isValid(draw.m_indexBuffer) ) { - deviceCtx->DrawInstanced(numVertices - , draw.m_numInstances - , draw.m_startVertex - , 0 - ); + if (UINT32_MAX == draw.m_numIndices) + { + const IndexBufferD3D11& ib = m_indexBuffers[draw.m_indexBuffer.idx]; + const uint32_t indexSize = 0 == (ib.m_flags & BGFX_BUFFER_INDEX32) ? 2 : 4; + numIndices = ib.m_size/indexSize; + numPrimsSubmitted = numIndices/prim.m_div - prim.m_sub; + numInstances = draw.m_numInstances; + numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + + if (numInstances > 1) + { + deviceCtx->DrawIndexedInstanced(numIndices + , draw.m_numInstances + , 0 + , draw.m_startVertex + , 0 + ); + } + else + { + deviceCtx->DrawIndexed(numIndices + , 0 + , draw.m_startVertex + ); + } + } + 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; + + if (numInstances > 1) + { + deviceCtx->DrawIndexedInstanced(numIndices + , draw.m_numInstances + , draw.m_startIndex + , draw.m_startVertex + , 0 + ); + } + else + { + deviceCtx->DrawIndexed(numIndices + , draw.m_startIndex + , draw.m_startVertex + ); + } + } } else { - deviceCtx->Draw(numVertices - , draw.m_startVertex - ); + numPrimsSubmitted = numVertices/prim.m_div - prim.m_sub; + numInstances = draw.m_numInstances; + numPrimsRendered = numPrimsSubmitted*draw.m_numInstances; + + if (numInstances > 1) + { + deviceCtx->DrawInstanced(numVertices + , draw.m_numInstances + , draw.m_startVertex + , 0 + ); + } + else + { + deviceCtx->Draw(numVertices + , draw.m_startVertex + ); + } } } statsNumPrimsSubmitted[primIndex] += numPrimsSubmitted; statsNumPrimsRendered[primIndex] += numPrimsRendered; statsNumInstances[primIndex] += numInstances; - statsNumIndices += numIndices; + statsNumDrawIndirect[primIndex] += numDrawIndirect; + statsNumIndices += numIndices; } } @@ -4174,11 +4231,12 @@ BX_PRAGMA_DIAGNOSTIC_POP(); ); for (uint32_t ii = 0; ii < BX_COUNTOF(s_primName); ++ii) { - tvm.printf(10, pos++, 0x8e, " %9s: %7d (#inst: %5d), submitted: %7d" + tvm.printf(10, pos++, 0x8e, " %9s: %7d (#inst: %5d), submitted: %7d, indirect %7d" , s_primName[ii] , statsNumPrimsRendered[ii] , statsNumInstances[ii] , statsNumPrimsSubmitted[ii] + , statsNumDrawIndirect[ii] ); }