Reland "D3D12: Stage BindGroups on CPU descriptor heaps."

This reverts commit c7f454c241
and relands commit 2479860e4b.

> D3D12: Stage BindGroups on CPU descriptor heaps.
>
> Instead of directly populating GPU heaps, pre-encoded
> BindGroups are staged on CPU heaps then copied over
> to the GPU. Non-shader visible allocators are stored
> on the BGL, which hands out fixed-size chunks to
> simplify memory managment. To enable memory re-use,
> CPU allocations are tied to the lifetime of BindGroup
> objects.

Reason for revert: We can reland this CL now that the CTS suppression merged.

Note: Adds validation to ensure binding size > 0.

Bug: dawn:155
Bug: dawn:375
Change-Id: I75b9773bbb7c70bcea803a7ad8b6480d21ea90f7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/18904
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Bryan Bernhart
2020-04-06 22:07:42 +00:00
committed by Commit Bot service account
parent c64242d4c2
commit cb859a2037
16 changed files with 694 additions and 82 deletions

View File

@@ -82,7 +82,7 @@ TEST(Math, AlignPtr) {
ASSERT_GE(aligned - unaligned, 0);
ASSERT_LT(static_cast<size_t>(aligned - unaligned), kTestAlignment);
ASSERT_EQ(reinterpret_cast<uintptr_t>(aligned) & (kTestAlignment -1), 0u);
ASSERT_EQ(reinterpret_cast<uintptr_t>(aligned) & (kTestAlignment - 1), 0u);
}
}
@@ -191,3 +191,21 @@ TEST(Math, SRGBToLinear) {
ASSERT_FLOAT_EQ(SRGBToLinear(0.5f), 0.21404114f);
}
// Tests for RoundUp
TEST(Math, RoundUp) {
ASSERT_EQ(RoundUp(2, 2), 2u);
ASSERT_EQ(RoundUp(2, 4), 4u);
ASSERT_EQ(RoundUp(6, 2), 6u);
ASSERT_EQ(RoundUp(8, 4), 8u);
ASSERT_EQ(RoundUp(12, 6), 12u);
ASSERT_EQ(RoundUp(3, 3), 3u);
ASSERT_EQ(RoundUp(3, 5), 5u);
ASSERT_EQ(RoundUp(5, 3), 6u);
ASSERT_EQ(RoundUp(9, 5), 10u);
// Test extrema
ASSERT_EQ(RoundUp(0x7FFFFFFFFFFFFFFFull, 0x8000000000000000ull), 0x8000000000000000ull);
ASSERT_EQ(RoundUp(1, 1), 1u);
}

View File

@@ -240,7 +240,7 @@ TEST_F(BindGroupValidationTest, BufferBindingType) {
binding.textureView = nullptr;
binding.buffer = nullptr;
binding.offset = 0;
binding.size = 0;
binding.size = 1024;
wgpu::BindGroupDescriptor descriptor;
descriptor.layout = layout;
@@ -421,7 +421,9 @@ TEST_F(BindGroupValidationTest, BufferBindingOOB) {
// Success case, touching the end of the buffer works
utils::MakeBindGroup(device, layout, {{0, buffer, 3*256, 256}});
utils::MakeBindGroup(device, layout, {{0, buffer, 1024, 0}});
// Error case, zero size is invalid.
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 1024, 0}}));
// Success case, touching the full buffer works
utils::MakeBindGroup(device, layout, {{0, buffer, 0, 1024}});

View File

