use ash::vk;
use concinnity_core::gfx::render_types::{
self, LightUniforms, NUM_SHADOW_CASCADES, ShadowUniforms, SpotShadowData,
};
use concinnity_core::render::backend_init::ShadowParams;
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::lights;
use super::InitGpu;
use crate::vulkan::context::{VkShadow, VkSpotShadow};
use crate::vulkan::draw::upload_shadow_uniforms;
use crate::vulkan::render_pass::create_shadow_render_pass;
use crate::vulkan::resources::create_descriptor_set_layout;
use crate::vulkan::swapchain::create_shadow_framebuffers;
use crate::vulkan::texture::{create_sampler_shadow, create_shadow_map_array};
pub(super) fn build_shadow(
gpu: &InitGpu<'_>,
shadows: &ShadowParams,
light_uniforms: &LightUniforms,
) -> RenderResult<VkShadow> {
let InitGpu { hw, frames, .. } = *gpu;
let device = &hw.device;
let map = create_shadow_map_array(&gpu.upload(), shadows.map_size, NUM_SHADOW_CASCADES as u32)?;
let render_pass = create_shadow_render_pass(device)?;
let sampler = create_sampler_shadow(device)?;
let global_set_layout = create_descriptor_set_layout(
device,
&crate::vulkan::descriptor_layout::shadow_global_set(),
)?;
let framebuffers = if shadows.map_size > 0 {
create_shadow_framebuffers(device, render_pass.handle(), &map, shadows.map_size)?
} else {
Vec::new()
};
let shadow_ubo_size = std::mem::size_of::<ShadowUniforms>() as u64;
let mut ubos = Vec::with_capacity(frames);
for _ in 0..frames {
ubos.push(hw.alloc.create_buffer(
shadow_ubo_size,
vk::BufferUsageFlags::UNIFORM_BUFFER,
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
)?);
}
let uniforms = concinnity_core::render::csm::empty_shadow_uniforms();
for ubo in &ubos {
upload_shadow_uniforms(ubo, &uniforms);
}
Ok(VkShadow {
render_pass,
map,
map_size: shadows.map_size,
framebuffers,
global_set_layout,
sampler,
ubos,
uniforms,
light_dir: lights::sun_direction(light_uniforms),
cadence: shadows.cadence,
scheduler: Default::default(),
render_mask: 0,
})
}
pub(super) fn build_spot_shadow(
gpu: &InitGpu<'_>,
shadow: &VkShadow,
spot_shadows: &[SpotShadowData],
) -> RenderResult<VkSpotShadow> {
let hw = gpu.hw;
let slice_size = render_types::spot_shadow_slice_size(shadow.map_size);
let map = create_shadow_map_array(&gpu.upload(), slice_size, spot_shadows.len() as u32)?;
crate::vulkan::draw::spot_shadow::build_spot_shadow(
crate::vulkan::draw::spot_shadow::SpotShadowBuild {
alloc: &hw.alloc,
instance: &hw.instance,
device: &hw.device,
physical_device: hw.physical_device,
map,
render_pass: shadow.render_pass.handle(),
set_layout: shadow.global_set_layout.handle(),
slice_size,
spot_shadows,
},
)
}