From 9040ecbe4fd9bf897ae9e3a8670db9efbbb038b4 Mon Sep 17 00:00:00 2001 From: "Bernhart, Bryan" Date: Fri, 2 Feb 2024 14:15:27 -0800 Subject: [PATCH] Move DXGI adapter out of ResidencyManager. Pulls out DXGI-specific logic from ResidencyManager to support non-DXGI adapters in the future. Issue: #683 --- src/gpgmm/d3d12/BudgetUpdateD3D12.cpp | 46 ++++++++-------- src/gpgmm/d3d12/BudgetUpdateD3D12.h | 38 ++++++++----- src/gpgmm/d3d12/ResidencyManagerD3D12.cpp | 65 +++++++++++++++++------ src/gpgmm/d3d12/ResidencyManagerD3D12.h | 51 +++++++++++++----- 4 files changed, 135 insertions(+), 65 deletions(-) diff --git a/src/gpgmm/d3d12/BudgetUpdateD3D12.cpp b/src/gpgmm/d3d12/BudgetUpdateD3D12.cpp index 84651b44..4d7570d3 100644 --- a/src/gpgmm/d3d12/BudgetUpdateD3D12.cpp +++ b/src/gpgmm/d3d12/BudgetUpdateD3D12.cpp @@ -24,24 +24,38 @@ namespace gpgmm::d3d12 { // BudgetUpdateTask - BudgetUpdateTask::BudgetUpdateTask(ResidencyManager* const residencyManager, - IDXGIAdapter3* adapter) + BudgetUpdateTask::BudgetUpdateTask() = default; + + BudgetUpdateTask::~BudgetUpdateTask() = default; + + HRESULT BudgetUpdateTask::GetLastError() const { + std::lock_guard lock(mMutex); + return mLastError; + } + + void BudgetUpdateTask::SetLastError(HRESULT hr) { + std::lock_guard lock(mMutex); + mLastError = hr; + } + + // BudgetUpdateTaskDXGI + + BudgetUpdateTaskDXGI::BudgetUpdateTaskDXGI(ResidencyManagerDXGI* const residencyManager) : mResidencyManager(residencyManager), - mAdapter(std::move(adapter)), mBudgetNotificationUpdateEvent(CreateEventW(NULL, FALSE, FALSE, NULL)), mUnregisterAndExitEvent(CreateEventW(NULL, FALSE, FALSE, NULL)) { ASSERT(mResidencyManager != nullptr); - ASSERT(mAdapter != nullptr); - mLastError = mAdapter->RegisterVideoMemoryBudgetChangeNotificationEvent( - mBudgetNotificationUpdateEvent, &mCookie); + mLastError = + mResidencyManager->GetAdapter()->RegisterVideoMemoryBudgetChangeNotificationEvent( + mBudgetNotificationUpdateEvent, &mCookie); } - BudgetUpdateTask::~BudgetUpdateTask() { + BudgetUpdateTaskDXGI::~BudgetUpdateTaskDXGI() { CloseHandle(mUnregisterAndExitEvent); CloseHandle(mBudgetNotificationUpdateEvent); } - MaybeError BudgetUpdateTask::operator()() { + MaybeError BudgetUpdateTaskDXGI::operator()() { HRESULT hr = GetLastError(); bool isExiting = false; while (!isExiting && SUCCEEDED(hr)) { @@ -77,28 +91,18 @@ namespace gpgmm::d3d12 { if (FAILED(hr)) { ErrorLog(ErrorCode::kBudgetInvalid, mResidencyManager) << "Unable to update budget: " + - GetErrorResultMessage(hr, mResidencyManager->mDevice); + GetErrorResultMessage(hr, mResidencyManager->GetDevice()); } SetLastError(hr); return GetErrorCode(hr); } - HRESULT BudgetUpdateTask::GetLastError() const { - std::lock_guard lock(mMutex); - return mLastError; - } - - bool BudgetUpdateTask::UnregisterAndExit() { - mAdapter->UnregisterVideoMemoryBudgetChangeNotification(mCookie); + bool BudgetUpdateTaskDXGI::UnregisterAndExit() { + mResidencyManager->GetAdapter()->UnregisterVideoMemoryBudgetChangeNotification(mCookie); return SetEvent(mUnregisterAndExitEvent); } - void BudgetUpdateTask::SetLastError(HRESULT hr) { - std::lock_guard lock(mMutex); - mLastError = hr; - } - // BudgetUpdateEvent BudgetUpdateEvent::BudgetUpdateEvent(std::shared_ptr event, diff --git a/src/gpgmm/d3d12/BudgetUpdateD3D12.h b/src/gpgmm/d3d12/BudgetUpdateD3D12.h index b36b5e0e..69848956 100644 --- a/src/gpgmm/d3d12/BudgetUpdateD3D12.h +++ b/src/gpgmm/d3d12/BudgetUpdateD3D12.h @@ -23,34 +23,44 @@ namespace gpgmm::d3d12 { - class ResidencyManager; - // Creates a long-lived task to recieve and process OS budget change events. class BudgetUpdateTask : public VoidCallback { public: - BudgetUpdateTask(ResidencyManager* const residencyManager, IDXGIAdapter3* adapter); + BudgetUpdateTask(); ~BudgetUpdateTask() override; - MaybeError operator()() override; - - HRESULT GetLastError() const; - // Shutdown the event loop. - bool UnregisterAndExit(); + virtual bool UnregisterAndExit() = 0; - private: + virtual HRESULT GetLastError() const; + + protected: void SetLastError(HRESULT hr); - ResidencyManager* const mResidencyManager; - IDXGIAdapter3* mAdapter = nullptr; + mutable std::mutex mMutex; // Protect access between threads for members below. + HRESULT mLastError = S_OK; + }; + + class ResidencyManagerDXGI; + + class BudgetUpdateTaskDXGI final : public BudgetUpdateTask { + public: + BudgetUpdateTaskDXGI(ResidencyManagerDXGI* const residencyManager); + ~BudgetUpdateTaskDXGI() override; + + // VoidCallback interface + MaybeError operator()() override; + + // BudgetUpdateTask interface + bool UnregisterAndExit() override; + + private: + ResidencyManagerDXGI* const mResidencyManager; HANDLE mBudgetNotificationUpdateEvent = INVALID_HANDLE_VALUE; HANDLE mUnregisterAndExitEvent = INVALID_HANDLE_VALUE; DWORD mCookie = 0; // Used to unregister from notifications. - - mutable std::mutex mMutex; // Protect access between threads for members below. - HRESULT mLastError = S_OK; }; class BudgetUpdateEvent final : public Event { diff --git a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp index 2f895dd5..879e06e7 100644 --- a/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp +++ b/src/gpgmm/d3d12/ResidencyManagerD3D12.cpp @@ -86,11 +86,16 @@ namespace gpgmm::d3d12 { SetLogLevel(GetMessageSeverity(descriptor.MinLogLevel)); + std::unique_ptr residencyManager; ComPtr dxgiAdapter3; - GPGMM_RETURN_IF_FAILED(pAdapter->QueryInterface(IID_PPV_ARGS(&dxgiAdapter3))); - - std::unique_ptr residencyManager = std::unique_ptr( - new ResidencyManager(descriptor, pDevice, dxgiAdapter3.Get(), std::move(caps))); + if (SUCCEEDED(pAdapter->QueryInterface(IID_PPV_ARGS(&dxgiAdapter3)))) { + residencyManager = std::make_unique( + descriptor, pDevice, dxgiAdapter3.Get(), std::move(caps)); + } else { + ErrorLog(ErrorCode::kInvalidArgument) + << "Residency management is not supported for this adapter."; + return E_NOINTERFACE; + } // Enable automatic memory budget updates. if (descriptor.Flags & RESIDENCY_MANAGER_FLAG_ALLOW_BACKGROUND_BUDGET_UPDATES) { @@ -160,10 +165,8 @@ namespace gpgmm::d3d12 { ResidencyManager::ResidencyManager(const RESIDENCY_MANAGER_DESC& descriptor, ID3D12Device* pDevice, - IDXGIAdapter3* pAdapter, std::unique_ptr caps) : mDevice(pDevice), - mAdapter(pAdapter), mMaxPctOfMemoryToBudget(descriptor.MaxPctOfMemoryToBudget == 0 ? kDefaultMaxPctOfMemoryToBudget : descriptor.MaxPctOfMemoryToBudget), @@ -180,9 +183,7 @@ namespace gpgmm::d3d12 { mInitialFenceValue(descriptor.InitialFenceValue), mIsAlwaysInBudget(descriptor.Flags & RESIDENCY_MANAGER_FLAG_ALWAYS_IN_BUDGET) { GPGMM_TRACE_EVENT_OBJECT_NEW(this); - ASSERT(mDevice != nullptr); - ASSERT(mAdapter != nullptr); } void ResidencyManager::DeleteThis() { @@ -358,12 +359,8 @@ namespace gpgmm::d3d12 { return S_OK; } - // Residency heap segments are 1:1 with DXGI memory segment groups. - DXGI_QUERY_VIDEO_MEMORY_INFO queryVideoMemoryInfoOut; - GPGMM_RETURN_IF_FAILED( - mAdapter->QueryVideoMemoryInfo(0, static_cast(heapSegment), - &queryVideoMemoryInfoOut), - mDevice); + RESIDENCY_MEMORY_INFO queryVideoMemoryInfoOut = {}; + GPGMM_RETURN_IF_FAILED(QueryMemoryInfoImpl(heapSegment, &queryVideoMemoryInfoOut)); // The memory budget provided by QueryMemoryInfo is defined by the operating // system, and may be lower than expected in certain scenarios. Under memory pressure, we @@ -828,8 +825,7 @@ namespace gpgmm::d3d12 { // Return True if successfully registered or False if error. HRESULT ResidencyManager::StartBudgetNotificationUpdates() { if (mBudgetNotificationUpdateEvent == nullptr) { - std::shared_ptr task = - std::make_shared(this, mAdapter); + std::shared_ptr task = CreateBudgetUpdateTask(); mBudgetNotificationUpdateEvent = std::make_shared( TaskScheduler::GetOrCreateInstance()->PostTask(task), task); } @@ -923,4 +919,41 @@ namespace gpgmm::d3d12 { return DebugObject::SetDebugNameImpl(Name); } + ID3D12Device* ResidencyManager::GetDevice() const { + return mDevice; + } + + // ResidencyManagerDXGI + + ResidencyManagerDXGI::ResidencyManagerDXGI(const RESIDENCY_MANAGER_DESC& descriptor, + ID3D12Device* pDevice, + IDXGIAdapter3* pAdapter, + std::unique_ptr caps) + : ResidencyManager(descriptor, pDevice, std::move(caps)), mAdapter(pAdapter) { + ASSERT(mAdapter != nullptr); + } + + ResidencyManagerDXGI::~ResidencyManagerDXGI() = default; + + HRESULT ResidencyManagerDXGI::QueryMemoryInfoImpl(const RESIDENCY_HEAP_SEGMENT& heapSegment, + RESIDENCY_MEMORY_INFO* pMemoryInfoOut) { + // Residency heap segments are 1:1 with DXGI memory segment groups. + DXGI_QUERY_VIDEO_MEMORY_INFO queryVideoMemoryInfoOut; + GPGMM_RETURN_IF_FAILED(mAdapter->QueryVideoMemoryInfo( + 0, static_cast(heapSegment), &queryVideoMemoryInfoOut)); + pMemoryInfoOut->AvailableForReservation = queryVideoMemoryInfoOut.AvailableForReservation; + pMemoryInfoOut->Budget = queryVideoMemoryInfoOut.Budget; + pMemoryInfoOut->CurrentReservation = queryVideoMemoryInfoOut.CurrentReservation; + pMemoryInfoOut->CurrentUsage = queryVideoMemoryInfoOut.CurrentUsage; + return S_OK; + } + + std::shared_ptr ResidencyManagerDXGI::CreateBudgetUpdateTask() { + return std::make_shared(this); + } + + IDXGIAdapter3* ResidencyManagerDXGI::GetAdapter() const { + return mAdapter; + } + } // namespace gpgmm::d3d12 diff --git a/src/gpgmm/d3d12/ResidencyManagerD3D12.h b/src/gpgmm/d3d12/ResidencyManagerD3D12.h index 4f6a7312..f478491e 100644 --- a/src/gpgmm/d3d12/ResidencyManagerD3D12.h +++ b/src/gpgmm/d3d12/ResidencyManagerD3D12.h @@ -26,10 +26,6 @@ #include #include -namespace gpgmm { - class TaskScheduler; -} // namespace gpgmm - namespace gpgmm::d3d12 { class BudgetUpdateTask; @@ -40,7 +36,7 @@ namespace gpgmm::d3d12 { class ResourceAllocator; class ResourceHeapAllocator; - class ResidencyManager final : public DebugObject, public IResidencyManager, public ObjectBase { + class ResidencyManager : public DebugObject, public IResidencyManager, public ObjectBase { public: static HRESULT CreateResidencyManager(const RESIDENCY_MANAGER_DESC& descriptor, ID3D12Device* pDevice, @@ -75,16 +71,26 @@ namespace gpgmm::d3d12 { HRESULT LockHeap(ResidencyHeap* pHeap); HRESULT UnlockHeap(ResidencyHeap* pHeap); - private: - friend ResidencyHeap; - friend ResourceAllocator; - friend ResourceHeapAllocator; + HRESULT UpdateMemorySegments(); + + ID3D12Device* GetDevice() const; + protected: ResidencyManager(const RESIDENCY_MANAGER_DESC& descriptor, ID3D12Device* pDevice, - IDXGIAdapter3* pAdapter, std::unique_ptr caps); + // Should be overridden per adapter type. + virtual HRESULT QueryMemoryInfoImpl(const RESIDENCY_HEAP_SEGMENT& heapSegment, + RESIDENCY_MEMORY_INFO* pMemoryInfoOut) = 0; + + virtual std::shared_ptr CreateBudgetUpdateTask() = 0; + + private: + friend ResidencyHeap; + friend ResourceAllocator; + friend ResourceHeapAllocator; + // Unknown interface void DeleteThis() override; @@ -98,9 +104,6 @@ namespace gpgmm::d3d12 { HRESULT QueryStatsInternal(RESIDENCY_MANAGER_STATS* pResidencyManagerStats); - friend BudgetUpdateTask; - HRESULT UpdateMemorySegments(); - bool IsUMA() const; // ObjectBase interface @@ -134,7 +137,6 @@ namespace gpgmm::d3d12 { HRESULT EnsureResidencyFenceExists(); ID3D12Device* mDevice = nullptr; - IDXGIAdapter3* mAdapter = nullptr; const float mMaxPctOfMemoryToBudget; const float mMinPctOfBudgetToReserve; @@ -156,6 +158,27 @@ namespace gpgmm::d3d12 { std::shared_ptr mBudgetNotificationUpdateEvent; }; + class ResidencyManagerDXGI final : public ResidencyManager { + public: + ResidencyManagerDXGI(const RESIDENCY_MANAGER_DESC& descriptor, + ID3D12Device* pDevice, + IDXGIAdapter3* pAdapter, + std::unique_ptr caps); + + ~ResidencyManagerDXGI() override; + + IDXGIAdapter3* GetAdapter() const; + + private: + // ResidencyManager overloads + HRESULT QueryMemoryInfoImpl(const RESIDENCY_HEAP_SEGMENT& heapSegment, + RESIDENCY_MEMORY_INFO* pMemoryInfoOut) override; + + std::shared_ptr CreateBudgetUpdateTask() override; + + IDXGIAdapter3* mAdapter = nullptr; + }; + } // namespace gpgmm::d3d12 #endif // SRC_GPGMM_D3D12_RESIDENCYMANAGERD3D12_H_