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
4 changes: 2 additions & 2 deletions src/gpgmm/common/DedicatedMemoryAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ namespace gpgmm {
GPGMM_TRY_ASSIGN(GetNextInChain()->TryAllocateMemory(request), allocation);

mInfo.UsedBlockCount++;
mInfo.UsedBlockUsage += request.SizeInBytes;
mInfo.UsedBlockUsage += allocation->GetSize();

return std::make_unique<MemoryAllocation>(
this, allocation->GetMemory(), /*offset*/ 0, allocation->GetMethod(),
new MemoryBlock{0, request.SizeInBytes}, request.SizeInBytes);
new MemoryBlock{0, allocation->GetSize()}, request.SizeInBytes);
}

void DedicatedMemoryAllocator::DeallocateMemory(std::unique_ptr<MemoryAllocation> allocation) {
Expand Down
9 changes: 6 additions & 3 deletions src/gpgmm/common/DedicatedMemoryAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@

#include "gpgmm/common/MemoryAllocator.h"

#include <memory>

namespace gpgmm {

// DedicatedMemoryAllocator sub-allocates memory with exactly one block.
// DedicatedMemoryAllocator allocates from device memory with exactly one block.
// DedicatedMemoryAllocator is useful in situations where whole memory objects could be reused
// without the need for sub-allocation. DedicatedMemoryAllocator also allows
// memory to be tracked.
class DedicatedMemoryAllocator final : public MemoryAllocator {
public:
DedicatedMemoryAllocator(std::unique_ptr<MemoryAllocator> memoryAllocator);
Expand All @@ -33,6 +34,8 @@ namespace gpgmm {
uint64_t GetMemoryAlignment() const override;

MemoryAllocatorInfo GetInfo() const override;

private:
const char* GetTypename() const override;
};

Expand Down
6 changes: 6 additions & 0 deletions src/gpgmm/d3d12/ResourceAllocatorD3D12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,9 @@ namespace gpgmm::d3d12 {
/*slabGrowthFactor*/ descriptor.MemoryGrowthFactor,
/*memoryAllocator*/ std::move(pooledOrNonPooledAllocator));
}
case ALLOCATOR_ALGORITHM_DEDICATED:
return std::make_unique<DedicatedMemoryAllocator>(
/*memoryAllocator*/ std::move(pooledOrNonPooledAllocator));
default: {
UNREACHABLE();
return {};
Expand Down Expand Up @@ -677,6 +680,9 @@ namespace gpgmm::d3d12 {
/*slabMemoryGrowth*/ 1,
/*memoryAllocator*/ std::move(pooledOrNonPooledAllocator));
}
case ALLOCATOR_ALGORITHM_DEDICATED:
return std::make_unique<DedicatedMemoryAllocator>(
/*memoryAllocator*/ std::move(pooledOrNonPooledAllocator));
default:
UNREACHABLE();
return {};
Expand Down
38 changes: 34 additions & 4 deletions src/gpgmm/d3d12/ResourceAllocatorD3D12.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,14 @@ namespace gpgmm::d3d12 {
*/
ALLOCATOR_FLAG_DISABLE_MEMORY_PREFETCH = 0x4,

/** \brief Tell GPGMM to allocate exactly what is needed, and to de-allocate
memory immediately once no longer needed (instead of re-using it).
/** \brief Disables recycling of GPU memory.

Forces the creation of new heaps and to de-allocate heaps immediately once no longer needed
(instead of re-using it).

This is very slow and not recommended for general use but may be useful for running with the
minimal possible GPU memory footprint or debugging OOM failures.
minimal possible GPU memory footprint, avoiding out-of-memory, or debugging possible
corruption of heaps.
*/
ALLOCATOR_FLAG_ALWAYS_ON_DEMAND = 0x8,

Expand All @@ -99,7 +102,20 @@ namespace gpgmm::d3d12 {
*/
enum ALLOCATOR_ALGORITHM {
/** \brief Use default allocation mechanism.
*/

Relies on internal heuristics to automatically determine the best allocation mechanism. The
selection of algorithm depends on:

1. The heap properties or flags specified by the user.
2. The size the resource being created.
3. The amount of available memory.

In general, the most-efficent resource allocator will be attempted first (efficent
being defined as fastest service-time to allocate/deallocate with smallest memory
footprint), subject to other constraints. However, since it's impossible to predict all
future memory accesses, allocation techniques that rely on amortization of GPU heaps may not
prove to be faster as expected. Further experimentation is recommended.
*/
ALLOCATOR_ALGORITHM_DEFAULT = 0,

/** \brief Use the slab allocation mechanism.
Expand Down Expand Up @@ -140,6 +156,20 @@ namespace gpgmm::d3d12 {
Segmented pool allocate/deallocates in O(Log2) time using O(N * K) space.
*/
ALLOCATOR_ALGORITHM_SEGMENTED_POOL = 4,

/** \brief Use the dedicated allocation mechanism.

Allows resources to be created as a dedicated allocation, rather than sub-allocated.

A dedicated allocation allocates exactly what is needed for the resource and nothing more.

Internally, dedicated allocations are "placed resources" which allows the heap to be
recycled by GPGMM. Otherwise, ALLOCATOR_FLAG_ALWAYS_COMMITED is equivelent to a "dedicated
allocation" but without heaps being recycled by GPGMM.

Dedicated allocation allocates/deallocates in O(1) time using O(N * pageSize) space.
*/
ALLOCATOR_ALGORITHM_DEDICATED = 5,
};

/** \struct ALLOCATOR_DESC
Expand Down
1 change: 1 addition & 0 deletions src/include/min/gpgmm_d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ namespace gpgmm::d3d12 {
ALLOCATOR_ALGORITHM_BUDDY_SYSTEM = 2,
ALLOCATOR_ALGORITHM_FIXED_POOL = 3,
ALLOCATOR_ALGORITHM_SEGMENTED_POOL = 4,
ALLOCATOR_ALGORITHM_DEDICATED = 5,
};

DEFINE_ENUM_FLAG_OPERATORS(ALLOCATOR_ALGORITHM)
Expand Down
21 changes: 20 additions & 1 deletion src/tests/end2end/D3D12ResourceAllocatorTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferOversized) {
ResourceAllocator::CreateAllocator(CreateBasicAllocatorDesc(), &resourceAllocator));
ASSERT_NE(resourceAllocator, nullptr);

constexpr uint64_t kOversizedBuffer = 32ll * 1024ll * 1024ll * 1024ll; // 32GB
constexpr uint64_t kOversizedBuffer = GPGMM_GB_TO_BYTES(32);
ComPtr<ResourceAllocation> allocation;
ASSERT_FAILED(resourceAllocator->CreateResource({}, CreateBasicBufferDesc(kOversizedBuffer + 1),
D3D12_RESOURCE_STATE_COMMON, nullptr,
Expand Down Expand Up @@ -232,6 +232,25 @@ TEST_F(D3D12ResourceAllocatorTests, CreateBufferSubAllocated) {
ALLOCATION_DESC allocationDesc = {};
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;

for (auto& alloc : GenerateBufferAllocations()) {
ComPtr<ResourceAllocation> allocation;
EXPECT_EQ(SUCCEEDED(resourceAllocator->CreateResource(
allocationDesc, CreateBasicBufferDesc(alloc.size, alloc.alignment),
D3D12_RESOURCE_STATE_COMMON, nullptr, &allocation)),
alloc.succeeds);
}
}
{
ALLOCATOR_DESC newAllocatorDesc = allocatorDesc;
newAllocatorDesc.SubAllocationAlgorithm = ALLOCATOR_ALGORITHM_DEDICATED;

ComPtr<ResourceAllocator> resourceAllocator;
ASSERT_SUCCEEDED(ResourceAllocator::CreateAllocator(newAllocatorDesc, &resourceAllocator));
ASSERT_NE(resourceAllocator, nullptr);

ALLOCATION_DESC allocationDesc = {};
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;

for (auto& alloc : GenerateBufferAllocations()) {
ComPtr<ResourceAllocation> allocation;
EXPECT_EQ(SUCCEEDED(resourceAllocator->CreateResource(
Expand Down