diff --git a/src/gpgmm/d3d12/HeapD3D12.cpp b/src/gpgmm/d3d12/HeapD3D12.cpp index c1a9ffa9f..978d61a3f 100644 --- a/src/gpgmm/d3d12/HeapD3D12.cpp +++ b/src/gpgmm/d3d12/HeapD3D12.cpp @@ -25,19 +25,27 @@ namespace gpgmm::d3d12 { // static HRESULT Heap::CreateHeap(const HEAP_DESC& descriptor, - ResidencyManager* const residencyManager, + ResidencyManager* const pResidencyManager, CreateHeapFn&& createHeapFn, - Heap** heapOut) { + Heap** ppHeapOut) { + // Always use the memory segment specified. DXGI_MEMORY_SEGMENT_GROUP memorySegmentGroup = {}; - if (residencyManager != nullptr) { + if (descriptor.MemorySegment == RESIDENCY_SEGMENT_LOCAL) { + memorySegmentGroup = DXGI_MEMORY_SEGMENT_GROUP_LOCAL; + } else if (descriptor.MemorySegment == RESIDENCY_SEGMENT_NON_LOCAL) { + memorySegmentGroup = DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL; + } + + // Else, infer the memory segment using the heap type. + if (pResidencyManager != nullptr && descriptor.MemorySegment == RESIDENCY_SEGMENT_UNKNOWN) { memorySegmentGroup = - residencyManager->GetPreferredMemorySegmentGroup(descriptor.HeapType); + pResidencyManager->GetPreferredMemorySegmentGroup(descriptor.HeapType); + } - // Ensure enough free memory exists before allocating to avoid an out-of-memory error - // when over budget. - if (descriptor.AlwaysInBudget) { - ReturnIfFailed(residencyManager->Evict(descriptor.SizeInBytes, memorySegmentGroup)); - } + // Ensure enough free memory exists before allocating to avoid an out-of-memory error + // when over budget. + if (pResidencyManager != nullptr && descriptor.AlwaysInBudget) { + ReturnIfFailed(pResidencyManager->Evict(descriptor.SizeInBytes, memorySegmentGroup)); } ComPtr pageable; @@ -50,15 +58,15 @@ namespace gpgmm::d3d12 { descriptor.SizeInBytes, descriptor.Alignment, descriptor.IsExternal)); - if (residencyManager != nullptr) { - ReturnIfFailed(residencyManager->InsertHeap(heap.get())); + if (pResidencyManager != nullptr) { + ReturnIfFailed(pResidencyManager->InsertHeap(heap.get())); } ReturnIfFailed(heap->SetDebugName(descriptor.DebugName)); GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(heap.get(), descriptor); - if (heapOut != nullptr) { - *heapOut = heap.release(); + if (ppHeapOut != nullptr) { + *ppHeapOut = heap.release(); } return S_OK; diff --git a/src/gpgmm/d3d12/HeapD3D12.h b/src/gpgmm/d3d12/HeapD3D12.h index 78ed47452..a0b0799ba 100644 --- a/src/gpgmm/d3d12/HeapD3D12.h +++ b/src/gpgmm/d3d12/HeapD3D12.h @@ -32,6 +32,18 @@ namespace gpgmm::d3d12 { class ResidencyManager; class ResourceAllocator; + /** \enum RESIDENCY_SEGMENT + Specifies which type of segment the heap belongs to. + + RESIDENCY_SEGMENT is equivelent to DXGI_MEMORY_SEGMENT_GROUP but also has + RESIDENCY_SEGMENT_UNKNOWN. + */ + enum RESIDENCY_SEGMENT { + RESIDENCY_SEGMENT_UNKNOWN, + RESIDENCY_SEGMENT_LOCAL, + RESIDENCY_SEGMENT_NON_LOCAL, + }; + /** \struct HEAP_INFO Additional information about the heap. */ @@ -85,6 +97,12 @@ namespace gpgmm::d3d12 { */ bool IsExternal; + /** \brief Specifies the memory segment to use for residency. + + Allows any heap to specify a segment which does not have a attributed heap type. + */ + RESIDENCY_SEGMENT MemorySegment; + /** \brief Debug name associated with the heap. */ std::string DebugName; @@ -121,15 +139,15 @@ namespace gpgmm::d3d12 { implicit D3D12 heap OR 2) an explicit D3D12 heap used with placed resources. @param descriptor A reference to HEAP_DESC structure that describes the heap. - @param residencyManager A pointer to the ResidencyManager used to manage this heap. + @param pResidencyManager A pointer to the ResidencyManager used to manage this heap. @param createHeapFn A callback function which creates a ID3D12Pageable derived type. - @param[out] heapOut Pointer to a memory block that recieves a pointer to the + @param[out] ppHeapOut Pointer to a memory block that recieves a pointer to the heap. */ static HRESULT CreateHeap(const HEAP_DESC& descriptor, - ResidencyManager* const residencyManager, + ResidencyManager* const pResidencyManager, CreateHeapFn&& createHeapFn, - Heap** heapOut); + Heap** ppHeapOut); // TODO: Make private. Heap(ComPtr pageable, diff --git a/src/gpgmm/d3d12/JSONSerializerD3D12.cpp b/src/gpgmm/d3d12/JSONSerializerD3D12.cpp index dc2952e12..a135eb3fd 100644 --- a/src/gpgmm/d3d12/JSONSerializerD3D12.cpp +++ b/src/gpgmm/d3d12/JSONSerializerD3D12.cpp @@ -168,6 +168,7 @@ namespace gpgmm::d3d12 { dict.AddItem("HeapType", desc.HeapType); dict.AddItem("AlwaysInBudget", desc.AlwaysInBudget); dict.AddItem("IsExternal", desc.IsExternal); + dict.AddItem("MemorySegment", desc.MemorySegment); dict.AddItem("DebugName", desc.DebugName); return dict; } diff --git a/src/tests/end2end/D3D12ResidencyManagerTests.cpp b/src/tests/end2end/D3D12ResidencyManagerTests.cpp index 1837e6e90..c44eba6d8 100644 --- a/src/tests/end2end/D3D12ResidencyManagerTests.cpp +++ b/src/tests/end2end/D3D12ResidencyManagerTests.cpp @@ -92,6 +92,39 @@ class D3D12ResidencyManagerTests : public D3D12TestBase, public ::testing::Test } }; +TEST_F(D3D12ResidencyManagerTests, CreateResourceHeap) { + ComPtr residencyManager; + ASSERT_SUCCEEDED(ResidencyManager::CreateResidencyManager( + CreateBasicResidencyDesc(kDefaultBudget), &residencyManager)); + + constexpr uint64_t kHeapSize = GPGMM_MB_TO_BYTES(10); + + auto createResourceHeapFn = [&](ID3D12Pageable** ppPageableOut) -> HRESULT { + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; + + D3D12_HEAP_DESC heapDesc = {}; + heapDesc.Properties = heapProperties; + heapDesc.SizeInBytes = kHeapSize; + + ComPtr heap; + if (FAILED(mDevice->CreateHeap(&heapDesc, IID_PPV_ARGS(&heap)))) { + return E_FAIL; + } + *ppPageableOut = heap.Detach(); + return S_OK; + }; + + HEAP_DESC resourceHeapDesc = {}; + resourceHeapDesc.SizeInBytes = kHeapSize; + resourceHeapDesc.DebugName = "Resource heap"; + resourceHeapDesc.AlwaysInBudget = true; + resourceHeapDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + ASSERT_SUCCEEDED( + Heap::CreateHeap(resourceHeapDesc, residencyManager.Get(), createResourceHeapFn, nullptr)); +} + TEST_F(D3D12ResidencyManagerTests, CreateResidencySet) { ComPtr resourceAllocator; ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(CreateBasicAllocatorDesc(),