Add GPU sorting for gaussian splat rendering
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user