Define gaussian splat chunk data contract

This commit is contained in:
2026-04-11 07:07:21 +08:00
parent b3acb5afc2
commit 92d5cc61cf
3 changed files with 108 additions and 20 deletions

View File

@@ -295,16 +295,36 @@ SampleArtifactData BuildSampleArtifactData() {
sh[1].coefficients[index] = -0.02f * static_cast<float>(index + 1u);
}
const GaussianSplatChunkRecord chunks[1] = {
{
0x00010002u,
0x00030004u,
0x00050006u,
0x00070008u,
Vector2(-1.0f, 2.0f),
Vector2(-3.0f, 4.0f),
Vector2(-5.0f, 6.0f),
0x0009000Au,
0x000B000Cu,
0x000D000Eu,
0x000F0010u,
0x00110012u,
0x00130014u
}
};
SampleArtifactData sample;
sample.metadata.contentVersion = 1u;
sample.metadata.splatCount = 2u;
sample.metadata.chunkCount = 1u;
sample.metadata.bounds.SetMinMax(Vector3(-2.0f, -1.0f, -3.0f), Vector3(5.0f, 4.0f, 6.0f));
sample.metadata.positionFormat = GaussianSplatSectionFormat::VectorFloat32;
sample.metadata.otherFormat = GaussianSplatSectionFormat::OtherFloat32;
sample.metadata.colorFormat = GaussianSplatSectionFormat::ColorRGBA32F;
sample.metadata.shFormat = GaussianSplatSectionFormat::SHFloat32;
sample.metadata.chunkFormat = GaussianSplatSectionFormat::ChunkFloat32;
sample.sections.Reserve(4u);
sample.sections.Reserve(5u);
size_t payloadOffset = 0u;
auto appendSection = [&](GaussianSplatSectionType type,
GaussianSplatSectionFormat format,
@@ -355,6 +375,13 @@ SampleArtifactData BuildSampleArtifactData() {
sizeof(sh),
2u,
sizeof(GaussianSplatSHRecord));
appendSection(
GaussianSplatSectionType::Chunks,
GaussianSplatSectionFormat::ChunkFloat32,
chunks,
sizeof(chunks),
1u,
sizeof(GaussianSplatChunkRecord));
return sample;
}
@@ -392,41 +419,49 @@ TEST(RenderResourceCacheTest, GetOrCreateGaussianSplatUploadsStructuredSectionsA
EXPECT_EQ(cached->residencyState, RenderResourceCache::GaussianSplatResidencyState::GpuReady);
EXPECT_EQ(cached->contentVersion, 1u);
EXPECT_EQ(cached->splatCount, 2u);
EXPECT_EQ(cached->chunkCount, 0u);
EXPECT_EQ(cached->positions.elementStride, sizeof(GaussianSplatPositionRecord));
EXPECT_EQ(cached->chunkCount, 1u);
EXPECT_EQ(cached->positions.elementStride, sizeof(float) * 4u);
EXPECT_EQ(cached->other.elementStride, sizeof(GaussianSplatOtherRecord));
EXPECT_EQ(cached->color.elementStride, sizeof(GaussianSplatColorRecord));
EXPECT_EQ(cached->sh.elementStride, sizeof(GaussianSplatSHRecord));
EXPECT_EQ(cached->chunks.elementStride, sizeof(GaussianSplatChunkRecord));
EXPECT_EQ(cached->positions.elementCount, 2u);
EXPECT_EQ(cached->other.elementCount, 2u);
EXPECT_EQ(cached->color.elementCount, 2u);
EXPECT_EQ(cached->sh.elementCount, 2u);
EXPECT_EQ(cached->chunks.elementCount, 1u);
ASSERT_NE(cached->positions.buffer, nullptr);
ASSERT_NE(cached->positions.shaderResourceView, nullptr);
ASSERT_NE(cached->color.buffer, nullptr);
ASSERT_NE(cached->sh.buffer, nullptr);
ASSERT_NE(cached->chunks.buffer, nullptr);
const auto* uploadedPositions = static_cast<const MockCacheBuffer*>(cached->positions.buffer);
ASSERT_GE(uploadedPositions->GetBytes().size(), sizeof(GaussianSplatPositionRecord) * 2u);
const auto* uploadedPositionRecords = reinterpret_cast<const GaussianSplatPositionRecord*>(
uploadedPositions->GetBytes().data());
EXPECT_EQ(uploadedPositionRecords[0].position, Vector3(0.0f, 1.0f, 2.0f));
EXPECT_EQ(uploadedPositionRecords[1].position, Vector3(3.0f, 4.0f, 5.0f));
ASSERT_GE(uploadedPositions->GetBytes().size(), sizeof(float) * 4u * 2u);
const auto* uploadedPositionWords = reinterpret_cast<const float*>(uploadedPositions->GetBytes().data());
EXPECT_FLOAT_EQ(uploadedPositionWords[0], 0.0f);
EXPECT_FLOAT_EQ(uploadedPositionWords[1], 1.0f);
EXPECT_FLOAT_EQ(uploadedPositionWords[2], 2.0f);
EXPECT_FLOAT_EQ(uploadedPositionWords[3], 0.0f);
EXPECT_FLOAT_EQ(uploadedPositionWords[4], 3.0f);
EXPECT_FLOAT_EQ(uploadedPositionWords[5], 4.0f);
EXPECT_FLOAT_EQ(uploadedPositionWords[6], 5.0f);
EXPECT_FLOAT_EQ(uploadedPositionWords[7], 0.0f);
EXPECT_EQ(state->createBufferCalls, 4);
EXPECT_EQ(state->createShaderViewCalls, 4);
EXPECT_EQ(state->createBufferCalls, 5);
EXPECT_EQ(state->createShaderViewCalls, 5);
const RenderResourceCache::CachedGaussianSplat* cachedAgain =
cache.GetOrCreateGaussianSplat(&device, &gaussianSplat);
EXPECT_EQ(cachedAgain, cached);
EXPECT_EQ(state->createBufferCalls, 4);
EXPECT_EQ(state->createShaderViewCalls, 4);
EXPECT_EQ(state->createBufferCalls, 5);
EXPECT_EQ(state->createShaderViewCalls, 5);
cache.Shutdown();
EXPECT_EQ(state->shutdownBufferCalls, 4);
EXPECT_EQ(state->destroyBufferCalls, 4);
EXPECT_EQ(state->shutdownShaderViewCalls, 4);
EXPECT_EQ(state->destroyShaderViewCalls, 4);
EXPECT_EQ(state->shutdownBufferCalls, 5);
EXPECT_EQ(state->destroyBufferCalls, 5);
EXPECT_EQ(state->shutdownShaderViewCalls, 5);
EXPECT_EQ(state->destroyShaderViewCalls, 5);
}
TEST(RenderResourceCacheTest, GetOrCreateGaussianSplatSupportsArtifactRuntimeLoadPath) {
@@ -459,8 +494,9 @@ TEST(RenderResourceCacheTest, GetOrCreateGaussianSplatSupportsArtifactRuntimeLoa
ASSERT_NE(cached, nullptr);
EXPECT_EQ(cached->residencyState, RenderResourceCache::GaussianSplatResidencyState::GpuReady);
EXPECT_EQ(cached->splatCount, 2u);
EXPECT_EQ(state->createBufferCalls, 4);
EXPECT_EQ(state->createShaderViewCalls, 4);
EXPECT_EQ(cached->chunkCount, 1u);
EXPECT_EQ(state->createBufferCalls, 5);
EXPECT_EQ(state->createShaderViewCalls, 5);
}
manager.UnloadAll();