diff --git a/include/gpgmm_d3d12.h b/include/gpgmm_d3d12.h index 4e1d43b49..64acbbcfe 100644 --- a/include/gpgmm_d3d12.h +++ b/include/gpgmm_d3d12.h @@ -761,6 +761,14 @@ namespace gpgmm::d3d12 { \return A pointer to the IResidencyHeap used by this resource allocation. */ virtual IResidencyHeap* GetMemory() const = 0; + + /** \brief Get the residency manager that manages the memory for this resource allocation. + + @param[out] ppResidencyManagerOut Pointer to a memory block that receives a pointer to the + residency manager. Pass NULL to test if the residency manager exists. + \return S_OK when exists else S_FALSE if NULL was passed to test. + */ + virtual HRESULT GetResidencyManager(IResidencyManager * *ppResidencyManagerOut) const = 0; }; /** \enum RESOURCE_ALLOCATOR_FLAGS diff --git a/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp index 43b2ce023..3500df925 100644 --- a/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocationD3D12.cpp @@ -197,4 +197,19 @@ namespace gpgmm::d3d12 { return DebugObject::SetDebugName(Name); } + HRESULT ResourceAllocation::GetResidencyManager( + IResidencyManager** ppResidencyManagerOut) const { + ResidencyHeap* residencyHeap = static_cast(GetMemory()); + ASSERT(residencyHeap != nullptr); + + ComPtr residencyManager(residencyHeap->GetResidencyManager()); + if (ppResidencyManagerOut != nullptr) { + *ppResidencyManagerOut = residencyManager.Detach(); + } else { + return S_FALSE; + } + + return S_OK; + } + } // namespace gpgmm::d3d12 diff --git a/src/gpgmm/d3d12/ResourceAllocationD3D12.h b/src/gpgmm/d3d12/ResourceAllocationD3D12.h index 07fe934e9..96ec87f51 100644 --- a/src/gpgmm/d3d12/ResourceAllocationD3D12.h +++ b/src/gpgmm/d3d12/ResourceAllocationD3D12.h @@ -50,6 +50,7 @@ namespace gpgmm::d3d12 { uint64_t GetOffsetFromResource() const override; RESOURCE_ALLOCATION_INFO GetInfo() const override; IResidencyHeap* GetMemory() const override; + HRESULT GetResidencyManager(IResidencyManager** ppResidencyManagerOut) const override; DEFINE_UNKNOWN_OVERRIDES() diff --git a/src/mvi/gpgmm_d3d12.cpp b/src/mvi/gpgmm_d3d12.cpp index 86cbf348f..55365653c 100644 --- a/src/mvi/gpgmm_d3d12.cpp +++ b/src/mvi/gpgmm_d3d12.cpp @@ -298,6 +298,11 @@ namespace gpgmm::d3d12 { return E_NOTIMPL; } + HRESULT ResourceAllocation::GetResidencyManager( + IResidencyManager** ppResidencyManagerOut) const { + return E_NOTIMPL; + } + // ResourceAllocator HRESULT CreateResourceAllocator(const RESOURCE_ALLOCATOR_DESC& allocatorDescriptor, diff --git a/src/mvi/gpgmm_d3d12.h b/src/mvi/gpgmm_d3d12.h index 22aec1327..b6fe75dd5 100644 --- a/src/mvi/gpgmm_d3d12.h +++ b/src/mvi/gpgmm_d3d12.h @@ -162,6 +162,7 @@ namespace gpgmm::d3d12 { uint64_t GetOffsetFromResource() const override; RESOURCE_ALLOCATION_INFO GetInfo() const override; IResidencyHeap* GetMemory() const override; + HRESULT GetResidencyManager(IResidencyManager** ppResidencyManagerOut) const override; // IUnknown interface HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override; diff --git a/src/tests/end2end/D3D12ResidencyManagerTests.cpp b/src/tests/end2end/D3D12ResidencyManagerTests.cpp index ed33fdb06..d514c6b90 100644 --- a/src/tests/end2end/D3D12ResidencyManagerTests.cpp +++ b/src/tests/end2end/D3D12ResidencyManagerTests.cpp @@ -497,6 +497,9 @@ TEST_F(D3D12ResidencyManagerTests, CreateResidencyManager) { &residencyManager)); EXPECT_NE(resourceAllocator, nullptr); EXPECT_NE(residencyManager, nullptr); + + // Both the resource allocator and |residencyManager| have ownership. + EXPECT_EQ(GetRefCount(residencyManager.Get()), 2); } // Create allocator with residency, seperately, but no adapter should fail. @@ -521,9 +524,61 @@ TEST_F(D3D12ResidencyManagerTests, CreateResidencyManager) { &resourceAllocator)); EXPECT_NE(resourceAllocator, nullptr); EXPECT_NE(residencyManager, nullptr); + + // Both the resource allocator and |residencyManager| have ownership. + EXPECT_EQ(GetRefCount(residencyManager.Get()), 2); } } +// Verify getting the residency manager from the allocation doesn't destroy it. +TEST_F(D3D12ResidencyManagerTests, GetResidencyManager) { + ComPtr residencyManager; + ComPtr resourceAllocator; + ASSERT_SUCCEEDED(CreateResourceAllocator(CreateBasicAllocatorDesc(), mDevice.Get(), + mAdapter.Get(), &resourceAllocator, + &residencyManager)); + + // Resource allocator must have ownership of the |residencyManager| object. + EXPECT_EQ(GetRefCount(residencyManager.Get()), 2); + + ComPtr allocationWithResidency; + ASSERT_SUCCEEDED(resourceAllocator->CreateResource({}, CreateBasicBufferDesc(1), + D3D12_RESOURCE_STATE_COMMON, nullptr, + &allocationWithResidency)); + + // Each allocation must have ownership of the |residencyManager| object. + EXPECT_EQ(GetRefCount(residencyManager.Get()), 3); + + // Ownership must remain unchanged if no residency manager pointer was specified. + EXPECT_SUCCEEDED(allocationWithResidency->GetResidencyManager(nullptr)); + EXPECT_EQ(GetRefCount(residencyManager.Get()), 3); + + ComPtr residencyManagerAgain; + EXPECT_SUCCEEDED( + allocationWithResidency->GetResidencyManager(residencyManagerAgain.GetAddressOf())); + + // Creating a pointer to residency manager must claim ownership. + EXPECT_EQ(GetRefCount(residencyManager.Get()), 4); + + // Use the resource manager object from the new pointer. + EXPECT_SUCCEEDED(residencyManagerAgain->LockHeap(allocationWithResidency->GetMemory())); + EXPECT_SUCCEEDED(residencyManagerAgain->UnlockHeap(allocationWithResidency->GetMemory())); + + // Getting a NULL pointer to a residency manager cannot claim ownership. + EXPECT_SUCCEEDED(allocationWithResidency->GetResidencyManager(nullptr)); + EXPECT_EQ(GetRefCount(residencyManager.Get()), 4); + + // Release the allocator (and allocation), relinquishing ownership. + allocationWithResidency = nullptr; + resourceAllocator = nullptr; + + EXPECT_EQ(GetRefCount(residencyManager.Get()), 2); + + // Releasing the residency manager cannot destroy the |residencyManager| object. + residencyManager = nullptr; + EXPECT_EQ(GetRefCount(residencyManagerAgain.Get()), 1); +} + // Verify the residency manager will not increment the device refcount upon creation. TEST_F(D3D12ResidencyManagerTests, CreateResidencyManagerWithoutDeviceAddRef) { const uint32_t beforeDeviceRefCount = GetRefCount(mDevice.Get());