summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineD3D12
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-01-03 06:29:01 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-01-03 06:29:01 +0000
commit7501af2487700060526c5b0c7fc78cc1ee2965cf (patch)
treeed71d7704284e995bfbf17361fb82f4aa7e8dd79 /Graphics/GraphicsEngineD3D12
parentUpdated third-party submodules (diff)
downloadDiligentCore-7501af2487700060526c5b0c7fc78cc1ee2965cf.tar.gz
DiligentCore-7501af2487700060526c5b0c7fc78cc1ee2965cf.zip
Added query interface; implemented queries in D3D11 and D3D12
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
-rw-r--r--Graphics/GraphicsEngineD3D12/CMakeLists.txt5
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandContext.h20
-rw-r--r--Graphics/GraphicsEngineD3D12/include/D3D12TypeConversions.h3
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.h10
-rw-r--r--Graphics/GraphicsEngineD3D12/include/FenceD3D12Impl.h2
-rw-r--r--Graphics/GraphicsEngineD3D12/include/QueryD3D12Impl.h79
-rw-r--r--Graphics/GraphicsEngineD3D12/include/QueryManager.h85
-rw-r--r--Graphics/GraphicsEngineD3D12/include/RenderDeviceD3D12Impl.h7
-rw-r--r--Graphics/GraphicsEngineD3D12/interface/QueryD3D12.h52
-rw-r--r--Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp34
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp52
-rw-r--r--Graphics/GraphicsEngineD3D12/src/QueryD3D12Impl.cpp146
-rw-r--r--Graphics/GraphicsEngineD3D12/src/QueryManager.cpp208
-rw-r--r--Graphics/GraphicsEngineD3D12/src/RenderDeviceD3D12Impl.cpp18
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");