use crate::directx::context::{FRAMES, MAX_CLONE_DRAWS, MAX_SKINNED_OBJECTS};
use crate::directx::decal::MAX_DECALS;
use crate::directx::particle::MAX_EMITTERS;
use super::HIZ_MAX_MIPS;
pub(in crate::directx) struct SrvHeapParams {
pub n_objects: usize,
pub n_clusters: usize,
pub n_atlases: usize,
pub bloom_count: usize,
pub taa_srv_extra: usize,
pub ssao_srv_extra: usize,
pub ssr_srv_extra: usize,
pub ssgi_srv_extra: usize,
pub gbuffer_srv_extra: usize,
pub rt_output_srv_extra: usize,
pub refl_composite_srv_extra: usize,
pub planar_resolve_srv_extra: usize,
pub albedo_count: usize,
pub normal_count: usize,
}
pub(in crate::directx) struct SrvHeapLayout {
pub object_base_slot: usize,
pub hdr_srv_slot: usize,
pub bloom_srv_base_slot: usize,
pub lut_srv_slot: usize,
pub taa_srv_base_slot: usize,
pub ssao_srv_base_slot: usize,
pub ssao_white_srv_slot: usize,
pub ssr_srv_base_slot: usize,
pub decal_depth_srv_slot: usize,
pub decal_srv_base_slot: usize,
pub chunk_srv_base_slot: usize,
pub skinned_srv_base_slot: usize,
pub particle_srv_base_slot: usize,
pub clone_srv_base_slot: usize,
pub fog_froxel_uav_slot: usize,
pub fog_froxel_srv_slot: usize,
pub upscale_uav_slot: usize,
pub upscale_srv_slot: usize,
pub raymarch_srv_base_slot: usize,
pub hiz_srv_slot: usize,
pub hiz_uav_base_slot: usize,
pub transparent_scene_copy_srv_slot: usize,
pub ssgi_gi_srv_slot: usize,
pub gbuffer_srv_base_slot: usize,
pub rt_output_srv_slot: usize,
pub refl_composite_srv_base_slot: usize,
pub planar_resolve_srv_base_slot: usize,
pub flat_pool_base_slot: usize,
pub probe_cube_base_slot: usize,
pub spot_shadow_srv_slot: usize,
pub ltc_srv_base_slot: usize,
pub srv_slots: usize,
}
const GLOBAL_SRV_COUNT: usize = 3;
const PROBE_CUBE_COUNT: usize = concinnity_core::render::uniforms::MAX_PROBES;
impl SrvHeapLayout {
pub(in crate::directx) fn compute(p: &SrvHeapParams) -> Self {
let object_base_slot = GLOBAL_SRV_COUNT;
let hdr_srv_slot =
object_base_slot + p.n_objects * 2 + p.n_clusters * 2 + p.n_atlases.max(1);
let bloom_srv_base_slot = hdr_srv_slot + 1;
let lut_srv_slot = bloom_srv_base_slot + p.bloom_count;
let taa_srv_base_slot = lut_srv_slot + 1;
let ssao_srv_base_slot = taa_srv_base_slot + p.taa_srv_extra;
let ssao_white_srv_slot = ssao_srv_base_slot + p.ssao_srv_extra;
let ssr_srv_base_slot = ssao_white_srv_slot + 1;
let decal_depth_srv_slot = ssr_srv_base_slot + p.ssr_srv_extra;
let decal_srv_base_slot = decal_depth_srv_slot + 1;
let chunk_srv_base_slot = decal_srv_base_slot + MAX_DECALS;
let skinned_srv_base_slot = chunk_srv_base_slot + 2;
let particle_srv_base_slot = skinned_srv_base_slot + MAX_SKINNED_OBJECTS * 2;
let clone_srv_base_slot = particle_srv_base_slot + MAX_EMITTERS;
let fog_froxel_uav_slot = clone_srv_base_slot + MAX_CLONE_DRAWS * 2;
let fog_froxel_srv_slot = fog_froxel_uav_slot + 1;
let upscale_uav_slot = fog_froxel_srv_slot + 1;
let upscale_srv_slot = upscale_uav_slot + 1;
let raymarch_srv_base_slot = upscale_srv_slot + 1;
let hiz_srv_slot = raymarch_srv_base_slot + 4;
let hiz_uav_base_slot = hiz_srv_slot + 1;
let transparent_scene_copy_srv_slot = hiz_uav_base_slot + HIZ_MAX_MIPS;
let ssgi_gi_srv_slot = transparent_scene_copy_srv_slot + 1;
let gbuffer_srv_base_slot = ssgi_gi_srv_slot + p.ssgi_srv_extra;
let rt_output_srv_slot = gbuffer_srv_base_slot + p.gbuffer_srv_extra;
let refl_composite_srv_base_slot = rt_output_srv_slot + p.rt_output_srv_extra;
let planar_resolve_srv_base_slot =
refl_composite_srv_base_slot + p.refl_composite_srv_extra;
let flat_pool_base_slot = planar_resolve_srv_base_slot + p.planar_resolve_srv_extra;
let probe_cube_base_slot = flat_pool_base_slot + FRAMES * (p.albedo_count + p.normal_count);
let spot_shadow_srv_slot = probe_cube_base_slot + PROBE_CUBE_COUNT;
let ltc_srv_base_slot = spot_shadow_srv_slot + 1;
let srv_slots = ltc_srv_base_slot + 2;
Self {
object_base_slot,
hdr_srv_slot,
bloom_srv_base_slot,
lut_srv_slot,
taa_srv_base_slot,
ssao_srv_base_slot,
ssao_white_srv_slot,
ssr_srv_base_slot,
decal_depth_srv_slot,
decal_srv_base_slot,
chunk_srv_base_slot,
skinned_srv_base_slot,
particle_srv_base_slot,
clone_srv_base_slot,
fog_froxel_uav_slot,
fog_froxel_srv_slot,
upscale_uav_slot,
upscale_srv_slot,
raymarch_srv_base_slot,
hiz_srv_slot,
hiz_uav_base_slot,
transparent_scene_copy_srv_slot,
ssgi_gi_srv_slot,
gbuffer_srv_base_slot,
rt_output_srv_slot,
refl_composite_srv_base_slot,
planar_resolve_srv_base_slot,
flat_pool_base_slot,
probe_cube_base_slot,
spot_shadow_srv_slot,
ltc_srv_base_slot,
srv_slots,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_gap_free(p: &SrvHeapParams) {
let l = SrvHeapLayout::compute(p);
let blocks: [(usize, usize); 31] = [
(
l.object_base_slot,
p.n_objects * 2 + p.n_clusters * 2 + p.n_atlases.max(1),
),
(l.hdr_srv_slot, 1),
(l.bloom_srv_base_slot, p.bloom_count),
(l.lut_srv_slot, 1),
(l.taa_srv_base_slot, p.taa_srv_extra),
(l.ssao_srv_base_slot, p.ssao_srv_extra),
(l.ssao_white_srv_slot, 1),
(l.ssr_srv_base_slot, p.ssr_srv_extra),
(l.decal_depth_srv_slot, 1),
(l.decal_srv_base_slot, MAX_DECALS),
(l.chunk_srv_base_slot, 2),
(l.skinned_srv_base_slot, MAX_SKINNED_OBJECTS * 2),
(l.particle_srv_base_slot, MAX_EMITTERS),
(l.clone_srv_base_slot, MAX_CLONE_DRAWS * 2),
(l.fog_froxel_uav_slot, 1),
(l.fog_froxel_srv_slot, 1),
(l.upscale_uav_slot, 1),
(l.upscale_srv_slot, 1),
(l.raymarch_srv_base_slot, 4),
(l.hiz_srv_slot, 1),
(l.hiz_uav_base_slot, HIZ_MAX_MIPS),
(l.transparent_scene_copy_srv_slot, 1),
(l.ssgi_gi_srv_slot, p.ssgi_srv_extra),
(l.gbuffer_srv_base_slot, p.gbuffer_srv_extra),
(l.rt_output_srv_slot, p.rt_output_srv_extra),
(l.refl_composite_srv_base_slot, p.refl_composite_srv_extra),
(l.planar_resolve_srv_base_slot, p.planar_resolve_srv_extra),
(
l.flat_pool_base_slot,
FRAMES * (p.albedo_count + p.normal_count),
),
(l.probe_cube_base_slot, PROBE_CUBE_COUNT),
(l.spot_shadow_srv_slot, 1),
(l.ltc_srv_base_slot, 2),
];
let mut expected_base = GLOBAL_SRV_COUNT;
for (i, (base, count)) in blocks.iter().enumerate() {
assert_eq!(
*base, expected_base,
"block {i} base {base} should sit at running total {expected_base}",
);
expected_base += count;
}
assert_eq!(
l.srv_slots, expected_base,
"srv_slots must cover every block exactly",
);
assert!(l.srv_slots >= GLOBAL_SRV_COUNT);
}
#[test]
fn layout_gap_free_all_features_on() {
assert_gap_free(&SrvHeapParams {
n_objects: 7,
n_clusters: 3,
n_atlases: 2,
bloom_count: 6,
taa_srv_extra: 2,
ssao_srv_extra: 2,
ssr_srv_extra: 1,
ssgi_srv_extra: 1,
gbuffer_srv_extra: 3,
rt_output_srv_extra: 1,
refl_composite_srv_extra: 2,
planar_resolve_srv_extra: 2,
albedo_count: 9,
normal_count: 4,
});
}
#[test]
fn layout_gap_free_all_features_off() {
assert_gap_free(&SrvHeapParams {
n_objects: 0,
n_clusters: 0,
n_atlases: 0,
bloom_count: 0,
taa_srv_extra: 0,
ssao_srv_extra: 0,
ssr_srv_extra: 0,
ssgi_srv_extra: 0,
gbuffer_srv_extra: 0,
rt_output_srv_extra: 0,
refl_composite_srv_extra: 0,
planar_resolve_srv_extra: 0,
albedo_count: 1,
normal_count: 1,
});
}
#[test]
fn layout_gap_free_mixed_features() {
assert_gap_free(&SrvHeapParams {
n_objects: 100,
n_clusters: 0,
n_atlases: 1,
bloom_count: 5,
taa_srv_extra: 2,
ssao_srv_extra: 0,
ssr_srv_extra: 1,
ssgi_srv_extra: 0,
gbuffer_srv_extra: 3,
rt_output_srv_extra: 1,
refl_composite_srv_extra: 2,
planar_resolve_srv_extra: 1,
albedo_count: 50,
normal_count: 12,
});
}
#[test]
fn first_block_clears_the_global_srvs() {
let l = SrvHeapLayout::compute(&SrvHeapParams {
n_objects: 0,
n_clusters: 0,
n_atlases: 0,
bloom_count: 0,
taa_srv_extra: 0,
ssao_srv_extra: 0,
ssr_srv_extra: 0,
ssgi_srv_extra: 0,
gbuffer_srv_extra: 0,
rt_output_srv_extra: 0,
refl_composite_srv_extra: 0,
planar_resolve_srv_extra: 0,
albedo_count: 1,
normal_count: 1,
});
assert_eq!(l.object_base_slot, GLOBAL_SRV_COUNT);
assert!(l.hdr_srv_slot >= GLOBAL_SRV_COUNT);
}
}