Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions include/gpgmm_d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -1136,10 +1136,10 @@ namespace gpgmm::d3d12 {

/** \brief Forces use of the resource allocator or E_FAIL.

The flag disables the fall-back behavior of reverting to the D3D12 runtime/driver provided
allocator (CreateCommittedResource) when resource allocation fails.
The flag disables the fall-back behavior of using
RESOURCE_ALLOCATION_FLAG_ALWAYS_COMMITTED as a last resort.

Mostly used for debug and testing when certain allocation methods unexpectedly fail.
Mostly used for debug and testing when certain allocations unexpectedly fail.
*/
RESOURCE_ALLOCATION_FLAG_NEVER_FALLBACK = 0x40,

Expand All @@ -1160,6 +1160,14 @@ namespace gpgmm::d3d12 {
is normally not tracked.
*/
RESOURCE_ALLOCATION_FLAG_ALWAYS_WARN_ON_ALIGNMENT_MISMATCH = 0x100,

/** \brief Disable re-use of resource heap.

A committed resource is allocated through D3D12 instead of GPGMM. This could be favorable
for large static resources. Otherwise, this is mostly used for debugging and testing
purposes.
*/
RESOURCE_ALLOCATION_FLAG_ALWAYS_COMMITTED = 0x200,
};

DEFINE_ENUM_FLAG_OPERATORS(RESOURCE_ALLOCATION_FLAGS)
Expand Down
30 changes: 30 additions & 0 deletions src/gpgmm/d3d12/ResourceAllocationD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,36 @@ namespace gpgmm::d3d12 {
return DebugObject::SetDebugName(Name);
}

HRESULT STDMETHODCALLTYPE ResourceAllocation::QueryInterface(REFIID riid, void** ppvObject) {
ResidencyHeap* residencyHeap = static_cast<ResidencyHeap*>(GetMemory());

// Only committed resources can be exported. Committed resources are created
// without explicit heaps.
ComPtr<ID3D12Heap> heap;
if (SUCCEEDED(residencyHeap->QueryInterface(IID_PPV_ARGS(&heap)))) {
ErrorLog(ErrorCode::kBadOperation, this)
<< "QueryInterface is not supported for this resource allocation.";
return E_INVALIDARG;
}

// Exported resource cannot remain managed for residency.
if (SUCCEEDED(residencyHeap->GetResidencyManager(nullptr))) {
ErrorLog(ErrorCode::kBadOperation, this) << "QueryInterface does not supported resource "
"allocations under residency management.";
return E_INVALIDARG;
}

return mResource->QueryInterface(riid, ppvObject);
}

ULONG STDMETHODCALLTYPE ResourceAllocation::AddRef() {
return Unknown::AddRef();
}

ULONG STDMETHODCALLTYPE ResourceAllocation::Release() {
return Unknown::Release();
}

HRESULT ResourceAllocation::GetResourceAllocator(
IResourceAllocator** ppResourceAllocatorOut) const {
ComPtr<IResourceAllocator> resourceAllocator(mResourceAllocator);
Expand Down
7 changes: 5 additions & 2 deletions src/gpgmm/d3d12/ResourceAllocationD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,15 @@ namespace gpgmm::d3d12 {
IResidencyHeap* GetMemory() const override;
HRESULT GetResourceAllocator(IResourceAllocator** ppResourceAllocatorOut) const override;

DEFINE_UNKNOWN_OVERRIDES()

// IDebugObject interface
LPCWSTR GetDebugName() const override;
HRESULT SetDebugName(LPCWSTR Name) override;

// IUnknown interface
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;

private:
friend ResourceAllocator;

Expand Down
5 changes: 3 additions & 2 deletions src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1177,14 +1177,15 @@ namespace gpgmm::d3d12 {

// Resource is always committed when heaps flags are incompatible with the resource heap
// type or if specified by the flag.
bool isAlwaysCommitted = mIsAlwaysCommitted;
bool isAlwaysCommitted = mIsAlwaysCommitted || (allocationDescriptor.Flags &
RESOURCE_ALLOCATION_FLAG_ALWAYS_COMMITTED);

// Check memory requirements.
D3D12_HEAP_FLAGS heapFlags =
GetHeapFlags(resourceHeapType, IsCreateHeapNotResidentEnabled());
if (!HasAllFlags(heapFlags, allocationDescriptor.ExtraRequiredHeapFlags)) {
WarnLog(MessageId::kPerformanceWarning, this)
<< "RESOURCE_ALLOCATOR_FLAG_ALWAYS_COMMITTED was not requested but enabled anyway "
<< "RESOURCE_ALLOCATION_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 "
Expand Down
22 changes: 22 additions & 0 deletions src/tests/end2end/D3D12ResourceAllocatorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,28 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferImported) {
ASSERT_EQ(internalAllocation->GetResource(), internalAllocationAgain->GetResource());
}

TEST_F(D3D12ResourceAllocatorTests, CreateBufferExported) {
ComPtr<IResourceAllocator> resourceAllocator;
ASSERT_SUCCEEDED(CreateResourceAllocator(CreateBasicAllocatorDesc(), mDevice.Get(),
mAdapter.Get(), &resourceAllocator, nullptr));
ASSERT_NE(resourceAllocator, nullptr);

RESOURCE_ALLOCATION_DESC externalAllocationDesc = {};
externalAllocationDesc.Flags |= RESOURCE_ALLOCATION_FLAG_ALWAYS_COMMITTED;

ComPtr<IResourceAllocation> internalAllocation;
ASSERT_SUCCEEDED(resourceAllocator->CreateResource(
externalAllocationDesc, CreateBasicBufferDesc(kBufferOf4MBAllocationSize), {}, nullptr,
&internalAllocation));

ComPtr<ID3D12Resource> externalResource;
ASSERT_SUCCEEDED(internalAllocation.As(&externalResource));

internalAllocation = nullptr;
EXPECT_NE(externalResource, nullptr);
EXPECT_REFCOUNT_EQ(externalResource.Get(), 1);
}

TEST_F(D3D12ResourceAllocatorTests, CreateBufferInvalid) {
ComPtr<IResourceAllocator> resourceAllocator;
ASSERT_SUCCEEDED(CreateResourceAllocator(CreateBasicAllocatorDesc(), mDevice.Get(),
Expand Down