fix: prevent selection outline crash on first selection

This commit is contained in:
2026-04-02 20:45:51 +08:00
parent 9ce779da43
commit 84e1ba3600
2 changed files with 55 additions and 13 deletions

View File

@@ -17,6 +17,7 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <optional>
#include <vector> #include <vector>
namespace XCEngine { namespace XCEngine {
@@ -31,7 +32,12 @@ struct ObjectIdOutlineStyle {
class BuiltinObjectIdOutlinePass { class BuiltinObjectIdOutlinePass {
public: public:
BuiltinObjectIdOutlinePass();
~BuiltinObjectIdOutlinePass() = default; ~BuiltinObjectIdOutlinePass() = default;
BuiltinObjectIdOutlinePass(const BuiltinObjectIdOutlinePass&) = delete;
BuiltinObjectIdOutlinePass& operator=(const BuiltinObjectIdOutlinePass&) = delete;
BuiltinObjectIdOutlinePass(BuiltinObjectIdOutlinePass&&) = delete;
BuiltinObjectIdOutlinePass& operator=(BuiltinObjectIdOutlinePass&&) = delete;
static constexpr uint32_t kMaxSelectedObjectCount = 256u; static constexpr uint32_t kMaxSelectedObjectCount = 256u;
@@ -55,6 +61,8 @@ private:
bool EnsureInitialized(const RenderContext& renderContext); bool EnsureInitialized(const RenderContext& renderContext);
bool CreateResources(const RenderContext& renderContext); bool CreateResources(const RenderContext& renderContext);
void DestroyResources(); void DestroyResources();
bool HasCreatedResources() const;
void ResetState();
RHI::RHIDevice* m_device = nullptr; RHI::RHIDevice* m_device = nullptr;
RHI::RHIType m_backendType = RHI::RHIType::D3D12; RHI::RHIType m_backendType = RHI::RHIType::D3D12;
@@ -64,7 +72,7 @@ private:
RHI::RHIDescriptorSet* m_constantSet = nullptr; RHI::RHIDescriptorSet* m_constantSet = nullptr;
RHI::RHIDescriptorPool* m_texturePool = nullptr; RHI::RHIDescriptorPool* m_texturePool = nullptr;
RHI::RHIDescriptorSet* m_textureSet = nullptr; RHI::RHIDescriptorSet* m_textureSet = nullptr;
Resources::ResourceHandle<Resources::Shader> m_builtinObjectIdOutlineShader; std::optional<Resources::ResourceHandle<Resources::Shader>> m_builtinObjectIdOutlineShader;
}; };
} // namespace Passes } // namespace Passes

View File

@@ -9,6 +9,7 @@
#include "Resources/BuiltinResources.h" #include "Resources/BuiltinResources.h"
#include <algorithm> #include <algorithm>
#include <utility>
namespace XCEngine { namespace XCEngine {
namespace Rendering { namespace Rendering {
@@ -85,6 +86,10 @@ RHI::GraphicsPipelineDesc CreatePipelineDesc(
} // namespace } // namespace
BuiltinObjectIdOutlinePass::BuiltinObjectIdOutlinePass() {
ResetState();
}
void BuiltinObjectIdOutlinePass::Shutdown() { void BuiltinObjectIdOutlinePass::Shutdown() {
DestroyResources(); DestroyResources();
} }
@@ -181,7 +186,9 @@ bool BuiltinObjectIdOutlinePass::EnsureInitialized(const RenderContext& renderCo
return true; return true;
} }
DestroyResources(); if (HasCreatedResources()) {
DestroyResources();
}
return CreateResources(renderContext); return CreateResources(renderContext);
} }
@@ -190,21 +197,23 @@ bool BuiltinObjectIdOutlinePass::CreateResources(const RenderContext& renderCont
return false; return false;
} }
m_device = renderContext.device; Resources::ResourceHandle<Resources::Shader> shader = Resources::ResourceManager::Get().Load<Resources::Shader>(
m_backendType = renderContext.backendType;
m_builtinObjectIdOutlineShader = Resources::ResourceManager::Get().Load<Resources::Shader>(
Resources::GetBuiltinObjectIdOutlineShaderPath()); Resources::GetBuiltinObjectIdOutlineShaderPath());
if (!m_builtinObjectIdOutlineShader.IsValid()) { if (!shader.IsValid()) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
"BuiltinObjectIdOutlinePass failed to load builtin object-id-outline shader resource"); "BuiltinObjectIdOutlinePass failed to load builtin object-id-outline shader resource");
DestroyResources(); ResetState();
return false; return false;
} }
m_device = renderContext.device;
m_backendType = renderContext.backendType;
m_builtinObjectIdOutlineShader.emplace(std::move(shader));
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(m_backendType); const Resources::ShaderBackend backend = ::XCEngine::Rendering::Detail::ToShaderBackend(m_backendType);
const Resources::ShaderPass* outlinePass = const Resources::ShaderPass* outlinePass =
FindObjectIdOutlineCompatiblePass(*m_builtinObjectIdOutlineShader.Get(), backend); FindObjectIdOutlineCompatiblePass(*m_builtinObjectIdOutlineShader->Get(), backend);
if (outlinePass == nullptr) { if (outlinePass == nullptr) {
Debug::Logger::Get().Error( Debug::Logger::Get().Error(
Debug::LogCategory::Rendering, Debug::LogCategory::Rendering,
@@ -276,10 +285,10 @@ bool BuiltinObjectIdOutlinePass::CreateResources(const RenderContext& renderCont
m_pipelineState = m_device->CreatePipelineState( m_pipelineState = m_device->CreatePipelineState(
CreatePipelineDesc( CreatePipelineDesc(
m_backendType, m_backendType,
m_pipelineLayout, m_pipelineLayout,
*m_builtinObjectIdOutlineShader.Get(), *m_builtinObjectIdOutlineShader->Get(),
outlinePass->name)); outlinePass->name));
if (m_pipelineState == nullptr || !m_pipelineState->IsValid()) { if (m_pipelineState == nullptr || !m_pipelineState->IsValid()) {
DestroyResources(); DestroyResources();
return false; return false;
@@ -288,6 +297,17 @@ bool BuiltinObjectIdOutlinePass::CreateResources(const RenderContext& renderCont
return true; return true;
} }
bool BuiltinObjectIdOutlinePass::HasCreatedResources() const {
return m_device != nullptr ||
m_pipelineLayout != nullptr ||
m_pipelineState != nullptr ||
m_constantPool != nullptr ||
m_constantSet != nullptr ||
m_texturePool != nullptr ||
m_textureSet != nullptr ||
m_builtinObjectIdOutlineShader.has_value();
}
void BuiltinObjectIdOutlinePass::DestroyResources() { void BuiltinObjectIdOutlinePass::DestroyResources() {
if (m_pipelineState != nullptr) { if (m_pipelineState != nullptr) {
m_pipelineState->Shutdown(); m_pipelineState->Shutdown();
@@ -325,9 +345,23 @@ void BuiltinObjectIdOutlinePass::DestroyResources() {
m_pipelineLayout = nullptr; m_pipelineLayout = nullptr;
} }
if (m_builtinObjectIdOutlineShader.has_value()) {
m_builtinObjectIdOutlineShader.reset();
}
ResetState();
}
void BuiltinObjectIdOutlinePass::ResetState() {
m_device = nullptr; m_device = nullptr;
m_backendType = RHI::RHIType::D3D12; m_backendType = RHI::RHIType::D3D12;
m_builtinObjectIdOutlineShader.Reset(); m_pipelineLayout = nullptr;
m_pipelineState = nullptr;
m_constantPool = nullptr;
m_constantSet = nullptr;
m_texturePool = nullptr;
m_textureSet = nullptr;
m_builtinObjectIdOutlineShader.reset();
} }
} // namespace Passes } // namespace Passes