Add gaussian splat compute shader contracts

This commit is contained in:
2026-04-11 01:30:59 +08:00
parent 4080b2e5fe
commit d9bc0f1457
9 changed files with 442 additions and 8 deletions

View File

@@ -13,6 +13,7 @@
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <regex>
#include <thread>
using namespace XCEngine::Resources;
@@ -71,6 +72,7 @@ TEST(ShaderLoader, CanLoad) {
EXPECT_TRUE(loader.CanLoad(GetBuiltinObjectIdOutlineShaderPath()));
EXPECT_TRUE(loader.CanLoad(GetBuiltinSelectionMaskShaderPath()));
EXPECT_TRUE(loader.CanLoad(GetBuiltinSelectionOutlineShaderPath()));
EXPECT_TRUE(loader.CanLoad(GetBuiltinGaussianSplatUtilitiesShaderPath()));
EXPECT_FALSE(loader.CanLoad("test.vert"));
EXPECT_FALSE(loader.CanLoad("test.frag"));
EXPECT_FALSE(loader.CanLoad("test.glsl"));
@@ -603,6 +605,100 @@ TEST(ShaderLoader, LoadShaderAuthoringBuildsComputeOnlyPassVariant) {
fs::remove_all(shaderRoot);
}
TEST(ShaderLoader, LoadShaderAuthoringBuildsComputeOnlyPassConstantBufferBindings) {
namespace fs = std::filesystem;
const fs::path shaderRoot = fs::temp_directory_path() / "xc_shader_authoring_compute_constants";
const fs::path shaderPath = shaderRoot / "compute_constants.shader";
fs::remove_all(shaderRoot);
fs::create_directories(shaderRoot);
WriteTextFile(
shaderPath,
R"(Shader "ComputeConstantsShader"
{
SubShader
{
Pass
{
Name "Prepare"
HLSLPROGRAM
#pragma target 4.5
#pragma compute PrepareCS
cbuffer PerObjectConstants
{
float4x4 ObjectToWorld;
};
StructuredBuffer<float4> InputData;
RWStructuredBuffer<uint> OutputOrder;
[numthreads(64, 1, 1)]
void PrepareCS(uint3 dispatchThreadId : SV_DispatchThreadID)
{
OutputOrder[dispatchThreadId.x] =
(uint)mul(ObjectToWorld, InputData[dispatchThreadId.x]).x;
}
ENDHLSL
}
}
}
)");
ShaderLoader loader;
LoadResult result = loader.Load(shaderPath.string().c_str());
ASSERT_TRUE(result);
ASSERT_NE(result.resource, nullptr);
Shader* shader = static_cast<Shader*>(result.resource);
ASSERT_NE(shader, nullptr);
const ShaderPass* pass = shader->FindPass("Prepare");
ASSERT_NE(pass, nullptr);
EXPECT_EQ(pass->resources.Size(), 3u);
const ShaderResourceBindingDesc* perObject =
shader->FindPassResourceBinding("Prepare", "PerObjectConstants");
ASSERT_NE(perObject, nullptr);
EXPECT_EQ(perObject->type, ShaderResourceType::ConstantBuffer);
EXPECT_EQ(perObject->set, 0u);
EXPECT_EQ(perObject->binding, 0u);
const ShaderStageVariant* computeVariant =
shader->FindVariant("Prepare", ShaderType::Compute, ShaderBackend::D3D12);
ASSERT_NE(computeVariant, nullptr);
XCEngine::RHI::ShaderCompileDesc d3d12CompileDesc = {};
::XCEngine::Rendering::Internal::ApplyShaderStageVariant(
*pass,
ShaderBackend::D3D12,
*computeVariant,
d3d12CompileDesc);
const std::string d3d12Source(
reinterpret_cast<const char*>(d3d12CompileDesc.source.data()),
d3d12CompileDesc.source.size());
EXPECT_TRUE(std::regex_search(
d3d12Source,
std::regex(R"(cbuffer\s+PerObjectConstants\s*:\s*register\(b0\))", std::regex::ECMAScript)));
XCEngine::RHI::ShaderCompileDesc vulkanCompileDesc = {};
::XCEngine::Rendering::Internal::ApplyShaderStageVariant(
*pass,
ShaderBackend::Vulkan,
*computeVariant,
vulkanCompileDesc);
const std::string vulkanSource(
reinterpret_cast<const char*>(vulkanCompileDesc.source.data()),
vulkanCompileDesc.source.size());
EXPECT_TRUE(std::regex_search(
vulkanSource,
std::regex(
R"(cbuffer\s+PerObjectConstants\s*:\s*register\(b0,\s*space0\))",
std::regex::ECMAScript)));
delete shader;
fs::remove_all(shaderRoot);
}
TEST(ShaderLoader, LoadShaderAuthoringRejectsPassMixingComputeAndGraphicsPragmas) {
namespace fs = std::filesystem;