1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! Shared render command recording logic.
//!
//! This module contains `record_render_commands` which is used by both
//! `render_to_target` and `surface_render` to avoid code duplication.
use super::super::shared;
use super::types::{self, PushLayout};
use super::utils::index_format_to_vk;
use super::{BufferHandle, PipelineHandle, RenderCommand};
use ash::vk;
/// Record render commands into a command buffer.
/// This is shared between render_to_target and surface_render to avoid duplication.
pub(super) fn record(
cmd: vk::CommandBuffer,
commands: &[RenderCommand],
logical_device: &types::LogicalDevice,
pipelines: &std::collections::HashMap<PipelineHandle, types::PipelineState>,
buffers: &std::collections::HashMap<BufferHandle, types::BufferState>,
current_pipeline: &mut Option<PipelineHandle>,
frame_table_slots: (u32, u32),
) -> anyhow::Result<()> {
for command in commands {
match command {
RenderCommand::ClearDepth(_) => {
// Depth clear is applied as attachment load at pass begin.
}
RenderCommand::SetPipeline(pipeline_handle) => {
*current_pipeline = Some(*pipeline_handle);
if let Some(pipeline) = pipelines.get(pipeline_handle) {
unsafe {
logical_device.device.cmd_bind_pipeline(
cmd,
vk::PipelineBindPoint::GRAPHICS,
pipeline.pipeline,
);
// Bind the global bindless descriptor set.
// Use the pipeline's layout (not bindless_pipeline_layout alone)
// when layouts combine bindless + user sets.
if let Some(bindless_set) = logical_device.bindless_descriptor_set {
logical_device.device.cmd_bind_descriptor_sets(
cmd,
vk::PipelineBindPoint::GRAPHICS,
pipeline.layout,
0,
std::slice::from_ref(&bindless_set),
&[],
);
}
}
}
}
RenderCommand::SetVertexBuffer { slot, buffer, offset } => {
if let Some(buf_state) = buffers.get(buffer) {
unsafe {
logical_device.device.cmd_bind_vertex_buffers(
cmd,
*slot,
std::slice::from_ref(&buf_state.buffer),
std::slice::from_ref(offset),
);
}
}
}
RenderCommand::BindResources { .. } => {
anyhow::bail!(
"RenderCommand::BindResources must be lowered before Vulkan record; \
use frame_table::prepare_render_commands or lower_render_pass_commands"
);
}
RenderCommand::BindResourcesRaw {
indices: _raw_indices,
user: raw_user,
frame_table_base,
} => {
if let Some(pipeline) = current_pipeline.and_then(|p| pipelines.get(&p)) {
let mut layout = PushLayout::default();
shared::fill_frame_table_dispatch(&mut layout, *frame_table_base, raw_user);
shared::set_frame_table_slots(&mut layout, frame_table_slots.0, frame_table_slots.1);
unsafe {
logical_device.device.cmd_push_constants(
cmd,
pipeline.layout,
vk::ShaderStageFlags::ALL,
0,
layout.as_bytes(),
);
}
}
}
RenderCommand::BindResourcesTyped { handles: typed_handles } => {
if let Some(pipeline) = current_pipeline.and_then(|p| pipelines.get(&p)) {
crate::backend::validate_typed_push_constants(
typed_handles,
&pipeline.push_constant_categories,
&pipeline.shader_debug_name,
)?;
}
anyhow::bail!(
"RenderCommand::BindResourcesTyped must be lowered before Vulkan record; \
use frame_table::lower_render_pass_commands or prepare_render_commands"
);
}
RenderCommand::SetIndexBuffer { buffer, offset, format } => {
if let Some(buf_state) = buffers.get(buffer) {
unsafe {
logical_device.device.cmd_bind_index_buffer(
cmd,
buf_state.buffer,
*offset,
index_format_to_vk(*format),
);
}
}
}
RenderCommand::Draw {
vertex_count,
instance_count,
first_vertex,
first_instance,
} => unsafe {
logical_device
.device
.cmd_draw(cmd, *vertex_count, *instance_count, *first_vertex, *first_instance);
},
RenderCommand::DrawIndexed {
index_count,
instance_count,
first_index,
base_vertex,
first_instance,
} => unsafe {
logical_device.device.cmd_draw_indexed(
cmd,
*index_count,
*instance_count,
*first_index,
*base_vertex,
*first_instance,
);
},
}
}
Ok(())
}