use ash::vk;
use concinnity_core::gfx::render_types::CompositeParams;
use concinnity_core::render::error::RenderResult;
use super::InitGpu;
use crate::vulkan::context::{
CompositeState, SwapchainState, VkDescriptors, VkSceneAssets, VkTargets,
};
use crate::vulkan::owned::OwnedSampler;
use crate::vulkan::pipeline::{compile_composite_shaders, create_composite_pipeline};
use crate::vulkan::post::bloom::composite_bloom_view;
use crate::vulkan::post::reflection_composite::VkReflectionCompositePass;
use crate::vulkan::render_pass::create_composite_render_pass;
use crate::vulkan::resources::{
alloc_descriptor_sets, create_descriptor_set_layout, source_set_bindings,
};
use crate::vulkan::set_writes::SetWrites;
use crate::vulkan::swapchain::{create_composite_framebuffers, write_composite_set};
pub(super) const COMPOSITE_SOURCES: u32 = 8;
pub(super) struct CompositeInputs<'a> {
pub(super) swapchain: &'a SwapchainState,
pub(super) descriptors: &'a VkDescriptors,
pub(super) scene: &'a VkSceneAssets,
pub(super) targets: &'a VkTargets,
pub(super) sampler: &'a OwnedSampler,
pub(super) reflection_composite: Option<&'a VkReflectionCompositePass>,
}
pub(super) fn build_composite(
gpu: &InitGpu<'_>,
inputs: CompositeInputs<'_>,
) -> RenderResult<CompositeState> {
let InitGpu {
hw,
frames,
hot_reload,
..
} = *gpu;
let device = &hw.device;
let CompositeInputs {
swapchain,
descriptors,
scene,
targets,
sampler,
reflection_composite,
} = inputs;
let render_pass = create_composite_render_pass(device, swapchain.format)?;
let framebuffers = create_composite_framebuffers(
device,
render_pass.handle(),
&swapchain.image_views,
swapchain.extent,
)?;
let set_layout = create_descriptor_set_layout(device, &source_set_bindings(COMPOSITE_SOURCES))?;
let composite_pc_range = vk::PushConstantRange::default()
.stage_flags(vk::ShaderStageFlags::FRAGMENT)
.offset(0)
.size(std::mem::size_of::<CompositeParams>() 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(&composite_pc_range)),
)
.map_err(|e| crate::vulkan::error::map_vk_result(e, "composite pipeline layout"))?;
let pipeline = {
let (cv, cf) = compile_composite_shaders(hot_reload)?;
create_composite_pipeline(
device,
render_pass.handle(),
pipeline_layout.handle(),
&cv,
&cf,
)?
};
let composite_layouts: Vec<_> = (0..frames).map(|_| set_layout.handle()).collect();
let sets = alloc_descriptor_sets(
device,
descriptors.descriptor_pool.handle(),
&composite_layouts,
)?;
for (i, &set) in sets.iter().enumerate() {
let scene_view = reflection_composite
.map(|c| c.output().view())
.unwrap_or(targets.hdr_resolve_images[i].view);
write_composite_set(
device,
set,
scene_view,
composite_bloom_view(&targets.transient_pool, scene.ssao_white.view, i),
scene.color_lut.view,
);
(COMPOSITE_SOURCES..2 * COMPOSITE_SOURCES)
.fold(SetWrites::new(set), |w, b| w.sampler(b, sampler.handle()))
.apply(device);
}
Ok(CompositeState {
render_pass,
framebuffers,
pipeline,
pipeline_layout,
_set_layout: set_layout,
sets,
})
}