diff --git a/src/gpgmm/d3d12/HeapD3D12.cpp b/src/gpgmm/d3d12/HeapD3D12.cpp index 978d61a3f..111a98be9 100644 --- a/src/gpgmm/d3d12/HeapD3D12.cpp +++ b/src/gpgmm/d3d12/HeapD3D12.cpp @@ -38,8 +38,7 @@ namespace gpgmm::d3d12 { // Else, infer the memory segment using the heap type. if (pResidencyManager != nullptr && descriptor.MemorySegment == RESIDENCY_SEGMENT_UNKNOWN) { - memorySegmentGroup = - pResidencyManager->GetPreferredMemorySegmentGroup(descriptor.HeapType); + memorySegmentGroup = pResidencyManager->GetMemorySegmentGroup(descriptor.HeapType); } // Ensure enough free memory exists before allocating to avoid an out-of-memory error diff --git a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp index da8a4cf7d..4212638d3 100644 --- a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp +++ b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp @@ -264,8 +264,8 @@ namespace gpgmm::d3d12 { heap->RemoveFromList(); // Untracked heaps are not attributed toward residency usage. - mInfo.MemoryCount++; - mInfo.MemoryUsage += heap->GetSize(); + mInfo.ResidentMemoryCount++; + mInfo.ResidentMemoryUsage += heap->GetSize(); } heap->AddResidencyLockRef(); @@ -302,8 +302,8 @@ namespace gpgmm::d3d12 { ReturnIfFailed(InsertHeapInternal(heap)); // Heaps tracked for residency are always attributed in residency usage. - mInfo.MemoryCount--; - mInfo.MemoryUsage -= heap->GetSize(); + mInfo.ResidentMemoryCount--; + mInfo.ResidentMemoryUsage -= heap->GetSize(); return S_OK; } @@ -692,13 +692,13 @@ namespace gpgmm::d3d12 { RESIDENCY_INFO ResidencyManager::GetInfo() const { RESIDENCY_INFO info = mInfo; for (const auto& node : mLocalVideoMemorySegment.cache) { - info.MemoryUsage += node.value()->GetSize(); - info.MemoryCount++; + info.ResidentMemoryUsage += node.value()->GetSize(); + info.ResidentMemoryCount++; } for (const auto& node : mNonLocalVideoMemorySegment.cache) { - info.MemoryUsage += node.value()->GetSize(); - info.MemoryCount++; + info.ResidentMemoryUsage += node.value()->GetSize(); + info.ResidentMemoryCount++; } return info; @@ -736,7 +736,7 @@ namespace gpgmm::d3d12 { mBudgetNotificationUpdateEvent = nullptr; } - DXGI_MEMORY_SEGMENT_GROUP ResidencyManager::GetPreferredMemorySegmentGroup( + DXGI_MEMORY_SEGMENT_GROUP ResidencyManager::GetMemorySegmentGroup( D3D12_HEAP_TYPE heapType) const { if (mIsUMA) { return DXGI_MEMORY_SEGMENT_GROUP_LOCAL; diff --git a/src/gpgmm/d3d12/ResidencyManagerD3D12.h b/src/gpgmm/d3d12/ResidencyManagerD3D12.h index 225e54457..1f23b0052 100644 --- a/src/gpgmm/d3d12/ResidencyManagerD3D12.h +++ b/src/gpgmm/d3d12/ResidencyManagerD3D12.h @@ -127,11 +127,11 @@ namespace gpgmm::d3d12 { struct RESIDENCY_INFO { /** \brief Amount of memory, in bytes, being made resident. */ - uint64_t MemoryUsage = 0; + uint64_t ResidentMemoryUsage = 0; /** \brief Number of heaps currently being made resident. */ - uint64_t MemoryCount = 0; + uint64_t ResidentMemoryCount = 0; }; class BudgetUpdateEvent; @@ -243,6 +243,16 @@ namespace gpgmm::d3d12 { */ RESIDENCY_INFO GetInfo() const; + /** \brief Divugles the memory segment used for the specified heap type. + + @param heapType A D3D12_HEAP_TYPE-typed value that specifies the heap to get the memory + segment for. + + \return A DXGI_MEMORY_SEGMENT_GROUP that provides the memory segment for the specified heap + type. + */ + DXGI_MEMORY_SEGMENT_GROUP GetMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const; + private: friend Heap; friend ResourceAllocator; @@ -269,8 +279,6 @@ namespace gpgmm::d3d12 { uint32_t numberOfObjectsToMakeResident, ID3D12Pageable** allocations); - DXGI_MEMORY_SEGMENT_GROUP GetPreferredMemorySegmentGroup(D3D12_HEAP_TYPE heapType) const; - LRUCache* GetVideoMemorySegmentCache(const DXGI_MEMORY_SEGMENT_GROUP& memorySegmentGroup); HRESULT QueryVideoMemoryInfo(const DXGI_MEMORY_SEGMENT_GROUP& memorySegmentGroup, diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp index c4ae4b3e4..90cef4182 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp @@ -794,7 +794,7 @@ namespace gpgmm::d3d12 { // Limit available memory to unused budget when residency is enabled. if (mResidencyManager != nullptr) { const DXGI_MEMORY_SEGMENT_GROUP segment = - mResidencyManager->GetPreferredMemorySegmentGroup(allocationDescriptor.HeapType); + mResidencyManager->GetMemorySegmentGroup(allocationDescriptor.HeapType); DXGI_QUERY_VIDEO_MEMORY_INFO* currentVideoInfo = mResidencyManager->GetVideoMemoryInfo(segment); diff --git a/src/tests/end2end/D3D12ResidencyManagerTests.cpp b/src/tests/end2end/D3D12ResidencyManagerTests.cpp index 8ecaf74ba..4f6213944 100644 --- a/src/tests/end2end/D3D12ResidencyManagerTests.cpp +++ b/src/tests/end2end/D3D12ResidencyManagerTests.cpp @@ -79,16 +79,12 @@ class D3D12ResidencyManagerTests : public D3D12TestBase, public ::testing::Test return residencyDesc; } - bool IsOverBudget(ResidencyManager* residencyManager) const { - ASSERT(residencyManager != nullptr); - - DXGI_QUERY_VIDEO_MEMORY_INFO* local = - residencyManager->GetVideoMemoryInfo(DXGI_MEMORY_SEGMENT_GROUP_LOCAL); - - DXGI_QUERY_VIDEO_MEMORY_INFO* nonLocal = - residencyManager->GetVideoMemoryInfo(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL); - - return local->Budget <= local->CurrentUsage && nonLocal->Budget <= nonLocal->CurrentUsage; + uint64_t GetBudgetLeft(ResidencyManager* residencyManager, + const DXGI_MEMORY_SEGMENT_GROUP& memorySegmentGroup) { + DXGI_QUERY_VIDEO_MEMORY_INFO* segment = + residencyManager->GetVideoMemoryInfo(memorySegmentGroup); + return (segment->Budget > segment->CurrentUsage) ? (segment->Budget - segment->CurrentUsage) + : 0; } }; @@ -127,8 +123,8 @@ TEST_F(D3D12ResidencyManagerTests, CreateResourceHeap) { Heap::CreateHeap(resourceHeapDesc, residencyManager.Get(), createHeapFn, &resourceHeap)); ASSERT_NE(resourceHeap, nullptr); - EXPECT_EQ(residencyManager->GetInfo().MemoryUsage, kHeapSize); - EXPECT_EQ(residencyManager->GetInfo().MemoryCount, 1u); + EXPECT_EQ(residencyManager->GetInfo().ResidentMemoryUsage, kHeapSize); + EXPECT_EQ(residencyManager->GetInfo().ResidentMemoryCount, 1u); ComPtr heap; resourceHeap->As(&heap); @@ -137,13 +133,13 @@ TEST_F(D3D12ResidencyManagerTests, CreateResourceHeap) { ASSERT_SUCCEEDED(residencyManager->LockHeap(resourceHeap.Get())); - EXPECT_EQ(residencyManager->GetInfo().MemoryUsage, kHeapSize); - EXPECT_EQ(residencyManager->GetInfo().MemoryCount, 1u); + EXPECT_EQ(residencyManager->GetInfo().ResidentMemoryUsage, kHeapSize); + EXPECT_EQ(residencyManager->GetInfo().ResidentMemoryCount, 1u); ASSERT_SUCCEEDED(residencyManager->UnlockHeap(resourceHeap.Get())); - EXPECT_EQ(residencyManager->GetInfo().MemoryUsage, kHeapSize); - EXPECT_EQ(residencyManager->GetInfo().MemoryCount, 1u); + EXPECT_EQ(residencyManager->GetInfo().ResidentMemoryUsage, kHeapSize); + EXPECT_EQ(residencyManager->GetInfo().ResidentMemoryCount, 1u); ASSERT_FAILED(residencyManager->UnlockHeap(resourceHeap.Get())); // Not locked } @@ -243,18 +239,23 @@ TEST_F(D3D12ResidencyManagerTests, OverBudget) { ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator( CreateBasicAllocatorDesc(), residencyManager.Get(), &resourceAllocator)); - const D3D12_RESOURCE_DESC bufferDesc = CreateBasicBufferDesc(GPGMM_MB_TO_BYTES(1)); + constexpr uint64_t kBufferMemorySize = GPGMM_MB_TO_BYTES(1); + const D3D12_RESOURCE_DESC bufferDesc = CreateBasicBufferDesc(kBufferMemorySize); + + ALLOCATION_DESC bufferAllocationDesc = {}; + bufferAllocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + const DXGI_MEMORY_SEGMENT_GROUP bufferMemorySegment = + residencyManager->GetMemorySegmentGroup(bufferAllocationDesc.HeapType); + const uint64_t memoryUnderBudget = GetBudgetLeft(residencyManager.Get(), bufferMemorySegment); // Keep allocating until we reach the budget. std::vector> allocationsBelowBudget = {}; - while (!IsOverBudget(residencyManager.Get())) { + while (resourceAllocator->GetInfo().UsedMemoryUsage + kBufferMemorySize < memoryUnderBudget) { ComPtr allocation; ASSERT_SUCCEEDED(resourceAllocator->CreateResource( {}, bufferDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)); allocationsBelowBudget.push_back(std::move(allocation)); - - // Prevent the first created resources from being evicted once over budget. - ASSERT_SUCCEEDED(residencyManager->UpdateVideoMemorySegments()); } // Created allocations below the budget should be resident. @@ -300,14 +301,24 @@ TEST_F(D3D12ResidencyManagerTests, OverBudgetUsingBudgetNotifications) { ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator( CreateBasicAllocatorDesc(), residencyManager.Get(), &resourceAllocator)); - const D3D12_RESOURCE_DESC bufferDesc = CreateBasicBufferDesc(GPGMM_MB_TO_BYTES(1)); + constexpr uint64_t kBufferMemorySize = GPGMM_MB_TO_BYTES(1); + const D3D12_RESOURCE_DESC bufferDesc = CreateBasicBufferDesc(kBufferMemorySize); + + ALLOCATION_DESC bufferAllocationDesc = {}; + bufferAllocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + const DXGI_MEMORY_SEGMENT_GROUP bufferMemorySegment = + residencyManager->GetMemorySegmentGroup(bufferAllocationDesc.HeapType); + + const uint64_t memoryUnderBudget = GetBudgetLeft(residencyManager.Get(), bufferMemorySegment); // Keep allocating until we reach the budget. std::vector> allocations = {}; - while (!IsOverBudget(residencyManager.Get())) { + while (resourceAllocator->GetInfo().UsedMemoryUsage + kBufferMemorySize < memoryUnderBudget) { ComPtr allocation; ASSERT_SUCCEEDED(resourceAllocator->CreateResource( - {}, bufferDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)); + bufferAllocationDesc, bufferDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)); + allocations.push_back(std::move(allocation)); } @@ -334,23 +345,23 @@ TEST_F(D3D12ResidencyManagerTests, OverBudgetWithGrowth) { std::vector> allocations = {}; std::vector resourceHeaps = {}; - const D3D12_RESOURCE_DESC bufferDesc = CreateBasicBufferDesc(GPGMM_MB_TO_BYTES(1)); + constexpr uint64_t kBufferMemorySize = GPGMM_MB_TO_BYTES(1); + const D3D12_RESOURCE_DESC bufferDesc = CreateBasicBufferDesc(kBufferMemorySize); + + ALLOCATION_DESC bufferAllocationDesc = {}; + bufferAllocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + const DXGI_MEMORY_SEGMENT_GROUP bufferMemorySegment = + residencyManager->GetMemorySegmentGroup(bufferAllocationDesc.HeapType); + const uint64_t memoryUnderBudget = GetBudgetLeft(residencyManager.Get(), bufferMemorySegment); - while (!IsOverBudget(residencyManager.Get())) { + while (resourceAllocator->GetInfo().UsedMemoryUsage + kBufferMemorySize < memoryUnderBudget) { ComPtr allocation; ASSERT_SUCCEEDED(resourceAllocator->CreateResource( - {}, bufferDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)); + bufferAllocationDesc, bufferDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)); resourceHeaps.push_back(allocation->GetMemory()); allocations.push_back(std::move(allocation)); - - // Prevent the first created resources from being evicted once over budget. - ASSERT_SUCCEEDED(residencyManager->UpdateVideoMemorySegments()); - } - - // Created allocations above the budget should be resident. - for (auto& allocation : allocations) { - EXPECT_TRUE(allocation->IsResident()); } // Check growth occured