Files
HelloVulkan/Engine/src/Vulkan/DescriptorManager.cpp
T
atdunbg 1d690067bd feat: IBL 预积分 GPU compute 化 + 环境资产入 Assets 层(动态切换)
CPU 逐像素卷积(venice 4k 阻塞 7.36s)→ 4 个 compute shader 一次性
提交:equirect→cube / irradiance / prefilter×5mip / BRDF LUT。
Cubemap 瘦身为纯资源持有类,生成职责移交 IblGenerator;
环境经 AssetManager 缓存(EnvRef),Renderer::SetEnvironment
动态换绑(RenderPass::OnEnvironmentChanged 广播)。
调试视图 +4:EnvCube / Irradiance / Prefilter / BRDF LUT。

性能前后对比(RTX 5060 Laptop,venice_dawn_1_4k.hdr):
- 改造前 CPU:7.36 s(主线程阻塞)
- 改造后 GPU:HDR decode 127-134ms + 资源 22-35ms + compute 17-19ms
  ≈ 165-190ms(约 40×);Neutral 兜底 ~6ms
- 运行中动态切换环境同量级(ms 级 GPU,decode 占大头)

冒烟:两构建目录 0 警告;运行期 0 validation(含两次环境切换 +
调试视图 9-12 轮播自动化验证)。
2026-09-24 13:23:59 +08:00

