refactor: ShaderManager 引用计数句柄——shader 生命周期自动化

- 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
This commit is contained in:
2026-10-02 20:20:07 +08:00
parent 47dd879977
commit b0d5ed4550
21 changed files with 223 additions and 217 deletions
@@ -27,6 +27,7 @@
#include <Engine/Core/Types.h> #include <Engine/Core/Types.h>
#include <Engine/Renderer/Cubemap.h> // DecodedEquirect(解码产物数据契约) #include <Engine/Renderer/Cubemap.h> // DecodedEquirect(解码产物数据契约)
#include <Engine/Vulkan/MemoryAllocator.h> #include <Engine/Vulkan/MemoryAllocator.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <string> #include <string>
@@ -36,7 +37,6 @@ namespace Engine {
class Device; class Device;
class DescriptorManager; class DescriptorManager;
class ShaderManager;
class Cubemap; class Cubemap;
class IblGenerator { class IblGenerator {
@@ -95,10 +95,11 @@ namespace Engine {
vk::PipelineLayout m_IblLayoutPush; vk::PipelineLayout m_IblLayoutPush;
vk::PipelineLayout m_LutLayout; vk::PipelineLayout m_LutLayout;
vk::ShaderEXT m_ToCubeShader{}; // compute shader(引用计数句柄,析构自动销毁)
vk::ShaderEXT m_IrrShader{}; ShaderManager::ShaderRef m_ToCubeShader;
vk::ShaderEXT m_PrefShader{}; ShaderManager::ShaderRef m_IrrShader;
vk::ShaderEXT m_LutShader{}; ShaderManager::ShaderRef m_PrefShader;
ShaderManager::ShaderRef m_LutShader;
vk::Sampler m_EquirectSampler; // S=repeat(经度环绕)T=clamp vk::Sampler m_EquirectSampler; // S=repeat(经度环绕)T=clamp
vk::CommandPool m_Pool; // 持久复用,每次生成 reset vk::CommandPool m_Pool; // 持久复用,每次生成 reset
@@ -13,13 +13,13 @@
#include <Engine/Core/Types.h> #include <Engine/Core/Types.h>
#include <Engine/RenderGraph/RenderGraph.h> #include <Engine/RenderGraph/RenderGraph.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace Engine { namespace Engine {
class Device; class Device;
class DescriptorManager; class DescriptorManager;
class ShaderManager;
namespace Passes { namespace Passes {
@@ -64,7 +64,7 @@ namespace Engine {
public: public:
FullscreenGpu(Device& device, DescriptorManager& descriptors, FullscreenGpu(Device& device, DescriptorManager& descriptors,
ShaderManager& shaders); ShaderManager& shaders);
~FullscreenGpu(); ~FullscreenGpu(); // 只清 sampler/layout(shader 随引用自动销毁)
FullscreenGpu(const FullscreenGpu&) = delete; FullscreenGpu(const FullscreenGpu&) = delete;
FullscreenGpu& operator=(const FullscreenGpu&) = delete; FullscreenGpu& operator=(const FullscreenGpu&) = delete;
@@ -72,9 +72,10 @@ namespace Engine {
vk::DescriptorSetLayout setLayout; // Set0 = {输入0, 输入1, 调试输入} vk::DescriptorSetLayout setLayout; // Set0 = {输入0, 输入1, 调试输入}
vk::PipelineLayout layout; // push 16B(FullscreenPush) vk::PipelineLayout layout; // push 16B(FullscreenPush)
vk::Sampler sampler; vk::Sampler sampler;
vk::ShaderEXT vert{}, extractFrag{}, blurFrag{}, tonemapFrag{}; // shader 引用计数句柄(析构自动销毁,零手工清理)
vk::ShaderEXT diffFrag{}; // temporal_diff(帧历史调试) ShaderManager::ShaderRef vert, extractFrag, blurFrag, tonemapFrag;
vk::ShaderEXT taaFrag{}; // taa(时域抗锯齿 resolve) ShaderManager::ShaderRef diffFrag; // temporal_diff(帧历史调试)
ShaderManager::ShaderRef taaFrag; // taa(时域抗锯齿 resolve)
// 各 pass 自己持有 per-slot set;分配统一走这里 // 各 pass 自己持有 per-slot set;分配统一走这里
vk::DescriptorSet AllocateSet(); vk::DescriptorSet AllocateSet();
@@ -87,7 +88,8 @@ namespace Engine {
// 全屏 pass 公共录制:动态状态/draw 全一致,仅附件 view、 // 全屏 pass 公共录制:动态状态/draw 全一致,仅附件 view、
// 输入 set、push 值不同 // 输入 set、push 值不同
void RecordFullscreen(RG::RenderGraphContext& ctx, vk::ImageView view, 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); const FullscreenPush& push);
private: private:
@@ -22,6 +22,7 @@
#include <Engine/Renderer/Passes/RenderPass.h> #include <Engine/Renderer/Passes/RenderPass.h>
#include <Engine/Renderer/SceneTypes.h> #include <Engine/Renderer/SceneTypes.h>
#include <Engine/Vulkan/Buffer.h> #include <Engine/Vulkan/Buffer.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace Engine { namespace Engine {
@@ -61,7 +62,7 @@ namespace Engine {
RG::TextureHandle m_Depth; RG::TextureHandle m_Depth;
vk::PipelineLayout m_Layout; // Set0 = uboSetLayout,无 push vk::PipelineLayout m_Layout; // Set0 = uboSetLayout,无 push
vk::ShaderEXT m_Vert{}, m_Frag{}; ShaderManager::ShaderRef m_Vert, m_Frag; // 析构自动销毁
// 1×1 像素暂存(host visible,持久映射);拷贝录制时置位 // 1×1 像素暂存(host visible,持久映射);拷贝录制时置位
Scope<Buffer> m_Staging; Scope<Buffer> m_Staging;
@@ -23,12 +23,11 @@ namespace Engine {
class OutlinePass final : public RenderPass { class OutlinePass final : public RenderPass {
public: public:
// color:描边色(LDR);widthPx:描边宽度(物理像素) // color:描边色(LDR);widthPx:描边宽度(物理像素)
OutlinePass(Device& device, FullscreenGpu& gpu, ShaderManager& shaders, OutlinePass(FullscreenGpu& gpu, ShaderManager& shaders,
FrameSceneData& frame, FrameSceneData& frame,
RG::TextureHandle mask, RG::TextureHandle present, RG::TextureHandle mask, RG::TextureHandle present,
const glm::vec3& color = glm::vec3(1.0f, 0.62f, 0.05f), const glm::vec3& color = glm::vec3(1.0f, 0.62f, 0.05f),
f32 widthPx = 6.0f); f32 widthPx = 6.0f);
~OutlinePass() override;
OutlinePass(const OutlinePass&) = delete; OutlinePass(const OutlinePass&) = delete;
OutlinePass& operator=(const OutlinePass&) = delete; OutlinePass& operator=(const OutlinePass&) = delete;
@@ -37,14 +36,13 @@ namespace Engine {
void OnTargetsRebuilt(RG::RenderGraph& rg) override; void OnTargetsRebuilt(RG::RenderGraph& rg) override;
private: private:
Device& m_Device;
FullscreenGpu& m_Gpu; FullscreenGpu& m_Gpu;
FrameSceneData& m_Frame; FrameSceneData& m_Frame;
RG::TextureHandle m_Mask; RG::TextureHandle m_Mask;
RG::TextureHandle m_Present; RG::TextureHandle m_Present;
glm::vec3 m_Color; glm::vec3 m_Color;
f32 m_WidthPx; f32 m_WidthPx;
ShaderObject m_Frag{}; ShaderManager::ShaderRef m_Frag; // 析构自动销毁
std::vector<vk::DescriptorSet> m_Sets; // per-frame slot std::vector<vk::DescriptorSet> m_Sets; // per-frame slot
}; };
@@ -19,6 +19,7 @@
#include <Engine/Renderer/Passes/RenderPass.h> #include <Engine/Renderer/Passes/RenderPass.h>
#include <Engine/Renderer/SceneTypes.h> #include <Engine/Renderer/SceneTypes.h>
#include <Engine/Vulkan/UniformBuffer.h> #include <Engine/Vulkan/UniformBuffer.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace Engine { namespace Engine {
@@ -64,7 +65,7 @@ namespace Engine {
UniformBuffer& m_TriVB; UniformBuffer& m_TriVB;
vk::PipelineLayout m_Layout; // 无描述符,push = viewProj 64B vk::PipelineLayout m_Layout; // 无描述符,push = viewProj 64B
vk::ShaderEXT m_Vert{}, m_Frag{}; ShaderManager::ShaderRef m_Vert, m_Frag; // 析构自动销毁
std::array<u32, kMaxFramesInFlight> m_LineCounts{}; std::array<u32, kMaxFramesInFlight> m_LineCounts{};
std::array<u32, kMaxFramesInFlight> m_TriCounts{}; std::array<u32, kMaxFramesInFlight> m_TriCounts{};
@@ -14,6 +14,7 @@
#include <Engine/Core/FrameContext.h> #include <Engine/Core/FrameContext.h>
#include <Engine/Renderer/SceneTypes.h> #include <Engine/Renderer/SceneTypes.h>
#include <Engine/RenderGraph/RenderGraph.h> #include <Engine/RenderGraph/RenderGraph.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <array> #include <array>
#include <vector> #include <vector>
@@ -22,7 +23,6 @@ namespace Engine {
class Device; class Device;
class DescriptorManager; class DescriptorManager;
class ShaderManager;
class UniformBuffer; class UniformBuffer;
class Cubemap; class Cubemap;
class Buffer; class Buffer;
@@ -40,7 +40,7 @@ namespace Engine {
UniformBuffer& skinOffsetBuffer, UniformBuffer& skinOffsetBuffer,
UniformBuffer& skinPaletteBuffer, UniformBuffer& skinPaletteBuffer,
UniformBuffer& entityIdBuffer); UniformBuffer& entityIdBuffer);
~SceneGpu(); ~SceneGpu(); // 只清 sampler/layout/set(shader 随引用自动销毁)
SceneGpu(const SceneGpu&) = delete; SceneGpu(const SceneGpu&) = delete;
SceneGpu& operator=(const SceneGpu&) = delete; SceneGpu& operator=(const SceneGpu&) = delete;
@@ -76,10 +76,11 @@ namespace Engine {
std::array<Scope<Buffer>, kMaxFramesInFlight> indirectCmdBuffers; std::array<Scope<Buffer>, kMaxFramesInFlight> indirectCmdBuffers;
std::array<Scope<Buffer>, kMaxFramesInFlight> indirectCountBuffers; std::array<Scope<Buffer>, kMaxFramesInFlight> indirectCountBuffers;
vk::ShaderEXT forwardVert{}, forwardFrag{}; // shader 引用计数句柄(析构自动销毁,零手工清理)
ShaderManager::ShaderRef forwardVert, forwardFrag;
// 透明变体:同 simple_shader + gl_FragDepth=1.0(见 frag 注释) // 透明变体:同 simple_shader + gl_FragDepth=1.0(见 frag 注释)
vk::ShaderEXT translucentFrag{}; ShaderManager::ShaderRef translucentFrag;
vk::ShaderEXT shadowVert{}, shadowFrag{}; ShaderManager::ShaderRef shadowVert, shadowFrag;
// RG 重编译后重绑阴影图(物理镜像按槽位各一份) // RG 重编译后重绑阴影图(物理镜像按槽位各一份)
void BindShadowMaps(RG::RenderGraph& rg, void BindShadowMaps(RG::RenderGraph& rg,
@@ -26,10 +26,9 @@ namespace Engine {
class SelectionMaskPass final : public RenderPass { class SelectionMaskPass final : public RenderPass {
public: public:
SelectionMaskPass(Device& device, ShaderManager& shaders, SelectionMaskPass(ShaderManager& shaders,
SceneGpu& gpu, FrameSceneData& frame, SceneGpu& gpu, FrameSceneData& frame,
RG::TextureHandle mask); RG::TextureHandle mask);
~SelectionMaskPass() override;
SelectionMaskPass(const SelectionMaskPass&) = delete; SelectionMaskPass(const SelectionMaskPass&) = delete;
SelectionMaskPass& operator=(const SelectionMaskPass&) = delete; SelectionMaskPass& operator=(const SelectionMaskPass&) = delete;
@@ -38,11 +37,10 @@ namespace Engine {
void OnTargetsRebuilt(RG::RenderGraph& rg) override {} void OnTargetsRebuilt(RG::RenderGraph& rg) override {}
private: private:
Device& m_Device;
SceneGpu& m_Gpu; SceneGpu& m_Gpu;
FrameSceneData& m_Frame; FrameSceneData& m_Frame;
RG::TextureHandle m_Mask; RG::TextureHandle m_Mask;
ShaderObject m_Frag{}; ShaderManager::ShaderRef m_Frag; // 析构自动销毁
}; };
} // namespace Passes } // namespace Passes
@@ -18,6 +18,7 @@
#include <Engine/Core/FrameContext.h> #include <Engine/Core/FrameContext.h>
#include <Engine/Renderer/Passes/RenderPass.h> #include <Engine/Renderer/Passes/RenderPass.h>
#include <Engine/Renderer/SceneTypes.h> #include <Engine/Renderer/SceneTypes.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace Engine { namespace Engine {
@@ -52,7 +53,7 @@ namespace Engine {
vk::DescriptorSetLayout m_SetLayout; // Set0 = {samplerCube} vk::DescriptorSetLayout m_SetLayout; // Set0 = {samplerCube}
vk::PipelineLayout m_Layout; // push = invVP 64B vk::PipelineLayout m_Layout; // push = invVP 64B
vk::ShaderEXT m_Vert{}, m_Frag{}; ShaderManager::ShaderRef m_Vert, m_Frag; // 析构自动销毁
std::array<vk::DescriptorSet, kMaxFramesInFlight> m_Sets{}; std::array<vk::DescriptorSet, kMaxFramesInFlight> m_Sets{};
}; };
+52 -18
View File
@@ -1,6 +1,16 @@
// //
// Created by atdunbg on 2026/9/20. // 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 #ifndef HELLOVULKAN_SHADERMANAGER_H
#define HELLOVULKAN_SHADERMANAGER_H #define HELLOVULKAN_SHADERMANAGER_H
@@ -10,6 +20,7 @@
#include <Engine/Core/Types.h> #include <Engine/Core/Types.h>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -17,31 +28,54 @@ namespace Engine {
class Device; class Device;
struct ShaderObject {
vk::ShaderEXT Handle;
vk::ShaderStageFlagBits Stage;
};
class ShaderManager { class ShaderManager {
public: 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<Entry> e)
: m_Entry(std::move(e)) {}
std::shared_ptr<Entry> m_Entry;
};
explicit ShaderManager(Device& device);
~ShaderManager() = default; // shader 随引用计数自动释放
ShaderManager(const ShaderManager&) = delete; ShaderManager(const ShaderManager&) = delete;
ShaderManager& operator=(const ShaderManager&) = delete; ShaderManager& operator=(const ShaderManager&) = delete;
// 改成接受 vector ShaderRef CreateFromFile(const std::string& spvPath,
ShaderObject CreateFromFile(const std::string& spvPath, vk::ShaderStageFlagBits stage,
vk::ShaderStageFlagBits stage, const std::vector<vk::DescriptorSetLayout>& layouts = {},
const std::vector<vk::DescriptorSetLayout>& layouts = {}, u32 pushConstantSize = 0);
u32 pushConstantSize = 0);
ShaderObject CreateFromSPIRV(const std::vector<u32>& spirv, ShaderRef CreateFromSPIRV(const std::vector<u32>& spirv,
vk::ShaderStageFlagBits stage, vk::ShaderStageFlagBits stage,
const std::vector<vk::DescriptorSetLayout>& layouts = {}, const std::vector<vk::DescriptorSetLayout>& layouts = {},
u32 pushConstantSize = 0) const; u32 pushConstantSize = 0) const;
void Destroy(const ShaderObject& shader) const;
private: private:
static std::vector<u32> ReadSPIRV(const std::string& path); static std::vector<u32> ReadSPIRV(const std::string& path);
+9 -12
View File
@@ -78,19 +78,19 @@ namespace Engine
m_ToCubeShader = shaders.CreateFromFile( m_ToCubeShader = shaders.CreateFromFile(
dir + "ibl_equirect_to_cube.comp.spv", dir + "ibl_equirect_to_cube.comp.spv",
vk::ShaderStageFlagBits::eCompute, vk::ShaderStageFlagBits::eCompute,
{m_IblSetLayout}).Handle; {m_IblSetLayout});
m_IrrShader = shaders.CreateFromFile( m_IrrShader = shaders.CreateFromFile(
dir + "ibl_irradiance.comp.spv", dir + "ibl_irradiance.comp.spv",
vk::ShaderStageFlagBits::eCompute, vk::ShaderStageFlagBits::eCompute,
{m_IblSetLayout}).Handle; {m_IblSetLayout});
m_PrefShader = shaders.CreateFromFile( m_PrefShader = shaders.CreateFromFile(
dir + "ibl_prefilter.comp.spv", dir + "ibl_prefilter.comp.spv",
vk::ShaderStageFlagBits::eCompute, vk::ShaderStageFlagBits::eCompute,
{m_IblSetLayout}, sizeof(f32)).Handle; {m_IblSetLayout}, sizeof(f32));
m_LutShader = shaders.CreateFromFile( m_LutShader = shaders.CreateFromFile(
dir + "ibl_brdf_lut.comp.spv", dir + "ibl_brdf_lut.comp.spv",
vk::ShaderStageFlagBits::eCompute, vk::ShaderStageFlagBits::eCompute,
{m_LutSetLayout}).Handle; {m_LutSetLayout});
if (!m_ToCubeShader || !m_IrrShader || !m_PrefShader || !m_LutShader) { if (!m_ToCubeShader || !m_IrrShader || !m_PrefShader || !m_LutShader) {
ENGINE_FATAL("IblGenerator: failed to create compute shaders"); ENGINE_FATAL("IblGenerator: failed to create compute shaders");
@@ -125,10 +125,7 @@ namespace Engine
{ {
const auto& vkDevice = m_Device.GetDevice(); const auto& vkDevice = m_Device.GetDevice();
for (const vk::ShaderEXT s : {m_ToCubeShader, m_IrrShader, // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄
m_PrefShader, m_LutShader}) {
if (s) vkDevice.destroyShaderEXT(s);
}
vkDevice.destroySampler(m_EquirectSampler); vkDevice.destroySampler(m_EquirectSampler);
vkDevice.destroyPipelineLayout(m_IblLayout); vkDevice.destroyPipelineLayout(m_IblLayout);
vkDevice.destroyPipelineLayout(m_IblLayoutPush); vkDevice.destroyPipelineLayout(m_IblLayoutPush);
@@ -412,7 +409,7 @@ namespace Engine
// 4c. ① equirect → env cube // 4c. ① equirect → env cube
std::array<vk::ShaderStageFlagBits, 1> computeStage = { std::array<vk::ShaderStageFlagBits, 1> computeStage = {
vk::ShaderStageFlagBits::eCompute}; vk::ShaderStageFlagBits::eCompute};
std::array<vk::ShaderEXT, 1> toCubeShaders = {m_ToCubeShader}; std::array<vk::ShaderEXT, 1> toCubeShaders = {m_ToCubeShader.GetHandle()};
m_Cmd.bindShadersEXT(computeStage, toCubeShaders); m_Cmd.bindShadersEXT(computeStage, toCubeShaders);
m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
m_IblLayout, 0, setToCube, {}); m_IblLayout, 0, setToCube, {});
@@ -434,7 +431,7 @@ namespace Engine
vk::DependencyInfo{}.setImageMemoryBarriers(envToRead)); vk::DependencyInfo{}.setImageMemoryBarriers(envToRead));
// 4d. ② irradiance(env → irr) // 4d. ② irradiance(env → irr)
std::array<vk::ShaderEXT, 1> irrShaders = {m_IrrShader}; std::array<vk::ShaderEXT, 1> irrShaders = {m_IrrShader.GetHandle()};
m_Cmd.bindShadersEXT(computeStage, irrShaders); m_Cmd.bindShadersEXT(computeStage, irrShaders);
m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
m_IblLayout, 0, setIrr, {}); m_IblLayout, 0, setIrr, {});
@@ -443,7 +440,7 @@ namespace Engine
kFaceCount); kFaceCount);
// 4e. ③ prefilter(env → pref,每 mip 一次 dispatch + push roughness) // 4e. ③ prefilter(env → pref,每 mip 一次 dispatch + push roughness)
std::array<vk::ShaderEXT, 1> prefShaders = {m_PrefShader}; std::array<vk::ShaderEXT, 1> prefShaders = {m_PrefShader.GetHandle()};
m_Cmd.bindShadersEXT(computeStage, prefShaders); m_Cmd.bindShadersEXT(computeStage, prefShaders);
for (u32 m = 0; m < kPrefilterMips; ++m) { for (u32 m = 0; m < kPrefilterMips; ++m) {
const u32 dim = kPrefilterFaceSize >> m; const u32 dim = kPrefilterFaceSize >> m;
@@ -459,7 +456,7 @@ namespace Engine
} }
// 4f. ④ BRDF LUT(独立纯数学) // 4f. ④ BRDF LUT(独立纯数学)
std::array<vk::ShaderEXT, 1> lutShaders = {m_LutShader}; std::array<vk::ShaderEXT, 1> lutShaders = {m_LutShader.GetHandle()};
m_Cmd.bindShadersEXT(computeStage, lutShaders); m_Cmd.bindShadersEXT(computeStage, lutShaders);
m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
m_LutLayout, 0, setLut, {}); m_LutLayout, 0, setLut, {});
+2 -2
View File
@@ -67,8 +67,8 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
}; };
std::array<vk::ShaderEXT, 2> shaders = { std::array<vk::ShaderEXT, 2> shaders = {
m_Gpu.forwardVert, m_Gpu.forwardVert.GetHandle(),
translucent ? m_Gpu.translucentFrag : m_Gpu.forwardFrag}; (translucent ? m_Gpu.translucentFrag : m_Gpu.forwardFrag).GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
// Set 0:本帧槽位的 UBO;Set 2:本帧槽位的阴影图 // Set 0:本帧槽位的 UBO;Set 2:本帧槽位的阴影图
+9 -15
View File
@@ -74,12 +74,12 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{setLayout}, std::vector<vk::DescriptorSetLayout>{setLayout},
static_cast<u32>(sizeof(FullscreenPush))); static_cast<u32>(sizeof(FullscreenPush)));
vert = vertShader.Handle; vert = std::move(vertShader);
tonemapFrag = tonemapF.Handle; tonemapFrag = std::move(tonemapF);
extractFrag = extractF.Handle; extractFrag = std::move(extractF);
blurFrag = blurF.Handle; blurFrag = std::move(blurF);
diffFrag = diffF.Handle; diffFrag = std::move(diffF);
taaFrag = taaF.Handle; taaFrag = std::move(taaF);
if (!vert || !tonemapFrag || !extractFrag || !blurFrag || if (!vert || !tonemapFrag || !extractFrag || !blurFrag ||
!diffFrag || !taaFrag) { !diffFrag || !taaFrag) {
@@ -91,13 +91,7 @@ namespace Engine::Passes
{ {
const auto& vkDevice = m_Device.GetDevice(); const auto& vkDevice = m_Device.GetDevice();
if (vert) vkDevice.destroyShaderEXT(vert); // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄
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);
vkDevice.destroySampler(sampler); vkDevice.destroySampler(sampler);
vkDevice.destroyPipelineLayout(layout); vkDevice.destroyPipelineLayout(layout);
vkDevice.destroyDescriptorSetLayout(setLayout); vkDevice.destroyDescriptorSetLayout(setLayout);
@@ -119,7 +113,7 @@ namespace Engine::Passes
void FullscreenGpu::RecordFullscreen(RG::RenderGraphContext& ctx, void FullscreenGpu::RecordFullscreen(RG::RenderGraphContext& ctx,
vk::ImageView view, vk::ImageView view,
vk::ShaderEXT frag, const ShaderManager::ShaderRef& frag,
const vk::DescriptorSet& set, const vk::DescriptorSet& set,
const FullscreenPush& push) const FullscreenPush& push)
{ {
@@ -147,7 +141,7 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
}; };
std::array<vk::ShaderEXT, 2> shaders = {vert, frag}; std::array<vk::ShaderEXT, 2> shaders = {vert.GetHandle(), frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
+5 -8
View File
@@ -67,8 +67,8 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eFragment, vk::ShaderStageFlagBits::eFragment,
std::vector<vk::DescriptorSetLayout>{gpu.uboSetLayout}, 0); std::vector<vk::DescriptorSetLayout>{gpu.uboSetLayout}, 0);
m_Vert = vert.Handle; m_Vert = std::move(vert);
m_Frag = frag.Handle; m_Frag = std::move(frag);
if (!m_Vert || !m_Frag) { if (!m_Vert || !m_Frag) {
ENGINE_FATAL("HitProxyPass: failed to create shader objects"); ENGINE_FATAL("HitProxyPass: failed to create shader objects");
} }
@@ -83,11 +83,8 @@ namespace Engine::Passes
HitProxyPass::~HitProxyPass() HitProxyPass::~HitProxyPass()
{ {
const auto& vkDevice = m_Device.GetDevice(); // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄
m_Device.GetDevice().destroyPipelineLayout(m_Layout);
if (m_Vert) vkDevice.destroyShaderEXT(m_Vert);
if (m_Frag) vkDevice.destroyShaderEXT(m_Frag);
vkDevice.destroyPipelineLayout(m_Layout);
} }
bool HitProxyPass::TakeResult(u32& outBits) bool HitProxyPass::TakeResult(u32& outBits)
@@ -143,7 +140,7 @@ namespace Engine::Passes
const std::array<vk::ShaderStageFlagBits, 2> stages = { const std::array<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment}; vk::ShaderStageFlagBits::eFragment};
const std::array<vk::ShaderEXT, 2> shaders = {m_Vert, m_Frag}; const std::array<vk::ShaderEXT, 2> shaders = {m_Vert.GetHandle(), m_Frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
// Set0 = uboSets(UBO + 实例矩阵 + 蒙皮 + 实体 id) // Set0 = uboSets(UBO + 实例矩阵 + 蒙皮 + 实体 id)
+3 -10
View File
@@ -9,7 +9,6 @@
#include <Engine/Renderer/Passes/OutlinePass.h> #include <Engine/Renderer/Passes/OutlinePass.h>
#include <Engine/Renderer/Passes/FullscreenGpu.h> #include <Engine/Renderer/Passes/FullscreenGpu.h>
#include <Engine/Vulkan/ShaderManager.h> #include <Engine/Vulkan/ShaderManager.h>
#include <Engine/Vulkan/Device.h>
#include <Engine/Core/FrameContext.h> #include <Engine/Core/FrameContext.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -18,11 +17,11 @@
namespace Engine::Passes namespace Engine::Passes
{ {
OutlinePass::OutlinePass(Device& device, FullscreenGpu& gpu, ShaderManager& shaders, OutlinePass::OutlinePass(FullscreenGpu& gpu, ShaderManager& shaders,
FrameSceneData& frame, FrameSceneData& frame,
RG::TextureHandle mask, RG::TextureHandle present, RG::TextureHandle mask, RG::TextureHandle present,
const glm::vec3& color, f32 widthPx) 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_Color(color), m_WidthPx(widthPx) {
m_Frag = shaders.CreateFromFile( m_Frag = shaders.CreateFromFile(
"shaders/outline.frag.spv", "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) void OutlinePass::Register(RG::RenderGraph& rg)
{ {
rg.AddPass("Outline", [this](RG::RenderGraphContext& ctx) { rg.AddPass("Outline", [this](RG::RenderGraphContext& ctx) {
@@ -66,7 +59,7 @@ namespace Engine::Passes
std::array<vk::ShaderStageFlagBits, 2> stages = { std::array<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment}; vk::ShaderStageFlagBits::eFragment};
std::array<vk::ShaderEXT, 2> shaders = {m_Gpu.vert, m_Frag.Handle}; std::array<vk::ShaderEXT, 2> shaders = {m_Gpu.vert.GetHandle(), m_Frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
@@ -84,8 +84,8 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{}, std::vector<vk::DescriptorSetLayout>{},
sizeof(glm::mat4)); sizeof(glm::mat4));
m_Vert = vert.Handle; m_Vert = std::move(vert);
m_Frag = frag.Handle; m_Frag = std::move(frag);
if (!m_Vert || !m_Frag) { if (!m_Vert || !m_Frag) {
ENGINE_FATAL("PhysicsDebugPass: failed to create shader objects"); ENGINE_FATAL("PhysicsDebugPass: failed to create shader objects");
} }
@@ -93,11 +93,8 @@ namespace Engine::Passes
PhysicsDebugPass::~PhysicsDebugPass() PhysicsDebugPass::~PhysicsDebugPass()
{ {
const auto& vkDevice = m_Device.GetDevice(); // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄
m_Device.GetDevice().destroyPipelineLayout(m_Layout);
if (m_Vert) vkDevice.destroyShaderEXT(m_Vert);
if (m_Frag) vkDevice.destroyShaderEXT(m_Frag);
vkDevice.destroyPipelineLayout(m_Layout);
} }
void PhysicsDebugPass::PrepareFrame(u32 frameSlot, void PhysicsDebugPass::PrepareFrame(u32 frameSlot,
@@ -168,7 +165,7 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
}; };
const std::array<vk::ShaderEXT, 2> shaders = {m_Vert, m_Frag}; const std::array<vk::ShaderEXT, 2> shaders = {m_Vert.GetHandle(), m_Frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
// layout 的 push range 是 vertex|fragment(CreatePipelineLayout 默认), // layout 的 push range 是 vertex|fragment(CreatePipelineLayout 默认),
+6 -11
View File
@@ -113,11 +113,11 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{uboSetLayout}, std::vector<vk::DescriptorSetLayout>{uboSetLayout},
sizeof(glm::mat4)); sizeof(glm::mat4));
forwardVert = vert.Handle; forwardVert = std::move(vert);
forwardFrag = frag.Handle; forwardFrag = std::move(frag);
translucentFrag = transFrag.Handle; translucentFrag = std::move(transFrag);
shadowVert = shadowVertShader.Handle; shadowVert = std::move(shadowVertShader);
shadowFrag = shadowFragShader.Handle; shadowFrag = std::move(shadowFragShader);
if (!forwardVert || !forwardFrag || !translucentFrag || if (!forwardVert || !forwardFrag || !translucentFrag ||
!shadowVert || !shadowFrag) { !shadowVert || !shadowFrag) {
@@ -190,12 +190,7 @@ namespace Engine::Passes
{ {
const auto& vkDevice = m_Device.GetDevice(); const auto& vkDevice = m_Device.GetDevice();
if (forwardVert) vkDevice.destroyShaderEXT(forwardVert); // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄
if (forwardFrag) vkDevice.destroyShaderEXT(forwardFrag);
if (translucentFrag) vkDevice.destroyShaderEXT(translucentFrag);
if (shadowVert) vkDevice.destroyShaderEXT(shadowVert);
if (shadowFrag) vkDevice.destroyShaderEXT(shadowFrag);
vkDevice.destroySampler(shadowSampler); vkDevice.destroySampler(shadowSampler);
vkDevice.destroyPipelineLayout(forwardLayout); vkDevice.destroyPipelineLayout(forwardLayout);
vkDevice.destroyPipelineLayout(shadowLayout); vkDevice.destroyPipelineLayout(shadowLayout);
@@ -5,7 +5,6 @@
#include <Engine/Renderer/Passes/SelectionMaskPass.h> #include <Engine/Renderer/Passes/SelectionMaskPass.h>
#include <Engine/Renderer/Passes/SceneGpu.h> #include <Engine/Renderer/Passes/SceneGpu.h>
#include <Engine/Vulkan/ShaderManager.h> #include <Engine/Vulkan/ShaderManager.h>
#include <Engine/Vulkan/Device.h>
#include <Engine/Renderer/Vertex.h> #include <Engine/Renderer/Vertex.h>
#include <Engine/Renderer/Mesh.h> #include <Engine/Renderer/Mesh.h>
@@ -13,10 +12,10 @@
namespace Engine::Passes namespace Engine::Passes
{ {
SelectionMaskPass::SelectionMaskPass(Device& device, ShaderManager& shaders, SelectionMaskPass::SelectionMaskPass(ShaderManager& shaders,
SceneGpu& gpu, FrameSceneData& frame, SceneGpu& gpu, FrameSceneData& frame,
RG::TextureHandle mask) 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 // 恒 1 片元;布局数组必须与 forwardVert 完全一致(shader object
// 要求同程序各 shader 的 set layouts 逐项相同,VUID-08879), // 要求同程序各 shader 的 set layouts 逐项相同,VUID-08879),
@@ -29,12 +28,6 @@ namespace Engine::Passes
0); 0);
} }
SelectionMaskPass::~SelectionMaskPass()
{
// VkShaderEXT 是 Device 子对象,必须在 vkDestroyDevice 前销毁
if (m_Frag.Handle) m_Device.GetDevice().destroyShaderEXT(m_Frag.Handle);
}
void SelectionMaskPass::Register(RG::RenderGraph& rg) void SelectionMaskPass::Register(RG::RenderGraph& rg)
{ {
rg.AddPass("SelectionMask", [this](RG::RenderGraphContext& ctx) { rg.AddPass("SelectionMask", [this](RG::RenderGraphContext& ctx) {
@@ -66,8 +59,8 @@ namespace Engine::Passes
std::array<vk::ShaderStageFlagBits, 2> stages = { std::array<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment}; vk::ShaderStageFlagBits::eFragment};
std::array<vk::ShaderEXT, 2> shaders = {m_Gpu.forwardVert, std::array<vk::ShaderEXT, 2> shaders = {
m_Frag.Handle}; m_Gpu.forwardVert.GetHandle(), m_Frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
// Set0:本帧槽位 UBO + 实例/蒙皮 SSBO(Set1 材质、Set2 // Set0:本帧槽位 UBO + 实例/蒙皮 SSBO(Set1 材质、Set2
+2 -1
View File
@@ -42,7 +42,8 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
}; };
std::array<vk::ShaderEXT, 2> shaders = {m_Gpu.shadowVert, m_Gpu.shadowFrag}; std::array<vk::ShaderEXT, 2> shaders = {
m_Gpu.shadowVert.GetHandle(), m_Gpu.shadowFrag.GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
// ---- 动态状态(depth-only)---- // ---- 动态状态(depth-only)----
+4 -5
View File
@@ -48,8 +48,8 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{m_SetLayout}, std::vector<vk::DescriptorSetLayout>{m_SetLayout},
sizeof(glm::mat4)); sizeof(glm::mat4));
m_Vert = vert.Handle; m_Vert = std::move(vert);
m_Frag = frag.Handle; m_Frag = std::move(frag);
if (!m_Vert || !m_Frag) { if (!m_Vert || !m_Frag) {
ENGINE_FATAL("SkyboxPass: failed to create shader objects"); ENGINE_FATAL("SkyboxPass: failed to create shader objects");
} }
@@ -69,8 +69,7 @@ namespace Engine::Passes
{ {
const auto& vkDevice = m_Device.GetDevice(); const auto& vkDevice = m_Device.GetDevice();
if (m_Vert) vkDevice.destroyShaderEXT(m_Vert); // shader 随 ShaderRef 引用计数自动销毁,此处只清其余原生句柄
if (m_Frag) vkDevice.destroyShaderEXT(m_Frag);
vkDevice.destroyPipelineLayout(m_Layout); vkDevice.destroyPipelineLayout(m_Layout);
vkDevice.destroyDescriptorSetLayout(m_SetLayout); vkDevice.destroyDescriptorSetLayout(m_SetLayout);
} }
@@ -123,7 +122,7 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment vk::ShaderStageFlagBits::eFragment
}; };
const std::array<vk::ShaderEXT, 2> shaders = {m_Vert, m_Frag}; const std::array<vk::ShaderEXT, 2> shaders = {m_Vert.GetHandle(), m_Frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders); cmd.bindShadersEXT(stages, shaders);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
+2 -2
View File
@@ -423,7 +423,7 @@ namespace Engine
// UE 透墙可见语义)→ Outline(叠加在 Tonemap 后的 PresentTarget // UE 透墙可见语义)→ Outline(叠加在 Tonemap 后的 PresentTarget
// 上,恒定 LDR 描边色) // 上,恒定 LDR 描边色)
m_Passes.push_back(CreateScope<Passes::SelectionMaskPass>( m_Passes.push_back(CreateScope<Passes::SelectionMaskPass>(
*m_Device, *m_ShaderManager, *m_SceneGpu, frame, m_SelectionMask)); *m_ShaderManager, *m_SceneGpu, frame, m_SelectionMask));
m_Passes.push_back(CreateScope<Passes::TAAPass>( m_Passes.push_back(CreateScope<Passes::TAAPass>(
*m_FullscreenGpu, frame, /*historyAlpha*/ 0.9f, m_HDRColor, *m_FullscreenGpu, frame, /*historyAlpha*/ 0.9f, m_HDRColor,
m_Velocity, m_TAAColor)); m_Velocity, m_TAAColor));
@@ -440,7 +440,7 @@ namespace Engine
// 排在 Tonemap 前,会被 Tonemap 整帧覆盖(WAW 序 = 注册序)。 // 排在 Tonemap 前,会被 Tonemap 整帧覆盖(WAW 序 = 注册序)。
// Blit/ImGui 之前——它们把 PresentTarget 送去 backbuffer/UI。 // Blit/ImGui 之前——它们把 PresentTarget 送去 backbuffer/UI。
m_Passes.push_back(CreateScope<Passes::OutlinePass>( m_Passes.push_back(CreateScope<Passes::OutlinePass>(
*m_Device, *m_FullscreenGpu, *m_ShaderManager, frame, *m_FullscreenGpu, *m_ShaderManager, frame,
m_SelectionMask, m_PresentTarget)); m_SelectionMask, m_PresentTarget));
// Direct 模式适配器:PresentTarget → backbuffer(Viewport 模式空转)。 // Direct 模式适配器:PresentTarget → backbuffer(Viewport 模式空转)。
// 必须注册在 ImGui 之前:两者都写 backbuffer,WAW 边按声明序 // 必须注册在 ImGui 之前:两者都写 backbuffer,WAW 边按声明序
+89 -86
View File
@@ -8,105 +8,108 @@
#include <array> #include <array>
#include <fstream> #include <fstream>
#include <utility>
namespace Engine { namespace Engine {
ShaderManager::ShaderManager(Device& device) // Entry 析构在 cpp:destroyShaderEXT 需要 Device 完整类型,
: m_Device(device) // 持有方 TU 只有前置声明也不受影响
{ ShaderManager::ShaderRef::Entry::~Entry()
} {
if (handle && device) {
ShaderManager::~ShaderManager() device->GetDevice().destroyShaderEXT(handle);
{ }
}
ShaderObject ShaderManager::CreateFromFile(const std::string& spvPath,
const vk::ShaderStageFlagBits stage,
const std::vector<vk::DescriptorSetLayout>& 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<u32>& spirv,
const vk::ShaderStageFlagBits stage,
const std::vector<vk::DescriptorSetLayout>& 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);
} }
std::array<vk::PushConstantRange, 1> pushRanges; ShaderManager::ShaderManager(Device& device)
if (pushConstantSize > 0) { : m_Device(device)
// 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; ShaderManager::ShaderRef ShaderManager::CreateFromFile(const std::string& spvPath,
try { const vk::ShaderStageFlagBits stage,
const auto result = m_Device.GetDevice().createShadersEXT(createInfo); const std::vector<vk::DescriptorSetLayout>& layouts,
shader = result.value[0]; const u32 pushConstantSize)
} {
catch (const vk::SystemError& e) { const auto spirv = ReadSPIRV(spvPath);
ENGINE_ERROR("Failed to create shader object: {}", e.what()); if (spirv.empty()) {
return { nullptr, stage }; 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<u32>& spirv,
} const vk::ShaderStageFlagBits stage,
const std::vector<vk::DescriptorSetLayout>& 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 vk::ShaderCreateInfoEXT createInfo;
{ createInfo.setStage(stage)
if (shader.Handle) { .setNextStage(nextStage)
m_Device.GetDevice().destroyShaderEXT(shader.Handle); .setCodeType(vk::ShaderCodeTypeEXT::eSpirv)
} .setCodeSize(spirv.size() * sizeof(u32))
} .setPCode(spirv.data())
.setPName("main");
std::vector<u32> ShaderManager::ReadSPIRV(const std::string& path) if (!layouts.empty()) {
{ createInfo.setSetLayouts(layouts);
std::ifstream file(path, std::ios::binary | std::ios::ate); }
if (!file) {
ENGINE_ERROR("Failed to open: {}", path); std::array<vk::PushConstantRange, 1> pushRanges;
return {}; 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<ShaderRef::Entry>();
entry->handle = shader;
entry->stage = stage;
entry->device = &m_Device;
return ShaderRef(std::move(entry));
} }
const size_t size = file.tellg(); std::vector<u32> ShaderManager::ReadSPIRV(const std::string& path)
std::vector<u32> buffer(size / sizeof(u32)); {
file.seekg(0); std::ifstream file(path, std::ios::binary | std::ios::ate);
file.read(reinterpret_cast<char*>(buffer.data()), size); if (!file) {
file.close(); ENGINE_ERROR("Failed to open: {}", path);
return {};
}
return buffer; const size_t size = file.tellg();
} std::vector<u32> buffer(size / sizeof(u32));
file.seekg(0);
file.read(reinterpret_cast<char*>(buffer.data()), size);
file.close();
return buffer;
}
} // namespace Engine } // namespace Engine