diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-01-03 06:29:01 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-01-03 06:29:01 +0000 |
| commit | 7501af2487700060526c5b0c7fc78cc1ee2965cf (patch) | |
| tree | ed71d7704284e995bfbf17361fb82f4aa7e8dd79 /Graphics/GraphicsEngineD3D12 | |
| parent | Updated third-party submodules (diff) | |
| download | DiligentCore-7501af2487700060526c5b0c7fc78cc1ee2965cf.tar.gz DiligentCore-7501af2487700060526c5b0c7fc78cc1ee2965cf.zip | |
Added query interface; implemented queries in D3D11 and D3D12
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
14 files changed, 718 insertions, 3 deletions
diff --git a/Graphics/GraphicsEngineD3D12/CMakeLists.txt b/Graphics/GraphicsEngineD3D12/CMakeLists.txt index db7e42ef..6fbe75b5 100644 --- a/Graphics/GraphicsEngineD3D12/CMakeLists.txt +++ b/Graphics/GraphicsEngineD3D12/CMakeLists.txt @@ -21,6 +21,8 @@ set(INCLUDE include/GenerateMips.h include/pch.h include/PipelineStateD3D12Impl.h + include/QueryD3D12Impl.h + include/QueryManager.h include/RenderDeviceD3D12Impl.h include/RootSignature.h include/SamplerD3D12Impl.h @@ -43,6 +45,7 @@ set(INTERFACE interface/EngineFactoryD3D12.h interface/FenceD3D12.h interface/PipelineStateD3D12.h + interface/QueryD3D12.h interface/RenderDeviceD3D12.h interface/SamplerD3D12.h interface/ShaderD3D12.h @@ -68,6 +71,8 @@ set(SRC src/FenceD3D12Impl.cpp src/GenerateMips.cpp src/PipelineStateD3D12Impl.cpp + src/QueryD3D12Impl.cpp + src/QueryManager.cpp src/RenderDeviceD3D12Impl.cpp src/RootSignature.cpp src/SamplerD3D12Impl.cpp diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.h b/Graphics/GraphicsEngineD3D12/include/CommandContext.h index 90320f23..ed8824c5 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.h +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.h @@ -181,6 +181,26 @@ public: m_DynamicGPUDescriptorAllocators = Allocators; } + void BeginQuery(ID3D12QueryHeap* pQueryHeap, D3D12_QUERY_TYPE Type, UINT Index) + { + m_pCommandList->BeginQuery(pQueryHeap, Type, Index); + } + + void EndQuery(ID3D12QueryHeap* pQueryHeap, D3D12_QUERY_TYPE Type, UINT Index) + { + m_pCommandList->EndQuery(pQueryHeap, Type, Index); + } + + void ResolveQueryData(ID3D12QueryHeap* pQueryHeap, + D3D12_QUERY_TYPE Type, + UINT StartIndex, + UINT NumQueries, + ID3D12Resource* pDestinationBuffer, + UINT64 AlignedDestinationBufferOffset) + { + m_pCommandList->ResolveQueryData(pQueryHeap, Type, StartIndex, NumQueries, pDestinationBuffer, AlignedDestinationBufferOffset); + } + protected: void InsertAliasBarrier(D3D12ResourceBase& Before, D3D12ResourceBase& After, bool FlushImmediate = false); diff --git a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h index dc0f3d3d..bdaa3f5e 100644 --- a/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h +++ b/Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h @@ -68,4 +68,7 @@ D3D12_STATIC_BORDER_COLOR BorderColorToD3D12StaticBorderColor(const Float32 Bord D3D12_RESOURCE_STATES ResourceStateFlagsToD3D12ResourceStates(RESOURCE_STATE StateFlags); RESOURCE_STATE D3D12ResourceStatesToResourceStateFlags(D3D12_RESOURCE_STATES StateFlags); +D3D12_QUERY_HEAP_TYPE QueryTypeToD3D12QueryHeapType(QUERY_TYPE QueryType); +D3D12_QUERY_TYPE QueryTypeToD3D12QueryType(QUERY_TYPE QueryType); + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h index 36ef62b8..2253dbc2 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h @@ -36,6 +36,7 @@ #include "DeviceContextNextGenBase.h" #include "BufferD3D12Impl.h" #include "TextureD3D12Impl.h" +#include "QueryD3D12Impl.h" #include "PipelineStateD3D12Impl.h" #include "D3D12DynamicHeap.h" @@ -51,6 +52,7 @@ struct DeviceContextD3D12ImplTraits using PipelineStateType = PipelineStateD3D12Impl; using DeviceType = RenderDeviceD3D12Impl; using ICommandQueueType = ICommandQueueD3D12; + using QueryType = QueryD3D12Impl; }; /// Device context implementation in Direct3D12 backend. @@ -209,6 +211,12 @@ public: /// Implementation of IDeviceContext::WaitForIdle() in Direct3D12 backend. virtual void WaitForIdle() override final; + /// Implementation of IDeviceContext::BeginQuery() in Direct3D12 backend. + virtual void BeginQuery(IQuery* pQuery) override final; + + /// Implementation of IDeviceContext::EndQuery() in Direct3D12 backend. + virtual void EndQuery(IQuery* pQuery) override final; + /// Implementation of IDeviceContext::Flush() in Direct3D12 backend. virtual void Flush() override final; @@ -389,6 +397,8 @@ private: }; }; std::unordered_map<MappedTextureKey, TextureUploadSpace, MappedTextureKey::Hasher> m_MappedTextures; + + Int32 m_ActiveQueriesCounter = 0; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/FenceD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/FenceD3D12Impl.h index 49f5a929..cacc1e11 100644 --- a/Graphics/GraphicsEngineD3D12/include/FenceD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/FenceD3D12Impl.h @@ -51,6 +51,8 @@ public: const FenceDesc& Desc); ~FenceD3D12Impl(); + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_FenceD3D12, TFenceBase); + /// Implementation of IFence::GetCompletedValue() in Direct3D12 backend. virtual Uint64 GetCompletedValue() override final; diff --git a/Graphics/GraphicsEngineD3D12/include/QueryD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/QueryD3D12Impl.h new file mode 100644 index 00000000..94fb124b --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/QueryD3D12Impl.h @@ -0,0 +1,79 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of Diligent::QueryD3D12Impl class + +#include "QueryD3D12.h" +#include "QueryBase.h" +#include "RenderDeviceD3D12Impl.h" + +namespace Diligent +{ + +class FixedBlockMemoryAllocator; + +// https://microsoft.github.io/DirectX-Specs/d3d/CountersAndQueries.html#queries + +/// Query implementation in Direct3D12 backend. +class QueryD3D12Impl final : public QueryBase<IQueryD3D12, RenderDeviceD3D12Impl> +{ +public: + using TQueryBase = QueryBase<IQueryD3D12, RenderDeviceD3D12Impl>; + + QueryD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const QueryDesc& Desc); + ~QueryD3D12Impl(); + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_QueryD3D12, TQueryBase); + + /// Implementation of IQuery::GetData(). + virtual bool GetData(void* pData, Uint32 DataSize) override final; + + /// Implementation of IQueryD3D12::GetD3D12QueryHeap(). + virtual ID3D12QueryHeap* GetD3D12QueryHeap() override final + { + return m_pDevice->GetQueryManager().GetQueryHeap(m_Desc.Type); + } + + /// Implementation of IQueryD3D12::GetQueryHeapIndex(). + virtual Uint32 GetQueryHeapIndex() const override final + { + return m_QueryHeapIndex; + } + + bool OnEndQuery(IDeviceContext* pContext); + +private: + Uint32 m_QueryHeapIndex = static_cast<Uint32>(-1); + Uint64 m_QueryEndFenceValue = 0; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/QueryManager.h b/Graphics/GraphicsEngineD3D12/include/QueryManager.h new file mode 100644 index 00000000..a3e37645 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/include/QueryManager.h @@ -0,0 +1,85 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include <mutex> +#include <array> +#include <deque> +#include <vector> + +#include "Query.h" + +namespace Diligent +{ + +class CommandContext; + +class QueryManager +{ +public: + QueryManager(ID3D12Device* pd3d12Device, + const Uint32 QueryHeapSizes[]); + ~QueryManager(); + + // clang-format off + QueryManager (const QueryManager&) = delete; + QueryManager ( QueryManager&&) = delete; + QueryManager& operator = (const QueryManager&) = delete; + QueryManager& operator = ( QueryManager&&) = delete; + // clang-format on + + static constexpr Uint32 InvalidIndex = static_cast<Uint32>(-1); + + Uint32 AllocateQuery(QUERY_TYPE Type); + void ReleaseQuery(QUERY_TYPE Type, Uint32 Index); + + ID3D12QueryHeap* GetQueryHeap(QUERY_TYPE Type) + { + return m_Heaps[Type].pd3d12QueryHeap; + } + + void BeginQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index); + void EndQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index); + void ReadQueryData(QUERY_TYPE Type, Uint32 Index, void* pDataPtr, Uint32 DataSize) const; + +private: + struct QueryHeapInfo + { + CComPtr<ID3D12QueryHeap> pd3d12QueryHeap; + std::deque<Uint32> AvailableQueries; + std::vector<Uint32> ResolveBufferOffsets; + Uint32 HeapSize = 0; + }; + + std::mutex m_HeapMutex; + std::array<QueryHeapInfo, QUERY_TYPE_NUM_TYPES> m_Heaps; + + CComPtr<ID3D12Resource> m_pd3d12ResolveBuffer; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h index 30d77e73..248cabec 100644 --- a/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h +++ b/Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h @@ -39,6 +39,7 @@ #include "Atomics.h" #include "CommandQueueD3D12.h" #include "GenerateMips.h" +#include "QueryManager.h" namespace Diligent { @@ -80,6 +81,9 @@ public: /// Implementation of IRenderDevice::CreateFence() in Direct3D12 backend. virtual void CreateFence(const FenceDesc& Desc, IFence** ppFence) override final; + /// Implementation of IRenderDevice::CreateQuery() in Direct3D12 backend. + virtual void CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) override final; + /// Implementation of IRenderDeviceD3D12::GetD3D12Device(). virtual ID3D12Device* GetD3D12Device() override final { return m_pd3d12Device; } @@ -124,6 +128,7 @@ public: } const GenerateMipsHelper& GetMipsGenerator() const { return m_MipsGenerator; } + QueryManager& GetQueryManager() { return m_QueryMgr; } D3D_FEATURE_LEVEL GetD3DFeatureLevel() const; @@ -151,6 +156,8 @@ private: // Note: mips generator must be released after the device has been idled GenerateMipsHelper m_MipsGenerator; + + QueryManager m_QueryMgr; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/interface/QueryD3D12.h b/Graphics/GraphicsEngineD3D12/interface/QueryD3D12.h new file mode 100644 index 00000000..6dad3772 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/interface/QueryD3D12.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Definition of the Diligent::IQueryD3D12 interface + +#include "../../GraphicsEngine/interface/Query.h" + +namespace Diligent +{ + +// {72D109BE-7D70-4E54-84EF-C649DA190B2C} +static constexpr INTERFACE_ID IID_QueryD3D12 = + {0x72d109be, 0x7d70, 0x4e54, {0x84, 0xef, 0xc6, 0x49, 0xda, 0x19, 0xb, 0x2c}}; + +/// Exposes Direct3D12-specific functionality of a Query object. +class IQueryD3D12 : public IQuery +{ + /// Returns the Direct3D12 query heap that internal query object resides in. + virtual ID3D12QueryHeap* GetD3D12QueryHeap() = 0; + + /// Returns the index of a query object in Direct3D12 query heap. + virtual Uint32 GetQueryHeapIndex() const = 0; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp index d6d0f3a2..e0e8d3f7 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp @@ -467,4 +467,38 @@ RESOURCE_STATE D3D12ResourceStatesToResourceStateFlags(D3D12_RESOURCE_STATES Sta return static_cast<RESOURCE_STATE>(ResourceStates); } +D3D12_QUERY_TYPE QueryTypeToD3D12QueryType(QUERY_TYPE QueryType) +{ + // clang-format off + switch (QueryType) + { + case QUERY_TYPE_OCCLUSION: return D3D12_QUERY_TYPE_OCCLUSION; + case QUERY_TYPE_BINARY_OCCLUSION: return D3D12_QUERY_TYPE_BINARY_OCCLUSION; + case QUERY_TYPE_TIMESTAMP: return D3D12_QUERY_TYPE_TIMESTAMP; + case QUERY_TYPE_PIPELINE_STATISTICS: return D3D12_QUERY_TYPE_PIPELINE_STATISTICS; + + default: + UNEXPECTED("Unexpected query type"); + return static_cast<D3D12_QUERY_TYPE>(-1); + } + // clang-format on +} + +D3D12_QUERY_HEAP_TYPE QueryTypeToD3D12QueryHeapType(QUERY_TYPE QueryType) +{ + // clang-format off + switch (QueryType) + { + case QUERY_TYPE_OCCLUSION: return D3D12_QUERY_HEAP_TYPE_OCCLUSION; + case QUERY_TYPE_BINARY_OCCLUSION: return D3D12_QUERY_HEAP_TYPE_OCCLUSION; + case QUERY_TYPE_TIMESTAMP: return D3D12_QUERY_HEAP_TYPE_TIMESTAMP; + case QUERY_TYPE_PIPELINE_STATISTICS: return D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS; + + default: + UNEXPECTED("Unexpected query type"); + return static_cast<D3D12_QUERY_HEAP_TYPE>(-1); + } + // clang-format on +} + } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 70adc73f..eb49d52c 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -179,7 +179,9 @@ void DeviceContextD3D12Impl::SetPipelineState(IPipelineState* pPipelineState) return; // Never flush deferred context! - if (!m_bIsDeferred && m_State.NumCommands >= m_NumCommandsToFlush) + // For the query types which support both BeginQuery and EndQuery (all except for timestamp), + // a query for a given element must not span command list boundaries. + if (!m_bIsDeferred && m_State.NumCommands >= m_NumCommandsToFlush && m_ActiveQueriesCounter == 0) { Flush(true); } @@ -674,6 +676,12 @@ void DeviceContextD3D12Impl::Flush(bool RequestNewCmdCtx) m_pDevice->DisposeCommandContext(std::move(m_CurrCmdCtx)); } + if (m_ActiveQueriesCounter > 0) + { + LOG_ERROR_MESSAGE("Flushing device context that has ", m_ActiveQueriesCounter, + " active queries. Direct3D12 requires that queries are begun and ended in the same command list"); + } + // If there is no command list to submit, but there are pending fences, we need to signal them now if (!m_PendingFences.empty()) { @@ -733,6 +741,13 @@ void DeviceContextD3D12Impl::FinishFrame() } } + if (m_ActiveQueriesCounter > 0) + { + LOG_ERROR_MESSAGE("There are ", m_ActiveQueriesCounter, + " active queries in the device context when finishing the frame. " + "All queries must be ended before the frame is finished."); + } + VERIFY_EXPR(m_bIsDeferred || m_SubmittedBuffersCmdQueueMask == (Uint64{1} << m_CommandQueueId)); // Released pages are returned to the global dynamic memory manager hosted by render device. @@ -1677,6 +1692,41 @@ void DeviceContextD3D12Impl::WaitForIdle() m_pDevice->IdleCommandQueue(m_CommandQueueId, true); } +void DeviceContextD3D12Impl::BeginQuery(IQuery* pQuery) +{ + if (!TDeviceContextBase::BeginQuery(pQuery, 0)) + return; + + auto* pQueryD3D12Impl = ValidatedCast<QueryD3D12Impl>(pQuery); + const auto QueryType = pQueryD3D12Impl->GetDesc().Type; + if (QueryType != QUERY_TYPE_TIMESTAMP) + ++m_ActiveQueriesCounter; + + auto& QueueMgr = m_pDevice->GetQueryManager(); + auto& Ctx = GetCmdContext(); + auto Idx = pQueryD3D12Impl->GetQueryHeapIndex(); + QueueMgr.BeginQuery(Ctx, QueryType, Idx); +} + +void DeviceContextD3D12Impl::EndQuery(IQuery* pQuery) +{ + if (!TDeviceContextBase::EndQuery(pQuery, 0)) + return; + + auto* pQueryD3D12Impl = ValidatedCast<QueryD3D12Impl>(pQuery); + if (pQueryD3D12Impl->GetDesc().Type != QUERY_TYPE_TIMESTAMP) + { + VERIFY(m_ActiveQueriesCounter > 0, "Active query counter is 0 which means there was a mismatch between BeginQuery() / EndQuery() calls"); + --m_ActiveQueriesCounter; + } + + const auto QueryType = pQueryD3D12Impl->GetDesc().Type; + auto& QueueMgr = m_pDevice->GetQueryManager(); + auto& Ctx = GetCmdContext(); + auto Idx = pQueryD3D12Impl->GetQueryHeapIndex(); + QueueMgr.EndQuery(Ctx, QueryType, Idx); +} + void DeviceContextD3D12Impl::TransitionResourceStates(Uint32 BarrierCount, StateTransitionDesc* pResourceBarriers) { auto& CmdCtx = GetCmdContext(); diff --git a/Graphics/GraphicsEngineD3D12/src/QueryD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/QueryD3D12Impl.cpp new file mode 100644 index 00000000..073f839a --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/QueryD3D12Impl.cpp @@ -0,0 +1,146 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include <atlbase.h> + +#include "QueryD3D12Impl.h" +#include "RenderDeviceD3D12Impl.h" +#include "GraphicsAccessories.h" +#include "DeviceContextD3D12Impl.h" + +namespace Diligent +{ + +QueryD3D12Impl::QueryD3D12Impl(IReferenceCounters* pRefCounters, + RenderDeviceD3D12Impl* pDevice, + const QueryDesc& Desc) : + TQueryBase{pRefCounters, pDevice, Desc} +{ + auto& QueryMgr = pDevice->GetQueryManager(); + m_QueryHeapIndex = QueryMgr.AllocateQuery(m_Desc.Type); + if (m_QueryHeapIndex == QueryManager::InvalidIndex) + { + LOG_ERROR_AND_THROW("Failed to allocate D3D12 query for type ", GetQueryTypeString(m_Desc.Type), + ". Increase the query pool size in EngineD3D12CreateInfo."); + } +} + +QueryD3D12Impl::~QueryD3D12Impl() +{ + auto& QueryMgr = m_pDevice->GetQueryManager(); + QueryMgr.ReleaseQuery(m_Desc.Type, m_QueryHeapIndex); +} + +bool QueryD3D12Impl::OnEndQuery(IDeviceContext* pContext) +{ + if (!TQueryBase::OnEndQuery(pContext)) + return false; + + auto CmdQueueId = m_pContext.RawPtr<DeviceContextD3D12Impl>()->GetCommandQueueId(); + m_QueryEndFenceValue = m_pDevice->GetNextFenceValue(CmdQueueId); + + return true; +} + +bool QueryD3D12Impl::GetData(void* pData, Uint32 DataSize) +{ + auto CmdQueueId = m_pContext.RawPtr<DeviceContextD3D12Impl>()->GetCommandQueueId(); + auto CompletedFenceValue = m_pDevice->GetCompletedFenceValue(CmdQueueId); + if (CompletedFenceValue >= m_QueryEndFenceValue) + { + auto& QueryMgr = m_pDevice->GetQueryManager(); + + switch (m_Desc.Type) + { + case QUERY_TYPE_OCCLUSION: + { + UINT64 NumSamples; + QueryMgr.ReadQueryData(m_Desc.Type, m_QueryHeapIndex, &NumSamples, sizeof(NumSamples)); + auto& QueryData = *reinterpret_cast<QueryDataOcclusion*>(pData); + QueryData.NumSamples = NumSamples; + } + break; + + case QUERY_TYPE_BINARY_OCCLUSION: + { + UINT64 AnySamplePassed; + QueryMgr.ReadQueryData(m_Desc.Type, m_QueryHeapIndex, &AnySamplePassed, sizeof(AnySamplePassed)); + auto& QueryData = *reinterpret_cast<QueryDataBinaryOcclusion*>(pData); + QueryData.AnySamplePassed = AnySamplePassed != 0; + } + break; + + case QUERY_TYPE_TIMESTAMP: + { + UINT64 NumTicks; + QueryMgr.ReadQueryData(m_Desc.Type, m_QueryHeapIndex, &NumTicks, sizeof(NumTicks)); + auto& QueryData = *reinterpret_cast<QueryDataTimestamp*>(pData); + QueryData.NumTicks = NumTicks; + + const auto& CmdQueue = m_pDevice->GetCommandQueue(CmdQueueId); + auto* pd3d12Queue = const_cast<ICommandQueueD3D12&>(CmdQueue).GetD3D12CommandQueue(); + + UINT64 TimestampFrequency = 0; + pd3d12Queue->GetTimestampFrequency(&TimestampFrequency); + QueryData.Frequency = TimestampFrequency; + } + break; + + case QUERY_TYPE_PIPELINE_STATISTICS: + { + D3D12_QUERY_DATA_PIPELINE_STATISTICS d3d12QueryData; + QueryMgr.ReadQueryData(m_Desc.Type, m_QueryHeapIndex, &d3d12QueryData, sizeof(d3d12QueryData)); + auto& QueryData = *reinterpret_cast<QueryDataPipelineStatistics*>(pData); + + QueryData.InputVertices = d3d12QueryData.IAVertices; + QueryData.InputPrimitives = d3d12QueryData.IAPrimitives; + QueryData.GSPrimitives = d3d12QueryData.GSPrimitives; + QueryData.ClippingInvocations = d3d12QueryData.CInvocations; + QueryData.ClippingPrimitives = d3d12QueryData.CPrimitives; + QueryData.VSInvocations = d3d12QueryData.VSInvocations; + QueryData.GSInvocations = d3d12QueryData.GSInvocations; + QueryData.PSInvocations = d3d12QueryData.PSInvocations; + QueryData.HSInvocations = d3d12QueryData.HSInvocations; + QueryData.DSInvocations = d3d12QueryData.DSInvocations; + QueryData.CSInvocations = d3d12QueryData.CSInvocations; + } + break; + + default: + UNEXPECTED("Unexpected query type"); + } + + return true; + } + else + { + return false; + } +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/QueryManager.cpp b/Graphics/GraphicsEngineD3D12/src/QueryManager.cpp new file mode 100644 index 00000000..00a37076 --- /dev/null +++ b/Graphics/GraphicsEngineD3D12/src/QueryManager.cpp @@ -0,0 +1,208 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "pch.h" +#include "QueryManager.h" +#include "RenderDeviceD3D12Impl.h" +#include "D3D12TypeConversions.h" +#include "GraphicsAccessories.h" + +namespace Diligent +{ + +static Uint32 GetQueryDataSize(QUERY_TYPE QueryType) +{ + // clang-format off + switch (QueryType) + { + case QUERY_TYPE_OCCLUSION: + case QUERY_TYPE_BINARY_OCCLUSION: + case QUERY_TYPE_TIMESTAMP: + return sizeof(Uint64); + break; + + case QUERY_TYPE_PIPELINE_STATISTICS: + return sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS); + break; + + default: + UNEXPECTED("Unexpected query type"); + return 0; + } + // clang-format on +} + +QueryManager::QueryManager(ID3D12Device* pd3d12Device, + const Uint32 QueryHeapSizes[]) +{ + Uint32 ResolveBufferOffset = 0; + for (Uint32 QueryType = QUERY_TYPE_UNDEFINED + 1; QueryType < QUERY_TYPE_NUM_TYPES; ++QueryType) + { + // clang-format off + static_assert(QUERY_TYPE_OCCLUSION == 1, "Unexpected value of QUERY_TYPE_OCCLUSION. EngineD3D12CreateInfo::QueryPoolSizes must be updated"); + static_assert(QUERY_TYPE_BINARY_OCCLUSION == 2, "Unexpected value of QUERY_TYPE_BINARY_OCCLUSION. EngineD3D12CreateInfo::QueryPoolSizes must be updated"); + static_assert(QUERY_TYPE_TIMESTAMP == 3, "Unexpected value of QUERY_TYPE_TIMESTAMP. EngineD3D12CreateInfo::QueryPoolSizes must be updated"); + static_assert(QUERY_TYPE_PIPELINE_STATISTICS== 4, "Unexpected value of QUERY_TYPE_PIPELINE_STATISTICS. EngineD3D12CreateInfo::QueryPoolSizes must be updated"); + static_assert(QUERY_TYPE_NUM_TYPES == 5, "Unexpected value of QUERY_TYPE_NUM_TYPES. EngineD3D12CreateInfo::QueryPoolSizes must be updated"); + // clang-format on + auto& HeapInfo = m_Heaps[QueryType]; + + D3D12_QUERY_HEAP_DESC d3d12HeapDesc = {}; + + HeapInfo.HeapSize = QueryHeapSizes[QueryType]; + d3d12HeapDesc.Type = QueryTypeToD3D12QueryHeapType(static_cast<QUERY_TYPE>(QueryType)); + d3d12HeapDesc.Count = HeapInfo.HeapSize; + + auto hr = pd3d12Device->CreateQueryHeap(&d3d12HeapDesc, __uuidof(HeapInfo.pd3d12QueryHeap), reinterpret_cast<void**>(&HeapInfo.pd3d12QueryHeap)); + CHECK_D3D_RESULT_THROW(hr, "Failed to create D3D12 query heap of type"); + + Uint32 AlignedQueryDataSize = Align(GetQueryDataSize(static_cast<QUERY_TYPE>(QueryType)), Uint32{8}); + HeapInfo.AvailableQueries.resize(HeapInfo.HeapSize); + HeapInfo.ResolveBufferOffsets.resize(HeapInfo.HeapSize); + for (Uint32 i = 0; i < HeapInfo.HeapSize; ++i) + { + HeapInfo.AvailableQueries[i] = i; + HeapInfo.ResolveBufferOffsets[i] = ResolveBufferOffset; + ResolveBufferOffset += AlignedQueryDataSize; + } + } + + D3D12_RESOURCE_DESC D3D12BuffDesc = {}; + D3D12BuffDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + D3D12BuffDesc.Alignment = 0; + D3D12BuffDesc.Width = ResolveBufferOffset; + D3D12BuffDesc.Height = 1; + D3D12BuffDesc.DepthOrArraySize = 1; + D3D12BuffDesc.MipLevels = 1; + D3D12BuffDesc.Format = DXGI_FORMAT_UNKNOWN; + D3D12BuffDesc.SampleDesc.Count = 1; + D3D12BuffDesc.SampleDesc.Quality = 0; + // Layout must be D3D12_TEXTURE_LAYOUT_ROW_MAJOR, as buffer memory layouts are + // understood by applications and row-major texture data is commonly marshaled through buffers. + D3D12BuffDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + D3D12BuffDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + D3D12_HEAP_PROPERTIES HeapProps = {}; + HeapProps.Type = D3D12_HEAP_TYPE_READBACK; + HeapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProps.CreationNodeMask = 1; + HeapProps.VisibleNodeMask = 1; + + auto hr = pd3d12Device->CreateCommittedResource(&HeapProps, D3D12_HEAP_FLAG_NONE, + &D3D12BuffDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, + __uuidof(m_pd3d12ResolveBuffer), + reinterpret_cast<void**>(static_cast<ID3D12Resource**>(&m_pd3d12ResolveBuffer))); + if (FAILED(hr)) + LOG_ERROR_AND_THROW("Failed to create D3D12 resolve buffer"); +} + +QueryManager::~QueryManager() +{ + for (Uint32 QueryType = QUERY_TYPE_UNDEFINED + 1; QueryType < QUERY_TYPE_NUM_TYPES; ++QueryType) + { + auto& HeapInfo = m_Heaps[QueryType]; + if (HeapInfo.AvailableQueries.size() != HeapInfo.HeapSize) + { + auto OutstandingQueries = HeapInfo.HeapSize - HeapInfo.AvailableQueries.size(); + if (OutstandingQueries == 1) + { + LOG_ERROR_MESSAGE("One query of type ", GetQueryTypeString(static_cast<QUERY_TYPE>(QueryType)), + " has not been returned to the query manager"); + } + else + { + LOG_ERROR_MESSAGE(OutstandingQueries, " queries of type ", + GetQueryTypeString(static_cast<QUERY_TYPE>(QueryType)), + " have not been returned to the query manager"); + } + } + } +} + +Uint32 QueryManager::AllocateQuery(QUERY_TYPE Type) +{ + std::lock_guard<std::mutex> Lock(m_HeapMutex); + + Uint32 Index = InvalidIndex; + auto& HeapInfo = m_Heaps[Type]; + if (!HeapInfo.AvailableQueries.empty()) + { + Index = HeapInfo.AvailableQueries.front(); + HeapInfo.AvailableQueries.pop_front(); + } + + return Index; +} + +void QueryManager::ReleaseQuery(QUERY_TYPE Type, Uint32 Index) +{ + std::lock_guard<std::mutex> Lock(m_HeapMutex); + auto& HeapInfo = m_Heaps[Type]; + + VERIFY(Index < HeapInfo.HeapSize, "Query index ", Index, " is out of range"); +#ifdef _DEBUG + for (const auto& ind : HeapInfo.AvailableQueries) + { + VERIFY(ind != Index, "Index ", Index, " already present in available queries list"); + } +#endif + HeapInfo.AvailableQueries.push_back(Index); +} + +void QueryManager::BeginQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index) +{ + auto d3d12QueryType = QueryTypeToD3D12QueryType(Type); + Ctx.BeginQuery(m_Heaps[Type].pd3d12QueryHeap, d3d12QueryType, Index); +} + +void QueryManager::EndQuery(CommandContext& Ctx, QUERY_TYPE Type, Uint32 Index) +{ + auto d3d12QueryType = QueryTypeToD3D12QueryType(Type); + auto& HeapInfo = m_Heaps[Type]; + Ctx.EndQuery(HeapInfo.pd3d12QueryHeap, d3d12QueryType, Index); + Ctx.ResolveQueryData(HeapInfo.pd3d12QueryHeap, d3d12QueryType, Index, 1, m_pd3d12ResolveBuffer, HeapInfo.ResolveBufferOffsets[Index]); +} + +void QueryManager::ReadQueryData(QUERY_TYPE Type, Uint32 Index, void* pDataPtr, Uint32 DataSize) const +{ + auto& HeapInfo = m_Heaps[Type]; + auto QueryDataSize = GetQueryDataSize(Type); + VERIFY_EXPR(QueryDataSize == DataSize); + auto Offset = HeapInfo.ResolveBufferOffsets[Index]; + D3D12_RANGE ReadRange; + ReadRange.Begin = Offset; + ReadRange.End = Offset + QueryDataSize; + + void* pBufferData = nullptr; + // The pointer returned by Map is never offset by any values in pReadRange. + m_pd3d12ResolveBuffer->Map(0, &ReadRange, &pBufferData); + memcpy(pDataPtr, reinterpret_cast<const Uint8*>(pBufferData) + Offset, QueryDataSize); + m_pd3d12ResolveBuffer->Unmap(0, nullptr); +} + +} // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp index e7ecb784..ea00a31e 100644 --- a/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp @@ -37,6 +37,7 @@ #include "ShaderResourceBindingD3D12Impl.h" #include "DeviceContextD3D12Impl.h" #include "FenceD3D12Impl.h" +#include "QueryD3D12Impl.h" #include "EngineMemory.h" namespace Diligent @@ -107,7 +108,8 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo sizeof(SamplerD3D12Impl), sizeof(PipelineStateD3D12Impl), sizeof(ShaderResourceBindingD3D12Impl), - sizeof(FenceD3D12Impl) + sizeof(FenceD3D12Impl), + sizeof(QueryD3D12Impl) } }, m_pd3d12Device {pd3d12Device}, @@ -127,7 +129,8 @@ RenderDeviceD3D12Impl::RenderDeviceD3D12Impl(IReferenceCounters* pRefCo }, m_ContextPool (STD_ALLOCATOR_RAW_MEM(PooledCommandContext, GetRawAllocator(), "Allocator for vector<PooledCommandContext>")), m_DynamicMemoryManager{GetRawAllocator(), *this, EngineCI.NumDynamicHeapPagesToReserve, EngineCI.DynamicHeapPageSize}, - m_MipsGenerator {pd3d12Device} + m_MipsGenerator {pd3d12Device}, + m_QueryMgr {pd3d12Device, EngineCI.QueryPoolSizes} // clang-format on { m_DeviceCaps.DevType = DeviceType::D3D12; @@ -490,6 +493,17 @@ void RenderDeviceD3D12Impl::CreateFence(const FenceDesc& Desc, IFence** ppFence) }); } +void RenderDeviceD3D12Impl::CreateQuery(const QueryDesc& Desc, IQuery** ppQuery) +{ + CreateDeviceObject("Query", Desc, ppQuery, + [&]() // + { + QueryD3D12Impl* pQueryD3D12(NEW_RC_OBJ(m_QueryAllocator, "QueryD3D12Impl instance", QueryD3D12Impl)(this, Desc)); + pQueryD3D12->QueryInterface(IID_Query, reinterpret_cast<IObject**>(ppQuery)); + OnCreateDeviceObject(pQueryD3D12); + }); +} + DescriptorHeapAllocation RenderDeviceD3D12Impl::AllocateDescriptor(D3D12_DESCRIPTOR_HEAP_TYPE Type, UINT Count /*= 1*/) { VERIFY(Type >= D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && Type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES, "Invalid heap type"); |
