diff --git a/include/gpgmm_d3d12.h b/include/gpgmm_d3d12.h index fba8a1169..70bf4c949 100644 --- a/include/gpgmm_d3d12.h +++ b/include/gpgmm_d3d12.h @@ -258,6 +258,22 @@ namespace gpgmm::d3d12 { void* pCreateHeapContext, IResidencyHeap** ppResidencyHeapOut); + /** \brief Create a heap managed by GPGMM. + + This version of CreateResidencyHeap is a simpler way to create residency heaps by disallowing + use of RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET by specifying the pageable instead. + + @param descriptor A reference to RESIDENCY_HEAP_DESC structure that describes the heap. + @param pResidencyManager A pointer to the ResidencyManager used to manage this heap. + @param pPageable A pointer to the pageable object that represents the heap. + @param[out] ppResidencyHeapOut Pointer to a memory block that receives a pointer to the + heap. + */ + GPGMM_EXPORT HRESULT CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor, + IResidencyManager* const pResidencyManager, + ID3D12Pageable* pPageable, + IResidencyHeap** ppResidencyHeapOut); + /** \brief Represents a list of heaps which will be "made resident" upon executing a command-list. diff --git a/src/gpgmm/d3d12/ResidencyHeapD3D12.cpp b/src/gpgmm/d3d12/ResidencyHeapD3D12.cpp index f9df177cf..c81e15a1d 100644 --- a/src/gpgmm/d3d12/ResidencyHeapD3D12.cpp +++ b/src/gpgmm/d3d12/ResidencyHeapD3D12.cpp @@ -64,73 +64,34 @@ namespace gpgmm::d3d12 { pCreateHeapContext, ppResidencyHeapOut); } + HRESULT CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor, + IResidencyManager* const pResidencyManager, + ID3D12Pageable* pPageable, + IResidencyHeap** ppResidencyHeapOut) { + return ResidencyHeap::CreateResidencyHeap(descriptor, pResidencyManager, pPageable, + ppResidencyHeapOut); + } + // static HRESULT ResidencyHeap::CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor, IResidencyManager* const pResidencyManager, - CreateHeapFn createHeapFn, - void* pCreateHeapContext, + ID3D12Pageable* pPageable, IResidencyHeap** ppResidencyHeapOut) { - GPGMM_RETURN_IF_NULLPTR(pCreateHeapContext); - - const bool isResidencyDisabled = (pResidencyManager == nullptr); - - // Validate residency resource heap flags must also have a residency manager. - if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET) { - ErrorLog(MessageId::kInvalidArgument, true) - << "Creating a heap always in budget requires a residency manager to exist."; - return E_INVALIDARG; - } + GPGMM_TRACE_EVENT_OBJECT_CALL("Heap.CreateResidencyHeap", + (CREATE_HEAP_DESC{descriptor, pPageable})); - if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_RESIDENT) { - ErrorLog(MessageId::kInvalidArgument, true) - << "Creating a heap always residency requires a residency manager to exist."; - return E_INVALIDARG; - } + GPGMM_RETURN_IF_NULLPTR(pPageable); ResidencyManager* residencyManager = static_cast(pResidencyManager); - - // Ensure enough budget exists before creating the heap to avoid an out-of-memory error. - if (!isResidencyDisabled && (descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET)) { - uint64_t bytesEvicted = descriptor.SizeInBytes; - GPGMM_RETURN_IF_FAILED( - residencyManager->EvictInternal(descriptor.SizeInBytes, descriptor.HeapSegment, - &bytesEvicted), - residencyManager->mDevice); - - if (bytesEvicted < descriptor.SizeInBytes) { - DXGI_QUERY_VIDEO_MEMORY_INFO currentVideoInfo = {}; - if (SUCCEEDED(residencyManager->QueryVideoMemoryInfo(descriptor.HeapSegment, - ¤tVideoInfo))) { - ErrorLog(MessageId::kBudgetExceeded, true) - << "Unable to create heap because not enough budget exists (" - << GPGMM_BYTES_TO_MB(descriptor.SizeInBytes) << " vs " - << GPGMM_BYTES_TO_MB( - (currentVideoInfo.Budget > currentVideoInfo.CurrentUsage) - ? currentVideoInfo.Budget - currentVideoInfo.CurrentUsage - : 0) - << " MBs) and RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET was specified."; - } - return E_OUTOFMEMORY; - } - } - - ComPtr pageable; - GPGMM_RETURN_IF_FAILED(createHeapFn(pCreateHeapContext, &pageable), - GetDevice(pageable.Get())); - - // Pageable-based type is required for residency-managed heaps. - GPGMM_RETURN_IF_NULLPTR(pageable); - - GPGMM_TRACE_EVENT_OBJECT_CALL("Heap.CreateResidencyHeap", - (CREATE_HEAP_DESC{descriptor, pageable.Get()})); + const bool isResidencyDisabled = (pResidencyManager == nullptr); std::unique_ptr heap( - new ResidencyHeap(pageable, descriptor, isResidencyDisabled)); + new ResidencyHeap(pPageable, descriptor, isResidencyDisabled)); if (!isResidencyDisabled) { // Check if the underlying memory was implicitly made resident. D3D12_HEAP_FLAGS resourceHeapFlags = D3D12_HEAP_FLAG_NONE; - if (SUCCEEDED(GetResourceHeapFlags(pageable, &resourceHeapFlags))) { + if (SUCCEEDED(GetResourceHeapFlags(pPageable, &resourceHeapFlags))) { // Resource heaps created without the "create not resident" flag are always // resident. if (!(resourceHeapFlags & D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT)) { @@ -155,13 +116,13 @@ namespace gpgmm::d3d12 { // residency cache. if (heap->GetInfo().Status != RESIDENCY_HEAP_STATUS_UNKNOWN) { GPGMM_RETURN_IF_FAILED(residencyManager->InsertHeap(heap.get()), - GetDevice(pageable.Get())); + GetDevice(pPageable)); } else { if (descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_RESIDENT) { GPGMM_RETURN_IF_FAILED(residencyManager->LockHeap(heap.get()), - GetDevice(pageable.Get())); + GetDevice(pPageable)); GPGMM_RETURN_IF_FAILED(residencyManager->UnlockHeap(heap.get()), - GetDevice(pageable.Get())); + GetDevice(pPageable)); ASSERT(heap->GetInfo().Status == RESIDENCY_HEAP_STATUS_CURRENT); } } @@ -173,7 +134,7 @@ namespace gpgmm::d3d12 { } } - GPGMM_RETURN_IF_FAILED(heap->SetDebugName(descriptor.DebugName), GetDevice(pageable.Get())); + GPGMM_RETURN_IF_FAILED(heap->SetDebugName(descriptor.DebugName), GetDevice(pPageable)); GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(heap.get(), descriptor); DebugLog(heap.get(), MessageId::kObjectCreated) @@ -187,6 +148,64 @@ namespace gpgmm::d3d12 { return S_OK; } + // static + HRESULT ResidencyHeap::CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor, + IResidencyManager* const pResidencyManager, + CreateHeapFn createHeapFn, + void* pCreateHeapContext, + IResidencyHeap** ppResidencyHeapOut) { + GPGMM_RETURN_IF_NULLPTR(pCreateHeapContext); + + const bool isResidencyDisabled = (pResidencyManager == nullptr); + + // Validate residency resource heap flags must also have a residency manager. + if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET) { + ErrorLog(MessageId::kInvalidArgument, true) + << "Creating a heap always in budget requires a residency manager to exist."; + return E_INVALIDARG; + } + + if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_RESIDENT) { + ErrorLog(MessageId::kInvalidArgument, true) + << "Creating a heap always residency requires a residency manager to exist."; + return E_INVALIDARG; + } + + ResidencyManager* residencyManager = static_cast(pResidencyManager); + + // Ensure enough budget exists before creating the heap to avoid an out-of-memory error. + if (!isResidencyDisabled && (descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET)) { + uint64_t bytesEvicted = descriptor.SizeInBytes; + GPGMM_RETURN_IF_FAILED( + residencyManager->EvictInternal(descriptor.SizeInBytes, descriptor.HeapSegment, + &bytesEvicted), + residencyManager->mDevice); + + if (bytesEvicted < descriptor.SizeInBytes) { + DXGI_QUERY_VIDEO_MEMORY_INFO currentVideoInfo = {}; + if (SUCCEEDED(residencyManager->QueryVideoMemoryInfo(descriptor.HeapSegment, + ¤tVideoInfo))) { + ErrorLog(MessageId::kBudgetExceeded, true) + << "Unable to create heap because not enough budget exists (" + << GPGMM_BYTES_TO_MB(descriptor.SizeInBytes) << " vs " + << GPGMM_BYTES_TO_MB( + (currentVideoInfo.Budget > currentVideoInfo.CurrentUsage) + ? currentVideoInfo.Budget - currentVideoInfo.CurrentUsage + : 0) + << " MBs) and RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET was specified."; + } + return E_OUTOFMEMORY; + } + } + + ComPtr pageable; + GPGMM_RETURN_IF_FAILED(createHeapFn(pCreateHeapContext, &pageable), + GetDevice(pageable.Get())); + + return CreateResidencyHeap(descriptor, pResidencyManager, pageable.Get(), + ppResidencyHeapOut); + } + ResidencyHeap::ResidencyHeap(ComPtr pageable, const RESIDENCY_HEAP_DESC& descriptor, bool isResidencyDisabled) diff --git a/src/gpgmm/d3d12/ResidencyHeapD3D12.h b/src/gpgmm/d3d12/ResidencyHeapD3D12.h index 8927baea3..0512139ef 100644 --- a/src/gpgmm/d3d12/ResidencyHeapD3D12.h +++ b/src/gpgmm/d3d12/ResidencyHeapD3D12.h @@ -40,6 +40,11 @@ namespace gpgmm::d3d12 { void* pCreateHeapContext, IResidencyHeap** ppResidencyHeapOut); + static HRESULT CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor, + IResidencyManager* const pResidencyManager, + ID3D12Pageable* pPageable, + IResidencyHeap** ppResidencyHeapOut); + ~ResidencyHeap() override; // IResidencyHeap interface diff --git a/src/tests/end2end/D3D12ResidencyManagerTests.cpp b/src/tests/end2end/D3D12ResidencyManagerTests.cpp index f241f17f5..9ee3463d7 100644 --- a/src/tests/end2end/D3D12ResidencyManagerTests.cpp +++ b/src/tests/end2end/D3D12ResidencyManagerTests.cpp @@ -191,6 +191,13 @@ TEST_F(D3D12ResidencyManagerTests, CreateResourceHeap) { CreateResourceHeapCallbackContext::CreateHeap, &createHeapContext, nullptr)); + // Create a resource heap by importing the heap. + { + ComPtr pageable; + CreateResourceHeapCallbackContext::CreateHeap(&createHeapContext, &pageable); + ASSERT_SUCCEEDED(CreateResidencyHeap(resourceHeapDesc, nullptr, pageable.Get(), nullptr)); + } + // Create a resource heap without residency. ComPtr resourceHeap; ASSERT_SUCCEEDED(CreateResidencyHeap(resourceHeapDesc, nullptr,