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

D3D12: Added occlusion query support.

Branimir Karadžić 10 лет назад
Родитель
Сommit
a9099f6b28
2 измененных файлов с 129 добавлено и 2 удалено
  1. 104 2
      src/renderer_d3d12.cpp
  2. 25 0
      src/renderer_d3d12.h

+ 104 - 2
src/renderer_d3d12.cpp

@@ -364,6 +364,7 @@ namespace bgfx { namespace d3d12
 	static const GUID IID_ID3D12PipelineState       = { 0x765a30f3, 0xf624, 0x4c6f, { 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45 } };
 	static const GUID IID_ID3D12Resource            = { 0x696442be, 0xa72e, 0x4059, { 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad } };
 	static const GUID IID_ID3D12RootSignature       = { 0xc54a6b66, 0x72df, 0x4ee8, { 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14 } };
+	static const GUID IID_ID3D12QueryHeap           = { 0x0d9658ae, 0xed45, 0x469e, { 0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4 } };
 	static const GUID IID_IDXGIFactory4             = { 0x1bc6ea02, 0xef36, 0x464f, { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a } };
 
 	struct HeapProperty
@@ -885,6 +886,7 @@ namespace bgfx { namespace d3d12
 //									| BGFX_CAPS_SWAP_CHAIN
 									| BGFX_CAPS_TEXTURE_BLIT
 									| BGFX_CAPS_TEXTURE_READ_BACK
+									| BGFX_CAPS_OCCLUSION_QUERY
 									);
 				g_caps.maxTextureSize   = 16384;
 				g_caps.maxFBAttachments = uint8_t(bx::uint32_min(16, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) );
@@ -1036,6 +1038,7 @@ namespace bgfx { namespace d3d12
 				postReset();
 
 				m_batch.create(4<<10);
+				m_occlusionQuery.init();
 			}
 			return true;
 
@@ -1069,6 +1072,8 @@ namespace bgfx { namespace d3d12
 
 			preReset();
 
+			m_occlusionQuery.shutdown();
+
 			m_samplerAllocator.destroy();
 
 			for (uint32_t ii = 0; ii < BX_COUNTOF(m_scratchBuffer); ++ii)
@@ -2382,6 +2387,12 @@ data.NumQualityLevels = 0;
 			return sampler;
 		}
 
+		bool isVisible(Frame* _render, OcclusionQueryHandle _handle, bool _visible)
+		{
+			m_occlusionQuery.resolve(_render);
+			return _visible == (0 != _render->m_occlusion[_handle.idx]);
+		}
+
 		void commit(UniformBuffer& _uniformBuffer)
 		{
 			_uniformBuffer.reset();
@@ -2552,7 +2563,7 @@ data.NumQualityLevels = 0;
 				rect.top    = _rect.m_y;
 				rect.right  = _rect.m_x + _rect.m_width;
 				rect.bottom = _rect.m_y + _rect.m_height;
-				clear(_clear, _palette, &rect);
+				clear(_clear, _palette, &rect, 1);
 			}
 		}
 
@@ -2597,6 +2608,7 @@ data.NumQualityLevels = 0;
 
 		ID3D12Device* m_device;
 		ID3D12InfoQueue* m_infoQueue;
+		OcclusionQueryD3D12 m_occlusionQuery;
 
 		ID3D12DescriptorHeap* m_rtvDescriptorHeap;
 		ID3D12DescriptorHeap* m_dsvDescriptorHeap;
@@ -4318,6 +4330,78 @@ data.NumQualityLevels = 0;
 		}
 	}
 
