Просмотр исходного кода

D3D11: Added draw indirect support.

Branimir Karadžić 10 лет назад
Родитель
Сommit
d763196407
5 измененных файлов с 220 добавлено и 69 удалено
  1. 10 0
      include/bgfx.h
  2. 4 2
      include/bgfxdefines.h
  3. 25 0
      src/bgfx.cpp
  4. 56 0
      src/bgfx_p.h
  5. 125 67
      src/renderer_d3d11.cpp

+ 10 - 0
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);
 

+ 4 - 2
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)

+ 25 - 0
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();

+ 56 - 0
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;

+ 125 - 67
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
+								deviceCtx->DrawIndexedInstancedIndirect(ptr
+									, args
 									);
+								args += commandSize;
 							}
-							else
+						}
+						else
+						{
+							const VertexBufferD3D11& vb = m_vertexBuffers[draw.m_drawIndirectBuffer.idx];
+							ID3D11Buffer* ptr = vb.m_ptr;
+
+							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->DrawIndexed(numIndices
-									, 0
-									, draw.m_startVertex
+								deviceCtx->DrawInstancedIndirect(ptr
+									, args
 									);
+								args += commandSize;
+							}
+						}
+					}
+					else
+					{
+						if (isValid(draw.m_indexBuffer) )
+						{
+							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 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;
+							numPrimsSubmitted = numVertices/prim.m_div - prim.m_sub;
+							numInstances      = draw.m_numInstances;
+							numPrimsRendered  = numPrimsSubmitted*draw.m_numInstances;
 
 							if (numInstances > 1)
 							{
-								deviceCtx->DrawIndexedInstanced(numIndices
+								deviceCtx->DrawInstanced(numVertices
 									, draw.m_numInstances
-									, draw.m_startIndex
 									, draw.m_startVertex
 									, 0
 									);
 							}
 							else
 							{
-								deviceCtx->DrawIndexed(numIndices
-									, draw.m_startIndex
+								deviceCtx->Draw(numVertices
 									, draw.m_startVertex
 									);
 							}
 						}
 					}
-					else
-					{
-						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]
 						);
 				}