use concinnity_core::render::error::RenderResult;
use concinnity_core::render::post::device::PostExtent;
use concinnity_core::render::post::ssao::settings::SsaoSettings;
use concinnity_core::render::post::ssao::{OCCLUSION_FORMAT, SsaoInputs, SsaoPass, SsaoPipelines};
use windows::Win32::Graphics::Direct3D12::*;
use crate::directx::allocator::PooledTexture;
use crate::directx::context::DxContext;
use crate::directx::descriptor_slot::SrvSlot;
use crate::directx::post::post_device::{DxPostDevice, PooledTarget, PostPipeline, PostTarget};
pub(in crate::directx) struct SsaoState {
pub resources: Option<SsaoResources>,
#[expect(
dead_code,
reason = "held to keep the fallback texture resident; the pass binds white_srv_gpu"
)]
pub white: PooledTexture,
pub white_srv_gpu: SrvSlot,
}
pub(in crate::directx) struct SsaoResources {
pub(in crate::directx) settings: SsaoSettings,
pass: SsaoPass<PostPipeline, PostTarget>,
output: PooledTarget,
}
impl SsaoResources {
pub(in crate::directx) fn new(
device: &DxPostDevice,
settings: SsaoSettings,
extent: PostExtent,
ao_output: &ID3D12Resource,
) -> RenderResult<Self> {
Ok(Self {
settings,
pass: SsaoPass::new(device, extent)?,
output: device.pooled_target(ao_output, OCCLUSION_FORMAT, extent)?,
})
}
pub(in crate::directx) fn resize(
&mut self,
device: &DxPostDevice,
extent: PostExtent,
ao_output: &ID3D12Resource,
) -> RenderResult<()> {
self.pass.resize(device, extent)?;
self.repoint_output(device, extent, ao_output)
}
pub(in crate::directx) fn repoint_output(
&mut self,
device: &DxPostDevice,
extent: PostExtent,
ao_output: &ID3D12Resource,
) -> RenderResult<()> {
self.output = device.pooled_target(ao_output, OCCLUSION_FORMAT, extent)?;
Ok(())
}
pub(in crate::directx) fn swap_pipelines(&mut self, pipelines: SsaoPipelines<PostPipeline>) {
self.pass.swap_pipelines(pipelines);
}
}
impl DxContext {
pub(in crate::directx) fn ssao_ao_srv_gpu(&self) -> SrvSlot {
match &self.ssao.resources {
Some(s) => s.output.srv_gpu(),
None => self.ssao.white_srv_gpu,
}
}
pub(in crate::directx) fn encode_ssao(
&self,
cmd: &ID3D12GraphicsCommandList,
frame_idx: usize,
fov_y_radians: f32,
aspect: f32,
) -> RenderResult<()> {
let (Some(ssao), Some(gbuffer)) = (&self.ssao.resources, &self.gbuffer) else {
return Ok(());
};
ssao.pass.encode(
&self.post_device(frame_idx),
cmd,
SsaoInputs {
normal_depth: gbuffer.normal_depth_srv_gpu,
output: ssao.output.attachment(),
},
&ssao.settings.params(fov_y_radians, aspect),
)
}
}