diff --git a/engine/assets/builtin/shaders/gaussian-splat-utilities.shader b/engine/assets/builtin/shaders/gaussian-splat-utilities.shader index 7d8ea9e1..ab3ffb18 100644 --- a/engine/assets/builtin/shaders/gaussian-splat-utilities.shader +++ b/engine/assets/builtin/shaders/gaussian-splat-utilities.shader @@ -20,6 +20,25 @@ Shader "Builtin Gaussian Splat Utilities" float coefficients[45]; }; + struct GaussianSplatChunkData + { + uint colR; + uint colG; + uint colB; + uint colA; + float2 posX; + float2 posY; + float2 posZ; + uint sclX; + uint sclY; + uint sclZ; + uint shR; + uint shG; + uint shB; + }; + + static const uint GAUSSIAN_SPLAT_CHUNK_SIZE = 256u; + static const float SH_C1 = 0.4886025; static const float SH_C2[] = { 1.0925484, -1.0925484, 0.3153916, -1.0925484, 0.5462742 }; static const float SH_C3[] = { -0.5900436, 2.8906114, -0.4570458, 0.3731763, -0.4570458, 1.4453057, -0.5900436 }; @@ -211,6 +230,7 @@ Shader "Builtin Gaussian Splat Utilities" StructuredBuffer GaussianSplatOther; StructuredBuffer GaussianSplatColor; StructuredBuffer GaussianSplatSH; + StructuredBuffer GaussianSplatChunks; RWStructuredBuffer GaussianSplatSortDistances; RWStructuredBuffer GaussianSplatOrderBuffer; RWStructuredBuffer GaussianSplatViewDataBuffer; @@ -240,7 +260,16 @@ Shader "Builtin Gaussian Splat Utilities" const GaussianSplatOtherData otherData = GaussianSplatOther[index]; const float4 colorOpacity = GaussianSplatColor[index]; const GaussianSplatSHData shData = GaussianSplatSH[index]; + const GaussianSplatChunkData chunkData = GaussianSplatChunks[index / GAUSSIAN_SPLAT_CHUNK_SIZE]; const uint shOrder = min((uint)gSplatParams.z, 3u); + if (chunkData.posX.x > chunkData.posX.y || + chunkData.posY.x > chunkData.posY.y || + chunkData.posZ.x > chunkData.posZ.y) + { + GaussianSplatSortDistances[index] = 0xffffffffu; + GaussianSplatViewDataBuffer[index] = viewData; + return; + } const float3 worldCenter = mul(gModelMatrix, float4(localCenter, 1.0)).xyz; const float3 viewCenter = mul(gViewMatrix, float4(worldCenter, 1.0)).xyz; diff --git a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h b/engine/include/XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h index a74fcef5..2da253c8 100644 --- a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h +++ b/engine/include/XCEngine/Rendering/Builtin/BuiltinPassLayoutUtils.h @@ -46,6 +46,7 @@ inline bool TryBuildBuiltinPassResourceBindingPlan( location = &outPlan.material; break; case BuiltinPassResourceSemantic::MaterialBuffer: + case BuiltinPassResourceSemantic::MaterialTexture: break; case BuiltinPassResourceSemantic::Lighting: location = &outPlan.lighting; @@ -80,6 +81,9 @@ inline bool TryBuildBuiltinPassResourceBindingPlan( case BuiltinPassResourceSemantic::GaussianSplatSHBuffer: location = &outPlan.gaussianSplatSHBuffer; break; + case BuiltinPassResourceSemantic::GaussianSplatChunkBuffer: + location = &outPlan.gaussianSplatChunkBuffer; + break; case BuiltinPassResourceSemantic::GaussianSplatViewDataBuffer: location = &outPlan.gaussianSplatViewDataBuffer; break; @@ -109,7 +113,9 @@ inline bool TryBuildBuiltinPassResourceBindingPlan( break; } - if (semantic != BuiltinPassResourceSemantic::MaterialBuffer && location == nullptr) { + if (semantic != BuiltinPassResourceSemantic::MaterialBuffer && + semantic != BuiltinPassResourceSemantic::MaterialTexture && + location == nullptr) { return fail("Builtin pass resource semantic could not be mapped"); } if (location != nullptr && location->IsValid()) { @@ -137,6 +143,9 @@ inline bool TryBuildBuiltinPassResourceBindingPlan( if (semantic == BuiltinPassResourceSemantic::MaterialBuffer) { outPlan.materialBufferBindings.PushBack(resolvedBinding); outPlan.usesMaterialBuffers = true; + } else if (semantic == BuiltinPassResourceSemantic::MaterialTexture) { + outPlan.materialTextureBindings.PushBack(resolvedBinding); + outPlan.usesMaterialTextures = true; } outPlan.maxSetIndex = std::max(outPlan.maxSetIndex, binding.set); @@ -593,6 +602,11 @@ inline bool TryBuildBuiltinPassSetLayouts( setLayout.usesMaterialBuffers = true; setLayout.materialBufferBindings.push_back(binding); break; + case BuiltinPassResourceSemantic::MaterialTexture: + setLayout.usesTexture = true; + setLayout.usesMaterialTextures = true; + setLayout.materialTextureBindings.push_back(binding); + break; case BuiltinPassResourceSemantic::Lighting: setLayout.usesLighting = true; break; @@ -626,6 +640,9 @@ inline bool TryBuildBuiltinPassSetLayouts( case BuiltinPassResourceSemantic::GaussianSplatSHBuffer: setLayout.usesGaussianSplatSHBuffer = true; break; + case BuiltinPassResourceSemantic::GaussianSplatChunkBuffer: + setLayout.usesGaussianSplatChunkBuffer = true; + break; case BuiltinPassResourceSemantic::GaussianSplatViewDataBuffer: setLayout.usesGaussianSplatViewDataBuffer = true; break; diff --git a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h b/engine/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h index 553769c0..31d73783 100644 --- a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h +++ b/engine/include/XCEngine/Rendering/Builtin/BuiltinPassMetadataUtils.h @@ -183,6 +183,12 @@ inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic( return BuiltinPassResourceSemantic::GaussianSplatSHBuffer; } + if (semantic == Containers::String("gaussiansplatchunkbuffer") || + semantic == Containers::String("gaussiansplatchunks") || + semantic == Containers::String("splatchunks")) { + return BuiltinPassResourceSemantic::GaussianSplatChunkBuffer; + } + if (semantic == Containers::String("gaussiansplatviewdatabuffer") || semantic == Containers::String("gaussiansplatviewdata") || semantic == Containers::String("splatviewdata")) { @@ -221,6 +227,9 @@ inline BuiltinPassResourceSemantic ResolveBuiltinPassResourceSemantic( } switch (binding.type) { + case Resources::ShaderResourceType::Texture2D: + case Resources::ShaderResourceType::TextureCube: + return BuiltinPassResourceSemantic::MaterialTexture; case Resources::ShaderResourceType::StructuredBuffer: case Resources::ShaderResourceType::RawBuffer: case Resources::ShaderResourceType::RWStructuredBuffer: @@ -241,6 +250,8 @@ inline const char* BuiltinPassResourceSemanticToString(BuiltinPassResourceSemant return "Material"; case BuiltinPassResourceSemantic::MaterialBuffer: return "MaterialBuffer"; + case BuiltinPassResourceSemantic::MaterialTexture: + return "MaterialTexture"; case BuiltinPassResourceSemantic::Lighting: return "Lighting"; case BuiltinPassResourceSemantic::ShadowReceiver: @@ -263,6 +274,8 @@ inline const char* BuiltinPassResourceSemanticToString(BuiltinPassResourceSemant return "GaussianSplatColorBuffer"; case BuiltinPassResourceSemantic::GaussianSplatSHBuffer: return "GaussianSplatSHBuffer"; + case BuiltinPassResourceSemantic::GaussianSplatChunkBuffer: + return "GaussianSplatChunkBuffer"; case BuiltinPassResourceSemantic::GaussianSplatViewDataBuffer: return "GaussianSplatViewDataBuffer"; case BuiltinPassResourceSemantic::BaseColorTexture: @@ -350,6 +363,9 @@ inline bool IsBuiltinPassResourceTypeCompatible( type == Resources::ShaderResourceType::RawBuffer || type == Resources::ShaderResourceType::RWStructuredBuffer || type == Resources::ShaderResourceType::RWRawBuffer; + case BuiltinPassResourceSemantic::MaterialTexture: + return type == Resources::ShaderResourceType::Texture2D || + type == Resources::ShaderResourceType::TextureCube; case BuiltinPassResourceSemantic::VolumeField: return type == Resources::ShaderResourceType::StructuredBuffer || type == Resources::ShaderResourceType::RawBuffer; @@ -359,6 +375,7 @@ inline bool IsBuiltinPassResourceTypeCompatible( case BuiltinPassResourceSemantic::GaussianSplatOtherBuffer: case BuiltinPassResourceSemantic::GaussianSplatColorBuffer: case BuiltinPassResourceSemantic::GaussianSplatSHBuffer: + case BuiltinPassResourceSemantic::GaussianSplatChunkBuffer: case BuiltinPassResourceSemantic::GaussianSplatViewDataBuffer: return type == Resources::ShaderResourceType::StructuredBuffer || type == Resources::ShaderResourceType::RawBuffer || diff --git a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassTypes.h b/engine/include/XCEngine/Rendering/Builtin/BuiltinPassTypes.h index 41f7fa73..d5efeaa6 100644 --- a/engine/include/XCEngine/Rendering/Builtin/BuiltinPassTypes.h +++ b/engine/include/XCEngine/Rendering/Builtin/BuiltinPassTypes.h @@ -42,6 +42,7 @@ enum class BuiltinPassResourceSemantic : Core::uint8 { PerObject, Material, MaterialBuffer, + MaterialTexture, Lighting, ShadowReceiver, Environment, @@ -53,6 +54,7 @@ enum class BuiltinPassResourceSemantic : Core::uint8 { GaussianSplatOtherBuffer, GaussianSplatColorBuffer, GaussianSplatSHBuffer, + GaussianSplatChunkBuffer, GaussianSplatViewDataBuffer, BaseColorTexture, SourceColorTexture, @@ -73,6 +75,7 @@ struct BuiltinPassResourceBindingDesc { struct BuiltinPassResourceBindingPlan { Containers::Array bindings; Containers::Array materialBufferBindings; + Containers::Array materialTextureBindings; Core::uint32 maxSetIndex = 0; Core::uint32 firstDescriptorSet = 0; Core::uint32 descriptorSetCount = 0; @@ -80,6 +83,7 @@ struct BuiltinPassResourceBindingPlan { bool usesTextures = false; bool usesSamplers = false; bool usesMaterialBuffers = false; + bool usesMaterialTextures = false; PassResourceBindingLocation perObject = {}; PassResourceBindingLocation material = {}; PassResourceBindingLocation volumeField = {}; @@ -93,6 +97,7 @@ struct BuiltinPassResourceBindingPlan { PassResourceBindingLocation gaussianSplatOtherBuffer = {}; PassResourceBindingLocation gaussianSplatColorBuffer = {}; PassResourceBindingLocation gaussianSplatSHBuffer = {}; + PassResourceBindingLocation gaussianSplatChunkBuffer = {}; PassResourceBindingLocation gaussianSplatViewDataBuffer = {}; PassResourceBindingLocation baseColorTexture = {}; PassResourceBindingLocation sourceColorTexture = {}; @@ -116,6 +121,7 @@ struct BuiltinPassResourceBindingPlan { struct BuiltinPassSetLayoutMetadata { std::vector bindings; std::vector materialBufferBindings; + std::vector materialTextureBindings; RHI::DescriptorSetLayoutDesc layout = {}; RHI::DescriptorHeapType heapType = RHI::DescriptorHeapType::CBV_SRV_UAV; bool shaderVisible = false; @@ -126,6 +132,7 @@ struct BuiltinPassSetLayoutMetadata { bool usesEnvironment = false; bool usesPassConstants = false; bool usesMaterialBuffers = false; + bool usesMaterialTextures = false; bool usesVolumeField = false; bool usesGaussianSplatSortDistanceBuffer = false; bool usesGaussianSplatOrderBuffer = false; @@ -133,6 +140,7 @@ struct BuiltinPassSetLayoutMetadata { bool usesGaussianSplatOtherBuffer = false; bool usesGaussianSplatColorBuffer = false; bool usesGaussianSplatSHBuffer = false; + bool usesGaussianSplatChunkBuffer = false; bool usesGaussianSplatViewDataBuffer = false; bool usesTexture = false; bool usesBaseColorTexture = false; @@ -148,14 +156,16 @@ struct BuiltinPassSetLayoutMetadata { BuiltinPassSetLayoutMetadata(const BuiltinPassSetLayoutMetadata& other) : bindings(other.bindings) - , materialBufferBindings(other.materialBufferBindings) { + , materialBufferBindings(other.materialBufferBindings) + , materialTextureBindings(other.materialTextureBindings) { CopyFlagsFrom(other); SyncLayoutView(); } BuiltinPassSetLayoutMetadata(BuiltinPassSetLayoutMetadata&& other) noexcept : bindings(std::move(other.bindings)) - , materialBufferBindings(std::move(other.materialBufferBindings)) { + , materialBufferBindings(std::move(other.materialBufferBindings)) + , materialTextureBindings(std::move(other.materialTextureBindings)) { CopyFlagsFrom(other); SyncLayoutView(); other.layout = {}; @@ -165,6 +175,7 @@ struct BuiltinPassSetLayoutMetadata { if (this != &other) { bindings = other.bindings; materialBufferBindings = other.materialBufferBindings; + materialTextureBindings = other.materialTextureBindings; CopyFlagsFrom(other); SyncLayoutView(); } @@ -176,6 +187,7 @@ struct BuiltinPassSetLayoutMetadata { if (this != &other) { bindings = std::move(other.bindings); materialBufferBindings = std::move(other.materialBufferBindings); + materialTextureBindings = std::move(other.materialTextureBindings); CopyFlagsFrom(other); SyncLayoutView(); other.layout = {}; @@ -200,6 +212,7 @@ private: usesEnvironment = other.usesEnvironment; usesPassConstants = other.usesPassConstants; usesMaterialBuffers = other.usesMaterialBuffers; + usesMaterialTextures = other.usesMaterialTextures; usesVolumeField = other.usesVolumeField; usesGaussianSplatSortDistanceBuffer = other.usesGaussianSplatSortDistanceBuffer; usesGaussianSplatOrderBuffer = other.usesGaussianSplatOrderBuffer; @@ -207,6 +220,7 @@ private: usesGaussianSplatOtherBuffer = other.usesGaussianSplatOtherBuffer; usesGaussianSplatColorBuffer = other.usesGaussianSplatColorBuffer; usesGaussianSplatSHBuffer = other.usesGaussianSplatSHBuffer; + usesGaussianSplatChunkBuffer = other.usesGaussianSplatChunkBuffer; usesGaussianSplatViewDataBuffer = other.usesGaussianSplatViewDataBuffer; usesTexture = other.usesTexture; usesBaseColorTexture = other.usesBaseColorTexture; diff --git a/engine/include/XCEngine/Rendering/Passes/BuiltinGaussianSplatPass.h b/engine/include/XCEngine/Rendering/Passes/BuiltinGaussianSplatPass.h index 37a25bfd..65da2e33 100644 --- a/engine/include/XCEngine/Rendering/Passes/BuiltinGaussianSplatPass.h +++ b/engine/include/XCEngine/Rendering/Passes/BuiltinGaussianSplatPass.h @@ -100,6 +100,7 @@ private: PassResourceBindingLocation gaussianSplatOtherBuffer = {}; PassResourceBindingLocation gaussianSplatColorBuffer = {}; PassResourceBindingLocation gaussianSplatSHBuffer = {}; + PassResourceBindingLocation gaussianSplatChunkBuffer = {}; PassResourceBindingLocation gaussianSplatViewDataBuffer = {}; }; @@ -142,6 +143,7 @@ private: RHI::RHIResourceView* otherView = nullptr; RHI::RHIResourceView* colorView = nullptr; RHI::RHIResourceView* shView = nullptr; + RHI::RHIResourceView* chunkView = nullptr; RHI::RHIResourceView* viewDataView = nullptr; }; diff --git a/engine/src/Rendering/Passes/BuiltinGaussianSplatPass.cpp b/engine/src/Rendering/Passes/BuiltinGaussianSplatPass.cpp index e92cc7ea..4d94899b 100644 --- a/engine/src/Rendering/Passes/BuiltinGaussianSplatPass.cpp +++ b/engine/src/Rendering/Passes/BuiltinGaussianSplatPass.cpp @@ -244,7 +244,8 @@ bool BuiltinGaussianSplatPass::PrepareGaussianSplatResources( cachedGaussianSplat->positions.shaderResourceView == nullptr || cachedGaussianSplat->other.shaderResourceView == nullptr || cachedGaussianSplat->color.shaderResourceView == nullptr || - cachedGaussianSplat->sh.shaderResourceView == nullptr) { + cachedGaussianSplat->sh.shaderResourceView == nullptr || + cachedGaussianSplat->chunks.shaderResourceView == nullptr) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, "BuiltinGaussianSplatPass::PrepareGaussianSplatResources failed: gaussian splat GPU cache incomplete"); @@ -579,6 +580,7 @@ BuiltinGaussianSplatPass::PassResourceLayout* BuiltinGaussianSplatPass::GetOrCre passLayout.gaussianSplatOtherBuffer = bindingPlan.gaussianSplatOtherBuffer; passLayout.gaussianSplatColorBuffer = bindingPlan.gaussianSplatColorBuffer; passLayout.gaussianSplatSHBuffer = bindingPlan.gaussianSplatSHBuffer; + passLayout.gaussianSplatChunkBuffer = bindingPlan.gaussianSplatChunkBuffer; passLayout.gaussianSplatViewDataBuffer = bindingPlan.gaussianSplatViewDataBuffer; if (!passLayout.perObject.IsValid()) { @@ -601,9 +603,10 @@ BuiltinGaussianSplatPass::PassResourceLayout* BuiltinGaussianSplatPass::GetOrCre !passLayout.gaussianSplatOtherBuffer.IsValid() || !passLayout.gaussianSplatColorBuffer.IsValid() || !passLayout.gaussianSplatSHBuffer.IsValid() || + !passLayout.gaussianSplatChunkBuffer.IsValid() || !passLayout.gaussianSplatViewDataBuffer.IsValid()) { return failLayout( - "BuiltinGaussianSplatPass prepare-order pass requires sort distance, order, position, other, color, SH, and view-data gaussian splat buffer bindings"); + "BuiltinGaussianSplatPass prepare-order pass requires sort distance, order, position, other, color, SH, chunk, and view-data gaussian splat buffer bindings"); } } else if (usage == PassLayoutUsage::BitonicSort) { if (!passLayout.gaussianSplatSortDistanceBuffer.IsValid() || @@ -936,6 +939,20 @@ BuiltinGaussianSplatPass::CachedDescriptorSet* BuiltinGaussianSplatPass::GetOrCr } } + if (setLayout.usesGaussianSplatChunkBuffer) { + if (cachedGaussianSplat.chunks.shaderResourceView == nullptr || + !passLayout.gaussianSplatChunkBuffer.IsValid() || + passLayout.gaussianSplatChunkBuffer.set != setIndex) { + return nullptr; + } + + if (cachedDescriptorSet.chunkView != cachedGaussianSplat.chunks.shaderResourceView) { + cachedDescriptorSet.descriptorSet.set->Update( + passLayout.gaussianSplatChunkBuffer.binding, + cachedGaussianSplat.chunks.shaderResourceView); + } + } + if (setLayout.usesGaussianSplatViewDataBuffer) { if (resolvedViewDataView == nullptr || !passLayout.gaussianSplatViewDataBuffer.IsValid() || @@ -957,6 +974,7 @@ BuiltinGaussianSplatPass::CachedDescriptorSet* BuiltinGaussianSplatPass::GetOrCr cachedDescriptorSet.otherView = cachedGaussianSplat.other.shaderResourceView; cachedDescriptorSet.colorView = cachedGaussianSplat.color.shaderResourceView; cachedDescriptorSet.shView = cachedGaussianSplat.sh.shaderResourceView; + cachedDescriptorSet.chunkView = cachedGaussianSplat.chunks.shaderResourceView; cachedDescriptorSet.viewDataView = resolvedViewDataView; return &cachedDescriptorSet; } @@ -993,6 +1011,7 @@ void BuiltinGaussianSplatPass::DestroyPassResourceLayout(PassResourceLayout& pas passLayout.gaussianSplatOtherBuffer = {}; passLayout.gaussianSplatColorBuffer = {}; passLayout.gaussianSplatSHBuffer = {}; + passLayout.gaussianSplatChunkBuffer = {}; passLayout.gaussianSplatViewDataBuffer = {}; } @@ -1018,7 +1037,8 @@ bool BuiltinGaussianSplatPass::PrepareVisibleGaussianSplat( cachedGaussianSplat->positions.shaderResourceView == nullptr || cachedGaussianSplat->other.shaderResourceView == nullptr || cachedGaussianSplat->color.shaderResourceView == nullptr || - cachedGaussianSplat->sh.shaderResourceView == nullptr) { + cachedGaussianSplat->sh.shaderResourceView == nullptr || + cachedGaussianSplat->chunks.shaderResourceView == nullptr) { return fail("BuiltinGaussianSplatPass prepare-order failed: gaussian splat GPU cache is incomplete"); } @@ -1109,6 +1129,7 @@ bool BuiltinGaussianSplatPass::PrepareVisibleGaussianSplat( setLayout.usesGaussianSplatOtherBuffer || setLayout.usesGaussianSplatColorBuffer || setLayout.usesGaussianSplatSHBuffer || + setLayout.usesGaussianSplatChunkBuffer || setLayout.usesGaussianSplatViewDataBuffer)) { return fail("BuiltinGaussianSplatPass prepare-order failed: unexpected descriptor set layout"); } @@ -1122,6 +1143,7 @@ bool BuiltinGaussianSplatPass::PrepareVisibleGaussianSplat( setLayout.usesGaussianSplatOtherBuffer || setLayout.usesGaussianSplatColorBuffer || setLayout.usesGaussianSplatSHBuffer || + setLayout.usesGaussianSplatChunkBuffer || setLayout.usesGaussianSplatViewDataBuffer) ? visibleGaussianSplat.gaussianSplat : nullptr; diff --git a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp index 96608cf6..250d6bc3 100644 --- a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp +++ b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp @@ -1095,7 +1095,7 @@ TEST(BuiltinForwardPipeline_Test, BuiltinGaussianSplatUtilitiesShaderUsesCompute const ShaderPass* pass = shader->FindPass("GaussianSplatPrepareOrder"); ASSERT_NE(pass, nullptr); - EXPECT_EQ(pass->resources.Size(), 8u); + EXPECT_EQ(pass->resources.Size(), 9u); const ShaderResourceBindingDesc* perObject = shader->FindPassResourceBinding("GaussianSplatPrepareOrder", "PerObjectConstants"); @@ -1147,6 +1147,16 @@ 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); @@ -1255,12 +1265,13 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded BuiltinPassResourceBindingPlan plan = {}; String error; EXPECT_TRUE(TryBuildBuiltinPassResourceBindingPlan(*pass, plan, &error)) << error.CStr(); - ASSERT_EQ(plan.bindings.Size(), 8u); + ASSERT_EQ(plan.bindings.Size(), 9u); EXPECT_TRUE(plan.perObject.IsValid()); EXPECT_TRUE(plan.gaussianSplatPositionBuffer.IsValid()); EXPECT_TRUE(plan.gaussianSplatOtherBuffer.IsValid()); EXPECT_TRUE(plan.gaussianSplatColorBuffer.IsValid()); EXPECT_TRUE(plan.gaussianSplatSHBuffer.IsValid()); + EXPECT_TRUE(plan.gaussianSplatChunkBuffer.IsValid()); EXPECT_TRUE(plan.gaussianSplatSortDistanceBuffer.IsValid()); EXPECT_TRUE(plan.gaussianSplatOrderBuffer.IsValid()); EXPECT_TRUE(plan.gaussianSplatViewDataBuffer.IsValid()); @@ -1272,6 +1283,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.gaussianSplatSortDistanceBuffer.set, 4u); EXPECT_EQ(plan.gaussianSplatSortDistanceBuffer.binding, 0u); EXPECT_EQ(plan.gaussianSplatOrderBuffer.set, 4u); @@ -1289,10 +1302,11 @@ 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[4].usesGaussianSplatSortDistanceBuffer); EXPECT_TRUE(setLayouts[4].usesGaussianSplatOrderBuffer); EXPECT_TRUE(setLayouts[4].usesGaussianSplatViewDataBuffer); - ASSERT_EQ(setLayouts[2].bindings.size(), 4u); + ASSERT_EQ(setLayouts[2].bindings.size(), 5u); ASSERT_EQ(setLayouts[4].bindings.size(), 3u); EXPECT_EQ( static_cast(setLayouts[2].bindings[0].type), @@ -1306,6 +1320,9 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded EXPECT_EQ( static_cast(setLayouts[2].bindings[3].type), DescriptorType::SRV); + EXPECT_EQ( + static_cast(setLayouts[2].bindings[4].type), + DescriptorType::SRV); EXPECT_EQ( static_cast(setLayouts[4].bindings[0].type), DescriptorType::UAV); @@ -1327,6 +1344,9 @@ TEST(BuiltinForwardPipeline_Test, BuildsBuiltinPassResourceBindingPlanFromLoaded EXPECT_EQ( setLayouts[2].bindings[3].resourceDimension, ResourceViewDimension::StructuredBuffer); + EXPECT_EQ( + setLayouts[2].bindings[4].resourceDimension, + ResourceViewDimension::StructuredBuffer); EXPECT_EQ( setLayouts[4].bindings[0].resourceDimension, ResourceViewDimension::StructuredBuffer); @@ -1424,9 +1444,10 @@ 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.GetUnorderedAccessBindingPoint(4u, 0u), 4u); - EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 1u), 5u); - EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 2u), 6u); + EXPECT_EQ(pipelineLayout.GetShaderResourceBindingPoint(2u, 4u), 4u); + EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 0u), 5u); + EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 1u), 6u); + EXPECT_EQ(pipelineLayout.GetUnorderedAccessBindingPoint(4u, 2u), 7u); pipelineLayout.Shutdown(); delete shader; @@ -1479,6 +1500,10 @@ TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesGaussianSplatU d3d12Source, "StructuredBuffer GaussianSplatSH", "register(t3)")); + EXPECT_TRUE(SourceContainsRegisterBinding( + d3d12Source, + "StructuredBuffer GaussianSplatChunks", + "register(t4)")); EXPECT_TRUE(SourceContainsRegisterBinding( d3d12Source, "RWStructuredBuffer GaussianSplatSortDistances", @@ -1527,6 +1552,10 @@ TEST(BuiltinForwardPipeline_Test, VulkanRuntimeCompileDescRewritesGaussianSplatU vulkanSource, "StructuredBuffer GaussianSplatSH", "register(t3, space2)")); + EXPECT_TRUE(SourceContainsRegisterBinding( + vulkanSource, + "StructuredBuffer GaussianSplatChunks", + "register(t4, space2)")); EXPECT_TRUE(SourceContainsRegisterBinding( vulkanSource, "RWStructuredBuffer GaussianSplatSortDistances", @@ -1596,13 +1625,16 @@ 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) buffer type_RWStructuredBuffer_uint"), + glslSource.find("layout(binding = 4, std430) readonly buffer type_StructuredBuffer_GaussianSplatChunkData"), std::string::npos); EXPECT_NE( - glslSource.find("layout(binding = 5, std430) buffer GaussianSplatOrderBuffer"), + glslSource.find("layout(binding = 5, std430) buffer type_RWStructuredBuffer_uint"), std::string::npos); EXPECT_NE( - glslSource.find("layout(binding = 6, std430) buffer type_RWStructuredBuffer_GaussianSplatViewData"), + glslSource.find("layout(binding = 6, std430) buffer GaussianSplatOrderBuffer"), + std::string::npos); + EXPECT_NE( + glslSource.find("layout(binding = 7, std430) buffer type_RWStructuredBuffer_GaussianSplatViewData"), std::string::npos); delete shader;