diff --git a/include/gpgmm_d3d12.h b/include/gpgmm_d3d12.h index 2f108e52..fc9b9434 100644 --- a/include/gpgmm_d3d12.h +++ b/include/gpgmm_d3d12.h @@ -1454,6 +1454,25 @@ namespace gpgmm::d3d12 { IResidencyManager* pResidencyManager, IResourceAllocator** ppResourceAllocatorOut); + /** \brief Create a resource allocator from an existing resource allocator. + + Creating a resource allocator from another resource allocator allows resources heaps to be + re-used between allocators that have seperate configurations. For example, the application + developer may want a global resource allocator to service large requests using dedication + allocations but still prefer smaller requests to use sub-allocation. By creating a resource + allocator from another, the same pool can be re-used instead of managing multiple pools. + + @param allocatorDescriptor A reference to RESOURCE_ALLOCATOR_DESC structure that describes the + allocator. + @param pResourceAllocator allocator used to create the allocator. Required parameter. + @param[out] ppResourceAllocatorOut Pointer to a memory block that receives a pointer to the + resource allocator. Pass NULL to test if allocator creation would succeed, but not actually + create the allocator. + */ + GPGMM_EXPORT HRESULT CreateResourceAllocator(const RESOURCE_ALLOCATOR_DESC& allocatorDescriptor, + IResourceAllocator* pResourceAllocator, + IResourceAllocator** ppResourceAllocatorOut); + } // namespace gpgmm::d3d12 #endif // INCLUDE_GPGMM_D3D12_H_ diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp index 941f3793..6ca815e7 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp @@ -389,8 +389,18 @@ namespace gpgmm::d3d12 { IDXGIAdapter* pAdapter, IResidencyManager* pResidencyManager, IResourceAllocator** ppResourceAllocatorOut) { + return ResourceAllocator::CreateResourceAllocator(allocatorDescriptor, pDevice, pAdapter, + pResidencyManager, nullptr, + ppResourceAllocatorOut); + } + + HRESULT CreateResourceAllocator(const RESOURCE_ALLOCATOR_DESC& allocatorDescriptor, + IResourceAllocator* pResourceAllocator, + IResourceAllocator** ppResourceAllocatorOut) { + ResourceAllocator* resourceAllocator = static_cast(pResourceAllocator); return ResourceAllocator::CreateResourceAllocator( - allocatorDescriptor, pDevice, pAdapter, pResidencyManager, ppResourceAllocatorOut); + allocatorDescriptor, resourceAllocator->GetDevice(), resourceAllocator->GetAdapter(), + resourceAllocator->GetResidencyManager(), pResourceAllocator, ppResourceAllocatorOut); } // static @@ -423,7 +433,8 @@ namespace gpgmm::d3d12 { ComPtr resourceAllocator; GPGMM_RETURN_IF_FAILED(CreateResourceAllocator(allocatorDescriptor, pDevice, pAdapter, - residencyManager.Get(), &resourceAllocator)); + residencyManager.Get(), nullptr, + &resourceAllocator)); if (ppResourceAllocatorOut != nullptr) { *ppResourceAllocatorOut = resourceAllocator.Detach(); @@ -442,6 +453,7 @@ namespace gpgmm::d3d12 { ID3D12Device* pDevice, IDXGIAdapter* pAdapter, IResidencyManager* pResidencyManager, + IResourceAllocator* pResourceAllocator, IResourceAllocator** ppResourceAllocatorOut) { GPGMM_RETURN_IF_NULL(pDevice); @@ -571,10 +583,16 @@ namespace gpgmm::d3d12 { } #endif - std::unique_ptr resourceAllocator = - std::unique_ptr(new ResourceAllocator( - newDescriptor, pDevice, static_cast(pResidencyManager), + std::unique_ptr resourceAllocator; + if (pResourceAllocator == nullptr) { + resourceAllocator = std::unique_ptr(new ResourceAllocator( + newDescriptor, pDevice, pAdapter, static_cast(pResidencyManager), + std::move(caps))); + } else { + resourceAllocator = std::unique_ptr(new ResourceAllocator( + newDescriptor, static_cast(pResourceAllocator), std::move(caps))); + } GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(resourceAllocator.get(), newDescriptor); @@ -588,11 +606,33 @@ namespace gpgmm::d3d12 { return S_OK; } + ResourceAllocator::ResourceAllocator(const RESOURCE_ALLOCATOR_DESC& descriptor, + ResourceAllocator* allocator, + std::unique_ptr caps) + : ResourceAllocator(descriptor, + allocator->mDevice, + allocator->mAdapter, + allocator->mResidencyManager.Get(), + std::move(caps)) { + // Use the existing pooled allocators allocator. + for (uint32_t resourceHeapTypeIndex = 0; resourceHeapTypeIndex < kNumOfResourceHeapTypes; + resourceHeapTypeIndex++) { + mPooledOrNonPooledHeapAllocator[resourceHeapTypeIndex] = + allocator->mPooledOrNonPooledHeapAllocator[resourceHeapTypeIndex]; + mMSAAPooledOrNonPooledHeapAllocator[resourceHeapTypeIndex] = + allocator->mMSAAPooledOrNonPooledHeapAllocator[resourceHeapTypeIndex]; + mSmallBufferAllocatorOfType[resourceHeapTypeIndex] = + allocator->mSmallBufferAllocatorOfType[resourceHeapTypeIndex]; + } + } + ResourceAllocator::ResourceAllocator(const RESOURCE_ALLOCATOR_DESC& descriptor, ID3D12Device* pDevice, + IDXGIAdapter* pAdapter, ResidencyManager* pResidencyManager, std::unique_ptr caps) : mDevice(pDevice), + mAdapter(pAdapter), mResidencyManager(pResidencyManager), mCaps(std::move(caps)), mResourceHeapTier(descriptor.ResourceHeapTier), @@ -610,6 +650,7 @@ namespace gpgmm::d3d12 { RESOURCE_ALLOCATOR_FLAG_NEVER_OVER_ALLOCATE), mReleaseSizeInBytes(descriptor.ReleaseSizeInBytes) { ASSERT(mDevice != nullptr); + ASSERT(mAdapter != nullptr); GPGMM_TRACE_EVENT_OBJECT_NEW(this); @@ -1837,6 +1878,18 @@ namespace gpgmm::d3d12 { return DebugObject::SetDebugNameImpl(Name); } + ID3D12Device* ResourceAllocator::GetDevice() const { + return mDevice; + } + + IDXGIAdapter* ResourceAllocator::GetAdapter() const { + return mAdapter; + } + + IResidencyManager* ResourceAllocator::GetResidencyManager() const { + return mResidencyManager.Get(); + } + ImportResourceCallbackContext::ImportResourceCallbackContext(ID3D12Resource* resource) : mResource(resource) { } diff --git a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h index bcec2eca..8589904a 100644 --- a/src/gpgmm/d3d12/ResourceAllocatorD3D12.h +++ b/src/gpgmm/d3d12/ResourceAllocatorD3D12.h @@ -49,6 +49,11 @@ namespace gpgmm::d3d12 { ID3D12Device* pDevice, IDXGIAdapter* pAdapter, IResidencyManager* pResidencyManager, + IResourceAllocator* pResourceAllocator, + IResourceAllocator** ppResourceAllocatorOut); + + static HRESULT CreateResourceAllocator(const RESOURCE_ALLOCATOR_DESC& allocatorDescriptor, + IResourceAllocator* pResourceAllocator, IResourceAllocator** ppResourceAllocatorOut); ~ResourceAllocator() override; @@ -74,15 +79,24 @@ namespace gpgmm::d3d12 { LPCWSTR GetDebugName() const override; HRESULT SetDebugName(LPCWSTR Name) override; + ID3D12Device* GetDevice() const; + IDXGIAdapter* GetAdapter() const; + IResidencyManager* GetResidencyManager() const; + private: friend BufferAllocator; friend ResourceAllocation; ResourceAllocator(const RESOURCE_ALLOCATOR_DESC& descriptor, ID3D12Device* pDevice, + IDXGIAdapter* pAdapter, ResidencyManager* pResidencyManager, std::unique_ptr caps); + ResourceAllocator(const RESOURCE_ALLOCATOR_DESC& descriptor, + ResourceAllocator* allocator, + std::unique_ptr caps); + void DeleteThis() override; template @@ -153,6 +167,7 @@ namespace gpgmm::d3d12 { DEFINE_OBJECT_BASE_OVERRIDES(IResourceAllocator) ID3D12Device* mDevice = nullptr; + IDXGIAdapter* mAdapter = nullptr; ComPtr mResidencyManager; std::unique_ptr mCaps; diff --git a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp index 2acf6e88..f60931a6 100644 --- a/src/tests/end2end/D3D12ResourceAllocatorTests.cpp +++ b/src/tests/end2end/D3D12ResourceAllocatorTests.cpp @@ -2065,3 +2065,40 @@ TEST_F(D3D12ResourceAllocatorTests, AllocatorFeatures) { RESOURCE_ALLOCATOR_FEATURE_RESOURCE_ALLOCATION_SUPPORT, &data, sizeof(data))); } } + +// Create two resource allocations using different methods using the same heaps. +TEST_F(D3D12ResourceAllocatorTests, NestedAllocators) { + RESOURCE_ALLOCATOR_DESC desc = CreateBasicAllocatorDesc(); + desc.SubAllocationAlgorithm = RESOURCE_ALLOCATION_ALGORITHM_BUDDY_SYSTEM; + + ComPtr parentAllocator; + ASSERT_SUCCEEDED( + CreateResourceAllocator(desc, mDevice.Get(), mAdapter.Get(), &parentAllocator, nullptr)); + + { + ComPtr subAllocation; + ASSERT_SUCCEEDED(parentAllocator->CreateResource({}, CreateBasicBufferDesc(1), + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + &subAllocation)); + EXPECT_EQ(subAllocation->GetInfo().Type, RESOURCE_ALLOCATION_TYPE_SUBALLOCATED); + } + + RESOURCE_ALLOCATOR_STATS beforeStats = GetStats(parentAllocator); + EXPECT_GT(beforeStats.FreeHeapUsage, 0u); + + desc.SubAllocationAlgorithm = RESOURCE_ALLOCATION_ALGORITHM_DEDICATED; + + ComPtr childAllocator; + ASSERT_SUCCEEDED(CreateResourceAllocator(desc, parentAllocator.Get(), &childAllocator)); + + { + ComPtr dedicatedAllocation; + ASSERT_SUCCEEDED(childAllocator->CreateResource({}, CreateBasicBufferDesc(1), + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, + &dedicatedAllocation)); + EXPECT_EQ(dedicatedAllocation->GetInfo().Type, RESOURCE_ALLOCATION_TYPE_STANDALONE); + } + + RESOURCE_ALLOCATOR_STATS afterStats = GetStats(parentAllocator); + EXPECT_EQ(beforeStats.FreeHeapUsage, afterStats.FreeHeapUsage); +}