use ash::vk;
use concinnity_core::gfx::render_types::PostProcessParams;
use concinnity_core::render::error::RenderResult;
use super::InitGpu;
use crate::vulkan::context::{BloomState, HDR_FORMAT, VkTargets};
use crate::vulkan::owned::OwnedSampler;
use crate::vulkan::post::bloom::{
BloomDeviceContext, MAX_BLOOM_MIPS, alloc_bloom_input_sets, compile_bloom_shaders,
create_bloom_chain, create_bloom_framebuffers, create_bloom_pipeline, rebind_bloom_input0,
};
use crate::vulkan::post::reflection_composite::ReflectionCompositeResources;
use crate::vulkan::render_pass::create_bloom_render_pass;
use crate::vulkan::resources::{create_descriptor_set_layout, source_set_bindings};
pub(super) struct BloomInputs<'a> {
pub(super) targets: &'a VkTargets,
pub(super) extent: vk::Extent2D,
pub(super) sampler: &'a OwnedSampler,
pub(super) reflection_composite: Option<&'a ReflectionCompositeResources>,
}
pub(super) fn build_bloom(gpu: &InitGpu<'_>, inputs: BloomInputs<'_>) -> RenderResult<BloomState> {
let InitGpu {
hw,
command_pool,
frames,
hot_reload,
} = *gpu;
let device = &hw.device;
let BloomInputs {
targets,
extent,
sampler,
reflection_composite,
} = inputs;
let write_pass = create_bloom_render_pass(device, HDR_FORMAT, false)?;
let blend_pass = create_bloom_render_pass(device, HDR_FORMAT, true)?;
let set_layout = create_descriptor_set_layout(device, &source_set_bindings(1))?;
let post_pc_range = vk::PushConstantRange::default()
.stage_flags(vk::ShaderStageFlags::FRAGMENT)
.offset(0)
.size(std::mem::size_of::<PostProcessParams>() as u32);
let set_layouts = [set_layout.handle()];
let pipeline_layout = device
.create_pipeline_layout(
&vk::PipelineLayoutCreateInfo::default()
.set_layouts(&set_layouts)
.push_constant_ranges(std::slice::from_ref(&post_pc_range)),
)
.map_err(|e| crate::vulkan::error::map_vk_result(e, "bloom pipeline layout"))?;
let bs = compile_bloom_shaders(hot_reload)?;
let pipeline_prefilter = create_bloom_pipeline(
device,
write_pass.handle(),
pipeline_layout.handle(),
&bs.vert,
&bs.prefilter,
false,
)?;
let pipeline_downsample = create_bloom_pipeline(
device,
write_pass.handle(),
pipeline_layout.handle(),
&bs.vert,
&bs.downsample,
false,
)?;
let pipeline_upsample = create_bloom_pipeline(
device,
blend_pass.handle(),
pipeline_layout.handle(),
&bs.vert,
&bs.upsample,
true,
)?;
let bloom_top_pairs = targets.transient_pool.pairs_for_frames("bloom_top", frames);
let (mips, mip_extents) = create_bloom_chain(
&BloomDeviceContext {
alloc: &hw.alloc,
device,
command_pool,
queue: hw.graphics_queue,
},
extent,
frames,
&bloom_top_pairs,
)?;
let (write_framebuffers, blend_framebuffers) = create_bloom_framebuffers(
device,
write_pass.handle(),
blend_pass.handle(),
&mips,
&mip_extents,
)?;
let bloom_pool_capacity = frames as u32 * (MAX_BLOOM_MIPS + 1);
let bloom_pool_sizes = [
vk::DescriptorType::SAMPLED_IMAGE,
vk::DescriptorType::SAMPLER,
]
.map(|ty| {
vk::DescriptorPoolSize::default()
.ty(ty)
.descriptor_count(bloom_pool_capacity)
});
let descriptor_pool = device
.create_descriptor_pool(
&vk::DescriptorPoolCreateInfo::default()
.pool_sizes(&bloom_pool_sizes)
.max_sets(bloom_pool_capacity),
)
.map_err(|e| crate::vulkan::error::map_vk_result(e, "bloom descriptor pool"))?;
let input_sets = alloc_bloom_input_sets(
device,
descriptor_pool.handle(),
set_layout.handle(),
sampler.handle(),
&targets.hdr_resolve_images,
&mips,
)?;
if let Some(view) = reflection_composite.map(|c| c.output.view) {
for frame_sets in &input_sets {
rebind_bloom_input0(device, frame_sets[0], view);
}
}
Ok(BloomState {
write_pass,
blend_pass,
pipeline_prefilter,
pipeline_downsample,
pipeline_upsample,
pipeline_layout,
set_layout,
descriptor_pool,
mips,
mip_extents,
write_framebuffers,
blend_framebuffers,
input_sets,
})
}