use concinnity_core::gfx::render_types::{
self, LightUniforms, NUM_SHADOW_CASCADES, ShadowUniforms, SpotShadowData,
};
use concinnity_core::render::backend_init::ShadowParams;
use concinnity_core::render::csm;
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::lights;
use concinnity_core::render::spot_shadow;
use windows::Win32::Graphics::Direct3D12::*;
use super::heap_layout::{DSV_SHADOW_BASE_SLOT, DSV_SPOT_SHADOW_BASE_SLOT};
use super::{InitGpu, heaps};
use crate::directx::context::{DxDescriptors, DxTargets, align256};
use crate::directx::draw::shadow::ShadowState;
use crate::directx::draw::spot_shadow::SpotShadowState;
use crate::directx::draw::upload_static_records;
use crate::directx::error::map_hresult;
use crate::directx::texture::{create_fallback_shadow_array, create_shadow_map_array};
pub(super) fn build_shadow(
gpu: &InitGpu<'_>,
descriptors: &DxDescriptors,
targets: &DxTargets,
shadows: &ShadowParams,
light_uniforms: &LightUniforms,
) -> RenderResult<ShadowState> {
let hw = gpu.hw;
let dsv_descriptor_size = heaps::descriptor_size(&hw.device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
let effective_shadow_size = shadows.map_size;
let extent =
render_types::shadow_array_extent(effective_shadow_size, NUM_SHADOW_CASCADES as u32);
let (shadow_resource_opt, shadow_dsvs, shadow_srv_gpu) = if effective_shadow_size > 0 {
let (sm, dsvs) = create_shadow_map_array(
&hw.device,
extent.size,
extent.layers,
heaps::cpu_handle(
&targets.depth.heap,
dsv_descriptor_size,
DSV_SHADOW_BASE_SLOT,
),
dsv_descriptor_size,
descriptors.slot_cpu(0),
descriptors.slot_gpu(0),
)?;
(Some(sm), dsvs, descriptors.slot_gpu(0))
} else {
let fb = create_fallback_shadow_array(
&hw.alloc,
descriptors.slot_cpu(0),
descriptors.slot_gpu(0),
)?;
(Some(fb), Vec::new(), descriptors.slot_gpu(0))
};
Ok(ShadowState {
resource: shadow_resource_opt,
dsvs: shadow_dsvs,
map_size: effective_shadow_size,
layers: extent.layers,
srv_gpu: shadow_srv_gpu,
light_dir: lights::sun_direction(light_uniforms),
cadence: shadows.cadence,
scheduler: Default::default(),
render_mask: 0,
uniforms: csm::empty_shadow_uniforms(),
})
}
pub(super) fn build_spot_shadow(
gpu: &InitGpu<'_>,
descriptors: &DxDescriptors,
targets: &DxTargets,
spot_shadows: &[SpotShadowData],
shadow_map_size: u32,
) -> RenderResult<SpotShadowState> {
let hw = gpu.hw;
let spot_shadow_srv_slot = descriptors.layout.spot_shadow_srv_slot;
let dsv_descriptor_size = heaps::descriptor_size(&hw.device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
let spot_shadow_slice_size = render_types::spot_shadow_slice_size(shadow_map_size);
let (spot_shadow_resource, spot_shadow_dsvs) = if spot_shadows.is_empty() {
let fb = create_fallback_shadow_array(
&hw.alloc,
descriptors.slot_cpu(spot_shadow_srv_slot),
descriptors.slot_gpu(spot_shadow_srv_slot),
)?;
(Some(fb), Vec::new())
} else {
let (sm, dsvs) = create_shadow_map_array(
&hw.device,
spot_shadow_slice_size,
spot_shadows.len() as u32,
heaps::cpu_handle(
&targets.depth.heap,
dsv_descriptor_size,
DSV_SPOT_SHADOW_BASE_SLOT,
),
dsv_descriptor_size,
descriptors.slot_cpu(spot_shadow_srv_slot),
descriptors.slot_gpu(spot_shadow_srv_slot),
)?;
(Some(sm), dsvs)
};
let spot_shadow_data = if spot_shadows.is_empty() {
vec![SpotShadowData::ZERO]
} else {
spot_shadows.to_vec()
};
let spot_shadow_buffer = {
let size = align256((spot_shadow_data.len() * size_of::<SpotShadowData>()) as u64);
let buf = hw.alloc.alloc_buffer(
size,
D3D12_HEAP_TYPE_UPLOAD,
D3D12_RESOURCE_STATE_GENERIC_READ,
)?;
upload_static_records(&buf, &spot_shadow_data, "spot-shadow")?;
buf
};
let spot_shadow_ubo_stride = align256(size_of::<ShadowUniforms>() as u64);
let spot_shadow_ubo = {
let slots = spot_shadows.len().max(1) as u64;
let buf = hw.alloc.alloc_buffer(
spot_shadow_ubo_stride * slots,
D3D12_HEAP_TYPE_UPLOAD,
D3D12_RESOURCE_STATE_GENERIC_READ,
)?;
let mut ptr = std::ptr::null_mut::<std::ffi::c_void>();
unsafe { buf.Map(0, None, Some(&mut ptr)) }
.map_err(|e| map_hresult(e.code(), "map spot-shadow UBO"))?;
for (i, sd) in spot_shadows.iter().enumerate() {
let mut u = csm::empty_shadow_uniforms();
u.light_vps[0] = sd.light_vp;
u.active_cascades = 1;
unsafe {
std::ptr::copy_nonoverlapping(
&u as *const ShadowUniforms as *const u8,
(ptr as *mut u8).add(i * spot_shadow_ubo_stride as usize),
size_of::<ShadowUniforms>(),
);
}
}
unsafe { buf.Unmap(0, None) };
buf
};
Ok(SpotShadowState {
resource: spot_shadow_resource,
dsvs: spot_shadow_dsvs,
srv_gpu: descriptors.slot_gpu(spot_shadow_srv_slot),
buffer: spot_shadow_buffer,
ubo: spot_shadow_ubo,
ubo_stride: spot_shadow_ubo_stride,
slice_size: spot_shadow_slice_size,
frusta: spot_shadows
.iter()
.map(spot_shadow::slice_frustum)
.collect(),
scheduler: Default::default(),
render_mask: 0,
})
}