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
1 change: 0 additions & 1 deletion src/gpgmm/d3d12/JSONSerializerD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ namespace gpgmm::d3d12 {
dict.AddItem("MaxResourceHeapSize", desc.MaxResourceHeapSize);
dict.AddItem("MaxVideoMemoryBudget", desc.MaxVideoMemoryBudget);
dict.AddItem("Budget", desc.Budget);
dict.AddItem("EvictBatchSize", desc.EvictBatchSize);
dict.AddItem("MemoryFragmentationLimit", desc.MemoryFragmentationLimit);
return dict;
}
Expand Down
131 changes: 73 additions & 58 deletions src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,33 +295,65 @@ namespace gpgmm::d3d12 {
} // namespace

// static
HRESULT ResourceAllocator::CreateAllocator(const ALLOCATOR_DESC& descriptor,
ResourceAllocator** resourceAllocatorOut,
ResidencyManager** residencyManagerOut) {
if (descriptor.Adapter == nullptr || descriptor.Device == nullptr) {
HRESULT ResourceAllocator::CreateAllocator(const ALLOCATOR_DESC& allocatorDescriptor,
ResourceAllocator** ppResourceAllocatorOut,
ResidencyManager** ppResidencyManagerOut) {
ComPtr<ResidencyManager> residencyManager;
if (ppResidencyManagerOut != nullptr) {
RESIDENCY_DESC residencyDesc = {};
residencyDesc.Device = allocatorDescriptor.Device;
residencyDesc.IsUMA = allocatorDescriptor.IsUMA;
residencyDesc.VideoMemoryBudget = allocatorDescriptor.MaxVideoMemoryBudget;
residencyDesc.Budget = allocatorDescriptor.Budget;
ReturnIfFailed(allocatorDescriptor.Adapter.As(&residencyDesc.Adapter));

ReturnIfFailed(
ResidencyManager::CreateResidencyManager(residencyDesc, &residencyManager));
}

ComPtr<ResourceAllocator> resourceAllocator;
ReturnIfFailed(
CreateAllocator(allocatorDescriptor, residencyManager.Get(), &resourceAllocator));

if (ppResourceAllocatorOut != nullptr) {
*ppResourceAllocatorOut = resourceAllocator.Detach();
}

if (ppResidencyManagerOut != nullptr) {
*ppResidencyManagerOut = residencyManager.Detach();
}

return S_OK;
}

// static
HRESULT ResourceAllocator::CreateAllocator(const ALLOCATOR_DESC& allocatorDescriptor,
ResidencyManager* pResidencyManager,
ResourceAllocator** ppResourceAllocatorOut) {
if (allocatorDescriptor.Adapter == nullptr || allocatorDescriptor.Device == nullptr) {
return E_INVALIDARG;
}

std::unique_ptr<Caps> caps;
{
Caps* ptr = nullptr;
ReturnIfFailed(
Caps::CreateCaps(descriptor.Device.Get(), descriptor.Adapter.Get(), &ptr));
ReturnIfFailed(Caps::CreateCaps(allocatorDescriptor.Device.Get(),
allocatorDescriptor.Adapter.Get(), &ptr));
caps.reset(ptr);
}

ALLOCATOR_DESC newDescriptor = descriptor;
newDescriptor.MemoryGrowthFactor = (descriptor.MemoryGrowthFactor >= 1.0)
? descriptor.MemoryGrowthFactor
ALLOCATOR_DESC newDescriptor = allocatorDescriptor;
newDescriptor.MemoryGrowthFactor = (allocatorDescriptor.MemoryGrowthFactor >= 1.0)
? allocatorDescriptor.MemoryGrowthFactor
: kDefaultMemoryGrowthFactor;

newDescriptor.MaxResourceHeapSize =
(descriptor.MaxResourceHeapSize > 0)
? std::min(descriptor.MaxResourceHeapSize, caps->GetMaxResourceHeapSize())
(allocatorDescriptor.MaxResourceHeapSize > 0)
? std::min(allocatorDescriptor.MaxResourceHeapSize, caps->GetMaxResourceHeapSize())
: caps->GetMaxResourceHeapSize();

newDescriptor.MemoryFragmentationLimit = (descriptor.MemoryFragmentationLimit > 0)
? descriptor.MemoryFragmentationLimit
newDescriptor.MemoryFragmentationLimit = (allocatorDescriptor.MemoryFragmentationLimit > 0)
? allocatorDescriptor.MemoryFragmentationLimit
: kDefaultFragmentationLimit;

if (newDescriptor.PreferredResourceHeapSize > newDescriptor.MaxResourceHeapSize) {
Expand All @@ -330,9 +362,9 @@ namespace gpgmm::d3d12 {

if (newDescriptor.RecordOptions.Flags != ALLOCATOR_RECORD_FLAG_NONE) {
StartupEventTrace(
descriptor.RecordOptions.TraceFile,
allocatorDescriptor.RecordOptions.TraceFile,
static_cast<TraceEventPhase>(~newDescriptor.RecordOptions.Flags | 0),
descriptor.RecordOptions.EventScope & ALLOCATOR_RECORD_SCOPE_PER_PROCESS);
allocatorDescriptor.RecordOptions.EventScope & ALLOCATOR_RECORD_SCOPE_PER_PROCESS);

SetEventMessageLevel(GetLogSeverity(newDescriptor.RecordOptions.MinMessageLevel));
}
Expand All @@ -350,33 +382,15 @@ namespace gpgmm::d3d12 {
}
#endif

ComPtr<ResidencyManager> residencyManager;
if (residencyManagerOut != nullptr) {
RESIDENCY_DESC residencyDesc = {};
residencyDesc.Device = newDescriptor.Device;
residencyDesc.IsUMA = newDescriptor.IsUMA;
residencyDesc.VideoMemoryBudget = newDescriptor.MaxVideoMemoryBudget;
residencyDesc.Budget = newDescriptor.Budget;
residencyDesc.EvictBatchSize = newDescriptor.EvictBatchSize;
ReturnIfFailed(newDescriptor.Adapter.As(&residencyDesc.Adapter));

ReturnIfFailed(
ResidencyManager::CreateResidencyManager(residencyDesc, &residencyManager));
}

if (newDescriptor.Flags & ALLOCATOR_FLAG_ALWAYS_IN_BUDGET && !residencyManager) {
if (newDescriptor.Flags & ALLOCATOR_FLAG_ALWAYS_IN_BUDGET && !pResidencyManager) {
gpgmm::WarningLog() << "Residency must be specified and enabled to use "
"ALLOCATOR_FLAG_ALWAYS_IN_BUDGET.";
}

if (resourceAllocatorOut != nullptr) {
*resourceAllocatorOut =
new ResourceAllocator(newDescriptor, residencyManager, std::move(caps));
GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(*resourceAllocatorOut, newDescriptor);
}

if (residencyManagerOut != nullptr) {
*residencyManagerOut = residencyManager.Detach();
if (ppResourceAllocatorOut != nullptr) {
*ppResourceAllocatorOut =
new ResourceAllocator(newDescriptor, pResidencyManager, std::move(caps));
GPGMM_TRACE_EVENT_OBJECT_SNAPSHOT(*ppResourceAllocatorOut, newDescriptor);
}

return S_OK;
Expand Down Expand Up @@ -670,31 +684,31 @@ namespace gpgmm::d3d12 {
HRESULT ResourceAllocator::CreateResource(const ALLOCATION_DESC& allocationDescriptor,
const D3D12_RESOURCE_DESC& resourceDescriptor,
D3D12_RESOURCE_STATES initialResourceState,
const D3D12_CLEAR_VALUE* clearValue,
ResourceAllocation** resourceAllocationOut) {
if (!resourceAllocationOut) {
const D3D12_CLEAR_VALUE* pClearValue,
ResourceAllocation** ppResourceAllocationOut) {
if (!ppResourceAllocationOut) {
return E_POINTER;
}

GPGMM_TRACE_EVENT_OBJECT_CALL(
"ResourceAllocator.CreateResource",
(CREATE_RESOURCE_DESC{allocationDescriptor, resourceDescriptor, initialResourceState,
clearValue}));
pClearValue}));

std::lock_guard<std::mutex> lock(mMutex);
ReturnIfFailed(CreateResourceInternal(allocationDescriptor, resourceDescriptor,
initialResourceState, clearValue,
resourceAllocationOut));
initialResourceState, pClearValue,
ppResourceAllocationOut));

if (!allocationDescriptor.DebugName.empty()) {
(*resourceAllocationOut)->SetDebugName(allocationDescriptor.DebugName);
(*ppResourceAllocationOut)->SetDebugName(allocationDescriptor.DebugName);
}

// Insert a new (debug) allocator layer into the allocation so it can report details used
// during leak checks. Since we don't want to use it unless we are debugging, we hide it
// behind a macro.
#if defined(GPGMM_ENABLE_ALLOCATOR_CHECKS)
mDebugAllocator->AddLiveAllocation(*resourceAllocationOut);
mDebugAllocator->AddLiveAllocation(*ppResourceAllocationOut);
#endif

// Update the current usage counters.
Expand All @@ -705,11 +719,12 @@ namespace gpgmm::d3d12 {
return S_OK;
}

HRESULT ResourceAllocator::CreateResourceInternal(const ALLOCATION_DESC& allocationDescriptor,
const D3D12_RESOURCE_DESC& resourceDescriptor,
D3D12_RESOURCE_STATES initialResourceState,
const D3D12_CLEAR_VALUE* clearValue,
ResourceAllocation** resourceAllocationOut) {
HRESULT ResourceAllocator::CreateResourceInternal(
const ALLOCATION_DESC& allocationDescriptor,
const D3D12_RESOURCE_DESC& resourceDescriptor,
D3D12_RESOURCE_STATES initialResourceState,
const D3D12_CLEAR_VALUE* clearValue,
ResourceAllocation** ppResourceAllocationOut) {
TRACE_EVENT0(TraceEventCategory::Default, "ResourceAllocator.CreateResource");

// If d3d tells us the resource size is invalid, treat the error as OOM.
Expand Down Expand Up @@ -838,7 +853,7 @@ namespace gpgmm::d3d12 {
allocationDesc.OffsetFromResource = subAllocation.GetOffset();
allocationDesc.ResourceHeap = resourceHeap;

*resourceAllocationOut = new ResourceAllocation{
*ppResourceAllocationOut = new ResourceAllocation{
allocationDesc, mResidencyManager.Get(), subAllocation.GetAllocator(),
subAllocation.GetBlock(), std::move(committedResource)};

Expand Down Expand Up @@ -877,7 +892,7 @@ namespace gpgmm::d3d12 {
allocationDesc.OffsetFromResource = 0;
allocationDesc.ResourceHeap = resourceHeap;

*resourceAllocationOut = new ResourceAllocation{
*ppResourceAllocationOut = new ResourceAllocation{
allocationDesc, mResidencyManager.Get(), subAllocation.GetAllocator(),
subAllocation.GetBlock(), std::move(placedResource)};

Expand Down Expand Up @@ -916,7 +931,7 @@ namespace gpgmm::d3d12 {
allocationDesc.OffsetFromResource = 0;
allocationDesc.ResourceHeap = resourceHeap;

*resourceAllocationOut = new ResourceAllocation{
*ppResourceAllocationOut = new ResourceAllocation{
allocationDesc, mResidencyManager.Get(), allocation.GetAllocator(),
allocation.GetBlock(), std::move(placedResource)};

Expand Down Expand Up @@ -957,17 +972,17 @@ namespace gpgmm::d3d12 {
allocationDesc.OffsetFromResource = 0;
allocationDesc.ResourceHeap = resourceHeap;

*resourceAllocationOut = new ResourceAllocation{
*ppResourceAllocationOut = new ResourceAllocation{
allocationDesc, mResidencyManager.Get(), this, nullptr, std::move(committedResource)};

return S_OK;
}

HRESULT ResourceAllocator::CreateResource(ComPtr<ID3D12Resource> resource,
ResourceAllocation** resourceAllocationOut) {
ResourceAllocation** ppResourceAllocationOut) {
std::lock_guard<std::mutex> lock(mMutex);

if (!resourceAllocationOut) {
if (!ppResourceAllocationOut) {
return E_POINTER;
}

Expand Down Expand Up @@ -1005,7 +1020,7 @@ namespace gpgmm::d3d12 {
allocationDesc.OffsetFromResource = 0;
allocationDesc.ResourceHeap = resourceHeap;

*resourceAllocationOut =
*ppResourceAllocationOut =
new ResourceAllocation{allocationDesc, nullptr, this, nullptr, std::move(resource)};

return S_OK;
Expand Down
79 changes: 38 additions & 41 deletions src/gpgmm/d3d12/ResourceAllocatorD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,30 +318,6 @@ namespace gpgmm::d3d12 {
*/
uint64_t MaxResourceHeapSize;

/** \brief Maximum video memory available to budget by the allocator, expressed as a
percentage.

Optional parameter. When 0 is specified, the API will automatically set the max video
memory budget to 95%, leaving 5% for the OS and other applications.
*/
float MaxVideoMemoryBudget;

/** \brief Specify the budget, in bytes, for residency.

Allows a fixed budget to be artifically set for testing purposes.

Optional parameter. When 0 is specified, the API will not restrict the budget.
*/
uint64_t Budget;

/** \brief Specifies the amount of resource heaps, in bytes, to evict from residency at
once, should there not be enough budget left.

Optional parameter. When 0 is specified, the API will automatically set the video memory
evict size to 50MB.
*/
uint64_t EvictBatchSize;

/** \brief Memory fragmentation limit, expressed as a percentage of the resource heap size,
that is acceptable to be wasted due to fragmentation.

Expand Down Expand Up @@ -375,6 +351,13 @@ namespace gpgmm::d3d12 {
Optional parameter. When 0 is specified, the default of 1.25 is used (or 25% growth).
*/
double MemoryGrowthFactor;

/*
* \deprecated Access by creating a ResidencyManager directly, not through CreateAllocator.
Will be removed in a future version of GPGMM.
*/
float MaxVideoMemoryBudget;
uint64_t Budget;
};

/** \enum ALLOCATION_FLAGS
Expand Down Expand Up @@ -514,22 +497,36 @@ namespace gpgmm::d3d12 {
**/
class GPGMM_EXPORT ResourceAllocator final : public MemoryAllocator, public IUnknownImpl {
public:
/** \brief Create allocator and optional residency manager used to create and manage video
memory for the App specified device and adapter.
/** \brief Create allocator with residency.

Residency manager only exists if this adapter at-least supports DXGI 1.4.
Residency requires at-least DXGI version 1.4.

@param descriptor A reference to ALLOCATOR_DESC structure that describes the allocator.
@param[out] resourceAllocatorOut Pointer to a memory block that recieves a pointer to the
@param allocatorDescriptor A reference to ALLOCATOR_DESC structure that describes the
allocator.
@param[out] ppResourceAllocatorOut Pointer to a memory block that recieves a pointer to the
resource allocator. Pass NULL to test if allocator creation would succeed, but not actually
create the allocator.
@param[out] residencyManagerOut Pointer to a memory block that recieves a pointer to the
@param[out] ppResidencyManagerOut Pointer to a memory block that recieves a pointer to the
residency manager. If NULL is passed, the allocator will be created without using
residency for resources.
residency.
*/
static HRESULT CreateAllocator(const ALLOCATOR_DESC& allocatorDescriptor,
ResourceAllocator** ppResourceAllocatorOut,
ResidencyManager** ppResidencyManagerOut = nullptr);

/** \brief Create allocator using a specified residency manager.

@param allocatorDescriptor A reference to ALLOCATOR_DESC structure that describes the
allocator.
@param pResidencyManager Pointer to a memory block that recieves a pointer to the
residency manager.
@param[out] ppResourceAllocatorOut Pointer to a memory block that recieves a pointer to the
resource allocator. Pass NULL to test if allocator creation would succeed, but not actually
create the allocator.
*/
static HRESULT CreateAllocator(const ALLOCATOR_DESC& descriptor,
ResourceAllocator** resourceAllocatorOut,
ResidencyManager** residencyManagerOut = nullptr);
static HRESULT CreateAllocator(const ALLOCATOR_DESC& allocatorDescriptor,
ResidencyManager* pResidencyManager,
ResourceAllocator** ppResourceAllocatorOut);

~ResourceAllocator() override;

Expand All @@ -549,16 +546,16 @@ namespace gpgmm::d3d12 {
the resource.
@param initialResourceState The initial state of the resource, a bitwise OR'd combination of
D3D12_RESOURCE_STATES enumeration constants.
@param clearValue Specifies a D3D12_CLEAR_VALUE structure that describes the default value
@param pClearValue A pointer tp D3D12_CLEAR_VALUE structure that describes the default value
for a clear color.
@param[out] resourceAllocationOut An optional pointer to a memory block that recieves the
@param[out] ppResourceAllocationOut An optional pointer to a memory block that recieves the
required interface pointer to the created resource allocation object.
*/
HRESULT CreateResource(const ALLOCATION_DESC& allocationDescriptor,
const D3D12_RESOURCE_DESC& resourceDescriptor,
D3D12_RESOURCE_STATES initialResourceState,
const D3D12_CLEAR_VALUE* clearValue,
ResourceAllocation** resourceAllocationOut);
const D3D12_CLEAR_VALUE* pClearValue,
ResourceAllocation** ppResourceAllocationOut);

/** \brief Imports an existing D3D12 resource.

Expand All @@ -567,13 +564,13 @@ namespace gpgmm::d3d12 {
Residency is not supported for imported resources.

@param committedResource A COM managed pointer to a D3D12 committed resource.
@param[out] resourceAllocationOut Pointer to a memory block that recieves a pointer to the
@param[out] ppResourceAllocationOut Pointer to a memory block that recieves a pointer to the
resource allocation. Pass NULL to test if resource allocation creation would succeed, but
not actually create the resource allocation. If NULL is passed and resource allocation
creation would succeed, S_FALSE is returned.
*/
HRESULT CreateResource(ComPtr<ID3D12Resource> committedResource,
ResourceAllocation** resourceAllocationOut);
ResourceAllocation** ppResourceAllocationOut);

/** \brief Recycle resource heaps held internally by GPGMM.

Expand Down Expand Up @@ -632,7 +629,7 @@ namespace gpgmm::d3d12 {
const D3D12_RESOURCE_DESC& resourceDescriptor,
D3D12_RESOURCE_STATES initialResourceState,
const D3D12_CLEAR_VALUE* clearValue,
ResourceAllocation** resourceAllocationOut);
ResourceAllocation** ppResourceAllocationOut);

ResourceAllocator(const ALLOCATOR_DESC& descriptor,
ComPtr<ResidencyManager> residencyManager,
Expand Down
Loading