use ash::vk;
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::post::device::PostPassDevice;
use concinnity_core::render::post::ssr::settings::SsrSettings;
use concinnity_core::render::post::ssr::{SsrInputs, SsrPass, target_desc};
use crate::vulkan::context::VkContext;
use crate::vulkan::post::post_device::{PostPipeline, PostTarget, VkPostDevice, post_extent};
const TARGET_LABEL: &str = "ssr_reflection";
pub(in crate::vulkan) struct SsrResources {
pub(in crate::vulkan) settings: Option<SsrSettings>,
pass: SsrPass<PostPipeline>,
pub(in crate::vulkan) output: PostTarget,
}
impl SsrResources {
pub(in crate::vulkan) fn new(
device: &VkPostDevice,
settings: Option<SsrSettings>,
extent: vk::Extent2D,
) -> RenderResult<Self> {
Ok(Self {
settings,
pass: SsrPass::new(device)?,
output: device.create_target(TARGET_LABEL, &target_desc(), post_extent(extent))?,
})
}
pub(in crate::vulkan) fn rebuild(
&mut self,
device: &VkPostDevice,
extent: vk::Extent2D,
) -> RenderResult<()> {
self.output = device.create_target(TARGET_LABEL, &target_desc(), post_extent(extent))?;
Ok(())
}
pub(in crate::vulkan) fn swap_pipeline(&mut self, pipeline: PostPipeline) {
self.pass.swap_pipeline(pipeline);
}
}
impl VkContext {
pub(in crate::vulkan) fn ssr_authored(&self) -> bool {
self.ssr.as_ref().is_some_and(|s| s.settings.is_some())
}
pub(in crate::vulkan) fn encode_ssr_resolve(
&self,
cmd: vk::CommandBuffer,
frame_idx: usize,
fov_y_radians: f32,
aspect: f32,
cam_pos: [f32; 3],
) {
let Some(ssr) = &self.ssr else { return };
let Some(settings) = &ssr.settings else {
return;
};
let Some(gbuffer) = self.gbuffer_targets().and_then(|gb| gb.frame(frame_idx)) else {
return;
};
let v = self.state.view.matrix;
let inv_view_rot = [
[v[0][0], v[1][0], v[2][0], 0.0],
[v[0][1], v[1][1], v[2][1], 0.0],
[v[0][2], v[1][2], v[2][2], 0.0],
[0.0, 0.0, 0.0, 1.0],
];
let params = settings.params(
fov_y_radians,
aspect,
inv_view_rot,
cam_pos,
self.scene.prefilter_mip_count as f32,
self.state.view.sky_rot,
);
let device = self.post_device(frame_idx);
let scene =
&self.targets.hdr_resolve_images[frame_idx % self.targets.hdr_resolve_images.len()];
if let Err(e) = ssr.pass.encode(
&device,
&cmd,
SsrInputs {
target: device.target_attachment(&ssr.output),
scene: scene.view,
normal_depth: gbuffer.normal_depth,
roughness: gbuffer.roughness,
prefilter: self.scene.env_map.prefilter.view,
},
¶ms,
) {
tracing::error!("SSR resolve: {e}");
return;
}
self.encode_reflection_composite(cmd, ssr.output.view(), frame_idx);
}
}