Add GPU sorting for gaussian splat rendering

This commit is contained in:
2026-04-11 06:09:53 +08:00
parent 39632e1a04
commit 5200fca82f
7 changed files with 529 additions and 49 deletions

View File

@@ -1,6 +1,7 @@
#include "Rendering/Passes/Internal/BuiltinGaussianSplatPassResources.h"
#include "Components/GaussianSplatRendererComponent.h"
#include "Debug/Logger.h"
#include "Resources/GaussianSplat/GaussianSplat.h"
namespace XCEngine {
@@ -16,6 +17,9 @@ bool CreateStructuredBufferViews(
Core::uint32 elementStride,
BuiltinGaussianSplatPassResources::CachedBufferView& bufferView) {
if (device == nullptr || elementCount == 0u || elementStride == 0u) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::CreateStructuredBufferViews failed: invalid parameters");
return false;
}
@@ -23,10 +27,13 @@ bool CreateStructuredBufferViews(
bufferDesc.size = static_cast<Core::uint64>(elementCount) * static_cast<Core::uint64>(elementStride);
bufferDesc.stride = elementStride;
bufferDesc.bufferType = static_cast<uint32_t>(RHI::BufferType::Storage);
bufferDesc.flags = 0u;
bufferDesc.flags = static_cast<Core::uint64>(RHI::BufferFlags::AllowUnorderedAccess);
bufferView.buffer = device->CreateBuffer(bufferDesc);
if (bufferView.buffer == nullptr) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::CreateStructuredBufferViews failed: CreateBuffer returned null");
return false;
}
@@ -42,11 +49,17 @@ bool CreateStructuredBufferViews(
bufferView.shaderResourceView = device->CreateShaderResourceView(bufferView.buffer, viewDesc);
if (bufferView.shaderResourceView == nullptr) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::CreateStructuredBufferViews failed: CreateShaderResourceView returned null");
return false;
}
bufferView.unorderedAccessView = device->CreateUnorderedAccessView(bufferView.buffer, viewDesc);
if (bufferView.unorderedAccessView == nullptr) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::CreateStructuredBufferViews failed: CreateUnorderedAccessView returned null");
return false;
}
@@ -71,15 +84,25 @@ bool BuiltinGaussianSplatPassResources::EnsureWorkingSet(
visibleGaussianSplat.gaussianSplatRenderer == nullptr ||
visibleGaussianSplat.gaussianSplat == nullptr ||
!visibleGaussianSplat.gaussianSplat->IsValid()) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::EnsureWorkingSet failed: invalid input");
return false;
}
const Core::uint32 splatCapacity = visibleGaussianSplat.gaussianSplat->GetSplatCount();
const Core::uint32 sortCapacity = ComputeSortCapacity(splatCapacity);
if (splatCapacity == 0u) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::EnsureWorkingSet failed: splat capacity is zero");
return false;
}
if (!ResetForDevice(device)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::EnsureWorkingSet failed: ResetForDevice returned false");
return false;
}
@@ -88,7 +111,10 @@ bool BuiltinGaussianSplatPassResources::EnsureWorkingSet(
DestroyBufferView(workingSet.sortDistances);
DestroyBufferView(workingSet.orderIndices);
DestroyBufferView(workingSet.viewData);
if (!RecreateWorkingSet(device, splatCapacity, workingSet)) {
if (!RecreateWorkingSet(device, splatCapacity, sortCapacity, workingSet)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::EnsureWorkingSet failed: RecreateWorkingSet returned false");
m_workingSets.erase(visibleGaussianSplat.gaussianSplatRenderer);
return false;
}
@@ -219,19 +245,49 @@ bool BuiltinGaussianSplatPassResources::ResetForDevice(RHI::RHIDevice* device) {
bool BuiltinGaussianSplatPassResources::RecreateWorkingSet(
RHI::RHIDevice* device,
Core::uint32 splatCapacity,
Core::uint32 sortCapacity,
WorkingSet& workingSet) {
if (!CreateStructuredBufferView(device, splatCapacity, kSortDistanceStride, workingSet.sortDistances) ||
!CreateStructuredBufferView(device, splatCapacity, kOrderIndexStride, workingSet.orderIndices) ||
!CreateStructuredBufferView(device, splatCapacity, kViewDataStride, workingSet.viewData)) {
if (!CreateStructuredBufferView(device, sortCapacity, kSortDistanceStride, workingSet.sortDistances)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::RecreateWorkingSet failed: sort-distance buffer view creation failed");
DestroyBufferView(workingSet.sortDistances);
DestroyBufferView(workingSet.orderIndices);
DestroyBufferView(workingSet.viewData);
workingSet.renderer = nullptr;
workingSet.splatCapacity = 0u;
workingSet.sortCapacity = 0u;
return false;
}
if (!CreateStructuredBufferView(device, sortCapacity, kOrderIndexStride, workingSet.orderIndices)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::RecreateWorkingSet failed: order-index buffer view creation failed");
DestroyBufferView(workingSet.sortDistances);
DestroyBufferView(workingSet.orderIndices);
DestroyBufferView(workingSet.viewData);
workingSet.renderer = nullptr;
workingSet.splatCapacity = 0u;
workingSet.sortCapacity = 0u;
return false;
}
if (!CreateStructuredBufferView(device, splatCapacity, kViewDataStride, workingSet.viewData)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinGaussianSplatPassResources::RecreateWorkingSet failed: view-data buffer view creation failed");
DestroyBufferView(workingSet.sortDistances);
DestroyBufferView(workingSet.orderIndices);
DestroyBufferView(workingSet.viewData);
workingSet.renderer = nullptr;
workingSet.splatCapacity = 0u;
workingSet.sortCapacity = 0u;
return false;
}
workingSet.splatCapacity = splatCapacity;
workingSet.sortCapacity = sortCapacity;
return true;
}
@@ -291,6 +347,18 @@ bool BuiltinGaussianSplatPassResources::RecreateAccumulationSurface(
return true;
}
Core::uint32 BuiltinGaussianSplatPassResources::ComputeSortCapacity(Core::uint32 splatCapacity) {
if (splatCapacity == 0u) {
return 0u;
}
Core::uint32 sortCapacity = 1u;
while (sortCapacity < splatCapacity && sortCapacity <= (0x80000000u >> 1u)) {
sortCapacity <<= 1u;
}
return sortCapacity < splatCapacity ? splatCapacity : sortCapacity;
}
} // namespace Internal
} // namespace Passes
} // namespace Rendering