Precompute gaussian splat chunk visibility
This commit is contained in:
@@ -1147,16 +1147,6 @@ TEST(BuiltinForwardPipeline_Test, BuiltinGaussianSplatUtilitiesShaderUsesCompute
|
||||
ResolveBuiltinPassResourceSemantic(*sh),
|
||||
BuiltinPassResourceSemantic::GaussianSplatSHBuffer);
|
||||
|
||||
const ShaderResourceBindingDesc* chunks =
|
||||
shader->FindPassResourceBinding("GaussianSplatPrepareOrder", "GaussianSplatChunks");
|
||||
ASSERT_NE(chunks, nullptr);
|
||||
EXPECT_EQ(chunks->type, ShaderResourceType::StructuredBuffer);
|
||||
EXPECT_EQ(chunks->set, 2u);
|
||||
EXPECT_EQ(chunks->binding, 4u);
|
||||
EXPECT_EQ(
|
||||
ResolveBuiltinPassResourceSemantic(*chunks),
|
||||
BuiltinPassResourceSemantic::GaussianSplatChunkBuffer);
|
||||
|
||||
const ShaderResourceBindingDesc* sortDistances =
|
||||
shader->FindPassResourceBinding("GaussianSplatPrepareOrder", "GaussianSplatSortDistances");
|
||||
ASSERT_NE(sortDistances, nullptr);
|
||||
@@ -1167,6 +1157,16 @@ TEST(BuiltinForwardPipeline_Test, BuiltinGaussianSplatUtilitiesShaderUsesCompute
|
||||
ResolveBuiltinPassResourceSemantic(*sortDistances),
|
||||
BuiltinPassResourceSemantic::GaussianSplatSortDistanceBuffer);
|
||||
|
||||
const ShaderResourceBindingDesc* visibleChunks =
|
||||
shader->FindPassResourceBinding("GaussianSplatPrepareOrder", "GaussianSplatVisibleChunks");
|
||||
ASSERT_NE(visibleChunks, nullptr);
|
||||
EXPECT_EQ(visibleChunks->type, ShaderResourceType::StructuredBuffer);
|
||||
EXPECT_EQ(visibleChunks->set, 3u);
|
||||
EXPECT_EQ(visibleChunks->binding, 0u);
|
||||
EXPECT_EQ(
|
||||
ResolveBuiltinPassResourceSemantic(*visibleChunks),
|
||||
BuiltinPassResourceSemantic::GaussianSplatVisibleChunkBuffer);
|
||||
|
||||
const ShaderResourceBindingDesc* orderBuffer =
|
||||
shader->FindPassResourceBinding("GaussianSplatPrepareOrder", "GaussianSplatOrderBuffer");
|
||||
ASSERT_NE(orderBuffer, nullptr);
|
||||
@@ -1197,6 +1197,59 @@ TEST(BuiltinForwardPipeline_Test, BuiltinGaussianSplatUtilitiesShaderUsesCompute
|
||||
delete shader;
|
||||
}
|
||||
|
||||
TEST(BuiltinForwardPipeline_Test, BuiltinGaussianSplatMarkVisibleChunksShaderUsesComputeAuthoringContract) {
|
||||
ShaderLoader loader;
|
||||
LoadResult result = loader.Load(GetBuiltinGaussianSplatUtilitiesShaderPath());
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_NE(result.resource, nullptr);
|
||||
|
||||
Shader* shader = static_cast<Shader*>(result.resource);
|
||||
ASSERT_NE(shader, nullptr);
|
||||
|
||||
const ShaderPass* pass = shader->FindPass("GaussianSplatMarkVisibleChunks");
|
||||
ASSERT_NE(pass, nullptr);
|
||||
EXPECT_EQ(pass->resources.Size(), 3u);
|
||||
|
||||
const ShaderResourceBindingDesc* perObject =
|
||||
shader->FindPassResourceBinding("GaussianSplatMarkVisibleChunks", "PerObjectConstants");
|
||||
ASSERT_NE(perObject, nullptr);
|
||||
EXPECT_EQ(perObject->type, ShaderResourceType::ConstantBuffer);
|
||||
EXPECT_EQ(perObject->set, 0u);
|
||||
EXPECT_EQ(perObject->binding, 0u);
|
||||
EXPECT_EQ(
|
||||
ResolveBuiltinPassResourceSemantic(*perObject),
|
||||
BuiltinPassResourceSemantic::PerObject);
|
||||
|
||||
const ShaderResourceBindingDesc* chunks =
|
||||
shader->FindPassResourceBinding("GaussianSplatMarkVisibleChunks", "GaussianSplatChunks");
|
||||
ASSERT_NE(chunks, nullptr);
|
||||
EXPECT_EQ(chunks->type, ShaderResourceType::StructuredBuffer);
|
||||
EXPECT_EQ(chunks->set, 2u);
|
||||
EXPECT_EQ(chunks->binding, 0u);
|
||||
EXPECT_EQ(
|
||||
ResolveBuiltinPassResourceSemantic(*chunks),
|
||||
BuiltinPassResourceSemantic::GaussianSplatChunkBuffer);
|
||||
|
||||
const ShaderResourceBindingDesc* visibleChunks =
|
||||
shader->FindPassResourceBinding("GaussianSplatMarkVisibleChunks", "GaussianSplatVisibleChunks");
|
||||
ASSERT_NE(visibleChunks, nullptr);
|
||||
EXPECT_EQ(visibleChunks->type, ShaderResourceType::RWStructuredBuffer);
|
||||
EXPECT_EQ(visibleChunks->set, 4u);
|
||||
EXPECT_EQ(visibleChunks->binding, 0u);
|
||||
EXPECT_EQ(
|
||||
ResolveBuiltinPassResourceSemantic(*visibleChunks),
|
||||
BuiltinPassResourceSemantic::GaussianSplatVisibleChunkBuffer);
|
||||
|
||||
const ShaderStageVariant* computeVariant = shader->FindVariant(
|
||||
"GaussianSplatMarkVisibleChunks",
|
||||
XCEngine::Resources::ShaderType::Compute,
|
||||
XCEngine::Resources::ShaderBackend::D3D12);
|
||||
ASSERT_NE(computeVariant, nullptr);
|
||||
EXPECT_EQ(computeVariant->entryPoint, "GaussianSplatMarkVisibleChunksCS");
|
||||
|
||||
delete shader;
|
||||
}
|
||||
|
||||
TEST(BuiltinForwardPipeline_Test, BuiltinGaussianSplatBitonicSortShaderUsesComputeAuthoringContract) {
|
||||
ShaderLoader loader;
|
||||
LoadResult result = loader.Load(GetBuiltinGaussianSplatUtilitiesShaderPath());
|
||||
@@ -1271,7 +1324,7 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded
|
||||
EXPECT_TRUE(plan.gaussianSplatOtherBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatColorBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatSHBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatChunkBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatVisibleChunkBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatSortDistanceBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatOrderBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatViewDataBuffer.IsValid());
|
||||
@@ -1283,8 +1336,8 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded
|
||||
EXPECT_EQ(plan.gaussianSplatColorBuffer.binding, 2u);
|
||||
EXPECT_EQ(plan.gaussianSplatSHBuffer.set, 2u);
|
||||
EXPECT_EQ(plan.gaussianSplatSHBuffer.binding, 3u);
|
||||
EXPECT_EQ(plan.gaussianSplatChunkBuffer.set, 2u);
|
||||
EXPECT_EQ(plan.gaussianSplatChunkBuffer.binding, 4u);
|
||||
EXPECT_EQ(plan.gaussianSplatVisibleChunkBuffer.set, 3u);
|
||||
EXPECT_EQ(plan.gaussianSplatVisibleChunkBuffer.binding, 0u);
|
||||
EXPECT_EQ(plan.gaussianSplatSortDistanceBuffer.set, 4u);
|
||||
EXPECT_EQ(plan.gaussianSplatSortDistanceBuffer.binding, 0u);
|
||||
EXPECT_EQ(plan.gaussianSplatOrderBuffer.set, 4u);
|
||||
@@ -1302,11 +1355,12 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded
|
||||
EXPECT_TRUE(setLayouts[2].usesGaussianSplatOtherBuffer);
|
||||
EXPECT_TRUE(setLayouts[2].usesGaussianSplatColorBuffer);
|
||||
EXPECT_TRUE(setLayouts[2].usesGaussianSplatSHBuffer);
|
||||
EXPECT_TRUE(setLayouts[2].usesGaussianSplatChunkBuffer);
|
||||
EXPECT_TRUE(setLayouts[3].usesGaussianSplatVisibleChunkBuffer);
|
||||
EXPECT_TRUE(setLayouts[4].usesGaussianSplatSortDistanceBuffer);
|
||||
EXPECT_TRUE(setLayouts[4].usesGaussianSplatOrderBuffer);
|
||||
EXPECT_TRUE(setLayouts[4].usesGaussianSplatViewDataBuffer);
|
||||
ASSERT_EQ(setLayouts[2].bindings.size(), 5u);
|
||||
ASSERT_EQ(setLayouts[2].bindings.size(), 4u);
|
||||
ASSERT_EQ(setLayouts[3].bindings.size(), 1u);
|
||||
ASSERT_EQ(setLayouts[4].bindings.size(), 3u);
|
||||
EXPECT_EQ(
|
||||
static_cast<DescriptorType>(setLayouts[2].bindings[0].type),
|
||||
@@ -1320,9 +1374,6 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded
|
||||
EXPECT_EQ(
|
||||
static_cast<DescriptorType>(setLayouts[2].bindings[3].type),
|
||||
DescriptorType::SRV);
|
||||
EXPECT_EQ(
|
||||
static_cast<DescriptorType>(setLayouts[2].bindings[4].type),
|
||||
DescriptorType::SRV);
|
||||
EXPECT_EQ(
|
||||
static_cast<DescriptorType>(setLayouts[4].bindings[0].type),
|
||||
DescriptorType::UAV);
|
||||
@@ -1345,7 +1396,7 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded
|
||||
setLayouts[2].bindings[3].resourceDimension,
|
||||
ResourceViewDimension::StructuredBuffer);
|
||||
EXPECT_EQ(
|
||||
setLayouts[2].bindings[4].resourceDimension,
|
||||
setLayouts[3].bindings[0].resourceDimension,
|
||||
ResourceViewDimension::StructuredBuffer);
|
||||
EXPECT_EQ(
|
||||
setLayouts[4].bindings[0].resourceDimension,
|
||||
@@ -1360,6 +1411,51 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded
|
||||
delete shader;
|
||||
}
|
||||
|
||||
TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoadedGaussianSplatMarkVisibleChunksContract) {
|
||||
ShaderLoader loader;
|
||||
LoadResult result = loader.Load(GetBuiltinGaussianSplatUtilitiesShaderPath());
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_NE(result.resource, nullptr);
|
||||
|
||||
Shader* shader = static_cast<Shader*>(result.resource);
|
||||
ASSERT_NE(shader, nullptr);
|
||||
|
||||
const ShaderPass* pass = shader->FindPass("GaussianSplatMarkVisibleChunks");
|
||||
ASSERT_NE(pass, nullptr);
|
||||
|
||||
BuiltinPassResourceBindingPlan plan = {};
|
||||
String error;
|
||||
EXPECT_TRUE(TryBuildBuiltinPassResourceBindingPlan(*pass, plan, &error)) << error.CStr();
|
||||
ASSERT_EQ(plan.bindings.Size(), 3u);
|
||||
EXPECT_TRUE(plan.perObject.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatChunkBuffer.IsValid());
|
||||
EXPECT_TRUE(plan.gaussianSplatVisibleChunkBuffer.IsValid());
|
||||
EXPECT_EQ(plan.perObject.set, 0u);
|
||||
EXPECT_EQ(plan.gaussianSplatChunkBuffer.set, 2u);
|
||||
EXPECT_EQ(plan.gaussianSplatChunkBuffer.binding, 0u);
|
||||
EXPECT_EQ(plan.gaussianSplatVisibleChunkBuffer.set, 4u);
|
||||
EXPECT_EQ(plan.gaussianSplatVisibleChunkBuffer.binding, 0u);
|
||||
EXPECT_EQ(plan.firstDescriptorSet, 0u);
|
||||
EXPECT_EQ(plan.descriptorSetCount, 5u);
|
||||
|
||||
std::vector<BuiltinPassSetLayoutMetadata> setLayouts;
|
||||
ASSERT_TRUE(TryBuildBuiltinPassSetLayouts(plan, setLayouts, &error)) << error.CStr();
|
||||
ASSERT_EQ(setLayouts.size(), 5u);
|
||||
EXPECT_TRUE(setLayouts[0].usesPerObject);
|
||||
EXPECT_TRUE(setLayouts[2].usesGaussianSplatChunkBuffer);
|
||||
EXPECT_TRUE(setLayouts[4].usesGaussianSplatVisibleChunkBuffer);
|
||||
ASSERT_EQ(setLayouts[2].bindings.size(), 1u);
|
||||
ASSERT_EQ(setLayouts[4].bindings.size(), 1u);
|
||||
EXPECT_EQ(
|
||||
static_cast<DescriptorType>(setLayouts[2].bindings[0].type),
|
||||
DescriptorType::SRV);
|
||||
EXPECT_EQ(
|
||||
static_cast<DescriptorType>(setLayouts[4].bindings[0].type),
|
||||
DescriptorType::UAV);
|
||||
|
||||
delete shader;
|
||||
}
|
||||
|
||||
TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoadedGaussianSplatBitonicSortContract) {
|
||||
ShaderLoader loader;
|
||||
LoadResult result = loader.Load(GetBuiltinGaussianSplatUtilitiesShaderPath());
|
||||
@@ -1444,7 +1540,8 @@ TEST(BuiltinForwardPipeline_Test, OpenGLPipelineLayoutUsesUnifiedStorageBufferBi
|
||||
EXPECT_EQ(pipelineLayout.GetShaderResourceBindingPoint(2u, 1u), 1u);
|
||||
EXPECT_EQ(pipelineLayout.GetShaderResourceBindingPoint(2u, 2u), 2u);
|
||||
EXPECT_EQ(pipelineLayout.GetShaderResourceBindingPoint(2u, 3u), 3u);
|
||||
EXPECT_EQ(pipelineLayout.GetShaderResourceBindingPoint(2u, 4u), 4u);
|
||||
EXPECT_EQ(pipelineLayout.GetShaderResourceBindingPoint(2u, 4u), UINT32_MAX);
|
||||
EXPECT_EQ(pipelineLayout.GetShaderResourceBindingPoint(3u, 0u), 4u);
|
||||
EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 0u), 5u);
|
||||
EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 1u), 6u);
|
||||
EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 2u), 7u);
|
||||
@@ -1502,7 +1599,7 @@ TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesGaussianSplatU
|
||||
"register(t3)"));
|
||||
EXPECT_TRUE(SourceContainsRegisterBinding(
|
||||
d3d12Source,
|
||||
"StructuredBuffer<GaussianSplatChunkData> GaussianSplatChunks",
|
||||
"StructuredBuffer<uint> GaussianSplatVisibleChunks",
|
||||
"register(t4)"));
|
||||
EXPECT_TRUE(SourceContainsRegisterBinding(
|
||||
d3d12Source,
|
||||
@@ -1554,8 +1651,8 @@ TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesGaussianSplatU
|
||||
"register(t3, space2)"));
|
||||
EXPECT_TRUE(SourceContainsRegisterBinding(
|
||||
vulkanSource,
|
||||
"StructuredBuffer<GaussianSplatChunkData> GaussianSplatChunks",
|
||||
"register(t4, space2)"));
|
||||
"StructuredBuffer<uint> GaussianSplatVisibleChunks",
|
||||
"register(t0, space3)"));
|
||||
EXPECT_TRUE(SourceContainsRegisterBinding(
|
||||
vulkanSource,
|
||||
"RWStructuredBuffer<uint> GaussianSplatSortDistances",
|
||||
@@ -1625,7 +1722,7 @@ TEST(BuiltinForwardPipeline_Test, OpenGLRuntimeTranspilesGaussianSplatUtilitiesC
|
||||
glslSource.find("layout(binding = 3, std430) readonly buffer type_StructuredBuffer_GaussianSplatSHData"),
|
||||
std::string::npos);
|
||||
EXPECT_NE(
|
||||
glslSource.find("layout(binding = 4, std430) readonly buffer type_StructuredBuffer_GaussianSplatChunkData"),
|
||||
glslSource.find("layout(binding = 4, std430) readonly buffer"),
|
||||
std::string::npos);
|
||||
EXPECT_NE(
|
||||
glslSource.find("layout(binding = 5, std430) buffer type_RWStructuredBuffer_uint"),
|
||||
|
||||
@@ -284,6 +284,7 @@ GaussianSplat* CreateTestGaussianSplat(const char* path, XCEngine::Core::uint32
|
||||
|
||||
GaussianSplatMetadata metadata = {};
|
||||
metadata.splatCount = splatCount;
|
||||
metadata.chunkCount = (splatCount + 255u) / 256u;
|
||||
|
||||
XCEngine::Containers::Array<GaussianSplatSection> sections;
|
||||
sections.Resize(1);
|
||||
@@ -336,21 +337,24 @@ TEST(BuiltinGaussianSplatPassResources_Test, EnsureWorkingSetAllocatesAndReusesS
|
||||
EXPECT_EQ(workingSet->renderer, renderer);
|
||||
EXPECT_EQ(workingSet->splatCapacity, 8u);
|
||||
EXPECT_EQ(workingSet->sortCapacity, 8u);
|
||||
EXPECT_EQ(workingSet->chunkCapacity, 1u);
|
||||
EXPECT_EQ(workingSet->sortDistances.elementStride, sizeof(float));
|
||||
EXPECT_EQ(workingSet->orderIndices.elementStride, sizeof(XCEngine::Core::uint32));
|
||||
EXPECT_EQ(workingSet->visibleChunks.elementStride, sizeof(XCEngine::Core::uint32));
|
||||
EXPECT_EQ(workingSet->viewData.elementStride, sizeof(GaussianSplatViewData));
|
||||
EXPECT_EQ(workingSet->sortDistances.shaderResourceView->GetDimension(), XCEngine::RHI::ResourceViewDimension::StructuredBuffer);
|
||||
EXPECT_EQ(workingSet->sortDistances.unorderedAccessView->GetViewType(), XCEngine::RHI::ResourceViewType::UnorderedAccess);
|
||||
EXPECT_EQ(state->createBufferCalls, 3);
|
||||
EXPECT_EQ(state->createBufferShaderViewCalls, 3);
|
||||
EXPECT_EQ(state->createBufferUavCalls, 3);
|
||||
EXPECT_EQ(workingSet->visibleChunks.elementCount, 1u);
|
||||
EXPECT_EQ(state->createBufferCalls, 4);
|
||||
EXPECT_EQ(state->createBufferShaderViewCalls, 4);
|
||||
EXPECT_EQ(state->createBufferUavCalls, 4);
|
||||
|
||||
BuiltinGaussianSplatPassResources::WorkingSet* reusedWorkingSet = nullptr;
|
||||
ASSERT_TRUE(resources.EnsureWorkingSet(&device, item, reusedWorkingSet));
|
||||
EXPECT_EQ(reusedWorkingSet, workingSet);
|
||||
EXPECT_EQ(state->createBufferCalls, 3);
|
||||
EXPECT_EQ(state->createBufferShaderViewCalls, 3);
|
||||
EXPECT_EQ(state->createBufferUavCalls, 3);
|
||||
EXPECT_EQ(state->createBufferCalls, 4);
|
||||
EXPECT_EQ(state->createBufferShaderViewCalls, 4);
|
||||
EXPECT_EQ(state->createBufferUavCalls, 4);
|
||||
}
|
||||
|
||||
TEST(BuiltinGaussianSplatPassResources_Test, EnsureWorkingSetKeepsPerRendererIsolationAndRecreatesOnCapacityGrowth) {
|
||||
@@ -376,7 +380,7 @@ TEST(BuiltinGaussianSplatPassResources_Test, EnsureWorkingSetKeepsPerRendererIso
|
||||
ASSERT_NE(secondWorkingSet, nullptr);
|
||||
EXPECT_NE(firstWorkingSet, secondWorkingSet);
|
||||
EXPECT_EQ(resources.GetWorkingSetCount(), 2u);
|
||||
EXPECT_EQ(state->createBufferCalls, 6);
|
||||
EXPECT_EQ(state->createBufferCalls, 8);
|
||||
|
||||
std::unique_ptr<GaussianSplat> grownGaussianSplat(CreateTestGaussianSplat("GaussianSplats/first_grown.xcgsplat", 12u));
|
||||
firstItem.gaussianSplat = grownGaussianSplat.get();
|
||||
@@ -387,10 +391,11 @@ TEST(BuiltinGaussianSplatPassResources_Test, EnsureWorkingSetKeepsPerRendererIso
|
||||
EXPECT_EQ(grownWorkingSet, resources.FindWorkingSet(firstRenderer));
|
||||
EXPECT_EQ(grownWorkingSet->splatCapacity, 12u);
|
||||
EXPECT_EQ(grownWorkingSet->sortCapacity, 16u);
|
||||
EXPECT_EQ(grownWorkingSet->chunkCapacity, 1u);
|
||||
EXPECT_EQ(resources.GetWorkingSetCount(), 2u);
|
||||
EXPECT_EQ(state->createBufferCalls, 9);
|
||||
EXPECT_GE(state->bufferShutdownCalls, 3);
|
||||
EXPECT_GE(state->bufferDestroyCalls, 3);
|
||||
EXPECT_EQ(state->createBufferCalls, 12);
|
||||
EXPECT_GE(state->bufferShutdownCalls, 4);
|
||||
EXPECT_GE(state->bufferDestroyCalls, 4);
|
||||
}
|
||||
|
||||
TEST(BuiltinGaussianSplatPassResources_Test, EnsureWorkingSetRoundsSortBuffersUpToNextPowerOfTwo) {
|
||||
@@ -408,8 +413,10 @@ TEST(BuiltinGaussianSplatPassResources_Test, EnsureWorkingSetRoundsSortBuffersUp
|
||||
ASSERT_NE(workingSet, nullptr);
|
||||
EXPECT_EQ(workingSet->splatCapacity, 9u);
|
||||
EXPECT_EQ(workingSet->sortCapacity, 16u);
|
||||
EXPECT_EQ(workingSet->chunkCapacity, 1u);
|
||||
EXPECT_EQ(workingSet->sortDistances.elementCount, 16u);
|
||||
EXPECT_EQ(workingSet->orderIndices.elementCount, 16u);
|
||||
EXPECT_EQ(workingSet->visibleChunks.elementCount, 1u);
|
||||
EXPECT_EQ(workingSet->viewData.elementCount, 9u);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user