use concinnity_core::gfx::render_types;
use concinnity_core::render::error::RenderResult;
use windows::Win32::Graphics::Direct3D12::*;
use super::CullPlan;
use super::compute::{ComputeCull, status_buffer_size};
use crate::directx::context::{FRAMES, align256, dump_on_err};
use crate::directx::cull::{
INDIRECT_COMMAND_STRIDE, compile_cull_shader_shadow, create_cull_command_signature,
create_cull_pso,
};
use crate::directx::init::InitGpu;
use crate::directx::init::pipelines::{
compile_shadow_bindless_vs, create_shadow_bindless_root_signature, create_shadow_pso,
};
use crate::directx::texture::create_uav_buffer;
pub(super) struct ShadowCull {
pub(super) bindless_root_sig: Option<ID3D12RootSignature>,
pub(super) bindless_pso: Option<ID3D12PipelineState>,
pub(super) cmd_sig: Option<ID3D12CommandSignature>,
pub(super) cull_pso: Option<ID3D12PipelineState>,
pub(super) indirect_buffers: Vec<ID3D12Resource>,
pub(super) status_buffers: Vec<ID3D12Resource>,
pub(super) spot_indirect_buffers: Vec<ID3D12Resource>,
}
pub(super) fn build_shadow_cull(
gpu: &InitGpu<'_>,
compute: &ComputeCull,
plan: &CullPlan,
shadow_enabled: bool,
spot_slices: usize,
) -> RenderResult<ShadowCull> {
let (Some(crs), true) = (
compute.kernels.as_ref().map(|k| &k.root_sig),
shadow_enabled,
) else {
return Ok(ShadowCull {
bindless_root_sig: None,
bindless_pso: None,
cmd_sig: None,
cull_pso: None,
indirect_buffers: Vec::new(),
status_buffers: Vec::new(),
spot_indirect_buffers: Vec::new(),
});
};
let device = gpu.hw.alloc.device();
let info_queue = gpu.hw.info_queue.as_ref();
let hot_reload = gpu.hot_reload;
let svs = compile_shadow_bindless_vs(hot_reload)?;
let sbrs = dump_on_err(info_queue, create_shadow_bindless_root_signature(device))?;
let sbpso = dump_on_err(info_queue, create_shadow_pso(device, &sbrs, &svs))?;
let sbsig = dump_on_err(info_queue, create_cull_command_signature(device, &sbrs))?;
let scs = compile_cull_shader_shadow(hot_reload)?;
let cull_pso = dump_on_err(info_queue, create_cull_pso(device, crs, &scs))?;
let cascades = render_types::NUM_SHADOW_CASCADES as u64;
let shadow_indirect_size =
align256(cascades * (plan.n_cull as u64) * INDIRECT_COMMAND_STRIDE as u64);
let status_size = status_buffer_size(plan.n_cull);
let spot_indirect_size =
align256(spot_slices as u64 * (plan.n_cull as u64) * INDIRECT_COMMAND_STRIDE as u64);
let mut indirect_buffers: Vec<ID3D12Resource> = Vec::with_capacity(FRAMES);
let mut status_buffers: Vec<ID3D12Resource> = Vec::with_capacity(FRAMES);
let mut spot_indirect_buffers: Vec<ID3D12Resource> = Vec::new();
for _ in 0..FRAMES {
if spot_indirect_size > 0 {
spot_indirect_buffers.push(create_uav_buffer(
device,
spot_indirect_size,
D3D12_RESOURCE_STATE_COMMON,
)?);
}
indirect_buffers.push(create_uav_buffer(
device,
shadow_indirect_size,
D3D12_RESOURCE_STATE_COMMON,
)?);
status_buffers.push(create_uav_buffer(
device,
status_size,
D3D12_RESOURCE_STATE_COMMON,
)?);
}
Ok(ShadowCull {
bindless_root_sig: Some(sbrs),
bindless_pso: Some(sbpso),
cmd_sig: Some(sbsig),
cull_pso: Some(cull_pso),
indirect_buffers,
status_buffers,
spot_indirect_buffers,
})
}