From b0d5ed45500244b95be36e35ce0b95e0893ae169 Mon Sep 17 00:00:00 2001 From: atdunbg Date: Fri, 2 Oct 2026 20:20:07 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20ShaderManager=20=E5=BC=95=E7=94=A8?= =?UTF-8?q?=E8=AE=A1=E6=95=B0=E5=8F=A5=E6=9F=84=E2=80=94=E2=80=94shader=20?= =?UTF-8?q?=E7=94=9F=E5=91=BD=E5=91=A8=E6=9C=9F=E8=87=AA=E5=8A=A8=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ShaderObject 值类型 → ShaderRef(shared_ptr 语义,UE TShaderRef 对标):拷贝共享所有权,最后一个引用析构时自动销毁 VkShaderEXT, 持有方零清理代码——"新 pass 忘销毁"整类 bug 被机制消灭 - 删除公开 Destroy 与全部持有方手工 destroyShaderEXT(8 处); 各类析构只清 sampler/layout/set 等其余原生句柄 - RecordFullscreen 参数收窄为 const ShaderRef&(裸 handle 无法 再被误传);bind 点统一 GetHandle() - Outline/SelectionMask 撤掉上一轮补的 Device&(不再需要) - 验证:5s 探针自动退出 → exit 0、无 VUID-05137 泄漏、无 SIGSEGV --- Engine/include/Engine/Renderer/IblGenerator.h | 11 +- .../Engine/Renderer/Passes/FullscreenGpu.h | 14 +- .../Engine/Renderer/Passes/HitProxyPass.h | 3 +- .../Engine/Renderer/Passes/OutlinePass.h | 6 +- .../Engine/Renderer/Passes/PhysicsDebugPass.h | 3 +- .../include/Engine/Renderer/Passes/SceneGpu.h | 11 +- .../Renderer/Passes/SelectionMaskPass.h | 6 +- .../Engine/Renderer/Passes/SkyboxPass.h | 3 +- Engine/include/Engine/Vulkan/ShaderManager.h | 70 +++++-- Engine/src/Renderer/IblGenerator.cpp | 21 +-- Engine/src/Renderer/Passes/ForwardPass.cpp | 4 +- Engine/src/Renderer/Passes/FullscreenGpu.cpp | 24 +-- Engine/src/Renderer/Passes/HitProxyPass.cpp | 13 +- Engine/src/Renderer/Passes/OutlinePass.cpp | 13 +- .../src/Renderer/Passes/PhysicsDebugPass.cpp | 13 +- Engine/src/Renderer/Passes/SceneGpu.cpp | 17 +- .../src/Renderer/Passes/SelectionMaskPass.cpp | 15 +- Engine/src/Renderer/Passes/ShadowPass.cpp | 3 +- Engine/src/Renderer/Passes/SkyboxPass.cpp | 9 +- Engine/src/Renderer/Renderer.cpp | 4 +- Engine/src/Vulkan/ShaderManager.cpp | 177 +++++++++--------- 21 files changed, 223 insertions(+), 217 deletions(-) diff --git a/Engine/include/Engine/Renderer/IblGenerator.h b/Engine/include/Engine/Renderer/IblGenerator.h index 4610afd..731a9e3 100644 --- a/Engine/include/Engine/Renderer/IblGenerator.h +++ b/Engine/include/Engine/Renderer/IblGenerator.h @@ -27,6 +27,7 @@ #include #include // DecodedEquirect(解码产物数据契约) #include +#include #include #include #include @@ -36,7 +37,6 @@ namespace Engine { class Device; class DescriptorManager; - class ShaderManager; class Cubemap; class IblGenerator { @@ -95,10 +95,11 @@ namespace Engine { vk::PipelineLayout m_IblLayoutPush; vk::PipelineLayout m_LutLayout; - vk::ShaderEXT m_ToCubeShader{}; - vk::ShaderEXT m_IrrShader{}; - vk::ShaderEXT m_PrefShader{}; - vk::ShaderEXT m_LutShader{}; + // compute shader(引用计数句柄,析构自动销毁) + ShaderManager::ShaderRef m_ToCubeShader; + ShaderManager::ShaderRef m_IrrShader; + ShaderManager::ShaderRef m_PrefShader; + ShaderManager::ShaderRef m_LutShader; vk::Sampler m_EquirectSampler; // S=repeat(经度环绕)T=clamp vk::CommandPool m_Pool; // 持久复用,每次生成 reset diff --git a/Engine/include/Engine/Renderer/Passes/FullscreenGpu.h b/Engine/include/Engine/Renderer/Passes/FullscreenGpu.h index e784d74..203d224 100644 --- a/Engine/include/Engine/Renderer/Passes/FullscreenGpu.h +++ b/Engine/include/Engine/Renderer/Passes/FullscreenGpu.h @@ -13,13 +13,13 @@ #include #include +#include #include namespace Engine { class Device; class DescriptorManager; - class ShaderManager; namespace Passes { @@ -64,7 +64,7 @@ namespace Engine { public: FullscreenGpu(Device& device, DescriptorManager& descriptors, ShaderManager& shaders); - ~FullscreenGpu(); + ~FullscreenGpu(); // 只清 sampler/layout(shader 随引用自动销毁) FullscreenGpu(const FullscreenGpu&) = delete; FullscreenGpu& operator=(const FullscreenGpu&) = delete; @@ -72,9 +72,10 @@ namespace Engine { vk::DescriptorSetLayout setLayout; // Set0 = {输入0, 输入1, 调试输入} vk::PipelineLayout layout; // push 16B(FullscreenPush) vk::Sampler sampler; - vk::ShaderEXT vert{}, extractFrag{}, blurFrag{}, tonemapFrag{}; - vk::ShaderEXT diffFrag{}; // temporal_diff(帧历史调试) - vk::ShaderEXT taaFrag{}; // taa(时域抗锯齿 resolve) + // shader 引用计数句柄(析构自动销毁,零手工清理) + ShaderManager::ShaderRef vert, extractFrag, blurFrag, tonemapFrag; + ShaderManager::ShaderRef diffFrag; // temporal_diff(帧历史调试) + ShaderManager::ShaderRef taaFrag; // taa(时域抗锯齿 resolve) // 各 pass 自己持有 per-slot set;分配统一走这里 vk::DescriptorSet AllocateSet(); @@ -87,7 +88,8 @@ namespace Engine { // 全屏 pass 公共录制:动态状态/draw 全一致,仅附件 view、 // 输入 set、push 值不同 void RecordFullscreen(RG::RenderGraphContext& ctx, vk::ImageView view, - vk::ShaderEXT frag, const vk::DescriptorSet& set, + const ShaderManager::ShaderRef& frag, + const vk::DescriptorSet& set, const FullscreenPush& push); private: diff --git a/Engine/include/Engine/Renderer/Passes/HitProxyPass.h b/Engine/include/Engine/Renderer/Passes/HitProxyPass.h index 407752f..c9cfe97 100644 --- a/Engine/include/Engine/Renderer/Passes/HitProxyPass.h +++ b/Engine/include/Engine/Renderer/Passes/HitProxyPass.h @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace Engine { @@ -61,7 +62,7 @@ namespace Engine { RG::TextureHandle m_Depth; vk::PipelineLayout m_Layout; // Set0 = uboSetLayout,无 push - vk::ShaderEXT m_Vert{}, m_Frag{}; + ShaderManager::ShaderRef m_Vert, m_Frag; // 析构自动销毁 // 1×1 像素暂存(host visible,持久映射);拷贝录制时置位 Scope m_Staging; diff --git a/Engine/include/Engine/Renderer/Passes/OutlinePass.h b/Engine/include/Engine/Renderer/Passes/OutlinePass.h index 85c5253..f609477 100644 --- a/Engine/include/Engine/Renderer/Passes/OutlinePass.h +++ b/Engine/include/Engine/Renderer/Passes/OutlinePass.h @@ -23,12 +23,11 @@ namespace Engine { class OutlinePass final : public RenderPass { public: // color:描边色(LDR);widthPx:描边宽度(物理像素) - OutlinePass(Device& device, FullscreenGpu& gpu, ShaderManager& shaders, + OutlinePass(FullscreenGpu& gpu, ShaderManager& shaders, FrameSceneData& frame, RG::TextureHandle mask, RG::TextureHandle present, const glm::vec3& color = glm::vec3(1.0f, 0.62f, 0.05f), f32 widthPx = 6.0f); - ~OutlinePass() override; OutlinePass(const OutlinePass&) = delete; OutlinePass& operator=(const OutlinePass&) = delete; @@ -37,14 +36,13 @@ namespace Engine { void OnTargetsRebuilt(RG::RenderGraph& rg) override; private: - Device& m_Device; FullscreenGpu& m_Gpu; FrameSceneData& m_Frame; RG::TextureHandle m_Mask; RG::TextureHandle m_Present; glm::vec3 m_Color; f32 m_WidthPx; - ShaderObject m_Frag{}; + ShaderManager::ShaderRef m_Frag; // 析构自动销毁 std::vector m_Sets; // per-frame slot }; diff --git a/Engine/include/Engine/Renderer/Passes/PhysicsDebugPass.h b/Engine/include/Engine/Renderer/Passes/PhysicsDebugPass.h index ec2bbdf..40e9457 100644 --- a/Engine/include/Engine/Renderer/Passes/PhysicsDebugPass.h +++ b/Engine/include/Engine/Renderer/Passes/PhysicsDebugPass.h @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace Engine { @@ -64,7 +65,7 @@ namespace Engine { UniformBuffer& m_TriVB; vk::PipelineLayout m_Layout; // 无描述符,push = viewProj 64B - vk::ShaderEXT m_Vert{}, m_Frag{}; + ShaderManager::ShaderRef m_Vert, m_Frag; // 析构自动销毁 std::array m_LineCounts{}; std::array m_TriCounts{}; diff --git a/Engine/include/Engine/Renderer/Passes/SceneGpu.h b/Engine/include/Engine/Renderer/Passes/SceneGpu.h index 698c928..11d815b 100644 --- a/Engine/include/Engine/Renderer/Passes/SceneGpu.h +++ b/Engine/include/Engine/Renderer/Passes/SceneGpu.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,6 @@ namespace Engine { class Device; class DescriptorManager; - class ShaderManager; class UniformBuffer; class Cubemap; class Buffer; @@ -40,7 +40,7 @@ namespace Engine { UniformBuffer& skinOffsetBuffer, UniformBuffer& skinPaletteBuffer, UniformBuffer& entityIdBuffer); - ~SceneGpu(); + ~SceneGpu(); // 只清 sampler/layout/set(shader 随引用自动销毁) SceneGpu(const SceneGpu&) = delete; SceneGpu& operator=(const SceneGpu&) = delete; @@ -76,10 +76,11 @@ namespace Engine { std::array, kMaxFramesInFlight> indirectCmdBuffers; std::array, kMaxFramesInFlight> indirectCountBuffers; - vk::ShaderEXT forwardVert{}, forwardFrag{}; + // shader 引用计数句柄(析构自动销毁,零手工清理) + ShaderManager::ShaderRef forwardVert, forwardFrag; // 透明变体:同 simple_shader + gl_FragDepth=1.0(见 frag 注释) - vk::ShaderEXT translucentFrag{}; - vk::ShaderEXT shadowVert{}, shadowFrag{}; + ShaderManager::ShaderRef translucentFrag; + ShaderManager::ShaderRef shadowVert, shadowFrag; // RG 重编译后重绑阴影图(物理镜像按槽位各一份) void BindShadowMaps(RG::RenderGraph& rg, diff --git a/Engine/include/Engine/Renderer/Passes/SelectionMaskPass.h b/Engine/include/Engine/Renderer/Passes/SelectionMaskPass.h index 8e8bd27..9f4b103 100644 --- a/Engine/include/Engine/Renderer/Passes/SelectionMaskPass.h +++ b/Engine/include/Engine/Renderer/Passes/SelectionMaskPass.h @@ -26,10 +26,9 @@ namespace Engine { class SelectionMaskPass final : public RenderPass { public: - SelectionMaskPass(Device& device, ShaderManager& shaders, + SelectionMaskPass(ShaderManager& shaders, SceneGpu& gpu, FrameSceneData& frame, RG::TextureHandle mask); - ~SelectionMaskPass() override; SelectionMaskPass(const SelectionMaskPass&) = delete; SelectionMaskPass& operator=(const SelectionMaskPass&) = delete; @@ -38,11 +37,10 @@ namespace Engine { void OnTargetsRebuilt(RG::RenderGraph& rg) override {} private: - Device& m_Device; SceneGpu& m_Gpu; FrameSceneData& m_Frame; RG::TextureHandle m_Mask; - ShaderObject m_Frag{}; + ShaderManager::ShaderRef m_Frag; // 析构自动销毁 }; } // namespace Passes diff --git a/Engine/include/Engine/Renderer/Passes/SkyboxPass.h b/Engine/include/Engine/Renderer/Passes/SkyboxPass.h index e4899aa..283c3da 100644 --- a/Engine/include/Engine/Renderer/Passes/SkyboxPass.h +++ b/Engine/include/Engine/Renderer/Passes/SkyboxPass.h @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace Engine { @@ -52,7 +53,7 @@ namespace Engine { vk::DescriptorSetLayout m_SetLayout; // Set0 = {samplerCube} vk::PipelineLayout m_Layout; // push = invVP 64B - vk::ShaderEXT m_Vert{}, m_Frag{}; + ShaderManager::ShaderRef m_Vert, m_Frag; // 析构自动销毁 std::array m_Sets{}; }; diff --git a/Engine/include/Engine/Vulkan/ShaderManager.h b/Engine/include/Engine/Vulkan/ShaderManager.h index f37fc46..7fcea04 100644 --- a/Engine/include/Engine/Vulkan/ShaderManager.h +++ b/Engine/include/Engine/Vulkan/ShaderManager.h @@ -1,6 +1,16 @@ // // Created by atdunbg on 2026/9/20. // +// ShaderManager:shader object(VK_EXT_shader_object)创建工厂。 +// +// 生命周期模型(UE FShaderResource / TShaderRef 语义):Create* 返回 +// 引用计数句柄 ShaderRef,拷贝 = 共享所有权,最后一个引用析构时自动 +// 销毁 VkShaderEXT——持有方零清理代码,"新 pass 忘销毁"整类 bug 被 +// 机制消灭(曾因手工管理漏销毁退出时报 VUID-05137 泄漏)。 +// +// 唯一约束:ShaderRef 不得比 Device 活得久(引擎内所有持有方都在 +// Renderer 子树内、先于 Device 析构,天然满足;勿存进静态/长寿命容器)。 +// #ifndef HELLOVULKAN_SHADERMANAGER_H #define HELLOVULKAN_SHADERMANAGER_H @@ -10,6 +20,7 @@ #include #include +#include #include #include @@ -17,31 +28,54 @@ namespace Engine { class Device; - struct ShaderObject { - vk::ShaderEXT Handle; - vk::ShaderStageFlagBits Stage; - }; - class ShaderManager { public: - ShaderManager(Device& device); - ~ShaderManager(); + // ---- 引用计数句柄 ---- + // 空句柄(创建失败)可用 operator bool 判定,此时 GetHandle() + // 返回空 handle(bind 前由调用方判空跳过) + class ShaderRef { + public: + ShaderRef() = default; + + explicit operator bool() const { return m_Entry != nullptr; } + + vk::ShaderEXT GetHandle() const { + return m_Entry ? m_Entry->handle : vk::ShaderEXT{}; + } + + vk::ShaderStageFlagBits GetStage() const { return m_Entry->stage; } + + private: + friend class ShaderManager; + + struct Entry { + vk::ShaderEXT handle{}; + vk::ShaderStageFlagBits stage{}; + Device* device = nullptr; + ~Entry(); // cpp 定义:销毁 VkShaderEXT(需 Device 完整类型) + }; + + explicit ShaderRef(std::shared_ptr e) + : m_Entry(std::move(e)) {} + + std::shared_ptr m_Entry; + }; + + explicit ShaderManager(Device& device); + ~ShaderManager() = default; // shader 随引用计数自动释放 ShaderManager(const ShaderManager&) = delete; ShaderManager& operator=(const ShaderManager&) = delete; - // 改成接受 vector - ShaderObject CreateFromFile(const std::string& spvPath, - vk::ShaderStageFlagBits stage, - const std::vector& layouts = {}, - u32 pushConstantSize = 0); + ShaderRef CreateFromFile(const std::string& spvPath, + vk::ShaderStageFlagBits stage, + const std::vector& layouts = {}, + u32 pushConstantSize = 0); - ShaderObject CreateFromSPIRV(const std::vector& spirv, - vk::ShaderStageFlagBits stage, - const std::vector& layouts = {}, - u32 pushConstantSize = 0) const; - - void Destroy(const ShaderObject& shader) const; + ShaderRef CreateFromSPIRV(const std::vector& spirv, + vk::ShaderStageFlagBits stage, + const std::vector& layouts = {}, + u32 pushConstantSize = 0) const; private: static std::vector ReadSPIRV(const std::string& path); diff --git a/Engine/src/Renderer/IblGenerator.cpp b/Engine/src/Renderer/IblGenerator.cpp index f8d0db9..af8e434 100644 --- a/Engine/src/Renderer/IblGenerator.cpp +++ b/Engine/src/Renderer/IblGenerator.cpp @@ -78,19 +78,19 @@ namespace Engine m_ToCubeShader = shaders.CreateFromFile( dir + "ibl_equirect_to_cube.comp.spv", vk::ShaderStageFlagBits::eCompute, - {m_IblSetLayout}).Handle; + {m_IblSetLayout}); m_IrrShader = shaders.CreateFromFile( dir + "ibl_irradiance.comp.spv", vk::ShaderStageFlagBits::eCompute, - {m_IblSetLayout}).Handle; + {m_IblSetLayout}); m_PrefShader = shaders.CreateFromFile( dir + "ibl_prefilter.comp.spv", vk::ShaderStageFlagBits::eCompute, - {m_IblSetLayout}, sizeof(f32)).Handle; + {m_IblSetLayout}, sizeof(f32)); m_LutShader = shaders.CreateFromFile( dir + "ibl_brdf_lut.comp.spv", vk::ShaderStageFlagBits::eCompute, - {m_LutSetLayout}).Handle; + {m_LutSetLayout}); if (!m_ToCubeShader || !m_IrrShader || !m_PrefShader || !m_LutShader) { ENGINE_FATAL("IblGenerator: failed to create compute shaders"); @@ -125,10 +125,7 @@ namespace Engine { const auto& vkDevice = m_Device.GetDevice(); - for (const vk::ShaderEXT s : {m_ToCubeShader, m_IrrShader, - m_PrefShader, m_LutShader}) { - if (s) vkDevice.destroyShaderEXT(s); - } + // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄 vkDevice.destroySampler(m_EquirectSampler); vkDevice.destroyPipelineLayout(m_IblLayout); vkDevice.destroyPipelineLayout(m_IblLayoutPush); @@ -412,7 +409,7 @@ namespace Engine // 4c. ① equirect → env cube std::array computeStage = { vk::ShaderStageFlagBits::eCompute}; - std::array toCubeShaders = {m_ToCubeShader}; + std::array toCubeShaders = {m_ToCubeShader.GetHandle()}; m_Cmd.bindShadersEXT(computeStage, toCubeShaders); m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_IblLayout, 0, setToCube, {}); @@ -434,7 +431,7 @@ namespace Engine vk::DependencyInfo{}.setImageMemoryBarriers(envToRead)); // 4d. ② irradiance(env → irr) - std::array irrShaders = {m_IrrShader}; + std::array irrShaders = {m_IrrShader.GetHandle()}; m_Cmd.bindShadersEXT(computeStage, irrShaders); m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_IblLayout, 0, setIrr, {}); @@ -443,7 +440,7 @@ namespace Engine kFaceCount); // 4e. ③ prefilter(env → pref,每 mip 一次 dispatch + push roughness) - std::array prefShaders = {m_PrefShader}; + std::array prefShaders = {m_PrefShader.GetHandle()}; m_Cmd.bindShadersEXT(computeStage, prefShaders); for (u32 m = 0; m < kPrefilterMips; ++m) { const u32 dim = kPrefilterFaceSize >> m; @@ -459,7 +456,7 @@ namespace Engine } // 4f. ④ BRDF LUT(独立纯数学) - std::array lutShaders = {m_LutShader}; + std::array lutShaders = {m_LutShader.GetHandle()}; m_Cmd.bindShadersEXT(computeStage, lutShaders); m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_LutLayout, 0, setLut, {}); diff --git a/Engine/src/Renderer/Passes/ForwardPass.cpp b/Engine/src/Renderer/Passes/ForwardPass.cpp index 1ff7411..7debb95 100644 --- a/Engine/src/Renderer/Passes/ForwardPass.cpp +++ b/Engine/src/Renderer/Passes/ForwardPass.cpp @@ -67,8 +67,8 @@ namespace Engine::Passes vk::ShaderStageFlagBits::eFragment }; std::array shaders = { - m_Gpu.forwardVert, - translucent ? m_Gpu.translucentFrag : m_Gpu.forwardFrag}; + m_Gpu.forwardVert.GetHandle(), + (translucent ? m_Gpu.translucentFrag : m_Gpu.forwardFrag).GetHandle()}; cmd.bindShadersEXT(stages, shaders); // Set 0:本帧槽位的 UBO;Set 2:本帧槽位的阴影图 diff --git a/Engine/src/Renderer/Passes/FullscreenGpu.cpp b/Engine/src/Renderer/Passes/FullscreenGpu.cpp index 53bc50b..302f65f 100644 --- a/Engine/src/Renderer/Passes/FullscreenGpu.cpp +++ b/Engine/src/Renderer/Passes/FullscreenGpu.cpp @@ -74,12 +74,12 @@ namespace Engine::Passes std::vector{setLayout}, static_cast(sizeof(FullscreenPush))); - vert = vertShader.Handle; - tonemapFrag = tonemapF.Handle; - extractFrag = extractF.Handle; - blurFrag = blurF.Handle; - diffFrag = diffF.Handle; - taaFrag = taaF.Handle; + vert = std::move(vertShader); + tonemapFrag = std::move(tonemapF); + extractFrag = std::move(extractF); + blurFrag = std::move(blurF); + diffFrag = std::move(diffF); + taaFrag = std::move(taaF); if (!vert || !tonemapFrag || !extractFrag || !blurFrag || !diffFrag || !taaFrag) { @@ -91,13 +91,7 @@ namespace Engine::Passes { const auto& vkDevice = m_Device.GetDevice(); - if (vert) vkDevice.destroyShaderEXT(vert); - if (tonemapFrag) vkDevice.destroyShaderEXT(tonemapFrag); - if (extractFrag) vkDevice.destroyShaderEXT(extractFrag); - if (blurFrag) vkDevice.destroyShaderEXT(blurFrag); - if (diffFrag) vkDevice.destroyShaderEXT(diffFrag); - if (taaFrag) vkDevice.destroyShaderEXT(taaFrag); - + // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄 vkDevice.destroySampler(sampler); vkDevice.destroyPipelineLayout(layout); vkDevice.destroyDescriptorSetLayout(setLayout); @@ -119,7 +113,7 @@ namespace Engine::Passes void FullscreenGpu::RecordFullscreen(RG::RenderGraphContext& ctx, vk::ImageView view, - vk::ShaderEXT frag, + const ShaderManager::ShaderRef& frag, const vk::DescriptorSet& set, const FullscreenPush& push) { @@ -147,7 +141,7 @@ namespace Engine::Passes vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment }; - std::array shaders = {vert, frag}; + std::array shaders = {vert.GetHandle(), frag.GetHandle()}; cmd.bindShadersEXT(stages, shaders); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, diff --git a/Engine/src/Renderer/Passes/HitProxyPass.cpp b/Engine/src/Renderer/Passes/HitProxyPass.cpp index 015641f..6774f9a 100644 --- a/Engine/src/Renderer/Passes/HitProxyPass.cpp +++ b/Engine/src/Renderer/Passes/HitProxyPass.cpp @@ -67,8 +67,8 @@ namespace Engine::Passes vk::ShaderStageFlagBits::eFragment, std::vector{gpu.uboSetLayout}, 0); - m_Vert = vert.Handle; - m_Frag = frag.Handle; + m_Vert = std::move(vert); + m_Frag = std::move(frag); if (!m_Vert || !m_Frag) { ENGINE_FATAL("HitProxyPass: failed to create shader objects"); } @@ -83,11 +83,8 @@ namespace Engine::Passes HitProxyPass::~HitProxyPass() { - const auto& vkDevice = m_Device.GetDevice(); - - if (m_Vert) vkDevice.destroyShaderEXT(m_Vert); - if (m_Frag) vkDevice.destroyShaderEXT(m_Frag); - vkDevice.destroyPipelineLayout(m_Layout); + // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄 + m_Device.GetDevice().destroyPipelineLayout(m_Layout); } bool HitProxyPass::TakeResult(u32& outBits) @@ -143,7 +140,7 @@ namespace Engine::Passes const std::array stages = { vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment}; - const std::array shaders = {m_Vert, m_Frag}; + const std::array shaders = {m_Vert.GetHandle(), m_Frag.GetHandle()}; cmd.bindShadersEXT(stages, shaders); // Set0 = uboSets(UBO + 实例矩阵 + 蒙皮 + 实体 id) diff --git a/Engine/src/Renderer/Passes/OutlinePass.cpp b/Engine/src/Renderer/Passes/OutlinePass.cpp index b5f9372..a7ab4a8 100644 --- a/Engine/src/Renderer/Passes/OutlinePass.cpp +++ b/Engine/src/Renderer/Passes/OutlinePass.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include @@ -18,11 +17,11 @@ namespace Engine::Passes { - OutlinePass::OutlinePass(Device& device, FullscreenGpu& gpu, ShaderManager& shaders, + OutlinePass::OutlinePass(FullscreenGpu& gpu, ShaderManager& shaders, FrameSceneData& frame, RG::TextureHandle mask, RG::TextureHandle present, const glm::vec3& color, f32 widthPx) - : m_Device(device), m_Gpu(gpu), m_Frame(frame), m_Mask(mask), m_Present(present), + : m_Gpu(gpu), m_Frame(frame), m_Mask(mask), m_Present(present), m_Color(color), m_WidthPx(widthPx) { m_Frag = shaders.CreateFromFile( "shaders/outline.frag.spv", @@ -36,12 +35,6 @@ namespace Engine::Passes } } - OutlinePass::~OutlinePass() - { - // VkShaderEXT 是 Device 子对象,必须在 vkDestroyDevice 前销毁 - if (m_Frag.Handle) m_Device.GetDevice().destroyShaderEXT(m_Frag.Handle); - } - void OutlinePass::Register(RG::RenderGraph& rg) { rg.AddPass("Outline", [this](RG::RenderGraphContext& ctx) { @@ -66,7 +59,7 @@ namespace Engine::Passes std::array stages = { vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment}; - std::array shaders = {m_Gpu.vert, m_Frag.Handle}; + std::array shaders = {m_Gpu.vert.GetHandle(), m_Frag.GetHandle()}; cmd.bindShadersEXT(stages, shaders); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, diff --git a/Engine/src/Renderer/Passes/PhysicsDebugPass.cpp b/Engine/src/Renderer/Passes/PhysicsDebugPass.cpp index 89085ae..1b93b0c 100644 --- a/Engine/src/Renderer/Passes/PhysicsDebugPass.cpp +++ b/Engine/src/Renderer/Passes/PhysicsDebugPass.cpp @@ -84,8 +84,8 @@ namespace Engine::Passes std::vector{}, sizeof(glm::mat4)); - m_Vert = vert.Handle; - m_Frag = frag.Handle; + m_Vert = std::move(vert); + m_Frag = std::move(frag); if (!m_Vert || !m_Frag) { ENGINE_FATAL("PhysicsDebugPass: failed to create shader objects"); } @@ -93,11 +93,8 @@ namespace Engine::Passes PhysicsDebugPass::~PhysicsDebugPass() { - const auto& vkDevice = m_Device.GetDevice(); - - if (m_Vert) vkDevice.destroyShaderEXT(m_Vert); - if (m_Frag) vkDevice.destroyShaderEXT(m_Frag); - vkDevice.destroyPipelineLayout(m_Layout); + // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄 + m_Device.GetDevice().destroyPipelineLayout(m_Layout); } void PhysicsDebugPass::PrepareFrame(u32 frameSlot, @@ -168,7 +165,7 @@ namespace Engine::Passes vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment }; - const std::array shaders = {m_Vert, m_Frag}; + const std::array shaders = {m_Vert.GetHandle(), m_Frag.GetHandle()}; cmd.bindShadersEXT(stages, shaders); // layout 的 push range 是 vertex|fragment(CreatePipelineLayout 默认), diff --git a/Engine/src/Renderer/Passes/SceneGpu.cpp b/Engine/src/Renderer/Passes/SceneGpu.cpp index fe3ae22..487f782 100644 --- a/Engine/src/Renderer/Passes/SceneGpu.cpp +++ b/Engine/src/Renderer/Passes/SceneGpu.cpp @@ -113,11 +113,11 @@ namespace Engine::Passes std::vector{uboSetLayout}, sizeof(glm::mat4)); - forwardVert = vert.Handle; - forwardFrag = frag.Handle; - translucentFrag = transFrag.Handle; - shadowVert = shadowVertShader.Handle; - shadowFrag = shadowFragShader.Handle; + forwardVert = std::move(vert); + forwardFrag = std::move(frag); + translucentFrag = std::move(transFrag); + shadowVert = std::move(shadowVertShader); + shadowFrag = std::move(shadowFragShader); if (!forwardVert || !forwardFrag || !translucentFrag || !shadowVert || !shadowFrag) { @@ -190,12 +190,7 @@ namespace Engine::Passes { const auto& vkDevice = m_Device.GetDevice(); - if (forwardVert) vkDevice.destroyShaderEXT(forwardVert); - if (forwardFrag) vkDevice.destroyShaderEXT(forwardFrag); - if (translucentFrag) vkDevice.destroyShaderEXT(translucentFrag); - if (shadowVert) vkDevice.destroyShaderEXT(shadowVert); - if (shadowFrag) vkDevice.destroyShaderEXT(shadowFrag); - + // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄 vkDevice.destroySampler(shadowSampler); vkDevice.destroyPipelineLayout(forwardLayout); vkDevice.destroyPipelineLayout(shadowLayout); diff --git a/Engine/src/Renderer/Passes/SelectionMaskPass.cpp b/Engine/src/Renderer/Passes/SelectionMaskPass.cpp index 84a2d22..1110e20 100644 --- a/Engine/src/Renderer/Passes/SelectionMaskPass.cpp +++ b/Engine/src/Renderer/Passes/SelectionMaskPass.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -13,10 +12,10 @@ namespace Engine::Passes { - SelectionMaskPass::SelectionMaskPass(Device& device, ShaderManager& shaders, + SelectionMaskPass::SelectionMaskPass(ShaderManager& shaders, SceneGpu& gpu, FrameSceneData& frame, RG::TextureHandle mask) - : m_Device(device), m_Gpu(gpu), m_Frame(frame), m_Mask(mask) + : m_Gpu(gpu), m_Frame(frame), m_Mask(mask) { // 恒 1 片元;布局数组必须与 forwardVert 完全一致(shader object // 要求同程序各 shader 的 set layouts 逐项相同,VUID-08879), @@ -29,12 +28,6 @@ namespace Engine::Passes 0); } - SelectionMaskPass::~SelectionMaskPass() - { - // VkShaderEXT 是 Device 子对象,必须在 vkDestroyDevice 前销毁 - if (m_Frag.Handle) m_Device.GetDevice().destroyShaderEXT(m_Frag.Handle); - } - void SelectionMaskPass::Register(RG::RenderGraph& rg) { rg.AddPass("SelectionMask", [this](RG::RenderGraphContext& ctx) { @@ -66,8 +59,8 @@ namespace Engine::Passes std::array stages = { vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment}; - std::array shaders = {m_Gpu.forwardVert, - m_Frag.Handle}; + std::array shaders = { + m_Gpu.forwardVert.GetHandle(), m_Frag.GetHandle()}; cmd.bindShadersEXT(stages, shaders); // Set0:本帧槽位 UBO + 实例/蒙皮 SSBO(Set1 材质、Set2 diff --git a/Engine/src/Renderer/Passes/ShadowPass.cpp b/Engine/src/Renderer/Passes/ShadowPass.cpp index 3d7c2a9..6856ac4 100644 --- a/Engine/src/Renderer/Passes/ShadowPass.cpp +++ b/Engine/src/Renderer/Passes/ShadowPass.cpp @@ -42,7 +42,8 @@ namespace Engine::Passes vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment }; - std::array shaders = {m_Gpu.shadowVert, m_Gpu.shadowFrag}; + std::array shaders = { + m_Gpu.shadowVert.GetHandle(), m_Gpu.shadowFrag.GetHandle()}; cmd.bindShadersEXT(stages, shaders); // ---- 动态状态(depth-only)---- diff --git a/Engine/src/Renderer/Passes/SkyboxPass.cpp b/Engine/src/Renderer/Passes/SkyboxPass.cpp index 4aa7d82..1883dba 100644 --- a/Engine/src/Renderer/Passes/SkyboxPass.cpp +++ b/Engine/src/Renderer/Passes/SkyboxPass.cpp @@ -48,8 +48,8 @@ namespace Engine::Passes std::vector{m_SetLayout}, sizeof(glm::mat4)); - m_Vert = vert.Handle; - m_Frag = frag.Handle; + m_Vert = std::move(vert); + m_Frag = std::move(frag); if (!m_Vert || !m_Frag) { ENGINE_FATAL("SkyboxPass: failed to create shader objects"); } @@ -69,8 +69,7 @@ namespace Engine::Passes { const auto& vkDevice = m_Device.GetDevice(); - if (m_Vert) vkDevice.destroyShaderEXT(m_Vert); - if (m_Frag) vkDevice.destroyShaderEXT(m_Frag); + // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄 vkDevice.destroyPipelineLayout(m_Layout); vkDevice.destroyDescriptorSetLayout(m_SetLayout); } @@ -123,7 +122,7 @@ namespace Engine::Passes vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment }; - const std::array shaders = {m_Vert, m_Frag}; + const std::array shaders = {m_Vert.GetHandle(), m_Frag.GetHandle()}; cmd.bindShadersEXT(stages, shaders); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, diff --git a/Engine/src/Renderer/Renderer.cpp b/Engine/src/Renderer/Renderer.cpp index 161ba21..81f5087 100644 --- a/Engine/src/Renderer/Renderer.cpp +++ b/Engine/src/Renderer/Renderer.cpp @@ -423,7 +423,7 @@ namespace Engine // UE 透墙可见语义)→ Outline(叠加在 Tonemap 后的 PresentTarget // 上,恒定 LDR 描边色) m_Passes.push_back(CreateScope( - *m_Device, *m_ShaderManager, *m_SceneGpu, frame, m_SelectionMask)); + *m_ShaderManager, *m_SceneGpu, frame, m_SelectionMask)); m_Passes.push_back(CreateScope( *m_FullscreenGpu, frame, /*historyAlpha*/ 0.9f, m_HDRColor, m_Velocity, m_TAAColor)); @@ -440,7 +440,7 @@ namespace Engine // 排在 Tonemap 前,会被 Tonemap 整帧覆盖(WAW 序 = 注册序)。 // Blit/ImGui 之前——它们把 PresentTarget 送去 backbuffer/UI。 m_Passes.push_back(CreateScope( - *m_Device, *m_FullscreenGpu, *m_ShaderManager, frame, + *m_FullscreenGpu, *m_ShaderManager, frame, m_SelectionMask, m_PresentTarget)); // Direct 模式适配器:PresentTarget → backbuffer(Viewport 模式空转)。 // 必须注册在 ImGui 之前:两者都写 backbuffer,WAW 边按声明序 diff --git a/Engine/src/Vulkan/ShaderManager.cpp b/Engine/src/Vulkan/ShaderManager.cpp index 2474196..0b101fa 100644 --- a/Engine/src/Vulkan/ShaderManager.cpp +++ b/Engine/src/Vulkan/ShaderManager.cpp @@ -8,105 +8,108 @@ #include #include +#include namespace Engine { -ShaderManager::ShaderManager(Device& device) - : m_Device(device) -{ -} - -ShaderManager::~ShaderManager() -{ -} - -ShaderObject ShaderManager::CreateFromFile(const std::string& spvPath, - const vk::ShaderStageFlagBits stage, - const std::vector& layouts, - const u32 pushConstantSize) -{ - const auto spirv = ReadSPIRV(spvPath); - if (spirv.empty()) { - ENGINE_ERROR("Failed to read SPIR-V: {}", spvPath); - return { nullptr, stage }; - } - return CreateFromSPIRV(spirv, stage, layouts, pushConstantSize); -} - -ShaderObject ShaderManager::CreateFromSPIRV(const std::vector& spirv, - const vk::ShaderStageFlagBits stage, - const std::vector& layouts, - const u32 pushConstantSize) const -{ - vk::ShaderStageFlags nextStage = {}; - if (stage == vk::ShaderStageFlagBits::eVertex) { - nextStage = vk::ShaderStageFlagBits::eFragment; - } - // compute 单阶段:无 nextStage(VUID-09183 只约束 graphics 链) - - vk::ShaderCreateInfoEXT createInfo; - createInfo.setStage(stage) - .setNextStage(nextStage) - .setCodeType(vk::ShaderCodeTypeEXT::eSpirv) - .setCodeSize(spirv.size() * sizeof(u32)) - .setPCode(spirv.data()) - .setPName("main"); - - if (!layouts.empty()) { - createInfo.setSetLayouts(layouts); + // Entry 析构在 cpp:destroyShaderEXT 需要 Device 完整类型, + // 持有方 TU 只有前置声明也不受影响 + ShaderManager::ShaderRef::Entry::~Entry() + { + if (handle && device) { + device->GetDevice().destroyShaderEXT(handle); + } } - std::array pushRanges; - if (pushConstantSize > 0) { - // push range 是"程序级"声明:shader object 要求同一程序绑定的 - // 全部 shader(vert+frag)push range 定义完全一致(VUID-08878), - // 因此统一按 vertex|fragment 声明;shader 实际读取哪些字节由 - // GLSL 的 push_constant block 决定,声明范围只是能力上限。 - // compute 无程序链,单独按 eCompute 声明(layout/push 调用点一致) - pushRanges[0].setStageFlags(stage == vk::ShaderStageFlagBits::eCompute - ? vk::ShaderStageFlagBits::eCompute - : vk::ShaderStageFlagBits::eVertex | - vk::ShaderStageFlagBits::eFragment) - .setOffset(0) - .setSize(pushConstantSize); - createInfo.setPushConstantRanges(pushRanges); + ShaderManager::ShaderManager(Device& device) + : m_Device(device) + { } - vk::ShaderEXT shader; - try { - const auto result = m_Device.GetDevice().createShadersEXT(createInfo); - shader = result.value[0]; - } - catch (const vk::SystemError& e) { - ENGINE_ERROR("Failed to create shader object: {}", e.what()); - return { nullptr, stage }; + ShaderManager::ShaderRef ShaderManager::CreateFromFile(const std::string& spvPath, + const vk::ShaderStageFlagBits stage, + const std::vector& layouts, + const u32 pushConstantSize) + { + const auto spirv = ReadSPIRV(spvPath); + if (spirv.empty()) { + ENGINE_ERROR("Failed to read SPIR-V: {}", spvPath); + return {}; + } + return CreateFromSPIRV(spirv, stage, layouts, pushConstantSize); } - return { shader, stage }; -} + ShaderManager::ShaderRef ShaderManager::CreateFromSPIRV(const std::vector& spirv, + const vk::ShaderStageFlagBits stage, + const std::vector& layouts, + const u32 pushConstantSize) const + { + vk::ShaderStageFlags nextStage = {}; + if (stage == vk::ShaderStageFlagBits::eVertex) { + nextStage = vk::ShaderStageFlagBits::eFragment; + } + // compute 单阶段:无 nextStage(VUID-09183 只约束 graphics 链) -void ShaderManager::Destroy(const ShaderObject& shader) const -{ - if (shader.Handle) { - m_Device.GetDevice().destroyShaderEXT(shader.Handle); - } -} + vk::ShaderCreateInfoEXT createInfo; + createInfo.setStage(stage) + .setNextStage(nextStage) + .setCodeType(vk::ShaderCodeTypeEXT::eSpirv) + .setCodeSize(spirv.size() * sizeof(u32)) + .setPCode(spirv.data()) + .setPName("main"); -std::vector ShaderManager::ReadSPIRV(const std::string& path) -{ - std::ifstream file(path, std::ios::binary | std::ios::ate); - if (!file) { - ENGINE_ERROR("Failed to open: {}", path); - return {}; + if (!layouts.empty()) { + createInfo.setSetLayouts(layouts); + } + + std::array pushRanges; + if (pushConstantSize > 0) { + // push range 是"程序级"声明:shader object 要求同一程序绑定的 + // 全部 shader(vert+frag)push range 定义完全一致(VUID-08878), + // 因此统一按 vertex|fragment 声明;shader 实际读取哪些字节由 + // GLSL 的 push_constant block 决定,声明范围只是能力上限。 + // compute 无程序链,单独按 eCompute 声明(layout/push 调用点一致) + pushRanges[0].setStageFlags(stage == vk::ShaderStageFlagBits::eCompute + ? vk::ShaderStageFlagBits::eCompute + : vk::ShaderStageFlagBits::eVertex | + vk::ShaderStageFlagBits::eFragment) + .setOffset(0) + .setSize(pushConstantSize); + createInfo.setPushConstantRanges(pushRanges); + } + + vk::ShaderEXT shader; + try { + const auto result = m_Device.GetDevice().createShadersEXT(createInfo); + shader = result.value[0]; + } + catch (const vk::SystemError& e) { + ENGINE_ERROR("Failed to create shader object: {}", e.what()); + return {}; + } + + auto entry = std::make_shared(); + entry->handle = shader; + entry->stage = stage; + entry->device = &m_Device; + return ShaderRef(std::move(entry)); } - const size_t size = file.tellg(); - std::vector buffer(size / sizeof(u32)); - file.seekg(0); - file.read(reinterpret_cast(buffer.data()), size); - file.close(); + std::vector ShaderManager::ReadSPIRV(const std::string& path) + { + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file) { + ENGINE_ERROR("Failed to open: {}", path); + return {}; + } - return buffer; -} + const size_t size = file.tellg(); + std::vector buffer(size / sizeof(u32)); + file.seekg(0); + file.read(reinterpret_cast(buffer.data()), size); + file.close(); -} // namespace Engine \ No newline at end of file + return buffer; + } + +} // namespace Engine