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
16 changes: 16 additions & 0 deletions include/gpgmm_d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,22 @@ namespace gpgmm::d3d12 {
void* pCreateHeapContext,
IResidencyHeap** ppResidencyHeapOut);

/** \brief Create a heap managed by GPGMM.

This version of CreateResidencyHeap is a simpler way to create residency heaps by disallowing
use of RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET by specifying the pageable instead.

@param descriptor A reference to RESIDENCY_HEAP_DESC structure that describes the heap.
@param pResidencyManager A pointer to the ResidencyManager used to manage this heap.
@param pPageable A pointer to the pageable object that represents the heap.
@param[out] ppResidencyHeapOut Pointer to a memory block that receives a pointer to the
heap.
*/
GPGMM_EXPORT HRESULT CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor,
IResidencyManager* const pResidencyManager,
ID3D12Pageable* pPageable,
IResidencyHeap** ppResidencyHeapOut);

/** \brief Represents a list of heaps which will be "made resident" upon executing a
command-list.

Expand Down
135 changes: 77 additions & 58 deletions src/gpgmm/d3d12/ResidencyHeapD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,73 +64,34 @@ namespace gpgmm::d3d12 {
pCreateHeapContext, ppResidencyHeapOut);
}

HRESULT CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor,
IResidencyManager* const pResidencyManager,
ID3D12Pageable* pPageable,
IResidencyHeap** ppResidencyHeapOut) {
return ResidencyHeap::CreateResidencyHeap(descriptor, pResidencyManager, pPageable,
ppResidencyHeapOut);
}

// static
HRESULT ResidencyHeap::CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor,
IResidencyManager* const pResidencyManager,
CreateHeapFn createHeapFn,
void* pCreateHeapContext,
ID3D12Pageable* pPageable,
IResidencyHeap** ppResidencyHeapOut) {
GPGMM_RETURN_IF_NULLPTR(pCreateHeapContext);

const bool isResidencyDisabled = (pResidencyManager == nullptr);

// Validate residency resource heap flags must also have a residency manager.
if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET) {
ErrorLog(MessageId::kInvalidArgument, true)
<< "Creating a heap always in budget requires a residency manager to exist.";
return E_INVALIDARG;
}
GPGMM_TRACE_EVENT_OBJECT_CALL("Heap.CreateResidencyHeap",
(CREATE_HEAP_DESC{descriptor, pPageable}));

if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_RESIDENT) {
ErrorLog(MessageId::kInvalidArgument, true)
<< "Creating a heap always residency requires a residency manager to exist.";
return E_INVALIDARG;
}
GPGMM_RETURN_IF_NULLPTR(pPageable);

ResidencyManager* residencyManager = static_cast<ResidencyManager*>(pResidencyManager);

// Ensure enough budget exists before creating the heap to avoid an out-of-memory error.
if (!isResidencyDisabled && (descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET)) {
uint64_t bytesEvicted = descriptor.SizeInBytes;
GPGMM_RETURN_IF_FAILED(
residencyManager->EvictInternal(descriptor.SizeInBytes, descriptor.HeapSegment,
&bytesEvicted),
residencyManager->mDevice);

if (bytesEvicted < descriptor.SizeInBytes) {
DXGI_QUERY_VIDEO_MEMORY_INFO currentVideoInfo = {};
if (SUCCEEDED(residencyManager->QueryVideoMemoryInfo(descriptor.HeapSegment,
&currentVideoInfo))) {
ErrorLog(MessageId::kBudgetExceeded, true)
<< "Unable to create heap because not enough budget exists ("
<< GPGMM_BYTES_TO_MB(descriptor.SizeInBytes) << " vs "
<< GPGMM_BYTES_TO_MB(
(currentVideoInfo.Budget > currentVideoInfo.CurrentUsage)
? currentVideoInfo.Budget - currentVideoInfo.CurrentUsage
: 0)
<< " MBs) and RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET was specified.";
}
return E_OUTOFMEMORY;
}
}

ComPtr<ID3D12Pageable> pageable;
GPGMM_RETURN_IF_FAILED(createHeapFn(pCreateHeapContext, &pageable),
GetDevice(pageable.Get()));

// Pageable-based type is required for residency-managed heaps.
GPGMM_RETURN_IF_NULLPTR(pageable);

GPGMM_TRACE_EVENT_OBJECT_CALL("Heap.CreateResidencyHeap",
(CREATE_HEAP_DESC{descriptor, pageable.Get()}));
const bool isResidencyDisabled = (pResidencyManager == nullptr);

std::unique_ptr<ResidencyHeap> heap(
new ResidencyHeap(pageable, descriptor, isResidencyDisabled));
new ResidencyHeap(pPageable, descriptor, isResidencyDisabled));

if (!isResidencyDisabled) {
// Check if the underlying memory was implicitly made resident.
D3D12_HEAP_FLAGS resourceHeapFlags = D3D12_HEAP_FLAG_NONE;
if (SUCCEEDED(GetResourceHeapFlags(pageable, &resourceHeapFlags))) {
if (SUCCEEDED(GetResourceHeapFlags(pPageable, &resourceHeapFlags))) {
// Resource heaps created without the "create not resident" flag are always
// resident.
if (!(resourceHeapFlags & D3D12_HEAP_FLAG_CREATE_NOT_RESIDENT)) {
Expand All @@ -155,13 +116,13 @@ namespace gpgmm::d3d12 {
// residency cache.
if (heap->GetInfo().Status != RESIDENCY_HEAP_STATUS_UNKNOWN) {
GPGMM_RETURN_IF_FAILED(residencyManager->InsertHeap(heap.get()),
GetDevice(pageable.Get()));
GetDevice(pPageable));
} else {
if (descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_RESIDENT) {
GPGMM_RETURN_IF_FAILED(residencyManager->LockHeap(heap.get()),
GetDevice(pageable.Get()));
GetDevice(pPageable));
GPGMM_RETURN_IF_FAILED(residencyManager->UnlockHeap(heap.get()),
GetDevice(pageable.Get()));
GetDevice(pPageable));
ASSERT(heap->GetInfo().Status == RESIDENCY_HEAP_STATUS_CURRENT);
}
}
Expand All @@ -173,7 +134,7 @@ namespace gpgmm::d3d12 {
}
}

GPGMM_RETURN_IF_FAILED(heap->SetDebugName(descriptor.DebugName), GetDevice(pageable.Get()));
GPGMM_RETURN_IF_FAILED(heap->SetDebugName(descriptor.DebugName), GetDevice(pPageable));
GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(heap.get(), descriptor);

DebugLog(heap.get(), MessageId::kObjectCreated)
Expand All @@ -187,6 +148,64 @@ namespace gpgmm::d3d12 {
return S_OK;
}

// static
HRESULT ResidencyHeap::CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor,
IResidencyManager* const pResidencyManager,
CreateHeapFn createHeapFn,
void* pCreateHeapContext,
IResidencyHeap** ppResidencyHeapOut) {
GPGMM_RETURN_IF_NULLPTR(pCreateHeapContext);

const bool isResidencyDisabled = (pResidencyManager == nullptr);

// Validate residency resource heap flags must also have a residency manager.
if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET) {
ErrorLog(MessageId::kInvalidArgument, true)
<< "Creating a heap always in budget requires a residency manager to exist.";
return E_INVALIDARG;
}

if (isResidencyDisabled && descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_RESIDENT) {
ErrorLog(MessageId::kInvalidArgument, true)
<< "Creating a heap always residency requires a residency manager to exist.";
return E_INVALIDARG;
}

ResidencyManager* residencyManager = static_cast<ResidencyManager*>(pResidencyManager);

// Ensure enough budget exists before creating the heap to avoid an out-of-memory error.
if (!isResidencyDisabled && (descriptor.Flags & RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET)) {
uint64_t bytesEvicted = descriptor.SizeInBytes;
GPGMM_RETURN_IF_FAILED(
residencyManager->EvictInternal(descriptor.SizeInBytes, descriptor.HeapSegment,
&bytesEvicted),
residencyManager->mDevice);

if (bytesEvicted < descriptor.SizeInBytes) {
DXGI_QUERY_VIDEO_MEMORY_INFO currentVideoInfo = {};
if (SUCCEEDED(residencyManager->QueryVideoMemoryInfo(descriptor.HeapSegment,
&currentVideoInfo))) {
ErrorLog(MessageId::kBudgetExceeded, true)
<< "Unable to create heap because not enough budget exists ("
<< GPGMM_BYTES_TO_MB(descriptor.SizeInBytes) << " vs "
<< GPGMM_BYTES_TO_MB(
(currentVideoInfo.Budget > currentVideoInfo.CurrentUsage)
? currentVideoInfo.Budget - currentVideoInfo.CurrentUsage
: 0)
<< " MBs) and RESIDENCY_HEAP_FLAG_ALWAYS_IN_BUDGET was specified.";
}
return E_OUTOFMEMORY;
}
}

ComPtr<ID3D12Pageable> pageable;
GPGMM_RETURN_IF_FAILED(createHeapFn(pCreateHeapContext, &pageable),
GetDevice(pageable.Get()));

return CreateResidencyHeap(descriptor, pResidencyManager, pageable.Get(),
ppResidencyHeapOut);
}

ResidencyHeap::ResidencyHeap(ComPtr<ID3D12Pageable> pageable,
const RESIDENCY_HEAP_DESC& descriptor,
bool isResidencyDisabled)
Expand Down
5 changes: 5 additions & 0 deletions src/gpgmm/d3d12/ResidencyHeapD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ namespace gpgmm::d3d12 {
void* pCreateHeapContext,
IResidencyHeap** ppResidencyHeapOut);

static HRESULT CreateResidencyHeap(const RESIDENCY_HEAP_DESC& descriptor,
IResidencyManager* const pResidencyManager,
ID3D12Pageable* pPageable,
IResidencyHeap** ppResidencyHeapOut);

~ResidencyHeap() override;

// IResidencyHeap interface
Expand Down
7 changes: 7 additions & 0 deletions src/tests/end2end/D3D12ResidencyManagerTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ TEST_F(D3D12ResidencyManagerTests, CreateResourceHeap) {
CreateResourceHeapCallbackContext::CreateHeap,
&createHeapContext, nullptr));

// Create a resource heap by importing the heap.
{
ComPtr<ID3D12Pageable> pageable;
CreateResourceHeapCallbackContext::CreateHeap(&createHeapContext, &pageable);
ASSERT_SUCCEEDED(CreateResidencyHeap(resourceHeapDesc, nullptr, pageable.Get(), nullptr));
}

// Create a resource heap without residency.
ComPtr<IResidencyHeap> resourceHeap;
ASSERT_SUCCEEDED(CreateResidencyHeap(resourceHeapDesc, nullptr,
Expand Down