@@ -15,7 +15,9 @@
#include "tests/DawnTest.h"
#include "dawn_native/Toggles.h"
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/NonShaderVisibleDescriptorAllocatorD3D12.h"
#include "dawn_native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/WGPUHelpers.h"
@@ -93,6 +95,31 @@ class D3D12DescriptorHeapTests : public DawnTest {
wgpu::ShaderModule mSimpleFSModule;
};
class DummyNonShaderVisibleDescriptorAllocator {
public:
DummyNonShaderVisibleDescriptorAllocator(Device* device,
uint32_t descriptorCount,
uint32_t allocationsPerHeap)
: mAllocator(device,
descriptorCount,
allocationsPerHeap * descriptorCount,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {
}
CPUDescriptorHeapAllocation AllocateCPUDescriptors() {
dawn_native::ResultOrError<CPUDescriptorHeapAllocation> result =
mAllocator.AllocateCPUDescriptors();
return (result.IsSuccess()) ? result.AcquireSuccess() : CPUDescriptorHeapAllocation{};
}
void Deallocate(CPUDescriptorHeapAllocation& allocation) {
mAllocator.Deallocate(&allocation);
}
private:
NonShaderVisibleDescriptorAllocator mAllocator;
};
// Verify the shader visible heaps switch over within a single submit.
TEST_P(D3D12DescriptorHeapTests, SwitchOverHeaps) {
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device);
@@ -688,6 +715,157 @@ TEST_P(D3D12DescriptorHeapTests, EncodeManyUBOAndSamplers) {
}
}
// Verify a single allocate/deallocate.
// One non-shader visible heap will be created.
TEST_P(D3D12DescriptorHeapTests, Single) {
constexpr uint32_t kDescriptorCount = 4;
constexpr uint32_t kAllocationsPerHeap = 3;
DummyNonShaderVisibleDescriptorAllocator allocator(mD3DDevice, kDescriptorCount,
kAllocationsPerHeap);
CPUDescriptorHeapAllocation allocation = allocator.AllocateCPUDescriptors();
EXPECT_EQ(allocation.GetHeapIndex(), 0u);
EXPECT_NE(allocation.OffsetFrom(0, 0).ptr, 0u);
allocator.Deallocate(allocation);
EXPECT_FALSE(allocation.IsValid());
}
// Verify allocating many times causes the pool to increase in size.
// Creates |kNumOfHeaps| non-shader visible heaps.
TEST_P(D3D12DescriptorHeapTests, Sequential) {
constexpr uint32_t kDescriptorCount = 4;
constexpr uint32_t kAllocationsPerHeap = 3;
DummyNonShaderVisibleDescriptorAllocator allocator(mD3DDevice, kDescriptorCount,
kAllocationsPerHeap);
// Allocate |kNumOfHeaps| worth.
constexpr uint32_t kNumOfHeaps = 2;
std::set<uint32_t> allocatedHeaps;
std::vector<CPUDescriptorHeapAllocation> allocations;
for (uint32_t i = 0; i < kAllocationsPerHeap * kNumOfHeaps; i++) {
CPUDescriptorHeapAllocation allocation = allocator.AllocateCPUDescriptors();
EXPECT_EQ(allocation.GetHeapIndex(), i / kAllocationsPerHeap);
EXPECT_NE(allocation.OffsetFrom(0, 0).ptr, 0u);
allocations.push_back(allocation);
allocatedHeaps.insert(allocation.GetHeapIndex());
}
EXPECT_EQ(allocatedHeaps.size(), kNumOfHeaps);
// Deallocate all.
for (CPUDescriptorHeapAllocation& allocation : allocations) {
allocator.Deallocate(allocation);
EXPECT_FALSE(allocation.IsValid());
}
}
// Verify that re-allocating a number of allocations < pool size, all heaps are reused.
// Creates and reuses |kNumofHeaps| non-shader visible heaps.
TEST_P(D3D12DescriptorHeapTests, ReuseFreedHeaps) {
constexpr uint32_t kDescriptorCount = 4;
constexpr uint32_t kAllocationsPerHeap = 25;
DummyNonShaderVisibleDescriptorAllocator allocator(mD3DDevice, kDescriptorCount,
kAllocationsPerHeap);
constexpr uint32_t kNumofHeaps = 10;
std::list<CPUDescriptorHeapAllocation> allocations;
std::set<size_t> allocationPtrs;
// Allocate |kNumofHeaps| heaps worth.
for (uint32_t i = 0; i < kAllocationsPerHeap * kNumofHeaps; i++) {
CPUDescriptorHeapAllocation allocation = allocator.AllocateCPUDescriptors();
allocations.push_back(allocation);
EXPECT_TRUE(allocationPtrs.insert(allocation.OffsetFrom(0, 0).ptr).second);
}
// Deallocate all.
for (CPUDescriptorHeapAllocation& allocation : allocations) {
allocator.Deallocate(allocation);
EXPECT_FALSE(allocation.IsValid());
}
allocations.clear();
// Re-allocate all again.
std::set<size_t> reallocatedPtrs;
for (uint32_t i = 0; i < kAllocationsPerHeap * kNumofHeaps; i++) {
CPUDescriptorHeapAllocation allocation = allocator.AllocateCPUDescriptors();
allocations.push_back(allocation);
EXPECT_TRUE(reallocatedPtrs.insert(allocation.OffsetFrom(0, 0).ptr).second);
EXPECT_TRUE(std::find(allocationPtrs.begin(), allocationPtrs.end(),
allocation.OffsetFrom(0, 0).ptr) != allocationPtrs.end());
}
// Deallocate all again.
for (CPUDescriptorHeapAllocation& allocation : allocations) {
allocator.Deallocate(allocation);
EXPECT_FALSE(allocation.IsValid());
}
}
// Verify allocating then deallocating many times.
TEST_P(D3D12DescriptorHeapTests, AllocateDeallocateMany) {
constexpr uint32_t kDescriptorCount = 4;
constexpr uint32_t kAllocationsPerHeap = 25;
DummyNonShaderVisibleDescriptorAllocator allocator(mD3DDevice, kDescriptorCount,
kAllocationsPerHeap);
std::list<CPUDescriptorHeapAllocation> list3;
std::list<CPUDescriptorHeapAllocation> list5;
std::list<CPUDescriptorHeapAllocation> allocations;
constexpr uint32_t kNumofHeaps = 2;
// Allocate |kNumofHeaps| heaps worth.
for (uint32_t i = 0; i < kAllocationsPerHeap * kNumofHeaps; i++) {
CPUDescriptorHeapAllocation allocation = allocator.AllocateCPUDescriptors();
EXPECT_NE(allocation.OffsetFrom(0, 0).ptr, 0u);
if (i % 3 == 0) {
list3.push_back(allocation);
} else {
allocations.push_back(allocation);
}
}
// Deallocate every 3rd allocation.
for (auto it = list3.begin(); it != list3.end(); it = list3.erase(it)) {
allocator.Deallocate(*it);
}
// Allocate again.
for (uint32_t i = 0; i < kAllocationsPerHeap * kNumofHeaps; i++) {
CPUDescriptorHeapAllocation allocation = allocator.AllocateCPUDescriptors();
EXPECT_NE(allocation.OffsetFrom(0, 0).ptr, 0u);
if (i % 5 == 0) {
list5.push_back(allocation);
} else {
allocations.push_back(allocation);
}
}
// Deallocate every 5th allocation.
for (auto it = list5.begin(); it != list5.end(); it = list5.erase(it)) {
allocator.Deallocate(*it);
}
// Allocate again.
for (uint32_t i = 0; i < kAllocationsPerHeap * kNumofHeaps; i++) {
CPUDescriptorHeapAllocation allocation = allocator.AllocateCPUDescriptors();
EXPECT_NE(allocation.OffsetFrom(0, 0).ptr, 0u);
allocations.push_back(allocation);
}
// Deallocate remaining.
for (CPUDescriptorHeapAllocation& allocation : allocations) {
allocator.Deallocate(allocation);
EXPECT_FALSE(allocation.IsValid());
}
}
DAWN_INSTANTIATE_TEST(D3D12DescriptorHeapTests,
D3D12Backend(),
D3D12Backend({"use_d3d12_small_shader_visible_heap"}));