Preliminary changes to Vulkan memory suballocation

This mostly makes the MemoryAllocator not owned by the
BuddyResourceAllocator so that we don't need an extra class for the
dependency injection in the Vulkan backend. (the container for the
BuddyMemoryAllocator can be it's MemoryAllocator at the same time).

Also renames methods of MemoryAllocator to be more explicit.

Also renames the constructor parameter of BuddyMemoryAllocator to be
(subjectively) closer to what the represent.

BUG=dawn:27

Change-Id: I37355ad5b3cded143956f0adc4742fa1b717e9bc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/12661
Reviewed-by: Bryan Bernhart <bryan.bernhart@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2019-10-24 21:28:16 +00:00 committed by Commit Bot service account
parent 60a04dd18c
commit ca35435716
11 changed files with 77 additions and 62 deletions

View File

@ -197,7 +197,6 @@ source_set("libdawn_native_sources") {
"src/dawn_native/Forward.h",
"src/dawn_native/Instance.cpp",
"src/dawn_native/Instance.h",
"src/dawn_native/MemoryAllocator.h",
"src/dawn_native/ObjectBase.cpp",
"src/dawn_native/ObjectBase.h",
"src/dawn_native/PassResourceUsage.h",
@ -226,6 +225,7 @@ source_set("libdawn_native_sources") {
"src/dawn_native/RenderPipeline.cpp",
"src/dawn_native/RenderPipeline.h",
"src/dawn_native/ResourceHeap.h",
"src/dawn_native/ResourceHeapAllocator.h",
"src/dawn_native/ResourceMemoryAllocation.cpp",
"src/dawn_native/ResourceMemoryAllocation.h",
"src/dawn_native/RingBufferAllocator.cpp",

View File

@ -11,26 +11,30 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/BuddyMemoryAllocator.h"
#include "common/Math.h"
#include "dawn_native/ResourceHeapAllocator.h"
namespace dawn_native {
BuddyMemoryAllocator::BuddyMemoryAllocator(uint64_t maxBlockSize,
uint64_t memorySize,
std::unique_ptr<MemoryAllocator> client)
: mMemorySize(memorySize), mBuddyBlockAllocator(maxBlockSize), mClient(std::move(client)) {
ASSERT(memorySize <= maxBlockSize);
ASSERT(IsPowerOfTwo(mMemorySize));
ASSERT(maxBlockSize % mMemorySize == 0);
BuddyMemoryAllocator::BuddyMemoryAllocator(uint64_t maxSystemSize,
uint64_t memoryBlockSize,
ResourceHeapAllocator* heapAllocator)
: mMemoryBlockSize(memoryBlockSize),
mBuddyBlockAllocator(maxSystemSize),
mHeapAllocator(heapAllocator) {
ASSERT(memoryBlockSize <= maxSystemSize);
ASSERT(IsPowerOfTwo(mMemoryBlockSize));
ASSERT(maxSystemSize % mMemoryBlockSize == 0);
mTrackedSubAllocations.resize(maxBlockSize / mMemorySize);
mTrackedSubAllocations.resize(maxSystemSize / mMemoryBlockSize);
}
uint64_t BuddyMemoryAllocator::GetMemoryIndex(uint64_t offset) const {
ASSERT(offset != BuddyAllocator::kInvalidOffset);
return offset / mMemorySize;
return offset / mMemoryBlockSize;
}
ResultOrError<ResourceMemoryAllocation> BuddyMemoryAllocator::Allocate(uint64_t allocationSize,
@ -45,7 +49,7 @@ namespace dawn_native {
allocationSize = NextPowerOfTwo(allocationSize);
// Allocation cannot exceed the memory size.
if (allocationSize > mMemorySize) {
if (allocationSize > mMemoryBlockSize) {
return invalidAllocation;
}
@ -59,7 +63,7 @@ namespace dawn_native {
if (mTrackedSubAllocations[memoryIndex].refcount == 0) {
// Transfer ownership to this allocator
std::unique_ptr<ResourceHeapBase> memory;
DAWN_TRY_ASSIGN(memory, mClient->Allocate(mMemorySize));
DAWN_TRY_ASSIGN(memory, mHeapAllocator->AllocateResourceHeap(mMemoryBlockSize));
mTrackedSubAllocations[memoryIndex] = {/*refcount*/ 0, std::move(memory)};
}
@ -70,11 +74,11 @@ namespace dawn_native {
info.mMethod = AllocationMethod::kSubAllocated;
// Allocation offset is always local to the memory.
const uint64_t memoryOffset = blockOffset % mMemorySize;
const uint64_t memoryOffset = blockOffset % mMemoryBlockSize;
return ResourceMemoryAllocation{
info, memoryOffset, mTrackedSubAllocations[memoryIndex].mMemoryAllocation.get()};
} // namespace dawn_native
}
void BuddyMemoryAllocator::Deallocate(const ResourceMemoryAllocation& allocation) {
const AllocationInfo info = allocation.GetInfo();
@ -84,18 +88,18 @@ namespace dawn_native {
const uint64_t memoryIndex = GetMemoryIndex(info.mBlockOffset);
ASSERT(mTrackedSubAllocations[memoryIndex].refcount > 0);
mTrackedSubAllocations[memoryIndex].refcount--;
if (mTrackedSubAllocations[memoryIndex].refcount == 0) {
mClient->Deallocate(std::move(mTrackedSubAllocations[memoryIndex].mMemoryAllocation));
mHeapAllocator->DeallocateResourceHeap(
std::move(mTrackedSubAllocations[memoryIndex].mMemoryAllocation));
}
mBuddyBlockAllocator.Deallocate(info.mBlockOffset);
}
uint64_t BuddyMemoryAllocator::GetMemorySize() const {
return mMemorySize;
uint64_t BuddyMemoryAllocator::GetMemoryBlockSize() const {
return mMemoryBlockSize;
}
uint64_t BuddyMemoryAllocator::ComputeTotalNumOfHeapsForTesting() const {
@ -107,4 +111,5 @@ namespace dawn_native {
}
return count;
}
} // namespace dawn_native
} // namespace dawn_native

View File

@ -15,13 +15,16 @@
#ifndef DAWNNATIVE_BUDDYMEMORYALLOCATOR_H_
#define DAWNNATIVE_BUDDYMEMORYALLOCATOR_H_
#include <vector>
#include "dawn_native/BuddyAllocator.h"
#include "dawn_native/MemoryAllocator.h"
#include "dawn_native/Error.h"
#include "dawn_native/ResourceMemoryAllocation.h"
#include <vector>
namespace dawn_native {
class ResourceHeapAllocator;
// BuddyMemoryAllocator uses the buddy allocator to sub-allocate blocks of device
// memory created by MemoryAllocator clients. It creates a very large buddy system
// where backing device memory blocks equal a specified level in the system.
@ -31,23 +34,20 @@ namespace dawn_native {
// same memory index, the memory refcount is incremented to ensure de-allocating one doesn't
// release the other prematurely.
//
// The device will only create up to Log2(kMaxResourceSize) allocators and can prefer speed
// over memory footprint by selecting an allocator with a higher memory threshold which results
// in pre-allocating more memory.
//
// The resource allocation is guaranteed by the device to have compatible memory flags.
// The MemoryAllocator should return ResourceHeaps that are all compatible with each other.
// It should also outlive all the resources that are in the buddy allocator.
class BuddyMemoryAllocator {
public:
BuddyMemoryAllocator(uint64_t maxBlockSize,
uint64_t memorySize,
std::unique_ptr<MemoryAllocator> client);
BuddyMemoryAllocator(uint64_t maxSystemSize,
uint64_t memoryBlockSize,
ResourceHeapAllocator* heapAllocator);
~BuddyMemoryAllocator() = default;
ResultOrError<ResourceMemoryAllocation> Allocate(uint64_t allocationSize,
uint64_t alignment);
void Deallocate(const ResourceMemoryAllocation& allocation);
uint64_t GetMemorySize() const;
uint64_t GetMemoryBlockSize() const;
// For testing purposes.
uint64_t ComputeTotalNumOfHeapsForTesting() const;
@ -55,10 +55,10 @@ namespace dawn_native {
private:
uint64_t GetMemoryIndex(uint64_t offset) const;
uint64_t mMemorySize = 0;
uint64_t mMemoryBlockSize = 0;
BuddyAllocator mBuddyBlockAllocator;
std::unique_ptr<MemoryAllocator> mClient;
ResourceHeapAllocator* mHeapAllocator;
struct TrackedSubAllocations {
size_t refcount = 0;
@ -67,6 +67,7 @@ namespace dawn_native {
std::vector<TrackedSubAllocations> mTrackedSubAllocations;
};
} // namespace dawn_native
#endif // DAWNNATIVE_BUDDYMEMORYALLOCATOR_H_

View File

@ -12,21 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_MEMORYALLOCATOR_H_
#define DAWNNATIVE_MEMORYALLOCATOR_H_
#ifndef DAWNNATIVE_RESOURCEHEAPALLOCATOR_H_
#define DAWNNATIVE_RESOURCEHEAPALLOCATOR_H_
#include "dawn_native/Error.h"
#include "dawn_native/ResourceHeap.h"
namespace dawn_native {
// Interface for backend allocators that create physical device memory.
class MemoryAllocator {
public:
virtual ~MemoryAllocator() = default;
virtual ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size) = 0;
virtual void Deallocate(std::unique_ptr<ResourceHeapBase> allocation) = 0;
// Interface for backend allocators that create memory heaps resoruces can be suballocated in.
class ResourceHeapAllocator {
public:
virtual ~ResourceHeapAllocator() = default;
virtual ResultOrError<std::unique_ptr<ResourceHeapBase>> AllocateResourceHeap(
uint64_t size) = 0;
virtual void DeallocateResourceHeap(std::unique_ptr<ResourceHeapBase> allocation) = 0;
};
} // namespace dawn_native
#endif // DAWNNATIVE_MEMORYALLOCATOR_H_
#endif // DAWNNATIVE_RESOURCEHEAPALLOCATOR_H_

View File

@ -71,4 +71,4 @@ namespace dawn_native {
};
} // namespace dawn_native
#endif // DAWNNATIVE_RESOURCEMEMORYALLOCATION_H_
#endif // DAWNNATIVE_RESOURCEMEMORYALLOCATION_H_

View File

@ -24,7 +24,8 @@ namespace dawn_native { namespace d3d12 {
: mDevice(device), mHeapType(heapType), mHeapFlags(heapFlags) {
}
ResultOrError<std::unique_ptr<ResourceHeapBase>> HeapAllocator::Allocate(uint64_t size) {
ResultOrError<std::unique_ptr<ResourceHeapBase>> HeapAllocator::AllocateResourceHeap(
uint64_t size) {
D3D12_HEAP_DESC heapDesc;
heapDesc.SizeInBytes = size;
heapDesc.Properties.Type = mHeapType;
@ -47,8 +48,8 @@ namespace dawn_native { namespace d3d12 {
return {std::make_unique<Heap>(std::move(heap))};
}
void HeapAllocator::Deallocate(std::unique_ptr<ResourceHeapBase> heap) {
void HeapAllocator::DeallocateResourceHeap(std::unique_ptr<ResourceHeapBase> heap) {
mDevice->ReferenceUntilUnused(static_cast<Heap*>(heap.get())->GetD3D12Heap());
}
}} // namespace dawn_native::d3d12
}} // namespace dawn_native::d3d12

View File

@ -15,7 +15,7 @@
#ifndef DAWNNATIVE_D3D12_HEAPALLOCATORD3D12_H_
#define DAWNNATIVE_D3D12_HEAPALLOCATORD3D12_H_
#include "dawn_native/MemoryAllocator.h"
#include "dawn_native/ResourceHeapAllocator.h"
#include "dawn_native/d3d12/d3d12_platform.h"
namespace dawn_native { namespace d3d12 {
@ -23,13 +23,14 @@ namespace dawn_native { namespace d3d12 {
class Device;
// Wrapper to allocate a D3D12 heap.
class HeapAllocator : public MemoryAllocator {
class HeapAllocator : public ResourceHeapAllocator {
public:
HeapAllocator(Device* device, D3D12_HEAP_TYPE heapType, D3D12_HEAP_FLAGS heapFlags);
~HeapAllocator() override = default;
ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size) override;
void Deallocate(std::unique_ptr<ResourceHeapBase> allocation) override;
ResultOrError<std::unique_ptr<ResourceHeapBase>> AllocateResourceHeap(
uint64_t size) override;
void DeallocateResourceHeap(std::unique_ptr<ResourceHeapBase> allocation) override;
private:
Device* mDevice;
@ -39,4 +40,4 @@ namespace dawn_native { namespace d3d12 {
}} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_D3D12_HEAPALLOCATORD3D12_H_
#endif // DAWNNATIVE_D3D12_HEAPALLOCATORD3D12_H_

View File

@ -91,10 +91,10 @@ namespace dawn_native { namespace d3d12 {
ResourceAllocatorManager::ResourceAllocatorManager(Device* device) : mDevice(device) {
for (uint32_t i = 0; i < ResourceHeapKind::EnumCount; i++) {
const ResourceHeapKind resourceHeapKind = static_cast<ResourceHeapKind>(i);
mHeapAllocators[i] = std::make_unique<HeapAllocator>(
mDevice, GetD3D12HeapType(resourceHeapKind), GetD3D12HeapFlags(resourceHeapKind));
mSubAllocatedResourceAllocators[i] = std::make_unique<BuddyMemoryAllocator>(
kMaxHeapSize, kMinHeapSize,
std::make_unique<HeapAllocator>(mDevice, GetD3D12HeapType(resourceHeapKind),
GetD3D12HeapFlags(resourceHeapKind)));
kMaxHeapSize, kMinHeapSize, mHeapAllocators[i].get());
}
}

View File

@ -16,8 +16,8 @@
#define DAWNNATIVE_D3D12_RESOURCEALLOCATORMANAGERD3D12_H_
#include "common/SerialQueue.h"
#include "dawn_native/BuddyMemoryAllocator.h"
#include "dawn_native/d3d12/HeapAllocatorD3D12.h"
#include "dawn_native/d3d12/ResourceHeapAllocationD3D12.h"
#include <array>
@ -76,10 +76,11 @@ namespace dawn_native { namespace d3d12 {
std::array<std::unique_ptr<BuddyMemoryAllocator>, ResourceHeapKind::EnumCount>
mSubAllocatedResourceAllocators;
std::array<std::unique_ptr<HeapAllocator>, ResourceHeapKind::EnumCount> mHeapAllocators;
SerialQueue<ResourceHeapAllocation> mAllocationsToDelete;
};
}} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_D3D12_RESOURCEALLOCATORMANAGERD3D12_H_
#endif // DAWNNATIVE_D3D12_RESOURCEALLOCATORMANAGERD3D12_H_

View File

@ -34,6 +34,7 @@ namespace dawn_native { namespace d3d12 {
private:
ComPtr<ID3D12Resource> mResource;
};
}} // namespace dawn_native::d3d12
#endif // DAWNNATIVE_D3D12_RESOURCEHEAPALLOCATIOND3D12_H_
#endif // DAWNNATIVE_D3D12_RESOURCEHEAPALLOCATIOND3D12_H_

View File

@ -15,22 +15,23 @@
#include <gtest/gtest.h>
#include "dawn_native/BuddyMemoryAllocator.h"
#include "dawn_native/ResourceHeapAllocator.h"
using namespace dawn_native;
class DummyMemoryAllocator : public MemoryAllocator {
class DummyResourceHeapAllocator : public ResourceHeapAllocator {
public:
ResultOrError<std::unique_ptr<ResourceHeapBase>> Allocate(uint64_t size) override {
ResultOrError<std::unique_ptr<ResourceHeapBase>> AllocateResourceHeap(uint64_t size) override {
return std::make_unique<ResourceHeapBase>();
}
void Deallocate(std::unique_ptr<ResourceHeapBase> allocation) override {
void DeallocateResourceHeap(std::unique_ptr<ResourceHeapBase> allocation) override {
}
};
class DummyBuddyResourceAllocator {
public:
DummyBuddyResourceAllocator(uint64_t maxBlockSize, uint64_t memorySize)
: mAllocator(maxBlockSize, memorySize, std::make_unique<DummyMemoryAllocator>()) {
: mAllocator(maxBlockSize, memorySize, &mHeapAllocator) {
}
ResourceMemoryAllocation Allocate(uint64_t allocationSize, uint64_t alignment = 1) {
@ -48,6 +49,7 @@ class DummyBuddyResourceAllocator {
}
private:
DummyResourceHeapAllocator mHeapAllocator;
BuddyMemoryAllocator mAllocator;
};
@ -342,4 +344,4 @@ TEST(BuddyMemoryAllocatorTests, VariousSizeSameAlignment) {
ASSERT_EQ(allocation4.GetInfo().mMethod, AllocationMethod::kSubAllocated);
ASSERT_EQ(allocator.ComputeTotalNumOfHeapsForTesting(), 3u);
}
}