From 18f3f9f22787bfc4ba170be01c4f62bd80e9f3b1 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Sun, 5 Apr 2026 20:44:21 +0800 Subject: [PATCH] Split builtin object id pass resources --- engine/CMakeLists.txt | 1 + .../Rendering/Passes/BuiltinObjectIdPass.cpp | 348 ----------------- .../Passes/BuiltinObjectIdPassResources.cpp | 365 ++++++++++++++++++ 3 files changed, 366 insertions(+), 348 deletions(-) create mode 100644 engine/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index caffefc2..61d5630e 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -464,6 +464,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinDepthOnlyPass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinShadowCasterPass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPass.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinInfiniteGridPass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdOutlinePass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderSurface.cpp diff --git a/engine/src/Rendering/Passes/BuiltinObjectIdPass.cpp b/engine/src/Rendering/Passes/BuiltinObjectIdPass.cpp index 6dd6bec4..fa23c742 100644 --- a/engine/src/Rendering/Passes/BuiltinObjectIdPass.cpp +++ b/engine/src/Rendering/Passes/BuiltinObjectIdPass.cpp @@ -1,16 +1,9 @@ #include "Rendering/Passes/BuiltinObjectIdPass.h" -#include "Components/GameObject.h" #include "Core/Asset/ResourceManager.h" -#include "Debug/Logger.h" #include "RHI/RHICommandList.h" -#include "RHI/RHIPipelineLayout.h" -#include "RHI/RHIPipelineState.h" -#include "Rendering/BuiltinPassLayoutUtils.h" -#include "Rendering/Detail/ShaderVariantUtils.h" #include "Rendering/RenderSceneExtractor.h" #include "Rendering/RenderSurface.h" -#include "Resources/BuiltinResources.h" #include "Resources/Mesh/Mesh.h" #include @@ -20,79 +13,6 @@ namespace XCEngine { namespace Rendering { namespace Passes { -namespace { - -const Resources::ShaderPass* FindObjectIdCompatiblePass( - const Resources::Shader& shader, - Resources::ShaderBackend backend) { - for (const Resources::ShaderPass& shaderPass : shader.GetPasses()) { - if (ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::ObjectId) && - ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, shaderPass.name, backend)) { - return &shaderPass; - } - } - - const Resources::ShaderPass* objectIdPass = shader.FindPass("ObjectId"); - if (objectIdPass != nullptr && - ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, objectIdPass->name, backend)) { - return objectIdPass; - } - - const Resources::ShaderPass* editorObjectIdPass = shader.FindPass("EditorObjectId"); - if (editorObjectIdPass != nullptr && - ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, editorObjectIdPass->name, backend)) { - return editorObjectIdPass; - } - - if (shader.GetPassCount() > 0 && - ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, shader.GetPasses()[0].name, backend)) { - return &shader.GetPasses()[0]; - } - - return nullptr; -} - -RHI::GraphicsPipelineDesc CreatePipelineDesc( - RHI::RHIType backendType, - RHI::RHIPipelineLayout* pipelineLayout, - const Resources::Shader& shader, - const Containers::String& passName) { - RHI::GraphicsPipelineDesc pipelineDesc = {}; - pipelineDesc.pipelineLayout = pipelineLayout; - pipelineDesc.topologyType = static_cast(RHI::PrimitiveTopologyType::Triangle); - pipelineDesc.renderTargetCount = 1; - pipelineDesc.renderTargetFormats[0] = static_cast(RHI::Format::R8G8B8A8_UNorm); - pipelineDesc.depthStencilFormat = static_cast(RHI::Format::D24_UNorm_S8_UInt); - pipelineDesc.sampleCount = 1; - pipelineDesc.inputLayout = BuiltinObjectIdPass::BuildInputLayout(); - - pipelineDesc.rasterizerState.fillMode = static_cast(RHI::FillMode::Solid); - pipelineDesc.rasterizerState.cullMode = static_cast(RHI::CullMode::None); - pipelineDesc.rasterizerState.frontFace = static_cast(RHI::FrontFace::CounterClockwise); - pipelineDesc.rasterizerState.depthClipEnable = true; - - pipelineDesc.blendState.blendEnable = false; - pipelineDesc.blendState.colorWriteMask = static_cast(RHI::ColorWriteMask::All); - - pipelineDesc.depthStencilState.depthTestEnable = true; - pipelineDesc.depthStencilState.depthWriteEnable = true; - pipelineDesc.depthStencilState.depthFunc = static_cast(RHI::ComparisonFunc::LessEqual); - - const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(backendType); - if (const Resources::ShaderStageVariant* vertexVariant = - shader.FindVariant(passName, Resources::ShaderType::Vertex, backend)) { - ::XCEngine::Rendering::Detail::ApplyShaderStageVariant(*vertexVariant, pipelineDesc.vertexShader); - } - if (const Resources::ShaderStageVariant* fragmentVariant = - shader.FindVariant(passName, Resources::ShaderType::Fragment, backend)) { - ::XCEngine::Rendering::Detail::ApplyShaderStageVariant(*fragmentVariant, pipelineDesc.fragmentShader); - } - - return pipelineDesc; -} - -} // namespace - BuiltinObjectIdPass::~BuiltinObjectIdPass() { Shutdown(); } @@ -212,274 +132,6 @@ void BuiltinObjectIdPass::Shutdown() { DestroyResources(); } -bool BuiltinObjectIdPass::EnsureInitialized(const RenderContext& context) { - if (!context.IsValid()) { - return false; - } - - if (m_pipelineLayout != nullptr && - m_pipelineState != nullptr && - m_device == context.device && - m_backendType == context.backendType) { - return true; - } - - DestroyResources(); - return CreateResources(context); -} - -bool BuiltinObjectIdPass::CreateResources(const RenderContext& context) { - m_device = context.device; - m_backendType = context.backendType; - m_builtinObjectIdShader = Resources::ResourceManager::Get().Load( - Resources::GetBuiltinObjectIdShaderPath()); - if (!m_builtinObjectIdShader.IsValid()) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - "BuiltinObjectIdPass failed to load builtin object-id shader resource"); - DestroyResources(); - return false; - } - - const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(m_backendType); - const Resources::ShaderPass* objectIdPass = - FindObjectIdCompatiblePass(*m_builtinObjectIdShader.Get(), backend); - if (objectIdPass == nullptr) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - "BuiltinObjectIdPass could not resolve a valid ObjectId shader pass"); - DestroyResources(); - return false; - } - - const Containers::Array& resourceBindings = objectIdPass->resources; - if (resourceBindings.Empty()) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - (Containers::String("BuiltinObjectIdPass requires explicit resource bindings on shader pass: ") + - objectIdPass->name).CStr()); - DestroyResources(); - return false; - } - - BuiltinPassResourceBindingPlan bindingPlan = {}; - Containers::String bindingPlanError; - if (!TryBuildBuiltinPassResourceBindingPlan(resourceBindings, bindingPlan, &bindingPlanError)) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - (Containers::String("BuiltinObjectIdPass failed to resolve pass resource bindings: ") + bindingPlanError).CStr()); - DestroyResources(); - return false; - } - - if (!bindingPlan.perObject.IsValid() || - bindingPlan.bindings.Size() != 1u || - bindingPlan.descriptorSetCount != 1u || - !bindingPlan.usesConstantBuffers || - bindingPlan.usesTextures || - bindingPlan.usesSamplers) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - "BuiltinObjectIdPass requires exactly one PerObject constant-buffer binding"); - DestroyResources(); - return false; - } - - m_perObjectBinding = bindingPlan.perObject; - m_firstDescriptorSet = bindingPlan.firstDescriptorSet; - - std::vector setLayouts; - Containers::String setLayoutError; - if (!TryBuildBuiltinPassSetLayouts(bindingPlan, setLayouts, &setLayoutError)) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - (Containers::String("BuiltinObjectIdPass failed to build descriptor set layouts: ") + setLayoutError).CStr()); - DestroyResources(); - return false; - } - if (m_perObjectBinding.set >= setLayouts.size()) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - "BuiltinObjectIdPass produced an invalid PerObject descriptor set index"); - DestroyResources(); - return false; - } - m_perObjectSetLayout = setLayouts[m_perObjectBinding.set]; - RefreshBuiltinPassSetLayoutMetadata(m_perObjectSetLayout); - - std::vector nativeSetLayouts(setLayouts.size()); - for (size_t setIndex = 0; setIndex < setLayouts.size(); ++setIndex) { - nativeSetLayouts[setIndex] = setLayouts[setIndex].layout; - } - - RHI::RHIPipelineLayoutDesc pipelineLayoutDesc = {}; - pipelineLayoutDesc.setLayouts = nativeSetLayouts.empty() ? nullptr : nativeSetLayouts.data(); - pipelineLayoutDesc.setLayoutCount = static_cast(nativeSetLayouts.size()); - m_pipelineLayout = m_device->CreatePipelineLayout(pipelineLayoutDesc); - if (m_pipelineLayout == nullptr) { - DestroyResources(); - return false; - } - - m_pipelineState = m_device->CreatePipelineState( - CreatePipelineDesc( - m_backendType, - m_pipelineLayout, - *m_builtinObjectIdShader.Get(), - objectIdPass->name)); - if (m_pipelineState == nullptr || !m_pipelineState->IsValid()) { - if (m_pipelineState != nullptr) { - m_pipelineState->Shutdown(); - delete m_pipelineState; - m_pipelineState = nullptr; - } - DestroyResources(); - return false; - } - - return true; -} - -void BuiltinObjectIdPass::DestroyResources() { - m_resourceCache.Shutdown(); - - for (auto& descriptorSetEntry : m_perObjectSets) { - DestroyOwnedDescriptorSet(descriptorSetEntry.second); - } - m_perObjectSets.clear(); - - if (m_pipelineState != nullptr) { - m_pipelineState->Shutdown(); - delete m_pipelineState; - m_pipelineState = nullptr; - } - - if (m_pipelineLayout != nullptr) { - m_pipelineLayout->Shutdown(); - delete m_pipelineLayout; - m_pipelineLayout = nullptr; - } - - m_device = nullptr; - m_backendType = RHI::RHIType::D3D12; - m_perObjectBinding = {}; - m_perObjectSetLayout = {}; - m_firstDescriptorSet = 0; - m_builtinObjectIdShader.Reset(); -} - -RHI::RHIDescriptorSet* BuiltinObjectIdPass::GetOrCreatePerObjectSet(uint64_t objectId) { - if (m_perObjectBinding.IsValid() == false || - m_perObjectSetLayout.layout.bindingCount == 0) { - return nullptr; - } - - const auto existing = m_perObjectSets.find(objectId); - if (existing != m_perObjectSets.end()) { - return existing->second.set; - } - - RHI::DescriptorPoolDesc poolDesc = {}; - poolDesc.type = m_perObjectSetLayout.heapType; - poolDesc.descriptorCount = - CountBuiltinPassHeapDescriptors(m_perObjectSetLayout.heapType, m_perObjectSetLayout.bindings); - poolDesc.shaderVisible = m_perObjectSetLayout.shaderVisible; - - OwnedDescriptorSet descriptorSet = {}; - descriptorSet.pool = m_device->CreateDescriptorPool(poolDesc); - if (descriptorSet.pool == nullptr) { - return nullptr; - } - - descriptorSet.set = descriptorSet.pool->AllocateSet(m_perObjectSetLayout.layout); - if (descriptorSet.set == nullptr) { - DestroyOwnedDescriptorSet(descriptorSet); - return nullptr; - } - - const auto result = m_perObjectSets.emplace(objectId, descriptorSet); - return result.first->second.set; -} - -void BuiltinObjectIdPass::DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet) { - if (descriptorSet.set != nullptr) { - descriptorSet.set->Shutdown(); - delete descriptorSet.set; - descriptorSet.set = nullptr; - } - - if (descriptorSet.pool != nullptr) { - descriptorSet.pool->Shutdown(); - delete descriptorSet.pool; - descriptorSet.pool = nullptr; - } -} - -bool BuiltinObjectIdPass::DrawVisibleItem( - const RenderContext& context, - const RenderSceneData& sceneData, - const VisibleRenderItem& visibleItem) { - if (visibleItem.mesh == nullptr || visibleItem.gameObject == nullptr) { - return false; - } - - const RenderResourceCache::CachedMesh* cachedMesh = - m_resourceCache.GetOrCreateMesh(m_device, visibleItem.mesh); - if (cachedMesh == nullptr || cachedMesh->vertexBufferView == nullptr) { - return false; - } - - RHI::RHICommandList* commandList = context.commandList; - - RHI::RHIResourceView* vertexBuffers[] = { cachedMesh->vertexBufferView }; - const uint64_t offsets[] = { 0 }; - const uint32_t strides[] = { cachedMesh->vertexStride }; - commandList->SetVertexBuffers(0, 1, vertexBuffers, offsets, strides); - if (cachedMesh->indexBufferView != nullptr) { - commandList->SetIndexBuffer(cachedMesh->indexBufferView, 0); - } - - const uint64_t objectId = visibleItem.gameObject->GetID(); - RHI::RHIDescriptorSet* constantSet = GetOrCreatePerObjectSet(objectId); - if (constantSet == nullptr) { - return false; - } - - const PerObjectConstants constants = { - sceneData.cameraData.projection, - sceneData.cameraData.view, - visibleItem.localToWorld.Transpose(), - EncodeObjectIdToColor(objectId) - }; - constantSet->WriteConstant(m_perObjectBinding.binding, &constants, sizeof(constants)); - - RHI::RHIDescriptorSet* descriptorSets[] = { constantSet }; - commandList->SetGraphicsDescriptorSets(m_firstDescriptorSet, 1, descriptorSets, m_pipelineLayout); - - if (visibleItem.hasSection) { - const Containers::Array& sections = visibleItem.mesh->GetSections(); - if (visibleItem.sectionIndex >= sections.Size()) { - return false; - } - - const Resources::MeshSection& section = sections[visibleItem.sectionIndex]; - if (cachedMesh->indexBufferView != nullptr && section.indexCount > 0) { - commandList->DrawIndexed(section.indexCount, 1, section.startIndex, 0, 0); - } else if (section.vertexCount > 0) { - commandList->Draw(section.vertexCount, 1, section.baseVertex, 0); - } - return true; - } - - if (cachedMesh->indexBufferView != nullptr && cachedMesh->indexCount > 0) { - commandList->DrawIndexed(cachedMesh->indexCount, 1, 0, 0, 0); - } else if (cachedMesh->vertexCount > 0) { - commandList->Draw(cachedMesh->vertexCount, 1, 0, 0); - } - - return true; -} - } // namespace Passes } // namespace Rendering } // namespace XCEngine diff --git a/engine/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp b/engine/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp new file mode 100644 index 00000000..57e31544 --- /dev/null +++ b/engine/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp @@ -0,0 +1,365 @@ +#include "Rendering/Passes/BuiltinObjectIdPass.h" + +#include "Components/GameObject.h" +#include "Core/Asset/ResourceManager.h" +#include "Debug/Logger.h" +#include "RHI/RHICommandList.h" +#include "RHI/RHIPipelineLayout.h" +#include "RHI/RHIPipelineState.h" +#include "Rendering/BuiltinPassLayoutUtils.h" +#include "Rendering/Detail/ShaderVariantUtils.h" +#include "Rendering/RenderSceneExtractor.h" +#include "Rendering/RenderSurface.h" +#include "Resources/BuiltinResources.h" +#include "Resources/Mesh/Mesh.h" + +#include + +namespace XCEngine { +namespace Rendering { +namespace Passes { + +namespace { + +const Resources::ShaderPass* FindObjectIdCompatiblePass( + const Resources::Shader& shader, + Resources::ShaderBackend backend) { + for (const Resources::ShaderPass& shaderPass : shader.GetPasses()) { + if (ShaderPassMatchesBuiltinPass(shaderPass, BuiltinMaterialPass::ObjectId) && + ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, shaderPass.name, backend)) { + return &shaderPass; + } + } + + const Resources::ShaderPass* objectIdPass = shader.FindPass("ObjectId"); + if (objectIdPass != nullptr && + ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, objectIdPass->name, backend)) { + return objectIdPass; + } + + const Resources::ShaderPass* editorObjectIdPass = shader.FindPass("EditorObjectId"); + if (editorObjectIdPass != nullptr && + ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, editorObjectIdPass->name, backend)) { + return editorObjectIdPass; + } + + if (shader.GetPassCount() > 0 && + ::XCEngine::Rendering::Detail::ShaderPassHasGraphicsVariants(shader, shader.GetPasses()[0].name, backend)) { + return &shader.GetPasses()[0]; + } + + return nullptr; +} + +RHI::GraphicsPipelineDesc CreatePipelineDesc( + RHI::RHIType backendType, + RHI::RHIPipelineLayout* pipelineLayout, + const Resources::Shader& shader, + const Containers::String& passName) { + RHI::GraphicsPipelineDesc pipelineDesc = {}; + pipelineDesc.pipelineLayout = pipelineLayout; + pipelineDesc.topologyType = static_cast(RHI::PrimitiveTopologyType::Triangle); + pipelineDesc.renderTargetCount = 1; + pipelineDesc.renderTargetFormats[0] = static_cast(RHI::Format::R8G8B8A8_UNorm); + pipelineDesc.depthStencilFormat = static_cast(RHI::Format::D24_UNorm_S8_UInt); + pipelineDesc.sampleCount = 1; + pipelineDesc.inputLayout = BuiltinObjectIdPass::BuildInputLayout(); + + pipelineDesc.rasterizerState.fillMode = static_cast(RHI::FillMode::Solid); + pipelineDesc.rasterizerState.cullMode = static_cast(RHI::CullMode::None); + pipelineDesc.rasterizerState.frontFace = static_cast(RHI::FrontFace::CounterClockwise); + pipelineDesc.rasterizerState.depthClipEnable = true; + + pipelineDesc.blendState.blendEnable = false; + pipelineDesc.blendState.colorWriteMask = static_cast(RHI::ColorWriteMask::All); + + pipelineDesc.depthStencilState.depthTestEnable = true; + pipelineDesc.depthStencilState.depthWriteEnable = true; + pipelineDesc.depthStencilState.depthFunc = static_cast(RHI::ComparisonFunc::LessEqual); + + const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(backendType); + if (const Resources::ShaderStageVariant* vertexVariant = + shader.FindVariant(passName, Resources::ShaderType::Vertex, backend)) { + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant(*vertexVariant, pipelineDesc.vertexShader); + } + if (const Resources::ShaderStageVariant* fragmentVariant = + shader.FindVariant(passName, Resources::ShaderType::Fragment, backend)) { + ::XCEngine::Rendering::Detail::ApplyShaderStageVariant(*fragmentVariant, pipelineDesc.fragmentShader); + } + + return pipelineDesc; +} + +} // namespace + +bool BuiltinObjectIdPass::EnsureInitialized(const RenderContext& context) { + if (!context.IsValid()) { + return false; + } + + if (m_pipelineLayout != nullptr && + m_pipelineState != nullptr && + m_device == context.device && + m_backendType == context.backendType) { + return true; + } + + DestroyResources(); + return CreateResources(context); +} + +bool BuiltinObjectIdPass::CreateResources(const RenderContext& context) { + m_device = context.device; + m_backendType = context.backendType; + m_builtinObjectIdShader = Resources::ResourceManager::Get().Load( + Resources::GetBuiltinObjectIdShaderPath()); + if (!m_builtinObjectIdShader.IsValid()) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "BuiltinObjectIdPass failed to load builtin object-id shader resource"); + DestroyResources(); + return false; + } + + const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(m_backendType); + const Resources::ShaderPass* objectIdPass = + FindObjectIdCompatiblePass(*m_builtinObjectIdShader.Get(), backend); + if (objectIdPass == nullptr) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "BuiltinObjectIdPass could not resolve a valid ObjectId shader pass"); + DestroyResources(); + return false; + } + + const Containers::Array& resourceBindings = objectIdPass->resources; + if (resourceBindings.Empty()) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + (Containers::String("BuiltinObjectIdPass requires explicit resource bindings on shader pass: ") + + objectIdPass->name).CStr()); + DestroyResources(); + return false; + } + + BuiltinPassResourceBindingPlan bindingPlan = {}; + Containers::String bindingPlanError; + if (!TryBuildBuiltinPassResourceBindingPlan(resourceBindings, bindingPlan, &bindingPlanError)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + (Containers::String("BuiltinObjectIdPass failed to resolve pass resource bindings: ") + bindingPlanError).CStr()); + DestroyResources(); + return false; + } + + if (!bindingPlan.perObject.IsValid() || + bindingPlan.bindings.Size() != 1u || + bindingPlan.descriptorSetCount != 1u || + !bindingPlan.usesConstantBuffers || + bindingPlan.usesTextures || + bindingPlan.usesSamplers) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "BuiltinObjectIdPass requires exactly one PerObject constant-buffer binding"); + DestroyResources(); + return false; + } + + m_perObjectBinding = bindingPlan.perObject; + m_firstDescriptorSet = bindingPlan.firstDescriptorSet; + + std::vector setLayouts; + Containers::String setLayoutError; + if (!TryBuildBuiltinPassSetLayouts(bindingPlan, setLayouts, &setLayoutError)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + (Containers::String("BuiltinObjectIdPass failed to build descriptor set layouts: ") + setLayoutError).CStr()); + DestroyResources(); + return false; + } + if (m_perObjectBinding.set >= setLayouts.size()) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "BuiltinObjectIdPass produced an invalid PerObject descriptor set index"); + DestroyResources(); + return false; + } + m_perObjectSetLayout = setLayouts[m_perObjectBinding.set]; + RefreshBuiltinPassSetLayoutMetadata(m_perObjectSetLayout); + + std::vector nativeSetLayouts(setLayouts.size()); + for (size_t setIndex = 0; setIndex < setLayouts.size(); ++setIndex) { + nativeSetLayouts[setIndex] = setLayouts[setIndex].layout; + } + + RHI::RHIPipelineLayoutDesc pipelineLayoutDesc = {}; + pipelineLayoutDesc.setLayouts = nativeSetLayouts.empty() ? nullptr : nativeSetLayouts.data(); + pipelineLayoutDesc.setLayoutCount = static_cast(nativeSetLayouts.size()); + m_pipelineLayout = m_device->CreatePipelineLayout(pipelineLayoutDesc); + if (m_pipelineLayout == nullptr) { + DestroyResources(); + return false; + } + + m_pipelineState = m_device->CreatePipelineState( + CreatePipelineDesc( + m_backendType, + m_pipelineLayout, + *m_builtinObjectIdShader.Get(), + objectIdPass->name)); + if (m_pipelineState == nullptr || !m_pipelineState->IsValid()) { + if (m_pipelineState != nullptr) { + m_pipelineState->Shutdown(); + delete m_pipelineState; + m_pipelineState = nullptr; + } + DestroyResources(); + return false; + } + + return true; +} + +void BuiltinObjectIdPass::DestroyResources() { + m_resourceCache.Shutdown(); + + for (auto& descriptorSetEntry : m_perObjectSets) { + DestroyOwnedDescriptorSet(descriptorSetEntry.second); + } + m_perObjectSets.clear(); + + if (m_pipelineState != nullptr) { + m_pipelineState->Shutdown(); + delete m_pipelineState; + m_pipelineState = nullptr; + } + + if (m_pipelineLayout != nullptr) { + m_pipelineLayout->Shutdown(); + delete m_pipelineLayout; + m_pipelineLayout = nullptr; + } + + m_device = nullptr; + m_backendType = RHI::RHIType::D3D12; + m_perObjectBinding = {}; + m_perObjectSetLayout = {}; + m_firstDescriptorSet = 0; + m_builtinObjectIdShader.Reset(); +} + +RHI::RHIDescriptorSet* BuiltinObjectIdPass::GetOrCreatePerObjectSet(uint64_t objectId) { + if (m_perObjectBinding.IsValid() == false || + m_perObjectSetLayout.layout.bindingCount == 0) { + return nullptr; + } + + const auto existing = m_perObjectSets.find(objectId); + if (existing != m_perObjectSets.end()) { + return existing->second.set; + } + + RHI::DescriptorPoolDesc poolDesc = {}; + poolDesc.type = m_perObjectSetLayout.heapType; + poolDesc.descriptorCount = + CountBuiltinPassHeapDescriptors(m_perObjectSetLayout.heapType, m_perObjectSetLayout.bindings); + poolDesc.shaderVisible = m_perObjectSetLayout.shaderVisible; + + OwnedDescriptorSet descriptorSet = {}; + descriptorSet.pool = m_device->CreateDescriptorPool(poolDesc); + if (descriptorSet.pool == nullptr) { + return nullptr; + } + + descriptorSet.set = descriptorSet.pool->AllocateSet(m_perObjectSetLayout.layout); + if (descriptorSet.set == nullptr) { + DestroyOwnedDescriptorSet(descriptorSet); + return nullptr; + } + + const auto result = m_perObjectSets.emplace(objectId, descriptorSet); + return result.first->second.set; +} + +void BuiltinObjectIdPass::DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet) { + if (descriptorSet.set != nullptr) { + descriptorSet.set->Shutdown(); + delete descriptorSet.set; + descriptorSet.set = nullptr; + } + + if (descriptorSet.pool != nullptr) { + descriptorSet.pool->Shutdown(); + delete descriptorSet.pool; + descriptorSet.pool = nullptr; + } +} + +bool BuiltinObjectIdPass::DrawVisibleItem( + const RenderContext& context, + const RenderSceneData& sceneData, + const VisibleRenderItem& visibleItem) { + if (visibleItem.mesh == nullptr || visibleItem.gameObject == nullptr) { + return false; + } + + const RenderResourceCache::CachedMesh* cachedMesh = + m_resourceCache.GetOrCreateMesh(m_device, visibleItem.mesh); + if (cachedMesh == nullptr || cachedMesh->vertexBufferView == nullptr) { + return false; + } + + RHI::RHICommandList* commandList = context.commandList; + + RHI::RHIResourceView* vertexBuffers[] = { cachedMesh->vertexBufferView }; + const uint64_t offsets[] = { 0 }; + const uint32_t strides[] = { cachedMesh->vertexStride }; + commandList->SetVertexBuffers(0, 1, vertexBuffers, offsets, strides); + if (cachedMesh->indexBufferView != nullptr) { + commandList->SetIndexBuffer(cachedMesh->indexBufferView, 0); + } + + const uint64_t objectId = visibleItem.gameObject->GetID(); + RHI::RHIDescriptorSet* constantSet = GetOrCreatePerObjectSet(objectId); + if (constantSet == nullptr) { + return false; + } + + const PerObjectConstants constants = { + sceneData.cameraData.projection, + sceneData.cameraData.view, + visibleItem.localToWorld.Transpose(), + EncodeObjectIdToColor(objectId) + }; + constantSet->WriteConstant(m_perObjectBinding.binding, &constants, sizeof(constants)); + + RHI::RHIDescriptorSet* descriptorSets[] = { constantSet }; + commandList->SetGraphicsDescriptorSets(m_firstDescriptorSet, 1, descriptorSets, m_pipelineLayout); + + if (visibleItem.hasSection) { + const Containers::Array& sections = visibleItem.mesh->GetSections(); + if (visibleItem.sectionIndex >= sections.Size()) { + return false; + } + + const Resources::MeshSection& section = sections[visibleItem.sectionIndex]; + if (cachedMesh->indexBufferView != nullptr && section.indexCount > 0) { + commandList->DrawIndexed(section.indexCount, 1, section.startIndex, 0, 0); + } else if (section.vertexCount > 0) { + commandList->Draw(section.vertexCount, 1, section.baseVertex, 0); + } + return true; + } + + if (cachedMesh->indexBufferView != nullptr && cachedMesh->indexCount > 0) { + commandList->DrawIndexed(cachedMesh->indexCount, 1, 0, 0, 0); + } else if (cachedMesh->vertexCount > 0) { + commandList->Draw(cachedMesh->vertexCount, 1, 0, 0); + } + + return true; +} + +} // namespace Passes +} // namespace Rendering +} // namespace XCEngine