core: Define VK_USE_PLATFORM_XCB_KHR before including vkd3d_utils.h.
[vkmodelviewer.git] / Core / DynamicDescriptorHeap.cpp
blobac35f5029aa6c9395ed7f04ae16d71c5113fc10a
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // This code is licensed under the MIT License (MIT).
4 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
5 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
6 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
7 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
8 //
9 // Developed by Minigraph
11 // Author: James Stanard
14 #include "pch.h"
15 #include "DynamicDescriptorHeap.h"
16 #include "CommandContext.h"
17 #include "GraphicsCore.h"
18 #include "CommandListManager.h"
19 #include "RootSignature.h"
21 using namespace Graphics;
24 // DynamicDescriptorHeap Implementation
27 std::mutex DynamicDescriptorHeap::sm_Mutex;
28 std::vector<Microsoft::WRL::ComPtr<ID3D12DescriptorHeap>> DynamicDescriptorHeap::sm_DescriptorHeapPool[2];
29 std::queue<std::pair<uint64_t, ID3D12DescriptorHeap*>> DynamicDescriptorHeap::sm_RetiredDescriptorHeaps[2];
30 std::queue<ID3D12DescriptorHeap*> DynamicDescriptorHeap::sm_AvailableDescriptorHeaps[2];
32 ID3D12DescriptorHeap* DynamicDescriptorHeap::RequestDescriptorHeap(D3D12_DESCRIPTOR_HEAP_TYPE HeapType)
34 std::lock_guard<std::mutex> LockGuard(sm_Mutex);
36 uint32_t idx = HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ? 1 : 0;
38 while (!sm_RetiredDescriptorHeaps[idx].empty() && g_CommandManager.IsFenceComplete(sm_RetiredDescriptorHeaps[idx].front().first))
40 sm_AvailableDescriptorHeaps[idx].push(sm_RetiredDescriptorHeaps[idx].front().second);
41 sm_RetiredDescriptorHeaps[idx].pop();
44 if (!sm_AvailableDescriptorHeaps[idx].empty())
46 ID3D12DescriptorHeap* HeapPtr = sm_AvailableDescriptorHeaps[idx].front();
47 sm_AvailableDescriptorHeaps[idx].pop();
48 return HeapPtr;
50 else
52 D3D12_DESCRIPTOR_HEAP_DESC HeapDesc = {};
53 HeapDesc.Type = HeapType;
54 HeapDesc.NumDescriptors = kNumDescriptorsPerHeap;
55 HeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
56 HeapDesc.NodeMask = 1;
57 Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> HeapPtr;
58 ASSERT_SUCCEEDED(g_Device->CreateDescriptorHeap(&HeapDesc, MY_IID_PPV_ARGS(&HeapPtr)));
59 sm_DescriptorHeapPool[idx].emplace_back(HeapPtr);
60 return HeapPtr.Get();
64 void DynamicDescriptorHeap::DiscardDescriptorHeaps( D3D12_DESCRIPTOR_HEAP_TYPE HeapType, uint64_t FenceValue, const std::vector<ID3D12DescriptorHeap*>& UsedHeaps )
66 uint32_t idx = HeapType == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ? 1 : 0;
67 std::lock_guard<std::mutex> LockGuard(sm_Mutex);
68 for (auto iter = UsedHeaps.begin(); iter != UsedHeaps.end(); ++iter)
69 sm_RetiredDescriptorHeaps[idx].push(std::make_pair(FenceValue, *iter));
72 void DynamicDescriptorHeap::RetireCurrentHeap( void )
74 // Don't retire unused heaps.
75 if (m_CurrentOffset == 0)
77 ASSERT(m_CurrentHeapPtr == nullptr);
78 return;
81 ASSERT(m_CurrentHeapPtr != nullptr);
82 m_RetiredHeaps.push_back(m_CurrentHeapPtr);
83 m_CurrentHeapPtr = nullptr;
84 m_CurrentOffset = 0;
87 void DynamicDescriptorHeap::RetireUsedHeaps( uint64_t fenceValue )
89 DiscardDescriptorHeaps(m_DescriptorType, fenceValue, m_RetiredHeaps);
90 m_RetiredHeaps.clear();
93 DynamicDescriptorHeap::DynamicDescriptorHeap(CommandContext& OwningContext, D3D12_DESCRIPTOR_HEAP_TYPE HeapType)
94 : m_OwningContext(OwningContext), m_DescriptorType(HeapType)
96 m_CurrentHeapPtr = nullptr;
97 m_CurrentOffset = 0;
98 m_DescriptorSize = Graphics::g_Device->GetDescriptorHandleIncrementSize(HeapType);
101 DynamicDescriptorHeap::~DynamicDescriptorHeap()
105 void DynamicDescriptorHeap::CleanupUsedHeaps( uint64_t fenceValue )
107 RetireCurrentHeap();
108 RetireUsedHeaps(fenceValue);
109 m_GraphicsHandleCache.ClearCache();
110 m_ComputeHandleCache.ClearCache();
113 inline ID3D12DescriptorHeap* DynamicDescriptorHeap::GetHeapPointer()
115 if (m_CurrentHeapPtr == nullptr)
117 ASSERT(m_CurrentOffset == 0);
118 m_CurrentHeapPtr = RequestDescriptorHeap(m_DescriptorType);
119 m_FirstDescriptor = DescriptorHandle(
120 m_CurrentHeapPtr->GetCPUDescriptorHandleForHeapStart(),
121 m_CurrentHeapPtr->GetGPUDescriptorHandleForHeapStart());
124 return m_CurrentHeapPtr;
127 uint32_t DynamicDescriptorHeap::DescriptorHandleCache::ComputeStagedSize()
129 // Sum the maximum assigned offsets of stale descriptor tables to determine total needed space.
130 uint32_t NeededSpace = 0;
131 unsigned long RootIndex;
132 uint32_t StaleParams = m_StaleRootParamsBitMap;
133 while (_BitScanForward(&RootIndex, StaleParams))
135 StaleParams ^= (1 << RootIndex);
137 unsigned long MaxSetHandle;
138 ASSERT(TRUE == _BitScanReverse(&MaxSetHandle, m_RootDescriptorTable[RootIndex].AssignedHandlesBitMap),
139 "Root entry marked as stale but has no stale descriptors");
141 NeededSpace += MaxSetHandle + 1;
143 return NeededSpace;
146 void DynamicDescriptorHeap::DescriptorHandleCache::CopyAndBindStaleTables(
147 D3D12_DESCRIPTOR_HEAP_TYPE Type, uint32_t DescriptorSize,
148 DescriptorHandle DestHandleStart, ID3D12GraphicsCommandList* CmdList,
149 void (STDMETHODCALLTYPE ID3D12GraphicsCommandList::*SetFunc)(UINT, D3D12_GPU_DESCRIPTOR_HANDLE))
151 uint32_t StaleParamCount = 0;
152 uint32_t TableSize[DescriptorHandleCache::kMaxNumDescriptorTables];
153 uint32_t RootIndices[DescriptorHandleCache::kMaxNumDescriptorTables];
154 uint32_t NeededSpace = 0;
155 unsigned long RootIndex;
157 // Sum the maximum assigned offsets of stale descriptor tables to determine total needed space.
158 uint32_t StaleParams = m_StaleRootParamsBitMap;
159 while (_BitScanForward(&RootIndex, StaleParams))
161 RootIndices[StaleParamCount] = RootIndex;
162 StaleParams ^= (1 << RootIndex);
164 unsigned long MaxSetHandle;
165 ASSERT(TRUE == _BitScanReverse(&MaxSetHandle, m_RootDescriptorTable[RootIndex].AssignedHandlesBitMap),
166 "Root entry marked as stale but has no stale descriptors");
168 NeededSpace += MaxSetHandle + 1;
169 TableSize[StaleParamCount] = MaxSetHandle + 1;
171 ++StaleParamCount;
174 ASSERT(StaleParamCount <= DescriptorHandleCache::kMaxNumDescriptorTables,
175 "We're only equipped to handle so many descriptor tables");
177 m_StaleRootParamsBitMap = 0;
179 static const uint32_t kMaxDescriptorsPerCopy = 16;
180 UINT NumDestDescriptorRanges = 0;
181 D3D12_CPU_DESCRIPTOR_HANDLE pDestDescriptorRangeStarts[kMaxDescriptorsPerCopy];
182 UINT pDestDescriptorRangeSizes[kMaxDescriptorsPerCopy];
184 UINT NumSrcDescriptorRanges = 0;
185 D3D12_CPU_DESCRIPTOR_HANDLE pSrcDescriptorRangeStarts[kMaxDescriptorsPerCopy];
186 UINT pSrcDescriptorRangeSizes[kMaxDescriptorsPerCopy];
188 for (uint32_t i = 0; i < StaleParamCount; ++i)
190 RootIndex = RootIndices[i];
191 (CmdList->*SetFunc)(RootIndex, DestHandleStart.GetGpuHandle());
193 DescriptorTableCache& RootDescTable = m_RootDescriptorTable[RootIndex];
195 D3D12_CPU_DESCRIPTOR_HANDLE* SrcHandles = RootDescTable.TableStart;
196 uint64_t SetHandles = (uint64_t)RootDescTable.AssignedHandlesBitMap;
197 D3D12_CPU_DESCRIPTOR_HANDLE CurDest = DestHandleStart.GetCpuHandle();
198 DestHandleStart += TableSize[i] * DescriptorSize;
200 unsigned long SkipCount;
201 while (_BitScanForward64(&SkipCount, SetHandles))
203 // Skip over unset descriptor handles
204 SetHandles >>= SkipCount;
205 SrcHandles += SkipCount;
206 CurDest.ptr += SkipCount * DescriptorSize;
208 unsigned long DescriptorCount;
209 _BitScanForward64(&DescriptorCount, ~SetHandles);
210 SetHandles >>= DescriptorCount;
212 // If we run out of temp room, copy what we've got so far
213 if (NumSrcDescriptorRanges + DescriptorCount > kMaxDescriptorsPerCopy)
215 g_Device->CopyDescriptors(
216 NumDestDescriptorRanges, pDestDescriptorRangeStarts, pDestDescriptorRangeSizes,
217 NumSrcDescriptorRanges, pSrcDescriptorRangeStarts, pSrcDescriptorRangeSizes,
218 Type);
220 NumSrcDescriptorRanges = 0;
221 NumDestDescriptorRanges = 0;
224 // Setup destination range
225 pDestDescriptorRangeStarts[NumDestDescriptorRanges] = CurDest;
226 pDestDescriptorRangeSizes[NumDestDescriptorRanges] = DescriptorCount;
227 ++NumDestDescriptorRanges;
229 // Setup source ranges (one descriptor each because we don't assume they are contiguous)
230 for (uint32_t j = 0; j < DescriptorCount; ++j)
232 pSrcDescriptorRangeStarts[NumSrcDescriptorRanges] = SrcHandles[j];
233 pSrcDescriptorRangeSizes[NumSrcDescriptorRanges] = 1;
234 ++NumSrcDescriptorRanges;
237 // Move the destination pointer forward by the number of descriptors we will copy
238 SrcHandles += DescriptorCount;
239 CurDest.ptr += DescriptorCount * DescriptorSize;
243 g_Device->CopyDescriptors(
244 NumDestDescriptorRanges, pDestDescriptorRangeStarts, pDestDescriptorRangeSizes,
245 NumSrcDescriptorRanges, pSrcDescriptorRangeStarts, pSrcDescriptorRangeSizes,
246 Type);
249 void DynamicDescriptorHeap::CopyAndBindStagedTables( DescriptorHandleCache& HandleCache, ID3D12GraphicsCommandList* CmdList,
250 void (STDMETHODCALLTYPE ID3D12GraphicsCommandList::*SetFunc)(UINT, D3D12_GPU_DESCRIPTOR_HANDLE))
252 uint32_t NeededSize = HandleCache.ComputeStagedSize();
253 if (!HasSpace(NeededSize))
255 RetireCurrentHeap();
256 UnbindAllValid();
257 NeededSize = HandleCache.ComputeStagedSize();
260 // This can trigger the creation of a new heap
261 m_OwningContext.SetDescriptorHeap(m_DescriptorType, GetHeapPointer());
262 HandleCache.CopyAndBindStaleTables(m_DescriptorType, m_DescriptorSize, Allocate(NeededSize), CmdList, SetFunc);
265 void DynamicDescriptorHeap::UnbindAllValid( void )
267 m_GraphicsHandleCache.UnbindAllValid();
268 m_ComputeHandleCache.UnbindAllValid();
271 D3D12_GPU_DESCRIPTOR_HANDLE DynamicDescriptorHeap::UploadDirect( D3D12_CPU_DESCRIPTOR_HANDLE Handle )
273 if (!HasSpace(1))
275 RetireCurrentHeap();
276 UnbindAllValid();
279 m_OwningContext.SetDescriptorHeap(m_DescriptorType, GetHeapPointer());
281 DescriptorHandle DestHandle = m_FirstDescriptor + m_CurrentOffset * m_DescriptorSize;
282 m_CurrentOffset += 1;
284 g_Device->CopyDescriptorsSimple(1, DestHandle.GetCpuHandle(), Handle, m_DescriptorType);
286 return DestHandle.GetGpuHandle();
289 void DynamicDescriptorHeap::DescriptorHandleCache::UnbindAllValid()
291 m_StaleRootParamsBitMap = 0;
293 unsigned long TableParams = m_RootDescriptorTablesBitMap;
294 unsigned long RootIndex;
295 while (_BitScanForward(&RootIndex, TableParams))
297 TableParams ^= (1 << RootIndex);
298 if (m_RootDescriptorTable[RootIndex].AssignedHandlesBitMap != 0)
299 m_StaleRootParamsBitMap |= (1 << RootIndex);
303 void DynamicDescriptorHeap::DescriptorHandleCache::StageDescriptorHandles( UINT RootIndex, UINT Offset, UINT NumHandles, const D3D12_CPU_DESCRIPTOR_HANDLE Handles[] )
305 ASSERT(((1 << RootIndex) & m_RootDescriptorTablesBitMap) != 0, "Root parameter is not a CBV_SRV_UAV descriptor table");
306 ASSERT(Offset + NumHandles <= m_RootDescriptorTable[RootIndex].TableSize);
308 DescriptorTableCache& TableCache = m_RootDescriptorTable[RootIndex];
309 D3D12_CPU_DESCRIPTOR_HANDLE* CopyDest = TableCache.TableStart + Offset;
310 for (UINT i = 0; i < NumHandles; ++i)
311 CopyDest[i] = Handles[i];
312 TableCache.AssignedHandlesBitMap |= ((1 << NumHandles) - 1) << Offset;
313 m_StaleRootParamsBitMap |= (1 << RootIndex);
316 void DynamicDescriptorHeap::DescriptorHandleCache::ParseRootSignature( D3D12_DESCRIPTOR_HEAP_TYPE Type, const RootSignature& RootSig )
318 UINT CurrentOffset = 0;
320 ASSERT(RootSig.m_NumParameters <= 16, "Maybe we need to support something greater");
322 m_StaleRootParamsBitMap = 0;
323 m_RootDescriptorTablesBitMap = (Type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ?
324 RootSig.m_SamplerTableBitMap : RootSig.m_DescriptorTableBitMap);
326 unsigned long TableParams = m_RootDescriptorTablesBitMap;
327 unsigned long RootIndex;
328 while (_BitScanForward(&RootIndex, TableParams))
330 TableParams ^= (1 << RootIndex);
332 UINT TableSize = RootSig.m_DescriptorTableSize[RootIndex];
333 ASSERT(TableSize > 0);
335 DescriptorTableCache& RootDescriptorTable = m_RootDescriptorTable[RootIndex];
336 RootDescriptorTable.AssignedHandlesBitMap = 0;
337 RootDescriptorTable.TableStart = m_HandleCache + CurrentOffset;
338 RootDescriptorTable.TableSize = TableSize;
340 CurrentOffset += TableSize;
343 m_MaxCachedDescriptors = CurrentOffset;
345 ASSERT(m_MaxCachedDescriptors <= kMaxNumDescriptors, "Exceeded user-supplied maximum cache size");