Files
HelloVulkan/Engine/src/Vulkan/ShaderManager.cpp
T
atdunbg 952ba8135d feat: HDR 管线 + Tonemap pass,显示变换显式建模
管线:Shadow → Forward(写 HDRColor R16G16B16A16F) → Tonemap →
ImGui(loadOp=Load) → Present。对齐 UE/Unity 结构:场景线性值
进 HDR 离屏图,Tonemap(全屏三角,exposure push + gamma 编码)
显式完成显示变换,Backbuffer 只接收显示空间颜色。

- Swapchain 改 B8G8R8A8Unorm:Srgb 附件会硬件二次提亮,UI 泛白
  (#4296FA→#8CCBFC);Unorm 下写什么显示什么,编码责任归 Tonemap
- Shader object push range 规则落地:程序级声明——同一 pass 的
  全部 shader EXT range 定义必须一致(VUID-08878),layout 同样
  按 vertex|fragment 声明,push 调用点覆盖全部声明 stage(VUID-01796)
- Tonemap 装配:Set0 = HDR 图(per-frame-slot 描述符 + GetPhysicalView),
  clamp 占位待 ACES 替换,bloom/FXAA 等后处理在 HDR 域插 pass
- CMake 加 imgui_demo.cpp(ShowDemoWindow 链接)
- 修复:m_TonemapDescriptorSets 未 resize 即下标写入(启动即崩)

验证:5 pass 全活,validation 0 error 0 warning,UI 原生色彩无泛白
2026-09-22 19:00:56 +08:00

108 lines
3.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// Created by atdunbg on 2026/9/20.
//
#include <Engine/Vulkan/ShaderManager.h>
#include <Engine/Vulkan/Device.h>
#include <Engine/Core/Log.h>
#include <array>
#include <fstream>
namespace Engine {
ShaderManager::ShaderManager(Device& device)
: m_Device(device)
{
}
ShaderManager::~ShaderManager()
{
}
ShaderObject ShaderManager::CreateFromFile(const std::string& spvPath,
vk::ShaderStageFlagBits stage,
const std::vector<vk::DescriptorSetLayout>& layouts,
u32 pushConstantSize)
{
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,
vk::ShaderStageFlagBits stage,
const std::vector<vk::DescriptorSetLayout>& layouts,
u32 pushConstantSize)
{
vk::ShaderStageFlags nextStage = {};
if (stage == vk::ShaderStageFlagBits::eVertex) {
nextStage = vk::ShaderStageFlagBits::eFragment;
}
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;
if (pushConstantSize > 0) {
// push range 是"程序级"声明:shader object 要求同一程序绑定的
// 全部 shader(vert+frag)push range 定义完全一致(VUID-08878),
// 因此统一按 vertex|fragment 声明;shader 实际读取哪些字节由
// GLSL 的 push_constant block 决定,声明范围只是能力上限
pushRanges[0].setStageFlags(vk::ShaderStageFlagBits::eVertex |
vk::ShaderStageFlagBits::eFragment)
.setOffset(0)
.setSize(pushConstantSize);
createInfo.setPushConstantRanges(pushRanges);
}
vk::ShaderEXT shader;
try {
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 };
}
return { shader, stage };
}
void ShaderManager::Destroy(const ShaderObject& shader)
{
if (shader.Handle) {
m_Device.GetDevice().destroyShaderEXT(shader.Handle);
}
}
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 {};
}
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