Formalize gaussian splat prepare-order pass
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include "Rendering/FrameData/VisibleGaussianSplatItem.h"
|
||||
#include "Rendering/Internal/RenderSurfacePipelineUtils.h"
|
||||
#include "Rendering/Internal/ShaderVariantUtils.h"
|
||||
#include "Rendering/Passes/Internal/BuiltinGaussianSplatPassResources.h"
|
||||
#include "Rendering/RenderSurface.h"
|
||||
#include "Resources/BuiltinResources.h"
|
||||
#include "Resources/GaussianSplat/GaussianSplat.h"
|
||||
@@ -49,6 +50,21 @@ const Resources::ShaderPass* FindCompatibleGaussianSplatPass(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Resources::ShaderPass* FindCompatibleComputePass(
|
||||
const Resources::Shader& shader,
|
||||
const Containers::String& passName,
|
||||
const Resources::ShaderKeywordSet& keywordSet,
|
||||
Resources::ShaderBackend backend) {
|
||||
const Resources::ShaderPass* shaderPass = shader.FindPass(passName);
|
||||
if (shaderPass == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shader.FindVariant(passName, Resources::ShaderType::Compute, backend, keywordSet) != nullptr
|
||||
? shaderPass
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
RHI::GraphicsPipelineDesc CreatePipelineDesc(
|
||||
RHI::RHIType backendType,
|
||||
RHI::RHIPipelineLayout* pipelineLayout,
|
||||
@@ -89,6 +105,88 @@ RHI::GraphicsPipelineDesc CreatePipelineDesc(
|
||||
return pipelineDesc;
|
||||
}
|
||||
|
||||
RHI::ComputePipelineDesc CreateComputePipelineDesc(
|
||||
RHI::RHIType backendType,
|
||||
RHI::RHIPipelineLayout* pipelineLayout,
|
||||
const Resources::Shader& shader,
|
||||
const Resources::ShaderPass& shaderPass,
|
||||
const Containers::String& passName,
|
||||
const Resources::ShaderKeywordSet& keywordSet) {
|
||||
RHI::ComputePipelineDesc pipelineDesc = {};
|
||||
pipelineDesc.pipelineLayout = pipelineLayout;
|
||||
|
||||
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Internal::ToShaderBackend(backendType);
|
||||
if (const Resources::ShaderStageVariant* computeVariant =
|
||||
shader.FindVariant(passName, Resources::ShaderType::Compute, backend, keywordSet)) {
|
||||
::XCEngine::Rendering::Internal::ApplyShaderStageVariant(
|
||||
shader.GetPath(),
|
||||
shaderPass,
|
||||
backend,
|
||||
*computeVariant,
|
||||
pipelineDesc.computeShader);
|
||||
}
|
||||
|
||||
return pipelineDesc;
|
||||
}
|
||||
|
||||
const RHI::DescriptorSetLayoutBinding* FindSetLayoutBinding(
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
Core::uint32 binding) {
|
||||
for (const RHI::DescriptorSetLayoutBinding& layoutBinding : setLayout.bindings) {
|
||||
if (layoutBinding.binding == binding) {
|
||||
return &layoutBinding;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RHI::RHIResourceView* ResolveWorkingSetView(
|
||||
const Internal::BuiltinGaussianSplatPassResources::CachedBufferView& bufferView,
|
||||
const RHI::DescriptorSetLayoutBinding* layoutBinding) {
|
||||
if (layoutBinding == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
switch (static_cast<RHI::DescriptorType>(layoutBinding->type)) {
|
||||
case RHI::DescriptorType::UAV:
|
||||
return bufferView.unorderedAccessView;
|
||||
case RHI::DescriptorType::SRV:
|
||||
return bufferView.shaderResourceView;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BindFn>
|
||||
void BindDescriptorSetRanges(
|
||||
Core::uint32 firstDescriptorSet,
|
||||
std::vector<RHI::RHIDescriptorSet*>& descriptorSets,
|
||||
BindFn&& bindFn) {
|
||||
const Core::uint32 descriptorSetCount = static_cast<Core::uint32>(descriptorSets.size());
|
||||
Core::uint32 rangeStart = 0u;
|
||||
while (rangeStart < descriptorSetCount) {
|
||||
while (rangeStart < descriptorSetCount && descriptorSets[rangeStart] == nullptr) {
|
||||
++rangeStart;
|
||||
}
|
||||
if (rangeStart >= descriptorSetCount) {
|
||||
break;
|
||||
}
|
||||
|
||||
Core::uint32 rangeCount = 0u;
|
||||
while ((rangeStart + rangeCount) < descriptorSetCount &&
|
||||
descriptorSets[rangeStart + rangeCount] != nullptr) {
|
||||
++rangeCount;
|
||||
}
|
||||
|
||||
bindFn(
|
||||
firstDescriptorSet + rangeStart,
|
||||
rangeCount,
|
||||
descriptorSets.data() + rangeStart);
|
||||
rangeStart += rangeCount;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BuiltinGaussianSplatPass::~BuiltinGaussianSplatPass() {
|
||||
@@ -124,6 +222,19 @@ bool BuiltinGaussianSplatPass::PrepareGaussianSplatResources(
|
||||
cachedGaussianSplat->color.shaderResourceView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_passResources == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Internal::BuiltinGaussianSplatPassResources::WorkingSet* workingSet = nullptr;
|
||||
if (!m_passResources->EnsureWorkingSet(m_device, visibleGaussianSplat, workingSet) ||
|
||||
workingSet == nullptr ||
|
||||
workingSet->sortDistances.unorderedAccessView == nullptr ||
|
||||
workingSet->orderIndices.shaderResourceView == nullptr ||
|
||||
workingSet->orderIndices.unorderedAccessView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -177,6 +288,13 @@ bool BuiltinGaussianSplatPass::Execute(const RenderPassContext& context) {
|
||||
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
|
||||
|
||||
for (const VisibleGaussianSplatItem& visibleGaussianSplat : context.sceneData.visibleGaussianSplats) {
|
||||
if (!PrepareVisibleGaussianSplat(
|
||||
context.renderContext,
|
||||
context.sceneData,
|
||||
visibleGaussianSplat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DrawVisibleGaussianSplat(
|
||||
context.renderContext,
|
||||
context.surface,
|
||||
@@ -222,6 +340,16 @@ bool BuiltinGaussianSplatPass::CreateResources(const RenderContext& context) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_builtinGaussianSplatUtilitiesShader = Resources::ResourceManager::Get().Load<Resources::Shader>(
|
||||
Resources::GetBuiltinGaussianSplatUtilitiesShaderPath());
|
||||
if (!m_builtinGaussianSplatUtilitiesShader.IsValid()) {
|
||||
Debug::Logger::Get().Error(
|
||||
Debug::LogCategory::Rendering,
|
||||
"BuiltinGaussianSplatPass failed to load builtin gaussian splat utilities shader resource");
|
||||
DestroyResources();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_builtinGaussianSplatMaterial = std::make_unique<Resources::Material>();
|
||||
Resources::IResource::ConstructParams params = {};
|
||||
params.name = "BuiltinGaussianSplatMaterial";
|
||||
@@ -230,10 +358,17 @@ bool BuiltinGaussianSplatPass::CreateResources(const RenderContext& context) {
|
||||
m_builtinGaussianSplatMaterial->Initialize(params);
|
||||
m_builtinGaussianSplatMaterial->SetShader(m_builtinGaussianSplatShader);
|
||||
m_builtinGaussianSplatMaterial->SetRenderQueue(Resources::MaterialRenderQueue::Transparent);
|
||||
m_passResources = new Internal::BuiltinGaussianSplatPassResources();
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuiltinGaussianSplatPass::DestroyResources() {
|
||||
if (m_passResources != nullptr) {
|
||||
m_passResources->Shutdown();
|
||||
delete m_passResources;
|
||||
m_passResources = nullptr;
|
||||
}
|
||||
|
||||
m_resourceCache.Shutdown();
|
||||
|
||||
for (auto& pipelinePair : m_pipelineStates) {
|
||||
@@ -244,6 +379,14 @@ void BuiltinGaussianSplatPass::DestroyResources() {
|
||||
}
|
||||
m_pipelineStates.clear();
|
||||
|
||||
for (auto& pipelinePair : m_computePipelineStates) {
|
||||
if (pipelinePair.second != nullptr) {
|
||||
pipelinePair.second->Shutdown();
|
||||
delete pipelinePair.second;
|
||||
}
|
||||
}
|
||||
m_computePipelineStates.clear();
|
||||
|
||||
for (auto& descriptorSetPair : m_dynamicDescriptorSets) {
|
||||
DestroyOwnedDescriptorSet(descriptorSetPair.second.descriptorSet);
|
||||
}
|
||||
@@ -255,6 +398,7 @@ void BuiltinGaussianSplatPass::DestroyResources() {
|
||||
m_passResourceLayouts.clear();
|
||||
|
||||
m_builtinGaussianSplatMaterial.reset();
|
||||
m_builtinGaussianSplatUtilitiesShader.Reset();
|
||||
m_builtinGaussianSplatShader.Reset();
|
||||
m_device = nullptr;
|
||||
m_backendType = RHI::RHIType::D3D12;
|
||||
@@ -301,9 +445,30 @@ BuiltinGaussianSplatPass::ResolvedShaderPass BuiltinGaussianSplatPass::ResolveGa
|
||||
return resolved;
|
||||
}
|
||||
|
||||
BuiltinGaussianSplatPass::ResolvedShaderPass BuiltinGaussianSplatPass::ResolvePrepareOrderShaderPass(
|
||||
const RenderSceneData& sceneData) const {
|
||||
ResolvedShaderPass resolved = {};
|
||||
if (!m_builtinGaussianSplatUtilitiesShader.IsValid()) {
|
||||
return resolved;
|
||||
}
|
||||
|
||||
const Resources::Shader* shader = m_builtinGaussianSplatUtilitiesShader.Get();
|
||||
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Internal::ToShaderBackend(m_backendType);
|
||||
const Containers::String passName("GaussianSplatPrepareOrder");
|
||||
if (const Resources::ShaderPass* shaderPass =
|
||||
FindCompatibleComputePass(*shader, passName, sceneData.globalShaderKeywords, backend)) {
|
||||
resolved.shader = shader;
|
||||
resolved.pass = shaderPass;
|
||||
resolved.passName = passName;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
BuiltinGaussianSplatPass::PassResourceLayout* BuiltinGaussianSplatPass::GetOrCreatePassResourceLayout(
|
||||
const RenderContext& context,
|
||||
const ResolvedShaderPass& resolvedShaderPass) {
|
||||
const ResolvedShaderPass& resolvedShaderPass,
|
||||
PassLayoutUsage usage) {
|
||||
if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -345,21 +510,36 @@ BuiltinGaussianSplatPass::PassResourceLayout* BuiltinGaussianSplatPass::GetOrCre
|
||||
passLayout.descriptorSetCount = bindingPlan.descriptorSetCount;
|
||||
passLayout.perObject = bindingPlan.perObject;
|
||||
passLayout.material = bindingPlan.material;
|
||||
passLayout.gaussianSplatSortDistanceBuffer = bindingPlan.gaussianSplatSortDistanceBuffer;
|
||||
passLayout.gaussianSplatOrderBuffer = bindingPlan.gaussianSplatOrderBuffer;
|
||||
passLayout.gaussianSplatPositionBuffer = bindingPlan.gaussianSplatPositionBuffer;
|
||||
passLayout.gaussianSplatOtherBuffer = bindingPlan.gaussianSplatOtherBuffer;
|
||||
passLayout.gaussianSplatColorBuffer = bindingPlan.gaussianSplatColorBuffer;
|
||||
passLayout.gaussianSplatSHBuffer = bindingPlan.gaussianSplatSHBuffer;
|
||||
passLayout.gaussianSplatViewDataBuffer = bindingPlan.gaussianSplatViewDataBuffer;
|
||||
|
||||
if (!passLayout.perObject.IsValid()) {
|
||||
return failLayout("BuiltinGaussianSplatPass requires a PerObject resource binding");
|
||||
}
|
||||
if (!passLayout.material.IsValid()) {
|
||||
return failLayout("BuiltinGaussianSplatPass requires a Material resource binding");
|
||||
}
|
||||
if (!passLayout.gaussianSplatPositionBuffer.IsValid() ||
|
||||
!passLayout.gaussianSplatOtherBuffer.IsValid() ||
|
||||
!passLayout.gaussianSplatColorBuffer.IsValid()) {
|
||||
return failLayout("BuiltinGaussianSplatPass requires position, other, and color gaussian splat buffer bindings");
|
||||
|
||||
if (usage == PassLayoutUsage::Draw) {
|
||||
if (!passLayout.material.IsValid()) {
|
||||
return failLayout("BuiltinGaussianSplatPass requires a Material resource binding");
|
||||
}
|
||||
if (!passLayout.gaussianSplatOrderBuffer.IsValid() ||
|
||||
!passLayout.gaussianSplatPositionBuffer.IsValid() ||
|
||||
!passLayout.gaussianSplatOtherBuffer.IsValid() ||
|
||||
!passLayout.gaussianSplatColorBuffer.IsValid()) {
|
||||
return failLayout(
|
||||
"BuiltinGaussianSplatPass draw pass requires order, position, other, and color gaussian splat buffer bindings");
|
||||
}
|
||||
} else if (usage == PassLayoutUsage::PrepareOrder) {
|
||||
if (!passLayout.gaussianSplatSortDistanceBuffer.IsValid() ||
|
||||
!passLayout.gaussianSplatOrderBuffer.IsValid() ||
|
||||
!passLayout.gaussianSplatPositionBuffer.IsValid()) {
|
||||
return failLayout(
|
||||
"BuiltinGaussianSplatPass prepare-order pass requires sort distance, order, and position gaussian splat buffer bindings");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<RHI::DescriptorSetLayoutDesc> nativeSetLayouts(passLayout.setLayouts.size());
|
||||
@@ -392,7 +572,10 @@ RHI::RHIPipelineState* BuiltinGaussianSplatPass::GetOrCreatePipelineState(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PassResourceLayout* passLayout = GetOrCreatePassResourceLayout(context, resolvedShaderPass);
|
||||
PassResourceLayout* passLayout = GetOrCreatePassResourceLayout(
|
||||
context,
|
||||
resolvedShaderPass,
|
||||
PassLayoutUsage::Draw);
|
||||
if (passLayout == nullptr || passLayout->pipelineLayout == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -440,6 +623,54 @@ RHI::RHIPipelineState* BuiltinGaussianSplatPass::GetOrCreatePipelineState(
|
||||
return pipelineState;
|
||||
}
|
||||
|
||||
RHI::RHIPipelineState* BuiltinGaussianSplatPass::GetOrCreateComputePipelineState(
|
||||
const RenderContext& context,
|
||||
const RenderSceneData& sceneData) {
|
||||
const ResolvedShaderPass resolvedShaderPass = ResolvePrepareOrderShaderPass(sceneData);
|
||||
if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PassResourceLayout* passLayout = GetOrCreatePassResourceLayout(
|
||||
context,
|
||||
resolvedShaderPass,
|
||||
PassLayoutUsage::PrepareOrder);
|
||||
if (passLayout == nullptr || passLayout->pipelineLayout == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ComputePipelineKey pipelineKey = {};
|
||||
pipelineKey.shader = resolvedShaderPass.shader;
|
||||
pipelineKey.passName = resolvedShaderPass.passName;
|
||||
pipelineKey.keywordSignature =
|
||||
::XCEngine::Rendering::Internal::BuildShaderKeywordSignature(sceneData.globalShaderKeywords);
|
||||
|
||||
const auto existing = m_computePipelineStates.find(pipelineKey);
|
||||
if (existing != m_computePipelineStates.end()) {
|
||||
return existing->second;
|
||||
}
|
||||
|
||||
const RHI::ComputePipelineDesc pipelineDesc =
|
||||
CreateComputePipelineDesc(
|
||||
context.backendType,
|
||||
passLayout->pipelineLayout,
|
||||
*resolvedShaderPass.shader,
|
||||
*resolvedShaderPass.pass,
|
||||
resolvedShaderPass.passName,
|
||||
sceneData.globalShaderKeywords);
|
||||
RHI::RHIPipelineState* pipelineState = context.device->CreateComputePipelineState(pipelineDesc);
|
||||
if (pipelineState == nullptr || !pipelineState->IsValid()) {
|
||||
if (pipelineState != nullptr) {
|
||||
pipelineState->Shutdown();
|
||||
delete pipelineState;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_computePipelineStates.emplace(pipelineKey, pipelineState);
|
||||
return pipelineState;
|
||||
}
|
||||
|
||||
bool BuiltinGaussianSplatPass::CreateOwnedDescriptorSet(
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
OwnedDescriptorSet& descriptorSet) {
|
||||
@@ -468,14 +699,19 @@ BuiltinGaussianSplatPass::CachedDescriptorSet* BuiltinGaussianSplatPass::GetOrCr
|
||||
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||
Core::uint32 setIndex,
|
||||
Core::uint64 objectId,
|
||||
const Components::GaussianSplatRendererComponent* gaussianSplatRenderer,
|
||||
const Resources::Material* material,
|
||||
const Resources::GaussianSplat* gaussianSplat,
|
||||
const MaterialConstantPayloadView& materialConstants,
|
||||
const RenderResourceCache::CachedGaussianSplat& cachedGaussianSplat) {
|
||||
const RenderResourceCache::CachedGaussianSplat& cachedGaussianSplat,
|
||||
RHI::RHIResourceView* sortDistanceView,
|
||||
RHI::RHIResourceView* orderView,
|
||||
RHI::RHIResourceView* viewDataView) {
|
||||
DynamicDescriptorSetKey key = {};
|
||||
key.passLayout = passLayoutKey;
|
||||
key.setIndex = setIndex;
|
||||
key.objectId = objectId;
|
||||
key.gaussianSplatRenderer = gaussianSplatRenderer;
|
||||
key.material = material;
|
||||
key.gaussianSplat = gaussianSplat;
|
||||
|
||||
@@ -486,6 +722,41 @@ BuiltinGaussianSplatPass::CachedDescriptorSet* BuiltinGaussianSplatPass::GetOrCr
|
||||
}
|
||||
}
|
||||
|
||||
const Internal::BuiltinGaussianSplatPassResources::WorkingSet* workingSet =
|
||||
(gaussianSplatRenderer != nullptr && m_passResources != nullptr)
|
||||
? m_passResources->FindWorkingSet(gaussianSplatRenderer)
|
||||
: nullptr;
|
||||
RHI::RHIResourceView* resolvedSortDistanceView = sortDistanceView;
|
||||
RHI::RHIResourceView* resolvedOrderView = orderView;
|
||||
RHI::RHIResourceView* resolvedViewDataView = viewDataView;
|
||||
|
||||
if (setLayout.usesGaussianSplatSortDistanceBuffer && workingSet != nullptr) {
|
||||
if (const RHI::DescriptorSetLayoutBinding* layoutBinding =
|
||||
FindSetLayoutBinding(setLayout, passLayout.gaussianSplatSortDistanceBuffer.binding)) {
|
||||
if (RHI::RHIResourceView* view = ResolveWorkingSetView(workingSet->sortDistances, layoutBinding)) {
|
||||
resolvedSortDistanceView = view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesGaussianSplatOrderBuffer && workingSet != nullptr) {
|
||||
if (const RHI::DescriptorSetLayoutBinding* layoutBinding =
|
||||
FindSetLayoutBinding(setLayout, passLayout.gaussianSplatOrderBuffer.binding)) {
|
||||
if (RHI::RHIResourceView* view = ResolveWorkingSetView(workingSet->orderIndices, layoutBinding)) {
|
||||
resolvedOrderView = view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesGaussianSplatViewDataBuffer && workingSet != nullptr) {
|
||||
if (const RHI::DescriptorSetLayoutBinding* layoutBinding =
|
||||
FindSetLayoutBinding(setLayout, passLayout.gaussianSplatViewDataBuffer.binding)) {
|
||||
if (RHI::RHIResourceView* view = ResolveWorkingSetView(workingSet->viewData, layoutBinding)) {
|
||||
resolvedViewDataView = view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Core::uint64 materialVersion = material != nullptr ? material->GetChangeVersion() : 0u;
|
||||
if (setLayout.usesMaterial) {
|
||||
if (!passLayout.material.IsValid() ||
|
||||
@@ -516,6 +787,34 @@ BuiltinGaussianSplatPass::CachedDescriptorSet* BuiltinGaussianSplatPass::GetOrCr
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesGaussianSplatSortDistanceBuffer) {
|
||||
if (resolvedSortDistanceView == nullptr ||
|
||||
!passLayout.gaussianSplatSortDistanceBuffer.IsValid() ||
|
||||
passLayout.gaussianSplatSortDistanceBuffer.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (cachedDescriptorSet.sortDistanceView != resolvedSortDistanceView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.gaussianSplatSortDistanceBuffer.binding,
|
||||
resolvedSortDistanceView);
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesGaussianSplatOrderBuffer) {
|
||||
if (resolvedOrderView == nullptr ||
|
||||
!passLayout.gaussianSplatOrderBuffer.IsValid() ||
|
||||
passLayout.gaussianSplatOrderBuffer.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (cachedDescriptorSet.orderView != resolvedOrderView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.gaussianSplatOrderBuffer.binding,
|
||||
resolvedOrderView);
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesGaussianSplatOtherBuffer) {
|
||||
if (cachedGaussianSplat.other.shaderResourceView == nullptr ||
|
||||
!passLayout.gaussianSplatOtherBuffer.IsValid() ||
|
||||
@@ -558,11 +857,28 @@ BuiltinGaussianSplatPass::CachedDescriptorSet* BuiltinGaussianSplatPass::GetOrCr
|
||||
}
|
||||
}
|
||||
|
||||
if (setLayout.usesGaussianSplatViewDataBuffer) {
|
||||
if (resolvedViewDataView == nullptr ||
|
||||
!passLayout.gaussianSplatViewDataBuffer.IsValid() ||
|
||||
passLayout.gaussianSplatViewDataBuffer.set != setIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (cachedDescriptorSet.viewDataView != resolvedViewDataView) {
|
||||
cachedDescriptorSet.descriptorSet.set->Update(
|
||||
passLayout.gaussianSplatViewDataBuffer.binding,
|
||||
resolvedViewDataView);
|
||||
}
|
||||
}
|
||||
|
||||
cachedDescriptorSet.materialVersion = materialVersion;
|
||||
cachedDescriptorSet.sortDistanceView = resolvedSortDistanceView;
|
||||
cachedDescriptorSet.orderView = resolvedOrderView;
|
||||
cachedDescriptorSet.positionsView = cachedGaussianSplat.positions.shaderResourceView;
|
||||
cachedDescriptorSet.otherView = cachedGaussianSplat.other.shaderResourceView;
|
||||
cachedDescriptorSet.colorView = cachedGaussianSplat.color.shaderResourceView;
|
||||
cachedDescriptorSet.shView = cachedGaussianSplat.sh.shaderResourceView;
|
||||
cachedDescriptorSet.viewDataView = resolvedViewDataView;
|
||||
return &cachedDescriptorSet;
|
||||
}
|
||||
|
||||
@@ -592,10 +908,169 @@ void BuiltinGaussianSplatPass::DestroyPassResourceLayout(PassResourceLayout& pas
|
||||
passLayout.descriptorSetCount = 0;
|
||||
passLayout.perObject = {};
|
||||
passLayout.material = {};
|
||||
passLayout.gaussianSplatSortDistanceBuffer = {};
|
||||
passLayout.gaussianSplatOrderBuffer = {};
|
||||
passLayout.gaussianSplatPositionBuffer = {};
|
||||
passLayout.gaussianSplatOtherBuffer = {};
|
||||
passLayout.gaussianSplatColorBuffer = {};
|
||||
passLayout.gaussianSplatSHBuffer = {};
|
||||
passLayout.gaussianSplatViewDataBuffer = {};
|
||||
}
|
||||
|
||||
bool BuiltinGaussianSplatPass::PrepareVisibleGaussianSplat(
|
||||
const RenderContext& context,
|
||||
const RenderSceneData& sceneData,
|
||||
const VisibleGaussianSplatItem& visibleGaussianSplat) {
|
||||
if (visibleGaussianSplat.gameObject == nullptr ||
|
||||
visibleGaussianSplat.gaussianSplat == nullptr ||
|
||||
!visibleGaussianSplat.gaussianSplat->IsValid() ||
|
||||
m_passResources == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RenderResourceCache::CachedGaussianSplat* cachedGaussianSplat =
|
||||
m_resourceCache.GetOrCreateGaussianSplat(m_device, visibleGaussianSplat.gaussianSplat);
|
||||
if (cachedGaussianSplat == nullptr || cachedGaussianSplat->positions.shaderResourceView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Internal::BuiltinGaussianSplatPassResources::WorkingSet* workingSet = nullptr;
|
||||
if (!m_passResources->EnsureWorkingSet(m_device, visibleGaussianSplat, workingSet) ||
|
||||
workingSet == nullptr ||
|
||||
workingSet->sortDistances.unorderedAccessView == nullptr ||
|
||||
workingSet->orderIndices.unorderedAccessView == nullptr ||
|
||||
workingSet->orderIndices.shaderResourceView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ResolvedShaderPass resolvedShaderPass = ResolvePrepareOrderShaderPass(sceneData);
|
||||
if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PassLayoutKey passLayoutKey = {};
|
||||
passLayoutKey.shader = resolvedShaderPass.shader;
|
||||
passLayoutKey.passName = resolvedShaderPass.passName;
|
||||
|
||||
PassResourceLayout* passLayout = GetOrCreatePassResourceLayout(
|
||||
context,
|
||||
resolvedShaderPass,
|
||||
PassLayoutUsage::PrepareOrder);
|
||||
RHI::RHIPipelineState* pipelineState = GetOrCreateComputePipelineState(context, sceneData);
|
||||
if (passLayout == nullptr || pipelineState == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHICommandList* commandList = context.commandList;
|
||||
|
||||
if (workingSet->sortDistances.currentState != RHI::ResourceStates::UnorderedAccess) {
|
||||
commandList->TransitionBarrier(
|
||||
workingSet->sortDistances.unorderedAccessView,
|
||||
workingSet->sortDistances.currentState,
|
||||
RHI::ResourceStates::UnorderedAccess);
|
||||
workingSet->sortDistances.currentState = RHI::ResourceStates::UnorderedAccess;
|
||||
}
|
||||
|
||||
if (workingSet->orderIndices.currentState != RHI::ResourceStates::UnorderedAccess) {
|
||||
commandList->TransitionBarrier(
|
||||
workingSet->orderIndices.unorderedAccessView,
|
||||
workingSet->orderIndices.currentState,
|
||||
RHI::ResourceStates::UnorderedAccess);
|
||||
workingSet->orderIndices.currentState = RHI::ResourceStates::UnorderedAccess;
|
||||
}
|
||||
|
||||
commandList->SetPipelineState(pipelineState);
|
||||
|
||||
const PerObjectConstants perObjectConstants = {
|
||||
sceneData.cameraData.projection,
|
||||
sceneData.cameraData.view,
|
||||
visibleGaussianSplat.localToWorld.Transpose(),
|
||||
Math::Vector4(sceneData.cameraData.worldRight, 0.0f),
|
||||
Math::Vector4(sceneData.cameraData.worldUp, 0.0f)
|
||||
};
|
||||
|
||||
if (passLayout->descriptorSetCount > 0u) {
|
||||
std::vector<RHI::RHIDescriptorSet*> descriptorSets(passLayout->descriptorSetCount, nullptr);
|
||||
for (Core::uint32 descriptorOffset = 0u; descriptorOffset < passLayout->descriptorSetCount; ++descriptorOffset) {
|
||||
const Core::uint32 setIndex = passLayout->firstDescriptorSet + descriptorOffset;
|
||||
if (setIndex >= passLayout->setLayouts.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const BuiltinPassSetLayoutMetadata& setLayout = passLayout->setLayouts[setIndex];
|
||||
if (setLayout.layout.bindingCount == 0u) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(setLayout.usesPerObject ||
|
||||
setLayout.usesGaussianSplatSortDistanceBuffer ||
|
||||
setLayout.usesGaussianSplatOrderBuffer ||
|
||||
setLayout.usesGaussianSplatPositionBuffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Core::uint64 objectId =
|
||||
setLayout.usesPerObject ? visibleGaussianSplat.gameObject->GetID() : 0u;
|
||||
const Resources::GaussianSplat* gaussianSplatKey =
|
||||
(setLayout.usesGaussianSplatSortDistanceBuffer ||
|
||||
setLayout.usesGaussianSplatOrderBuffer ||
|
||||
setLayout.usesGaussianSplatPositionBuffer)
|
||||
? visibleGaussianSplat.gaussianSplat
|
||||
: nullptr;
|
||||
|
||||
CachedDescriptorSet* cachedDescriptorSet = GetOrCreateDynamicDescriptorSet(
|
||||
passLayoutKey,
|
||||
*passLayout,
|
||||
setLayout,
|
||||
setIndex,
|
||||
objectId,
|
||||
visibleGaussianSplat.gaussianSplatRenderer,
|
||||
nullptr,
|
||||
gaussianSplatKey,
|
||||
MaterialConstantPayloadView(),
|
||||
*cachedGaussianSplat,
|
||||
workingSet->sortDistances.unorderedAccessView,
|
||||
workingSet->orderIndices.unorderedAccessView,
|
||||
workingSet->viewData.unorderedAccessView);
|
||||
if (cachedDescriptorSet == nullptr || cachedDescriptorSet->descriptorSet.set == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RHI::RHIDescriptorSet* descriptorSet = cachedDescriptorSet->descriptorSet.set;
|
||||
if (setLayout.usesPerObject) {
|
||||
if (!passLayout->perObject.IsValid() || passLayout->perObject.set != setIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
descriptorSet->WriteConstant(
|
||||
passLayout->perObject.binding,
|
||||
&perObjectConstants,
|
||||
sizeof(perObjectConstants));
|
||||
}
|
||||
|
||||
descriptorSets[descriptorOffset] = descriptorSet;
|
||||
}
|
||||
|
||||
BindDescriptorSetRanges(
|
||||
passLayout->firstDescriptorSet,
|
||||
descriptorSets,
|
||||
[commandList, passLayout](Core::uint32 firstSet, Core::uint32 count, RHI::RHIDescriptorSet** sets) {
|
||||
commandList->SetComputeDescriptorSets(
|
||||
firstSet,
|
||||
count,
|
||||
sets,
|
||||
passLayout->pipelineLayout);
|
||||
});
|
||||
}
|
||||
|
||||
commandList->Dispatch((cachedGaussianSplat->splatCount + 63u) / 64u, 1u, 1u);
|
||||
|
||||
commandList->TransitionBarrier(
|
||||
workingSet->orderIndices.shaderResourceView,
|
||||
RHI::ResourceStates::UnorderedAccess,
|
||||
RHI::ResourceStates::NonPixelShaderResource);
|
||||
workingSet->orderIndices.currentState = RHI::ResourceStates::NonPixelShaderResource;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuiltinGaussianSplatPass::DrawVisibleGaussianSplat(
|
||||
@@ -618,6 +1093,17 @@ bool BuiltinGaussianSplatPass::DrawVisibleGaussianSplat(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_passResources == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Internal::BuiltinGaussianSplatPassResources::WorkingSet* workingSet = nullptr;
|
||||
if (!m_passResources->EnsureWorkingSet(m_device, visibleGaussianSplat, workingSet) ||
|
||||
workingSet == nullptr ||
|
||||
workingSet->orderIndices.shaderResourceView == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Resources::Material* material = ResolveGaussianSplatMaterial(visibleGaussianSplat);
|
||||
if (material == nullptr) {
|
||||
return false;
|
||||
@@ -632,7 +1118,10 @@ bool BuiltinGaussianSplatPass::DrawVisibleGaussianSplat(
|
||||
passLayoutKey.shader = resolvedShaderPass.shader;
|
||||
passLayoutKey.passName = resolvedShaderPass.passName;
|
||||
|
||||
PassResourceLayout* passLayout = GetOrCreatePassResourceLayout(context, resolvedShaderPass);
|
||||
PassResourceLayout* passLayout = GetOrCreatePassResourceLayout(
|
||||
context,
|
||||
resolvedShaderPass,
|
||||
PassLayoutUsage::Draw);
|
||||
RHI::RHIPipelineState* pipelineState = GetOrCreatePipelineState(context, surface, sceneData, material);
|
||||
if (passLayout == nullptr || pipelineState == nullptr) {
|
||||
return false;
|
||||
@@ -663,8 +1152,13 @@ bool BuiltinGaussianSplatPass::DrawVisibleGaussianSplat(
|
||||
}
|
||||
|
||||
const BuiltinPassSetLayoutMetadata& setLayout = passLayout->setLayouts[setIndex];
|
||||
if (setLayout.layout.bindingCount == 0u) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(setLayout.usesPerObject ||
|
||||
setLayout.usesMaterial ||
|
||||
setLayout.usesGaussianSplatOrderBuffer ||
|
||||
setLayout.usesGaussianSplatPositionBuffer ||
|
||||
setLayout.usesGaussianSplatOtherBuffer ||
|
||||
setLayout.usesGaussianSplatColorBuffer ||
|
||||
@@ -677,7 +1171,8 @@ bool BuiltinGaussianSplatPass::DrawVisibleGaussianSplat(
|
||||
const Resources::Material* materialKey =
|
||||
setLayout.usesMaterial ? material : nullptr;
|
||||
const Resources::GaussianSplat* gaussianSplatKey =
|
||||
(setLayout.usesGaussianSplatPositionBuffer ||
|
||||
(setLayout.usesGaussianSplatOrderBuffer ||
|
||||
setLayout.usesGaussianSplatPositionBuffer ||
|
||||
setLayout.usesGaussianSplatOtherBuffer ||
|
||||
setLayout.usesGaussianSplatColorBuffer ||
|
||||
setLayout.usesGaussianSplatSHBuffer)
|
||||
@@ -690,10 +1185,14 @@ bool BuiltinGaussianSplatPass::DrawVisibleGaussianSplat(
|
||||
setLayout,
|
||||
setIndex,
|
||||
objectId,
|
||||
visibleGaussianSplat.gaussianSplatRenderer,
|
||||
materialKey,
|
||||
gaussianSplatKey,
|
||||
materialConstants,
|
||||
*cachedGaussianSplat);
|
||||
*cachedGaussianSplat,
|
||||
nullptr,
|
||||
workingSet->orderIndices.shaderResourceView,
|
||||
workingSet->viewData.shaderResourceView);
|
||||
if (cachedDescriptorSet == nullptr || cachedDescriptorSet->descriptorSet.set == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -713,11 +1212,16 @@ bool BuiltinGaussianSplatPass::DrawVisibleGaussianSplat(
|
||||
descriptorSets[descriptorOffset] = descriptorSet;
|
||||
}
|
||||
|
||||
commandList->SetGraphicsDescriptorSets(
|
||||
BindDescriptorSetRanges(
|
||||
passLayout->firstDescriptorSet,
|
||||
passLayout->descriptorSetCount,
|
||||
descriptorSets.data(),
|
||||
passLayout->pipelineLayout);
|
||||
descriptorSets,
|
||||
[commandList, passLayout](Core::uint32 firstSet, Core::uint32 count, RHI::RHIDescriptorSet** sets) {
|
||||
commandList->SetGraphicsDescriptorSets(
|
||||
firstSet,
|
||||
count,
|
||||
sets,
|
||||
passLayout->pipelineLayout);
|
||||
});
|
||||
}
|
||||
|
||||
ApplyDynamicRenderState(ResolveEffectiveRenderState(resolvedShaderPass.pass, material), *commandList);
|
||||
|
||||
Reference in New Issue
Block a user