+	void OcclusionQueryD3D12::init()
+	{
+		D3D12_QUERY_HEAP_DESC queryHeapDesc;
+		queryHeapDesc.Count    = BX_COUNTOF(m_query);
+		queryHeapDesc.NodeMask = 1;
+		queryHeapDesc.Type     = D3D12_QUERY_HEAP_TYPE_OCCLUSION;
+		DX_CHECK(s_renderD3D12->m_device->CreateQueryHeap(&queryHeapDesc
+				, IID_ID3D12QueryHeap
+				, (void**)&m_queryHeap
+				) );
+
+		m_readback = createCommittedResource(s_renderD3D12->m_device
+						, HeapProperty::ReadBack
+						, BX_COUNTOF(m_query)*sizeof(uint64_t)
+						);
+
+		D3D12_RANGE range = { 0, BX_COUNTOF(m_query) };
+		m_readback->Map(0, &range, (void**)&m_result);
+	}
+
+	void OcclusionQueryD3D12::shutdown()
+	{
+		D3D12_RANGE range = { 0, 0 };
+		m_readback->Unmap(0, &range);
+
+		DX_RELEASE(m_queryHeap, 0);
+		DX_RELEASE(m_readback, 0);
+	}
+
+	void OcclusionQueryD3D12::begin(ID3D12GraphicsCommandList* _commandList, Frame* _render, OcclusionQueryHandle _handle)
+	{
+		while (0 == m_control.reserve(1) )
+		{
+			resolve(_render);
+		}
+
+		Query& query = m_query[m_control.m_current];
+		query.m_handle = _handle;
+		_commandList->BeginQuery(m_queryHeap
+			, D3D12_QUERY_TYPE_BINARY_OCCLUSION
+			, _handle.idx
+			);
+	}
+
+	void OcclusionQueryD3D12::end(ID3D12GraphicsCommandList* _commandList)
+	{
+		Query& query = m_query[m_control.m_current];
+		_commandList->EndQuery(m_queryHeap
+			, D3D12_QUERY_TYPE_BINARY_OCCLUSION
+			, query.m_handle.idx
+			);
+		_commandList->ResolveQueryData(m_queryHeap
+			, D3D12_QUERY_TYPE_BINARY_OCCLUSION
+			, query.m_handle.idx
+			, 1
+			, m_readback
+			, query.m_handle.idx * sizeof(uint64_t)
+			);
+		m_control.commit(1);
+	}
+
+	void OcclusionQueryD3D12::resolve(Frame* _render)
+	{
+		while (0 != m_control.available() )
+		{
+			Query& query = m_query[m_control.m_read];
+
+			_render->m_occlusion[query.m_handle.idx] = 0 < m_result[query.m_handle.idx];
+			m_control.consume(1);
+		}
+	}
+
 	struct Bind
 	{
 		D3D12_GPU_DESCRIPTOR_HANDLE m_srvHandle;
@@ -4413,6 +4497,8 @@ data.NumQualityLevels = 0;
 			, D3D12_RESOURCE_STATE_RENDER_TARGET
 			);
 
+		m_occlusionQuery.resolve(_render);
+
 		if (0 == (_render->m_debug&BGFX_DEBUG_IFH) )
 		{
 			m_batch.begin();
@@ -4718,6 +4804,14 @@ data.NumQualityLevels = 0;
 
 				const RenderDraw& draw = renderItem.draw;
 
+				const bool hasOcclusionQuery = 0 != (draw.m_stateFlags & BGFX_STATE_INTERNAL_OCCLUSION_QUERY);
+				if (isValid(draw.m_occlusionQuery)
+				&&  !hasOcclusionQuery
+				&&  !isVisible(_render, draw.m_occlusionQuery, 0 != (draw.m_submitFlags&BGFX_SUBMIT_INTERNAL_OCCLUSION_VISIBLE) ) )
+				{
+					continue;
+				}
+
 				const uint64_t newFlags = draw.m_stateFlags;
 				uint64_t changedFlags = currentState.m_stateFlags ^ draw.m_stateFlags;
 				currentState.m_stateFlags = newFlags;
@@ -4801,7 +4895,8 @@ data.NumQualityLevels = 0;
 					|| (0 != (BGFX_STATE_PT_MASK & changedFlags)
 					||  prim.m_toplogy != s_primInfo[primIndex].m_toplogy)
 					||  currentState.m_scissor != scissor
-					||  pso != currentPso)
+					||  pso != currentPso
+					||  hasOcclusionQuery)
 					{
 						m_batch.flush(m_commandList);
 					}
@@ -4977,6 +5072,13 @@ data.NumQualityLevels = 0;
 					statsNumPrimsRendered[primIndex]  += numPrimsRendered;
 					statsNumInstances[primIndex]      += draw.m_numInstances;
 					statsNumIndices                   += numIndices;
+
+					if (hasOcclusionQuery)
+					{
+						m_occlusionQuery.begin(m_commandList, _render, draw.m_occlusionQuery);
+						m_batch.flush(m_commandList);
+						m_occlusionQuery.end(m_commandList);
+					}
 				}
 			}
 

+ 25 - 0
src/renderer_d3d12.h

@@ -432,6 +432,31 @@ namespace bgfx { namespace d3d12
 		uint32_t m_flushPerBatch;
 	};
 
+	struct OcclusionQueryD3D12
+	{
+		OcclusionQueryD3D12()
+			: m_control(BX_COUNTOF(m_query) )
+		{
+		}
+
+		void init();
+		void shutdown();
+		void begin(ID3D12GraphicsCommandList* _commandList, Frame* _render, OcclusionQueryHandle _handle);
+		void end(ID3D12GraphicsCommandList* _commandList);
+		void resolve(Frame* _render);
+
+		struct Query
+		{
+			OcclusionQueryHandle m_handle;
+		};
+
+		ID3D12Resource*  m_readback;
+		ID3D12QueryHeap* m_queryHeap;
+		Query m_query[BGFX_CONFIG_MAX_OCCUSION_QUERIES];
+		uint64_t* m_result;
+		bx::RingBufferControl m_control;
+	};
+
 } /* namespace d3d12 */ } // namespace bgfx
 
 #endif // BGFX_RENDERER_D3D12_H_HEADER_GUARD