Skip to content

Commit

Permalink
Move DXGI adapter out of ResidencyManager.
Browse files Browse the repository at this point in the history
Pulls out DXGI-specific logic from ResidencyManager to support non-DXGI adapters in the future.

Issue: #683
  • Loading branch information
bbernhar committed Feb 2, 2024
1 parent 46fd45e commit 9040ecb
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 65 deletions.
46 changes: 25 additions & 21 deletions src/gpgmm/d3d12/BudgetUpdateD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::mutex> lock(mMutex);
return mLastError;
}

void BudgetUpdateTask::SetLastError(HRESULT hr) {
std::lock_guard<std::mutex> 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)) {
Expand Down Expand Up @@ -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<std::mutex> 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<std::mutex> lock(mMutex);
mLastError = hr;
}

// BudgetUpdateEvent

BudgetUpdateEvent::BudgetUpdateEvent(std::shared_ptr<Event> event,
Expand Down
38 changes: 24 additions & 14 deletions src/gpgmm/d3d12/BudgetUpdateD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
65 changes: 49 additions & 16 deletions src/gpgmm/d3d12/ResidencyManagerD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,16 @@ namespace gpgmm::d3d12 {

SetLogLevel(GetMessageSeverity(descriptor.MinLogLevel));

std::unique_ptr<ResidencyManager> residencyManager;
ComPtr<IDXGIAdapter3> dxgiAdapter3;
GPGMM_RETURN_IF_FAILED(pAdapter->QueryInterface(IID_PPV_ARGS(&dxgiAdapter3)));

std::unique_ptr<ResidencyManager> residencyManager = std::unique_ptr<ResidencyManager>(
new ResidencyManager(descriptor, pDevice, dxgiAdapter3.Get(), std::move(caps)));
if (SUCCEEDED(pAdapter->QueryInterface(IID_PPV_ARGS(&dxgiAdapter3)))) {
residencyManager = std::make_unique<ResidencyManagerDXGI>(
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) {
Expand Down Expand Up @@ -160,10 +165,8 @@ namespace gpgmm::d3d12 {

ResidencyManager::ResidencyManager(const RESIDENCY_MANAGER_DESC& descriptor,
ID3D12Device* pDevice,
IDXGIAdapter3* pAdapter,
std::unique_ptr<Caps> caps)
: mDevice(pDevice),
mAdapter(pAdapter),
mMaxPctOfMemoryToBudget(descriptor.MaxPctOfMemoryToBudget == 0
? kDefaultMaxPctOfMemoryToBudget
: descriptor.MaxPctOfMemoryToBudget),
Expand All @@ -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() {
Expand Down Expand Up @@ -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<DXGI_MEMORY_SEGMENT_GROUP>(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
Expand Down Expand Up @@ -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<BudgetUpdateTask> task =
std::make_shared<BudgetUpdateTask>(this, mAdapter);
std::shared_ptr<BudgetUpdateTask> task = CreateBudgetUpdateTask();
mBudgetNotificationUpdateEvent = std::make_shared<BudgetUpdateEvent>(
TaskScheduler::GetOrCreateInstance()->PostTask(task), task);
}
Expand Down Expand Up @@ -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> 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<DXGI_MEMORY_SEGMENT_GROUP>(heapSegment), &queryVideoMemoryInfoOut));
pMemoryInfoOut->AvailableForReservation = queryVideoMemoryInfoOut.AvailableForReservation;
pMemoryInfoOut->Budget = queryVideoMemoryInfoOut.Budget;
pMemoryInfoOut->CurrentReservation = queryVideoMemoryInfoOut.CurrentReservation;
pMemoryInfoOut->CurrentUsage = queryVideoMemoryInfoOut.CurrentUsage;
return S_OK;
}

std::shared_ptr<BudgetUpdateTask> ResidencyManagerDXGI::CreateBudgetUpdateTask() {
return std::make_shared<BudgetUpdateTaskDXGI>(this);
}

IDXGIAdapter3* ResidencyManagerDXGI::GetAdapter() const {
return mAdapter;
}

} // namespace gpgmm::d3d12
51 changes: 37 additions & 14 deletions src/gpgmm/d3d12/ResidencyManagerD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@
#include <memory>
#include <mutex>

namespace gpgmm {
class TaskScheduler;
} // namespace gpgmm

namespace gpgmm::d3d12 {

class BudgetUpdateTask;
Expand All @@ -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,
Expand Down Expand Up @@ -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> caps);

// Should be overridden per adapter type.
virtual HRESULT QueryMemoryInfoImpl(const RESIDENCY_HEAP_SEGMENT& heapSegment,
RESIDENCY_MEMORY_INFO* pMemoryInfoOut) = 0;

virtual std::shared_ptr<BudgetUpdateTask> CreateBudgetUpdateTask() = 0;

private:
friend ResidencyHeap;
friend ResourceAllocator;
friend ResourceHeapAllocator;

// Unknown interface
void DeleteThis() override;

Expand All @@ -98,9 +104,6 @@ namespace gpgmm::d3d12 {

HRESULT QueryStatsInternal(RESIDENCY_MANAGER_STATS* pResidencyManagerStats);

friend BudgetUpdateTask;
HRESULT UpdateMemorySegments();

bool IsUMA() const;

// ObjectBase interface
Expand Down Expand Up @@ -134,7 +137,6 @@ namespace gpgmm::d3d12 {
HRESULT EnsureResidencyFenceExists();

ID3D12Device* mDevice = nullptr;
IDXGIAdapter3* mAdapter = nullptr;

const float mMaxPctOfMemoryToBudget;
const float mMinPctOfBudgetToReserve;
Expand All @@ -156,6 +158,27 @@ namespace gpgmm::d3d12 {
std::shared_ptr<BudgetUpdateEvent> mBudgetNotificationUpdateEvent;
};

class ResidencyManagerDXGI final : public ResidencyManager {
public:
ResidencyManagerDXGI(const RESIDENCY_MANAGER_DESC& descriptor,
ID3D12Device* pDevice,
IDXGIAdapter3* pAdapter,
std::unique_ptr<Caps> caps);

~ResidencyManagerDXGI() override;

IDXGIAdapter3* GetAdapter() const;

private:
// ResidencyManager overloads
HRESULT QueryMemoryInfoImpl(const RESIDENCY_HEAP_SEGMENT& heapSegment,
RESIDENCY_MEMORY_INFO* pMemoryInfoOut) override;

std::shared_ptr<BudgetUpdateTask> CreateBudgetUpdateTask() override;

IDXGIAdapter3* mAdapter = nullptr;
};

} // namespace gpgmm::d3d12

#endif // SRC_GPGMM_D3D12_RESIDENCYMANAGERD3D12_H_

0 comments on commit 9040ecb

Please sign in to comment.