use ash::vk;
use concinnity_core::gfx::render_types;
use super::super::context::VkContext;
use crate::vulkan::depth;
use crate::vulkan::owned::VkDevice;
use crate::vulkan::record::cmd_push_constants;
#[derive(Clone, Copy)]
pub(in crate::vulkan) struct ShadowView {
pub uniforms_set: vk::DescriptorSet,
pub vp_index: u32,
pub indirect: vk::Buffer,
}
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.enabled() {
return;
}
self.upload_raymarch_shadow_view(frame_idx, elapsed);
let device = self.hw.device.clone();
let device = &device;
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.shadow_views_drawable();
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;
}
self.begin_shadow_slice(cmd, shadow_fb.handle(), self.shadow.map_size);
if gpu_driven
&& let Some(indirect) = self
.cull
.shadow_indirect_buffers
.get(frame_idx)
.and_then(|c| c.get(cascade_idx))
{
self.draw_shadow_view(
device,
cmd,
frame_idx,
ShadowView {
uniforms_set: self.descriptors.shadow_global_sets[frame_idx],
vp_index: cascade_idx as u32,
indirect: indirect.buffer(),
},
);
}
unsafe {
self.encode_sdf_shadow_cascade(cmd, frame_idx, cascade_idx);
device.cmd_end_render_pass(cmd);
}
}
}
pub(in crate::vulkan) fn shadow_views_drawable(&self) -> bool {
self.cull.shadow_bindless_pipeline.is_some() && self.cull_count() > 0
}
pub(in crate::vulkan) fn begin_shadow_slice(
&self,
cmd: vk::CommandBuffer,
framebuffer: vk::Framebuffer,
size: u32,
) {
let device = &self.hw.device;
let extent = vk::Extent2D {
width: size,
height: size,
};
let clear_depth = depth::CLEAR_VALUE;
let rp_begin = vk::RenderPassBeginInfo::default()
.render_pass(self.shadow.render_pass.handle())
.framebuffer(framebuffer)
.render_area(vk::Rect2D::default().extent(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: size as f32,
width: size as f32,
height: -(size 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(extent);
device.cmd_set_scissor(cmd, 0, std::slice::from_ref(&scissor));
}
}
pub(in crate::vulkan) fn draw_shadow_view(
&self,
device: &VkDevice,
cmd: vk::CommandBuffer,
frame_idx: usize,
view: ShadowView,
) {
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 stride = std::mem::size_of::<vk::DrawIndexedIndirectCommand>() as u32;
let prefix = self.skinned_record_base() 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,
&[view.uniforms_set, self.cull.bindless_sets[frame_idx]],
&[],
);
cmd_push_constants(
device,
cmd,
sb_layout.handle(),
vk::ShaderStageFlags::VERTEX,
&view.vp_index,
);
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, view.indirect, 0, prefix, stride);
self.inc_draw_calls(1);
}
if self.state.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,
view.indirect,
(self.skinned_record_base() * stride as usize) as u64,
self.state.draw.n_skinned as u32,
stride,
);
self.inc_draw_calls(1);
}
}
}
}