use concinnity_core::render::error::RenderResult;
use concinnity_core::render::post::device::{PostExtent, PostPassDevice};
use concinnity_core::render::post::ssr::settings::SsrSettings;
use concinnity_core::render::post::ssr::{SsrInputs, SsrPass, target_desc};
use windows::Win32::Graphics::Direct3D12::*;
use crate::directx::context::DxContext;
use crate::directx::descriptor_slot::SrvSlot;
use crate::directx::post::post_device::{DxPostDevice, PostPipeline, PostTarget};
const TARGET_LABEL: &str = "ssr_reflection";
pub(in crate::directx) struct SsrResolve {
pub(in crate::directx) settings: SsrSettings,
pass: SsrPass<PostPipeline>,
pub(in crate::directx) output: PostTarget,
}
pub(in crate::directx) struct SsrResources {
pub(in crate::directx) resolve: Option<SsrResolve>,
}
impl SsrResources {
pub(in crate::directx) fn new(
device: &DxPostDevice,
width: u32,
height: u32,
resolve_settings: Option<SsrSettings>,
) -> RenderResult<Self> {
let resolve = match resolve_settings {
Some(settings) => Some(SsrResolve {
settings,
pass: SsrPass::new(device)?,
output: device.create_target(
TARGET_LABEL,
&target_desc(),
PostExtent { width, height },
)?,
}),
None => None,
};
Ok(Self { resolve })
}
pub(in crate::directx) fn resize_to(
&mut self,
device: &DxPostDevice,
width: u32,
height: u32,
) -> RenderResult<()> {
if let Some(r) = self.resolve.as_mut() {
r.output =
device.create_target(TARGET_LABEL, &target_desc(), PostExtent { width, height })?;
}
Ok(())
}
pub(in crate::directx) fn swap_pipeline(&mut self, pipeline: PostPipeline) {
if let Some(r) = self.resolve.as_mut() {
r.pass.swap_pipeline(pipeline);
}
}
}
impl DxContext {
pub(in crate::directx) fn post_scene_target(&self) -> &ID3D12Resource {
match self
.reflection_composite
.as_ref()
.filter(|_| self.reflection_resolve_active())
{
Some(rc) => rc.output().resource(),
None => self.hdr_scene_target(),
}
}
pub(in crate::directx) fn post_scene_rtv(&self) -> D3D12_CPU_DESCRIPTOR_HANDLE {
match self
.reflection_composite
.as_ref()
.filter(|_| self.reflection_resolve_active())
{
Some(rc) => rc.output().rtv(),
None => self.hdr_scene_rtv(),
}
}
pub(in crate::directx) fn scene_srv_for_post(&self) -> SrvSlot {
if let Some(up) = &self.upscale.backend {
return up.output().srv_gpu();
}
if let Some(rc) = self.reflection_composite.as_ref()
&& self.reflection_resolve_active()
{
return rc.output().srv_gpu();
}
self.targets.hdr.srv_gpu
}
pub(in crate::directx) fn prefilter_cube_srv_gpu(&self) -> SrvSlot {
SrvSlot::at(
&self.descriptors.srv_heap,
self.descriptors.srv_descriptor_size,
2,
)
}
pub(in crate::directx) fn encode_ssr_resolve(
&self,
cmd: &ID3D12GraphicsCommandList,
frame_idx: usize,
fov_y_radians: f32,
aspect: f32,
cam_pos: [f32; 3],
) {
let Some(resolve) = self.ssr.as_ref().and_then(|s| s.resolve.as_ref()) else {
return;
};
let Some(gbuffer) = &self.gbuffer 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 = resolve.settings.params(
fov_y_radians,
aspect,
inv_view_rot,
cam_pos,
self.scene.env_map.prefilter_mip_count as f32,
self.state.view.sky_rot,
);
let device = self.post_device(frame_idx);
if let Err(e) = resolve.pass.encode(
&device,
cmd,
SsrInputs {
target: device.target_attachment(&resolve.output),
scene: self.targets.hdr.srv_gpu,
normal_depth: gbuffer.normal_depth_srv_gpu,
roughness: gbuffer.roughness_srv_gpu,
prefilter: self.prefilter_cube_srv_gpu(),
},
¶ms,
) {
tracing::error!("SSR resolve: {e}");
return;
}
self.encode_reflection_composite(cmd, frame_idx, resolve.output.srv_gpu());
}
}