From 97bfcd370509970d05a1134b451220321c84b6b2 Mon Sep 17 00:00:00 2001 From: "Bernhart, Bryan" Date: Wed, 12 Apr 2023 15:08:29 -0700 Subject: [PATCH] Refactoring D3D12 logging. --- src/gpgmm/BUILD.gn | 1 + src/gpgmm/CMakeLists.txt | 1 + src/gpgmm/d3d12/HeapD3D12.cpp | 10 +- src/gpgmm/d3d12/LogD3D12.h | 70 ++++++++++ src/gpgmm/d3d12/ResidencyManagerD3D12.cpp | 64 +++++---- src/gpgmm/d3d12/ResidencyManagerD3D12.h | 8 +- src/gpgmm/d3d12/ResourceAllocationD3D12.cpp | 5 +- src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp | 137 ++++++++++---------- src/gpgmm/d3d12/ResourceAllocatorD3D12.h | 11 +- 9 files changed, 188 insertions(+), 119 deletions(-) create mode 100644 src/gpgmm/d3d12/LogD3D12.h diff --git a/src/gpgmm/BUILD.gn b/src/gpgmm/BUILD.gn index 0eb2d951..9f9a0821 100644 --- a/src/gpgmm/BUILD.gn +++ b/src/gpgmm/BUILD.gn @@ -130,6 +130,7 @@ source_set("gpgmm_sources") { "d3d12/HeapD3D12.h", "d3d12/JSONSerializerD3D12.cpp", "d3d12/JSONSerializerD3D12.h", + "d3d12/LogD3D12.h", "d3d12/ResidencyListD3D12.cpp", "d3d12/ResidencyListD3D12.h", "d3d12/ResidencyManagerD3D12.cpp", diff --git a/src/gpgmm/CMakeLists.txt b/src/gpgmm/CMakeLists.txt index 6d914096..b20dc33f 100644 --- a/src/gpgmm/CMakeLists.txt +++ b/src/gpgmm/CMakeLists.txt @@ -71,6 +71,7 @@ if (GPGMM_ENABLE_D3D12) "d3d12/HeapD3D12.h" "d3d12/JSONSerializerD3D12.cpp" "d3d12/JSONSerializerD3D12.h" + "d3d12/LogD3D12.h" "d3d12/ResidencyListD3D12.cpp" "d3d12/ResidencyListD3D12.h" "d3d12/ResidencyManagerD3D12.cpp" diff --git a/src/gpgmm/d3d12/HeapD3D12.cpp b/src/gpgmm/d3d12/HeapD3D12.cpp index 2b7dca6b..4ba0748c 100644 --- a/src/gpgmm/d3d12/HeapD3D12.cpp +++ b/src/gpgmm/d3d12/HeapD3D12.cpp @@ -19,6 +19,7 @@ #include "gpgmm/common/TraceEvent.h" #include "gpgmm/d3d12/ErrorD3D12.h" #include "gpgmm/d3d12/JSONSerializerD3D12.h" +#include "gpgmm/d3d12/LogD3D12.h" #include "gpgmm/d3d12/ResidencyManagerD3D12.h" #include "gpgmm/d3d12/UtilsD3D12.h" @@ -84,7 +85,7 @@ namespace gpgmm::d3d12 { DXGI_QUERY_VIDEO_MEMORY_INFO currentVideoInfo = {}; if (SUCCEEDED(residencyManager->QueryVideoMemoryInfo(descriptor.HeapSegment, ¤tVideoInfo))) { - ErrorLog(MessageId::kBudgetExceeded) + ErrorLog(MessageId::kBudgetExceeded, true) << "Unable to create heap because not enough budget exists (" << GPGMM_BYTES_TO_MB(descriptor.SizeInBytes) << " vs " << GPGMM_BYTES_TO_MB( @@ -125,7 +126,7 @@ namespace gpgmm::d3d12 { // Heap created not resident requires no budget to be created. if (heap->mState == RESIDENCY_STATUS_PENDING_RESIDENCY && (descriptor.Flags & HEAP_FLAG_ALWAYS_IN_BUDGET)) { - ErrorLog(MessageId::kInvalidArgument) + ErrorLog(heap.get(), MessageId::kInvalidArgument) << "Creating a heap always in budget cannot be used with " "D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT."; return E_INVALIDARG; @@ -146,8 +147,7 @@ namespace gpgmm::d3d12 { } } else { if (descriptor.Flags & HEAP_FLAG_ALWAYS_IN_RESIDENCY) { - WarningLog(MessageId::kInvalidArgument, true, WCharToUTF8(heap->GetDebugName()), - heap.get()) + WarningLog(heap.get(), MessageId::kInvalidArgument) << "HEAP_FLAG_ALWAYS_IN_RESIDENCY was specified but had no effect becauase " "residency management is " "not being used."; @@ -157,7 +157,7 @@ namespace gpgmm::d3d12 { GPGMM_RETURN_IF_FAILED(heap->SetDebugName(descriptor.DebugName)); GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(heap.get(), descriptor); - DebugLog(MessageId::kObjectCreated, true, WCharToUTF8(heap->GetDebugName()), heap.get()) + DebugLog(heap.get(), MessageId::kObjectCreated) << "Created heap, Size=" << heap->GetInfo().SizeInBytes << ", ID3D12Pageable=" << ToHexStr(heap->mPageable.Get()); diff --git a/src/gpgmm/d3d12/LogD3D12.h b/src/gpgmm/d3d12/LogD3D12.h new file mode 100644 index 00000000..23636918 --- /dev/null +++ b/src/gpgmm/d3d12/LogD3D12.h @@ -0,0 +1,70 @@ +// Copyright 2022 The GPGMM Authors +// +// 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. + +#ifndef GPGMM_D3D12_LOGD3D12_H_ +#define GPGMM_D3D12_LOGD3D12_H_ + +#include "gpgmm/common/EventMessage.h" +#include "gpgmm/utils/WindowsUtils.h" + +namespace gpgmm::d3d12 { + + template + LogMessage DebugLog(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::DebugLog(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), object); + } + + template + LogMessage InfoLog(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::InfoLog(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), object); + } + + template + LogMessage WarningLog(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::WarningLog(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), + object); + } + + template + LogMessage ErrorLog(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::ErrorLog(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), object); + } + + template + EventMessage DebugEvent(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::DebugEvent(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), + object); + } + + template + EventMessage InfoEvent(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::InfoEvent(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), + object); + } + + template + EventMessage WarnEvent(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::WarnEvent(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), + object); + } + + template + EventMessage ErrorEvent(const BackendT* object, MessageId messageId = MessageId::kUnknown) { + return gpgmm::ErrorEvent(messageId, true, gpgmm::WCharToUTF8(object->GetDebugName()), + object); + } + +} // namespace gpgmm::d3d12 + +#endif // GPGMM_D3D12_LOGD3D12_H_ diff --git a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp index 4496ae1a..46b99622 100644 --- a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp +++ b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp @@ -24,6 +24,7 @@ #include "gpgmm/d3d12/FenceD3D12.h" #include "gpgmm/d3d12/HeapD3D12.h" #include "gpgmm/d3d12/JSONSerializerD3D12.h" +#include "gpgmm/d3d12/LogD3D12.h" #include "gpgmm/d3d12/ResidencyListD3D12.h" #include "gpgmm/d3d12/UtilsD3D12.h" #include "gpgmm/utils/Math.h" @@ -74,8 +75,7 @@ namespace gpgmm::d3d12 { break; } - DebugLog(MessageId::kBudgetUpdated, true, - WCharToUTF8(mResidencyManager->GetDebugName()), mResidencyManager) + DebugLog(mResidencyManager, MessageId::kBudgetUpdated) << "Updated budget from OS notification."; break; } @@ -92,8 +92,7 @@ namespace gpgmm::d3d12 { } if (FAILED(hr)) { - ErrorLog(MessageId::kBudgetInvalid, true, - WCharToUTF8(mResidencyManager->GetDebugName()), mResidencyManager) + ErrorLog(mResidencyManager, MessageId::kBudgetInvalid) << "Unable to update budget: " + GetDeviceErrorMessage(mResidencyManager->mDevice, hr); } @@ -213,8 +212,7 @@ namespace gpgmm::d3d12 { // Require automatic video memory budget updates. if (!(descriptor.Flags & RESIDENCY_FLAG_DISABLE_BUDGET_UPDATES_ON_WORKER_THREAD)) { GPGMM_RETURN_IF_FAILED(residencyManager->StartBudgetNotificationUpdates()); - DebugLog(MessageId::kBudgetUpdated, true, WCharToUTF8(residencyManager->GetDebugName()), - residencyManager.get()) + DebugLog(residencyManager.get(), MessageId::kBudgetUpdated) << "OS based memory budget updates were successfully enabled."; } @@ -242,13 +240,13 @@ namespace gpgmm::d3d12 { // Emit a warning if the budget was initialized to zero. // This means nothing will be ever evicted, which will lead to device lost. if (localVideoMemorySegmentInfo->Budget == 0) { - WarningLog(MessageId::kBudgetInvalid, true) + WarningLog(residencyManager.get(), MessageId::kBudgetInvalid) << "GPU memory segment (" << GetMemorySegmentName(DXGI_MEMORY_SEGMENT_GROUP_LOCAL, residencyManager->mIsUMA) << ") did not initialize a budget. This means either a restricted budget was not " "used or the first OS budget update hasn't occured."; if (!residencyManager->mIsUMA && nonLocalVideoMemorySegmentInfo->Budget == 0) { - WarningLog(MessageId::kBudgetInvalid, true) + WarningLog(residencyManager.get(), MessageId::kBudgetInvalid) << "GPU memory segment (" << GetMemorySegmentName(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, residencyManager->mIsUMA) @@ -266,9 +264,7 @@ namespace gpgmm::d3d12 { GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(residencyManager.get(), descriptor); - DebugLog(MessageId::kObjectCreated, true, WCharToUTF8(residencyManager->GetDebugName()), - residencyManager.get()) - << "Created residency manager"; + DebugLog(residencyManager.get(), MessageId::kObjectCreated) << "Created residency manager"; if (ppResidencyManagerOut != nullptr) { *ppResidencyManagerOut = residencyManager.release(); @@ -372,7 +368,7 @@ namespace gpgmm::d3d12 { } if (heap->IsInList()) { - ErrorLog(MessageId::kBadOperation, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kBadOperation) << "Heap was never being tracked for residency. This usually occurs when a " "non-resource heap was created by the developer and never made resident at " "creation or failure to call LockHeap beforehand."; @@ -507,16 +503,16 @@ namespace gpgmm::d3d12 { if (previousUsage > pVideoMemoryInfo->CurrentUsage && GPGMM_BYTES_TO_MB(previousUsage - pVideoMemoryInfo->CurrentUsage) > 0) { - DebugLog(MessageId::kMemoryUsageUpdated, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kMemoryUsageUpdated) << GetMemorySegmentName(heapSegment, mIsUMA) << " GPU memory usage went down by " << GPGMM_BYTES_TO_MB(previousUsage - pVideoMemoryInfo->CurrentUsage) << " MBs."; } else if (previousUsage < pVideoMemoryInfo->CurrentUsage && GPGMM_BYTES_TO_MB(pVideoMemoryInfo->CurrentUsage - previousUsage) > 0) { - DebugLog(MessageId::kMemoryUsageUpdated, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kMemoryUsageUpdated) << GetMemorySegmentName(heapSegment, mIsUMA) << " GPU memory usage went up by " << GPGMM_BYTES_TO_MB(pVideoMemoryInfo->CurrentUsage - previousUsage) << " MBs."; } else if (previousUsage < pVideoMemoryInfo->CurrentUsage) { - DebugLog(MessageId::kMemoryUsageUpdated, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kMemoryUsageUpdated) << GetMemorySegmentName(heapSegment, mIsUMA) << " GPU memory usage went up by " << GPGMM_BYTES_TO_MB(pVideoMemoryInfo->CurrentUsage) << " MBs."; } @@ -530,13 +526,13 @@ namespace gpgmm::d3d12 { if (previousBudget > pVideoMemoryInfo->Budget && GPGMM_BYTES_TO_MB(previousBudget - pVideoMemoryInfo->Budget) > 0) { - DebugLog(MessageId::kMemoryUsageUpdated, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kMemoryUsageUpdated) << GetMemorySegmentName(heapSegment, mIsUMA) << " GPU memory budget went down by " << GPGMM_BYTES_TO_MB(previousBudget - pVideoMemoryInfo->Budget) << " MBs."; } else if (previousBudget < pVideoMemoryInfo->Budget && GPGMM_BYTES_TO_MB(pVideoMemoryInfo->Budget - previousBudget) > 0) { - DebugLog(MessageId::kMemoryUsageUpdated, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kMemoryUsageUpdated) << GetMemorySegmentName(heapSegment, mIsUMA) << " GPU memory budget went up by " << GPGMM_BYTES_TO_MB(pVideoMemoryInfo->Budget - previousBudget) << " MBs."; } @@ -545,7 +541,7 @@ namespace gpgmm::d3d12 { // Ignore when no budget was specified. if (pVideoMemoryInfo->Budget > 0 && pVideoMemoryInfo->CurrentUsage > pVideoMemoryInfo->Budget) { - WarnEvent(MessageId::kBudgetExceeded, true, WCharToUTF8(GetDebugName()), this) + WarnEvent(this, MessageId::kBudgetExceeded) << GetMemorySegmentName(heapSegment, mIsUMA) << " GPU memory usage exceeds budget: " << GPGMM_BYTES_TO_MB(pVideoMemoryInfo->CurrentUsage) << " vs " << GPGMM_BYTES_TO_MB(pVideoMemoryInfo->Budget) << " MBs."; @@ -554,8 +550,7 @@ namespace gpgmm::d3d12 { SafeDivide(pVideoMemoryInfo->CurrentUsage, pVideoMemoryInfo->Budget); if (pVideoMemoryInfo->Budget > 0 && currentUsageOfBudget > kMinCurrentUsageOfBudgetReportingThreshold) { - EventMessage message = - WarnEvent(MessageId::kBudgetExceeded, true, WCharToUTF8(GetDebugName()), this); + EventMessage message = WarnEvent(this, MessageId::kBudgetExceeded); message << GetMemorySegmentName(heapSegment, mIsUMA) << " GPU memory usage is above budget threshold: " << uint64_t(currentUsageOfBudget * 100) << "% vs " @@ -631,7 +626,7 @@ namespace gpgmm::d3d12 { // If a budget wasn't provided, it not possible to evict. This is because either the budget // update event has not happened yet or was invalid. if (pVideoMemoryInfo->Budget == 0) { - WarnEvent(MessageId::kBudgetInvalid, true, WCharToUTF8(GetDebugName()), this) + WarnEvent(this, MessageId::kBudgetInvalid) << "GPU memory segment (" << GetMemorySegmentName(DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, IsUMA()) << ") was unable to evict memory because a budget was not specified."; @@ -705,7 +700,7 @@ namespace gpgmm::d3d12 { GPGMM_RETURN_IF_FAILED_ON_DEVICE( mDevice->Evict(objectEvictCount, objectsToEvict.data()), mDevice); - DebugEvent(MessageId::kBudgetExceeded, true, WCharToUTF8(GetDebugName()), this) + DebugEvent(this, MessageId::kBudgetExceeded) << "GPU page-out. Number of allocations: " << objectsToEvict.size() << " (" << bytesEvicted << " bytes)."; } @@ -730,7 +725,7 @@ namespace gpgmm::d3d12 { std::lock_guard lock(mMutex); if (count == 0) { - ErrorLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kInvalidArgument) << "ExecuteCommandLists is required to have at-least one residency " "list to be called."; return E_INVALIDARG; @@ -738,7 +733,7 @@ namespace gpgmm::d3d12 { // TODO: support multiple command lists. if (count > 1) { - ErrorLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kInvalidArgument) << "ExecuteCommandLists does not support multiple residency lists at this time. " "Please call ExecuteCommandLists per residency list as a workaround, if needed."; return E_NOTIMPL; @@ -799,7 +794,7 @@ namespace gpgmm::d3d12 { // If the heap should be already resident, calling MakeResident again will be redundant. // Tell the developer the heap wasn't properly tracked by the residency manager. if (heap->GetInfo().Status == RESIDENCY_STATUS_UNKNOWN) { - DebugLog(MessageId::kBadOperation, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kBadOperation) << "Residency state could not be determined for the heap (Heap=" << ToHexStr(heap) << "). This likely means the developer was attempting to make a " @@ -868,7 +863,7 @@ namespace gpgmm::d3d12 { GPGMM_RETURN_IF_FAILED(EvictInternal(sizeToMakeResident, heapSegment, nullptr)); - DebugEvent(MessageId::kBudgetExceeded, true, WCharToUTF8(GetDebugName()), this) + DebugEvent(this, MessageId::kBudgetExceeded) << "GPU page-in. Number of allocations: " << numberOfObjectsToMakeResident << " (" << sizeToMakeResident << " bytes)."; @@ -897,7 +892,7 @@ namespace gpgmm::d3d12 { GPGMM_RETURN_IF_FAILED( EvictInternal(mEvictSizeInBytes, heapSegment, &evictedSizeInBytes)); if (evictedSizeInBytes == 0) { - ErrorLog(MessageId::kBudgetInvalid, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kBudgetInvalid) << "Unable to evict enough heaps to stay within budget. This " "usually occurs when there is not enough available memory. " "Please reduce consumption by checking allocation sizes and " @@ -990,13 +985,14 @@ namespace gpgmm::d3d12 { DXGI_QUERY_VIDEO_MEMORY_INFO* info = GetVideoMemoryInfo(segmentGroup); ASSERT(info != nullptr); - DebugLog() << GetMemorySegmentName(segmentGroup, IsUMA()) << " GPU memory segment:"; - DebugLog() << "\tBudget: " << GPGMM_BYTES_TO_MB(info->Budget) << " MBs (" - << GPGMM_BYTES_TO_MB(info->CurrentUsage) << " used)."; + DebugLog(this) << GetMemorySegmentName(segmentGroup, IsUMA()) << " GPU memory segment:"; + DebugLog(this) << "\tBudget: " << GPGMM_BYTES_TO_MB(info->Budget) << " MBs (" + << GPGMM_BYTES_TO_MB(info->CurrentUsage) << " used)."; if (info->CurrentReservation == 0) { - DebugLog() << "\tReserved: " << GPGMM_BYTES_TO_MB(info->CurrentReservation) << " MBs (" - << GPGMM_BYTES_TO_MB(info->AvailableForReservation) << " available)."; + DebugLog(this) << "\tReserved: " << GPGMM_BYTES_TO_MB(info->CurrentReservation) + << " MBs (" << GPGMM_BYTES_TO_MB(info->AvailableForReservation) + << " available)."; } } @@ -1005,7 +1001,7 @@ namespace gpgmm::d3d12 { Heap* heap = static_cast(pHeap); if (heap->GetInfo().IsLocked) { - ErrorLog(MessageId::kBadOperation, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kBadOperation) << "Heap residency cannot be updated because it was locked. " "Please unlock the heap before updating the state."; return E_FAIL; @@ -1013,7 +1009,7 @@ namespace gpgmm::d3d12 { const RESIDENCY_STATUS oldState = heap->GetInfo().Status; if (state == RESIDENCY_STATUS_UNKNOWN && oldState != RESIDENCY_STATUS_UNKNOWN) { - ErrorLog(MessageId::kBadOperation, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kBadOperation) << "Heap residency cannot be unknown when previously known by the " "residency manager. " "Check the status before updating the state."; diff --git a/src/gpgmm/d3d12/ResidencyManagerD3D12.h b/src/gpgmm/d3d12/ResidencyManagerD3D12.h index 0a5ed851..61cf84c3 100644 --- a/src/gpgmm/d3d12/ResidencyManagerD3D12.h +++ b/src/gpgmm/d3d12/ResidencyManagerD3D12.h @@ -69,6 +69,10 @@ namespace gpgmm::d3d12 { DEFINE_UNKNOWN_OVERRIDES() + // IDebugObject interface + LPCWSTR GetDebugName() const override; + HRESULT SetDebugName(LPCWSTR Name) override; + private: friend Heap; friend ResourceAllocator; @@ -97,10 +101,6 @@ namespace gpgmm::d3d12 { // ObjectBase interface const char* GetTypename() const override; - // IDebugObject interface - LPCWSTR GetDebugName() const override; - HRESULT SetDebugName(LPCWSTR Name) override; - using LRUCache = LinkedList; struct VideoMemorySegment { diff --git a/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp index 88f4751c..1df6b8e5 100644 --- a/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp @@ -21,6 +21,7 @@ #include "gpgmm/d3d12/ErrorD3D12.h" #include "gpgmm/d3d12/HeapD3D12.h" #include "gpgmm/d3d12/JSONSerializerD3D12.h" +#include "gpgmm/d3d12/LogD3D12.h" #include "gpgmm/d3d12/ResidencyListD3D12.h" #include "gpgmm/d3d12/ResidencyManagerD3D12.h" #include "gpgmm/d3d12/UtilsD3D12.h" @@ -78,7 +79,7 @@ namespace gpgmm::d3d12 { // Allocation coordinates relative to the resource cannot be used when specifying // subresource-relative coordinates. if (subresource > 0 && GetInfo().Method == ALLOCATION_METHOD_SUBALLOCATED_WITHIN) { - gpgmm::ErrorEvent(MessageId::kBadOperation, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kBadOperation) << "Mapping a sub-allocation within a resource cannot use " "non-zero subresource-relative coordinates."; return E_INVALIDARG; @@ -114,7 +115,7 @@ namespace gpgmm::d3d12 { // Allocation coordinates relative to the resource cannot be used when specifying // subresource-relative coordinates. if (subresource > 0 && GetInfo().Method == ALLOCATION_METHOD_SUBALLOCATED_WITHIN) { - gpgmm::ErrorEvent(MessageId::kBadOperation, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kBadOperation) << "Unmapping a sub-allocation within a resource cannot use " "non-zero subresource-relative coordinates."; return; diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp index f5583ed4..4f71cfaf 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp @@ -30,6 +30,7 @@ #include "gpgmm/d3d12/ErrorD3D12.h" #include "gpgmm/d3d12/HeapD3D12.h" #include "gpgmm/d3d12/JSONSerializerD3D12.h" +#include "gpgmm/d3d12/LogD3D12.h" #include "gpgmm/d3d12/ResidencyManagerD3D12.h" #include "gpgmm/d3d12/ResourceAllocationD3D12.h" #include "gpgmm/d3d12/ResourceHeapAllocatorD3D12.h" @@ -70,48 +71,6 @@ namespace gpgmm::d3d12 { RESOURCE_HEAP_TYPE_INVALID, }; - D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo( - ID3D12Device* device, - D3D12_RESOURCE_DESC& resourceDescriptor) { - // Small textures can take advantage of smaller alignments. For example, - // if the most detailed mip can fit under 64KB, 4KB alignments can be used. - // Must be non-depth or without render-target to use small resource alignment. - // This also applies to MSAA textures (4MB => 64KB). - // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_resource_desc - if ((resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D || - resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D || - resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) && - IsAllowedToUseSmallAlignment(resourceDescriptor) && - (resourceDescriptor.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | - D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0) { - resourceDescriptor.Alignment = (resourceDescriptor.SampleDesc.Count > 1) - ? D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT - : D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT; - } - - D3D12_RESOURCE_ALLOCATION_INFO resourceInfo = - device->GetResourceAllocationInfo(0, 1, &resourceDescriptor); - - // If the requested resource alignment was rejected, let D3D tell us what the - // required alignment is for this resource. - if (resourceDescriptor.Alignment != 0 && - resourceDescriptor.Alignment != resourceInfo.Alignment) { - DebugLog(MessageId::kPerformanceWarning, true) - << "ID3D12Device::GetResourceAllocationInfo re-aligned: " - << resourceDescriptor.Alignment << " vs " << resourceInfo.Alignment - << " bytes."; - - resourceDescriptor.Alignment = 0; - resourceInfo = device->GetResourceAllocationInfo(0, 1, &resourceDescriptor); - } - - if (resourceInfo.SizeInBytes == 0) { - resourceInfo.SizeInBytes = kInvalidSize; - } - - return resourceInfo; - } - D3D12_HEAP_TYPE GetHeapType(RESOURCE_HEAP_TYPE resourceHeapType) { switch (resourceHeapType) { case RESOURCE_HEAP_TYPE_READBACK_ALLOW_ONLY_BUFFERS: @@ -606,8 +565,7 @@ namespace gpgmm::d3d12 { GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(resourceAllocator.get(), newDescriptor); - DebugLog(MessageId::kObjectCreated, true, WCharToUTF8(resourceAllocator->GetDebugName()), - resourceAllocator.get()) + DebugLog(resourceAllocator.get(), MessageId::kObjectCreated) << "Created resource allocator."; if (ppResourceAllocatorOut != nullptr) { @@ -937,6 +895,46 @@ namespace gpgmm::d3d12 { return S_OK; } + D3D12_RESOURCE_ALLOCATION_INFO ResourceAllocator::GetResourceAllocationInfo( + D3D12_RESOURCE_DESC& resourceDescriptor) const { + // Small textures can take advantage of smaller alignments. For example, + // if the most detailed mip can fit under 64KB, 4KB alignments can be used. + // Must be non-depth or without render-target to use small resource alignment. + // This also applies to MSAA textures (4MB => 64KB). + // https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_resource_desc + if ((resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE1D || + resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D || + resourceDescriptor.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) && + IsAllowedToUseSmallAlignment(resourceDescriptor) && + (resourceDescriptor.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | + D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) == 0) { + resourceDescriptor.Alignment = (resourceDescriptor.SampleDesc.Count > 1) + ? D3D12_SMALL_MSAA_RESOURCE_PLACEMENT_ALIGNMENT + : D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT; + } + + D3D12_RESOURCE_ALLOCATION_INFO resourceInfo = + mDevice->GetResourceAllocationInfo(0, 1, &resourceDescriptor); + + // If the requested resource alignment was rejected, let D3D tell us what the + // required alignment is for this resource. + if (resourceDescriptor.Alignment != 0 && + resourceDescriptor.Alignment != resourceInfo.Alignment) { + DebugLog(this, MessageId::kPerformanceWarning) + << "Re-aligned: " << resourceDescriptor.Alignment << " vs " + << resourceInfo.Alignment << " bytes."; + + resourceDescriptor.Alignment = 0; + resourceInfo = mDevice->GetResourceAllocationInfo(0, 1, &resourceDescriptor); + } + + if (resourceInfo.SizeInBytes == 0) { + resourceInfo.SizeInBytes = kInvalidSize; + } + + return resourceInfo; + } + HRESULT ResourceAllocator::CreateResource(const ALLOCATION_DESC& allocationDescriptor, const D3D12_RESOURCE_DESC& resourceDescriptor, D3D12_RESOURCE_STATES initialResourceState, @@ -991,9 +989,9 @@ namespace gpgmm::d3d12 { // Otherwise, creating a very large resource could overflow the allocator. D3D12_RESOURCE_DESC newResourceDesc = resourceDescriptor; const D3D12_RESOURCE_ALLOCATION_INFO resourceInfo = - GetResourceAllocationInfo(mDevice, newResourceDesc); + GetResourceAllocationInfo(newResourceDesc); if (resourceInfo.SizeInBytes > mMaxResourceHeapSize) { - ErrorLog(MessageId::kSizeExceeded, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kSizeExceeded) << "Unable to create resource allocation because the resource size exceeded " "the capabilities of the device: " << GPGMM_BYTES_TO_GB(resourceInfo.SizeInBytes) << " vs " @@ -1024,7 +1022,7 @@ namespace gpgmm::d3d12 { if (allocationDescriptor.HeapType != D3D12_HEAP_TYPE_READBACK) { heapType = D3D12_HEAP_TYPE_UPLOAD; } else { - DebugLog(MessageId::kPerformanceWarning, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kPerformanceWarning) << "Unable to optimize resource allocation for supported UMA adapter " "due to D3D12_HEAP_TYPE_READBACK being specified. Please consider " "using an unspecified heap type if CPU read-back efficency is " @@ -1035,7 +1033,7 @@ namespace gpgmm::d3d12 { const RESOURCE_HEAP_TYPE resourceHeapType = GetResourceHeapType( newResourceDesc.Dimension, heapType, newResourceDesc.Flags, mResourceHeapTier); if (resourceHeapType == RESOURCE_HEAP_TYPE_INVALID) { - ErrorLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kInvalidArgument) << "Unable to create resource allocation because the resource type was invalid due " "to the combination of resource flags, descriptor, and resource heap tier."; return E_INVALIDARG; @@ -1048,7 +1046,7 @@ namespace gpgmm::d3d12 { // Check memory requirements. D3D12_HEAP_FLAGS heapFlags = GetHeapFlags(resourceHeapType, IsCreateHeapNotResident()); if (!HasAllFlags(heapFlags, allocationDescriptor.ExtraRequiredHeapFlags)) { - WarningLog(MessageId::kPerformanceWarning, true, WCharToUTF8(GetDebugName()), this) + WarningLog(this, MessageId::kPerformanceWarning) << "ALLOCATOR_FLAG_ALWAYS_COMMITTED was not requested but enabled anyway because " "the required heap flags were incompatible with resource heap type (" << std::to_string(allocationDescriptor.ExtraRequiredHeapFlags) << " vs " @@ -1093,7 +1091,7 @@ namespace gpgmm::d3d12 { if (GPGMM_UNLIKELY(requiresPadding)) { request.SizeInBytes += allocationDescriptor.RequireResourceHeapPadding; if (!neverSubAllocate) { - WarningLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + WarningLog(this, MessageId::kInvalidArgument) << "Sub-allocation was enabled but has no effect when padding is requested: " << allocationDescriptor.RequireResourceHeapPadding << " bytes."; neverSubAllocate = true; @@ -1116,7 +1114,7 @@ namespace gpgmm::d3d12 { const uint64_t maxSegmentSize = mCaps->GetMaxSegmentSize(heapSegment); if (request.SizeInBytes > maxSegmentSize) { - ErrorLog(MessageId::kSizeExceeded, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kSizeExceeded) << "Unable to create resource allocation because the resource size exceeded " "the capabilities of the adapter: " << GPGMM_BYTES_TO_GB(request.SizeInBytes) << " vs " @@ -1140,7 +1138,7 @@ namespace gpgmm::d3d12 { request.AvailableForAllocation = allocationStats.FreeHeapUsage; - DebugLog(MessageId::kBudgetExceeded, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kBudgetExceeded) << "Current usage exceeded budget: " << GPGMM_BYTES_TO_MB(currentVideoInfo->CurrentUsage) << " vs " << GPGMM_BYTES_TO_MB(currentVideoInfo->Budget) << " MBs (" @@ -1291,7 +1289,7 @@ namespace gpgmm::d3d12 { // allocations where sub-allocation or pooling is otherwise ineffective. // The time and space complexity of committed resource is driver-defined. if (request.NeverAllocate) { - ErrorLog(MessageId::kAllocatorFailed, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kAllocatorFailed) << "Unable to allocate memory for resource because no memory was allowed to " "be created."; return E_OUTOFMEMORY; @@ -1299,7 +1297,7 @@ namespace gpgmm::d3d12 { // Committed resources cannot specify resource heap size. if (GPGMM_UNLIKELY(requiresPadding)) { - ErrorLog(MessageId::kAllocatorFailed, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kAllocatorFailed) << "Unable to allocate memory for resource because a padding was specified " "but no resource allocator could be used."; return E_INVALIDARG; @@ -1307,13 +1305,13 @@ namespace gpgmm::d3d12 { if (!isAlwaysCommitted) { if (allocationDescriptor.Flags & ALLOCATION_FLAG_NEVER_FALLBACK) { - ErrorLog(MessageId::kAllocatorFailed, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(this, MessageId::kAllocatorFailed) << "Unable to allocate memory for resource because no memory was could " "be created and fall-back was disabled."; return E_OUTOFMEMORY; } - InfoEvent(MessageId::kAllocatorFailed, true, WCharToUTF8(GetDebugName()), this) + InfoEvent(this, MessageId::kAllocatorFailed) << "Unable to allocate memory for a resource by using a heap, falling back to a " "committed resource."; } @@ -1325,7 +1323,7 @@ namespace gpgmm::d3d12 { initialResourceState, &committedResource, &resourceHeap)); if (resourceInfo.SizeInBytes > request.SizeInBytes) { - DebugLog(MessageId::kAlignmentMismatch, true, WCharToUTF8(GetDebugName()), this) + DebugLog(this, MessageId::kAlignmentMismatch) << "Resource heap size is larger then the requested size: " << resourceInfo.SizeInBytes << " vs " << request.SizeInBytes << " bytes."; } @@ -1362,8 +1360,7 @@ namespace gpgmm::d3d12 { std::lock_guard lock(mMutex); D3D12_RESOURCE_DESC desc = pCommittedResource->GetDesc(); - const D3D12_RESOURCE_ALLOCATION_INFO resourceInfo = - GetResourceAllocationInfo(mDevice, desc); + const D3D12_RESOURCE_ALLOCATION_INFO resourceInfo = GetResourceAllocationInfo(desc); D3D12_HEAP_PROPERTIES heapProperties; D3D12_HEAP_FLAGS heapFlags; @@ -1372,7 +1369,7 @@ namespace gpgmm::d3d12 { // TODO: enable validation conditionally? if (allocationDescriptor.HeapType != 0 && heapProperties.Type != allocationDescriptor.HeapType) { - ErrorLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(MessageId::kInvalidArgument) << "Unable to import a resource using a heap type that differs from the " "heap type used at creation. For important resources, it is recommended " "to not specify a heap type."; @@ -1380,7 +1377,7 @@ namespace gpgmm::d3d12 { } if (!HasAllFlags(heapFlags, allocationDescriptor.ExtraRequiredHeapFlags)) { - ErrorLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(MessageId::kInvalidArgument) << "Unable to import a resource using heap flags that differs from the " "heap flags used at creation. For important resources, it is recommended " "to not specify heap flags."; @@ -1388,7 +1385,7 @@ namespace gpgmm::d3d12 { } if (allocationDescriptor.RequireResourceHeapPadding > 0) { - ErrorLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(MessageId::kInvalidArgument) << "Unable to import a resource when using allocation flags which modify memory."; return E_INVALIDARG; } @@ -1397,7 +1394,7 @@ namespace gpgmm::d3d12 { (ALLOCATION_FLAG_DISABLE_RESIDENCY & ALLOCATION_FLAG_ALWAYS_ATTRIBUTE_HEAPS & ALLOCATION_FLAG_NEVER_ALLOCATE_MEMORY); if (allocationDescriptor.Flags & ~allowMask) { - ErrorLog(MessageId::kInvalidArgument, true, WCharToUTF8(GetDebugName()), this) + ErrorLog(MessageId::kInvalidArgument) << "Unable to import a resource when using allocation flags which modify memory."; return E_INVALIDARG; } @@ -1543,8 +1540,7 @@ namespace gpgmm::d3d12 { // sub-allocation is used. const uint64_t blocksPerHeap = SafeDivide(result.UsedBlockCount, result.UsedMemoryCount); if (blocksPerHeap > 1 && blocksPerHeap < kMinBlockToMemoryCountReportingThreshold) { - gpgmm::WarnEvent(MessageId::kPerformanceWarning, true, WCharToUTF8(GetDebugName()), - this) + WarnEvent(this, MessageId::kPerformanceWarning) << "Average number of resource allocations per heap is below threshold: " << blocksPerHeap << " blocks per heap (vs " << kMinBlockToMemoryCountReportingThreshold @@ -1558,8 +1554,7 @@ namespace gpgmm::d3d12 { 100; if (allocationUsagePct > 0 && allocationUsagePct < kMinAllocationUsageReportingThreshold * 100) { - gpgmm::WarnEvent(MessageId::kPerformanceWarning, true, WCharToUTF8(GetDebugName()), - this) + WarnEvent(this, MessageId::kPerformanceWarning) << "Average resource allocation usage is below threshold: " << allocationUsagePct << "% vs " << uint64_t(kMinAllocationUsageReportingThreshold * 100) << "%. This either means memory has become fragmented or the working set has " @@ -1626,7 +1621,8 @@ namespace gpgmm::d3d12 { switch (message->ID) { case D3D12_MESSAGE_ID_LIVE_HEAP: case D3D12_MESSAGE_ID_LIVE_RESOURCE: { - WarningLog() << "Device leak detected: " + std::string(message->pDescription); + WarningLog(this, MessageId::kPerformanceWarning) + << "Device leak detected: " + std::string(message->pDescription); } break; default: break; @@ -1676,8 +1672,9 @@ namespace gpgmm::d3d12 { return S_OK; } default: { - WarningLog() << "CheckFeatureSupport does not support feature (" + - std::to_string(feature) + ")."; + WarningLog(this, MessageId::kBadOperation) + << "CheckFeatureSupport does not support feature (" + std::to_string(feature) + + ")."; return E_INVALIDARG; } } diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h index 029bb1a6..02b65206 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h @@ -70,6 +70,10 @@ namespace gpgmm::d3d12 { DEFINE_UNKNOWN_OVERRIDES() + // IDebugObject interface + LPCWSTR GetDebugName() const override; + HRESULT SetDebugName(LPCWSTR Name) override; + private: friend BufferAllocator; friend ResourceAllocation; @@ -77,10 +81,6 @@ namespace gpgmm::d3d12 { // ObjectBase interface const char* GetTypename() const override; - // IDebugObject interface - LPCWSTR GetDebugName() const override; - HRESULT SetDebugName(LPCWSTR Name) override; - HRESULT CreateResourceInternal(const ALLOCATION_DESC& allocationDescriptor, const D3D12_RESOURCE_DESC& resourceDescriptor, D3D12_RESOURCE_STATES initialResourceState, @@ -142,6 +142,9 @@ namespace gpgmm::d3d12 { bool IsCreateHeapNotResident() const; bool IsResidencyEnabled() const; + D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo( + D3D12_RESOURCE_DESC& resourceDescriptor) const; + // MemoryAllocator interface void DeallocateMemory(std::unique_ptr allocation) override;