199 lines
7.5 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/DescriptorManager.h>
#include <Engine/Vulkan/Device.h>
#include <Engine/Core/Log.h>
namespace Engine
{
DescriptorManager::DescriptorManager(Device& device)
: m_Device(device)
{
m_Pools.push_back(CreateChunk());
ENGINE_INFO("DescriptorManager created (growable, chunk = {} sets)",
kChunkSets);
}
DescriptorManager::~DescriptorManager()
{
for (const auto pool : m_Pools) {
m_Device.GetDevice().destroyDescriptorPool(pool);
}
}
vk::DescriptorPool DescriptorManager::CreateChunk() const
{
std::array<vk::DescriptorPoolSize, 4> poolSizes = {
vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, kChunkSets),
vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, kChunkSets),
vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, kChunkSets),
vk::DescriptorPoolSize(vk::DescriptorType::eStorageImage, kChunkSets),
};
vk::DescriptorPoolCreateInfo poolInfo;
poolInfo.setMaxSets(kChunkSets)
.setPoolSizes(poolSizes)
.setFlags(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet);
return m_Device.GetDevice().createDescriptorPool(poolInfo);
}
vk::DescriptorSetLayout DescriptorManager::CreateLayout(const std::vector<DescriptorBinding>& bindings) const
{
std::vector<vk::DescriptorSetLayoutBinding> vkBindings;
for (auto& b : bindings)
{
vk::DescriptorSetLayoutBinding vkb;
vkb.setBinding(b.Binding)
.setDescriptorType(b.Type)
.setDescriptorCount(1)
.setStageFlags(b.Stages);
vkBindings.push_back(vkb);
}
vk::DescriptorSetLayoutCreateInfo layoutInfo;
layoutInfo.setBindings(vkBindings);
return m_Device.GetDevice().createDescriptorSetLayout(layoutInfo);
}
vk::DescriptorSet DescriptorManager::AllocateDescriptorSet(vk::DescriptorSetLayout layout)
{
// 从最新块分配;耗尽(OutOfPool/Fragmented)则追加一块重试
for (;;) {
try {
vk::DescriptorSetAllocateInfo allocInfo;
allocInfo.setDescriptorPool(m_Pools.back())
.setSetLayouts(layout);
auto sets = m_Device.GetDevice().allocateDescriptorSets(allocInfo);
return sets[0];
} catch (const vk::OutOfPoolMemoryError&) {
m_Pools.push_back(CreateChunk());
ENGINE_INFO("DescriptorManager: pool chunk grown -> {} chunks",
m_Pools.size());
} catch (const vk::FragmentedPoolError&) {
m_Pools.push_back(CreateChunk());
ENGINE_INFO("DescriptorManager: pool fragmented, new chunk -> {}",
m_Pools.size());
}
}
}
void DescriptorManager::UpdateUniformBuffer(const vk::DescriptorSet set, const u32 binding,
const vk::Buffer buffer, const u64 size) const
{
vk::DescriptorBufferInfo bufferInfo;
bufferInfo.setBuffer(buffer).setOffset(0).setRange(size);
vk::WriteDescriptorSet write;
write.setDstSet(set)
.setDstBinding(binding)
.setDstArrayElement(0)
.setDescriptorType(vk::DescriptorType::eUniformBuffer)
.setDescriptorCount(1)
.setBufferInfo(bufferInfo);
m_Device.GetDevice().updateDescriptorSets(write, {});
}
void DescriptorManager::UpdateStorageBuffer(const vk::DescriptorSet set, const u32 binding,
const vk::Buffer buffer, const u64 size) const
{
vk::DescriptorBufferInfo bufferInfo;
bufferInfo.setBuffer(buffer).setOffset(0).setRange(size);
vk::WriteDescriptorSet write;
write.setDstSet(set)
.setDstBinding(binding)
.setDstArrayElement(0)
.setDescriptorType(vk::DescriptorType::eStorageBuffer)
.setDescriptorCount(1)
.setBufferInfo(bufferInfo);
m_Device.GetDevice().updateDescriptorSets(write, {});
}
void DescriptorManager::UpdateTexture(const vk::DescriptorSet set, const u32 binding,
const vk::Sampler sampler, const vk::ImageView view) const
{
vk::DescriptorImageInfo imageInfo;
imageInfo.setSampler(sampler)
.setImageView(view)
.setImageLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
vk::WriteDescriptorSet write;
write.setDstSet(set)
.setDstBinding(binding)
.setDstArrayElement(0)
.setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
.setDescriptorCount(1)
.setImageInfo(imageInfo);
m_Device.GetDevice().updateDescriptorSets(write, {});
}
void DescriptorManager::UpdateStorageImage(const vk::DescriptorSet set,
const u32 binding,
const vk::ImageView view) const
{
// storage image 写(compute 输出):layout 必须 eGeneral
vk::DescriptorImageInfo imageInfo;
imageInfo.setImageView(view)
.setImageLayout(vk::ImageLayout::eGeneral);
vk::WriteDescriptorSet write;
write.setDstSet(set)
.setDstBinding(binding)
.setDstArrayElement(0)
.setDescriptorType(vk::DescriptorType::eStorageImage)
.setDescriptorCount(1)
.setImageInfo(imageInfo);
m_Device.GetDevice().updateDescriptorSets(write, {});
}
vk::PipelineLayout DescriptorManager::CreatePipelineLayout(vk::DescriptorSetLayout layout,
const u32 pushConstantSize) const
{
vk::PipelineLayoutCreateInfo info;
info.setSetLayouts(layout);
// 关键:数组声明在 if 外面,生命周期覆盖到 createPipelineLayout
std::array<vk::PushConstantRange, 1> pushRanges;
if (pushConstantSize > 0)
{
pushRanges[0].setStageFlags(vk::ShaderStageFlagBits::eVertex)
.setOffset(0)
.setSize(pushConstantSize);
info.setPushConstantRanges(pushRanges);
}
return m_Device.GetDevice().createPipelineLayout(info);
}
vk::PipelineLayout DescriptorManager::CreatePipelineLayout(const std::vector<vk::DescriptorSetLayout>& layouts,
const u32 pushConstantSize,
const vk::ShaderStageFlags pushStages) const
{
vk::PipelineLayoutCreateInfo info;
info.setSetLayouts(layouts);
std::array<vk::PushConstantRange, 1> pushRanges;
if (pushConstantSize > 0) {
// 与 ShaderManager 一致:程序级声明(默认 vertex|fragment)。
// 注意 vkCmdPushConstants 的 stageFlags 必须覆盖 range 的
// 全部 stage(VUID-01796),因此 push 调用点也要带同样的 stage
pushRanges[0].setStageFlags(pushStages)
.setOffset(0)
.setSize(pushConstantSize);
info.setPushConstantRanges(pushRanges);
}
return m_Device.GetDevice().createPipelineLayout(info);
}
} // namespace Engine