use ash::vk;
use concinnity_core::gfx::render_types;
use super::super::context::VkContext;
use crate::vulkan::owned::VkDevice;
impl VkContext {
pub(in crate::vulkan) fn encode_shadow_pass(
&self,
cmd: vk::CommandBuffer,
frame_idx: usize,
cam_pos: [f32; 3],
elapsed: f32,
) {
if self.shadow.pipeline.is_none() {
return;
}
self.upload_raymarch_shadow_view(frame_idx, elapsed);
let device = self.hw.device.clone();
let device = &device;
let sm = self.shadow.map_size;
let shadow_extent = vk::Extent2D {
width: sm,
height: sm,
};
let clear_depth = vk::ClearValue {
depth_stencil: vk::ClearDepthStencilValue {
depth: 1.0,
stencil: 0,
},
};
let all_cascades = (1u32 << render_types::NUM_SHADOW_CASCADES) - 1;
let render_mask = if self.shadow.render_mask == 0 {
all_cascades
} else {
self.shadow.render_mask
};
let gpu_driven = self.cull.shadow_bindless_pipeline.is_some() && self.cull_count() > 0;
if gpu_driven {
self.encode_shadow_culls(cmd, frame_idx, render_mask, cam_pos);
}
for (cascade_idx, shadow_fb) in self.shadow.framebuffers.iter().enumerate() {
if render_mask & (1u32 << cascade_idx) == 0 {
continue;
}
let rp_begin = vk::RenderPassBeginInfo::default()
.render_pass(self.shadow.render_pass.handle())
.framebuffer(shadow_fb.handle())
.render_area(vk::Rect2D::default().extent(shadow_extent))
.clear_values(std::slice::from_ref(&clear_depth));
unsafe {
device.cmd_begin_render_pass(cmd, &rp_begin, vk::SubpassContents::INLINE);
let vp = vk::Viewport {
x: 0.0,
y: sm as f32,
width: sm as f32,
height: -(sm as f32),
min_depth: 0.0,
max_depth: 1.0,
};
device.cmd_set_viewport(cmd, 0, std::slice::from_ref(&vp));
let scissor = vk::Rect2D::default().extent(shadow_extent);
device.cmd_set_scissor(cmd, 0, std::slice::from_ref(&scissor));
}
if gpu_driven {
self.encode_shadow_cascade_indirect(device, cmd, frame_idx, cascade_idx);
}
unsafe {
self.encode_sdf_shadow_cascade(cmd, frame_idx, cascade_idx);
device.cmd_end_render_pass(cmd);
}
}
}
fn encode_shadow_cascade_indirect(
&self,
device: &VkDevice,
cmd: vk::CommandBuffer,
frame_idx: usize,
cascade_idx: usize,
) {
let (Some(sb_pipeline), Some(sb_layout)) = (
self.cull.shadow_bindless_pipeline.as_ref(),
self.cull.shadow_bindless_pipeline_layout.as_ref(),
) else {
return;
};
let Some(indirect) = self
.cull
.shadow_indirect_buffers
.get(frame_idx)
.and_then(|c| c.get(cascade_idx).map(|b| b.buffer()))
else {
return;
};
let stride = std::mem::size_of::<vk::DrawIndexedIndirectCommand>() as u32;
let prefix = self.skinned_record_base() as u32;
let cascade = cascade_idx as u32;
unsafe {
device.cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, sb_pipeline.handle());
device.cmd_bind_descriptor_sets(
cmd,
vk::PipelineBindPoint::GRAPHICS,
sb_layout.handle(),
0,
&[
self.descriptors.shadow_global_sets[frame_idx],
self.cull.bindless_sets[frame_idx],
],
&[],
);
device.cmd_push_constants(
cmd,
sb_layout.handle(),
vk::ShaderStageFlags::VERTEX,
0,
&cascade.to_ne_bytes(),
);
device.cmd_bind_vertex_buffers(cmd, 0, &[self.geometry.vertex_buffer.buffer()], &[0]);
device.cmd_bind_index_buffer(
cmd,
self.geometry.index_buffer.buffer(),
0,
vk::IndexType::UINT32,
);
if prefix > 0 {
device.cmd_draw_indexed_indirect(cmd, indirect, 0, prefix, stride);
self.inc_draw_calls(1);
}
if self.draw.n_skinned > 0
&& let Some(deformed) = self.skinned.deformed.get(frame_idx)
{
device.cmd_bind_vertex_buffers(
cmd,
0,
std::slice::from_ref(&deformed.buffer),
&[0],
);
device.cmd_bind_index_buffer(
cmd,
self.skinned.index_buffer.buffer(),
0,
vk::IndexType::UINT32,
);
device.cmd_draw_indexed_indirect(
cmd,
indirect,
(self.skinned_record_base() * stride as usize) as u64,
self.draw.n_skinned as u32,
stride,
);
self.inc_draw_calls(1);
}
}
}
}