use ash::vk;
use concinnity_core::render::error::{RenderError, RenderResult};
use concinnity_core::render::post::ssao::settings::SsaoSettings;
use concinnity_core::render::post::ssao::{OCCLUSION_FORMAT, SsaoInputs, SsaoPass};
use super::super::context::VkContext;
use crate::vulkan::post::pass_cache::AttachmentRest;
use crate::vulkan::post::post_device::{
PostPipeline, PostTarget, VkAttachment, VkPostDevice, post_extent,
};
pub(in crate::vulkan) struct SsaoResources {
pub(in crate::vulkan) settings: SsaoSettings,
pass: SsaoPass<PostPipeline, PostTarget>,
}
impl SsaoResources {
pub(in crate::vulkan) fn new(
device: &VkPostDevice,
settings: SsaoSettings,
extent: vk::Extent2D,
) -> RenderResult<Self> {
Ok(Self {
settings,
pass: SsaoPass::new(device, post_extent(extent))?,
})
}
pub(in crate::vulkan) fn rebuild(
&mut self,
device: &VkPostDevice,
extent: vk::Extent2D,
) -> RenderResult<()> {
self.pass.resize(device, post_extent(extent))
}
pub(in crate::vulkan) fn swap_pipelines(
&mut self,
pipelines: concinnity_core::render::post::ssao::SsaoPipelines<PostPipeline>,
) {
self.pass.swap_pipelines(pipelines);
}
}
impl VkContext {
pub(in crate::vulkan) fn encode_ssao(
&self,
cmd: vk::CommandBuffer,
frame_idx: usize,
fov_y_radians: f32,
aspect: f32,
) -> RenderResult<()> {
let Some(ssao) = &self.ssao else {
return Ok(());
};
let Some(gbuffer) = self.gbuffer_targets().and_then(|gb| gb.frame(frame_idx)) else {
return Ok(());
};
let view = self
.targets
.transient_pool
.view_for("ao_output", frame_idx)
.ok_or_else(|| RenderError::Other("ao_output missing from transient pool".into()))?;
ssao.pass.encode(
&self.post_device(frame_idx),
&cmd,
SsaoInputs {
normal_depth: gbuffer.normal_depth,
output: VkAttachment {
view,
extent: self.targets.render_extent,
format: OCCLUSION_FORMAT,
rest: AttachmentRest::Graph,
},
},
&ssao.settings.params(fov_y_radians, aspect),
)
}
}