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
+9 -12
View File
@@ -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<vk::ShaderStageFlagBits, 1> computeStage = {
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.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
m_IblLayout, 0, setToCube, {});
@@ -434,7 +431,7 @@ namespace Engine
vk::DependencyInfo{}.setImageMemoryBarriers(envToRead));
// 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.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<vk::ShaderEXT, 1> prefShaders = {m_PrefShader};
std::array<vk::ShaderEXT, 1> 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<vk::ShaderEXT, 1> lutShaders = {m_LutShader};
std::array<vk::ShaderEXT, 1> lutShaders = {m_LutShader.GetHandle()};
m_Cmd.bindShadersEXT(computeStage, lutShaders);
m_Cmd.bindDescriptorSets(vk::PipelineBindPoint::eCompute,
m_LutLayout, 0, setLut, {});
+2 -2
View File
@@ -67,8 +67,8 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eFragment
};
std::array<vk::ShaderEXT, 2> 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:本帧槽位的阴影图
+9 -15
View File
@@ -74,12 +74,12 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{setLayout},
static_cast<u32>(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<vk::ShaderEXT, 2> shaders = {vert, frag};
std::array<vk::ShaderEXT, 2> shaders = {vert.GetHandle(), frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
+5 -8
View File
@@ -67,8 +67,8 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eFragment,
std::vector<vk::DescriptorSetLayout>{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<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex,
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);
// Set0 = uboSets(UBO + 实例矩阵 + 蒙皮 + 实体 id)
+3 -10
View File
@@ -9,7 +9,6 @@
#include <Engine/Renderer/Passes/OutlinePass.h>
#include <Engine/Renderer/Passes/FullscreenGpu.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <Engine/Vulkan/Device.h>
#include <Engine/Core/FrameContext.h>
#include <glm/glm.hpp>
@@ -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<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex,
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.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
@@ -84,8 +84,8 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{},
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<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);
// layout 的 push range 是 vertex|fragment(CreatePipelineLayout 默认),
+6 -11
View File
@@ -113,11 +113,11 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{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);
@@ -5,7 +5,6 @@
#include <Engine/Renderer/Passes/SelectionMaskPass.h>
#include <Engine/Renderer/Passes/SceneGpu.h>
#include <Engine/Vulkan/ShaderManager.h>
#include <Engine/Vulkan/Device.h>
#include <Engine/Renderer/Vertex.h>
#include <Engine/Renderer/Mesh.h>
@@ -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<vk::ShaderStageFlagBits, 2> stages = {
vk::ShaderStageFlagBits::eVertex,
vk::ShaderStageFlagBits::eFragment};
std::array<vk::ShaderEXT, 2> shaders = {m_Gpu.forwardVert,
m_Frag.Handle};
std::array<vk::ShaderEXT, 2> shaders = {
m_Gpu.forwardVert.GetHandle(), m_Frag.GetHandle()};
cmd.bindShadersEXT(stages, shaders);
// Set0:本帧槽位 UBO + 实例/蒙皮 SSBO(Set1 材质、Set2
+2 -1
View File
@@ -42,7 +42,8 @@ namespace Engine::Passes
vk::ShaderStageFlagBits::eVertex,
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);
// ---- 动态状态(depth-only)----
+4 -5
View File
@@ -48,8 +48,8 @@ namespace Engine::Passes
std::vector<vk::DescriptorSetLayout>{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<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.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
+2 -2
View File
@@ -423,7 +423,7 @@ namespace Engine
// UE 透墙可见语义)→ Outline(叠加在 Tonemap 后的 PresentTarget
// 上,恒定 LDR 描边色)
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_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<Passes::OutlinePass>(
*m_Device, *m_FullscreenGpu, *m_ShaderManager, frame,
*m_FullscreenGpu, *m_ShaderManager, frame,
m_SelectionMask, m_PresentTarget));
// Direct 模式适配器:PresentTarget → backbuffer(Viewport 模式空转)。
// 必须注册在 ImGui 之前:两者都写 backbuffer,WAW 边按声明序
+90 -87
View File
@@ -8,105 +8,108 @@
#include <array>
#include <fstream>
#include <utility>
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<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);
// Entry 析构在 cpp:destroyShaderEXT 需要 Device 完整类型,
// 持有方 TU 只有前置声明也不受影响
ShaderManager::ShaderRef::Entry::~Entry()
{
if (handle && device) {
device->GetDevice().destroyShaderEXT(handle);
}
}
std::array<vk::PushConstantRange, 1> 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<vk::DescriptorSetLayout>& 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<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
{
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<u32> 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<vk::PushConstantRange, 1> 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<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> buffer(size / sizeof(u32));
file.seekg(0);
file.read(reinterpret_cast<char*>(buffer.data()), size);
file.close();
std::vector<u32> 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<u32> buffer(size / sizeof(u32));
file.seekg(0);
file.read(reinterpret_cast<char*>(buffer.data()), size);
file.close();
} // namespace Engine
return buffer;
}
} // namespace Engine