1mod allocator;
6mod bind;
7mod bundle;
8mod compute;
9mod render;
10mod transfer;
11
12pub(crate) use self::allocator::CommandAllocator;
13pub use self::bundle::*;
14pub use self::compute::*;
15pub use self::render::*;
16pub use self::transfer::*;
17
18use crate::{
19 device::{all_buffer_stages, all_image_stages},
20 hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Storage, Token},
21 id,
22 resource::{Buffer, Texture},
23 span,
24 track::TrackerSet,
25 PrivateFeatures, Stored,
26};
27
28use hal::command::CommandBuffer as _;
29
30use std::thread::ThreadId;
31
32#[derive(Debug)]
33pub struct CommandBuffer<B: hal::Backend> {
34 pub(crate) raw: Vec<B::CommandBuffer>,
35 is_recording: bool,
36 recorded_thread_id: ThreadId,
37 pub(crate) device_id: Stored<id::DeviceId>,
38 pub(crate) trackers: TrackerSet,
39 pub(crate) used_swap_chain: Option<(Stored<id::SwapChainId>, B::Framebuffer)>,
40 limits: wgt::Limits,
41 private_features: PrivateFeatures,
42 #[cfg(feature = "trace")]
43 pub(crate) commands: Option<Vec<crate::device::trace::Command>>,
44}
45
46impl<B: GfxBackend> CommandBuffer<B> {
47 pub(crate) fn insert_barriers(
48 raw: &mut B::CommandBuffer,
49 base: &mut TrackerSet,
50 head: &TrackerSet,
51 buffer_guard: &Storage<Buffer<B>, id::BufferId>,
52 texture_guard: &Storage<Texture<B>, id::TextureId>,
53 ) {
54 use hal::command::CommandBuffer as _;
55
56 debug_assert_eq!(B::VARIANT, base.backend());
57 debug_assert_eq!(B::VARIANT, head.backend());
58
59 let buffer_barriers = base.buffers.merge_replace(&head.buffers).map(|pending| {
60 let buf = &buffer_guard[pending.id];
61 pending.into_hal(buf)
62 });
63 let texture_barriers = base.textures.merge_replace(&head.textures).map(|pending| {
64 let tex = &texture_guard[pending.id];
65 pending.into_hal(tex)
66 });
67 base.views.merge_extend(&head.views).unwrap();
68 base.bind_groups.merge_extend(&head.bind_groups).unwrap();
69 base.samplers.merge_extend(&head.samplers).unwrap();
70 base.compute_pipes
71 .merge_extend(&head.compute_pipes)
72 .unwrap();
73 base.render_pipes.merge_extend(&head.render_pipes).unwrap();
74 base.bundles.merge_extend(&head.bundles).unwrap();
75
76 let stages = all_buffer_stages() | all_image_stages();
77 unsafe {
78 raw.pipeline_barrier(
79 stages..stages,
80 hal::memory::Dependencies::empty(),
81 buffer_barriers.chain(texture_barriers),
82 );
83 }
84 }
85}
86
87#[derive(Copy, Clone, Debug)]
88pub struct BasePassRef<'a, C> {
89 pub commands: &'a [C],
90 pub dynamic_offsets: &'a [wgt::DynamicOffset],
91 pub string_data: &'a [u8],
92}
93
94#[doc(hidden)]
95#[derive(Debug)]
96#[cfg_attr(
97 any(feature = "serial-pass", feature = "trace"),
98 derive(serde::Serialize)
99)]
100#[cfg_attr(
101 any(feature = "serial-pass", feature = "replay"),
102 derive(serde::Deserialize)
103)]
104pub struct BasePass<C> {
105 pub commands: Vec<C>,
106 pub dynamic_offsets: Vec<wgt::DynamicOffset>,
107 pub string_data: Vec<u8>,
108}
109
110impl<C: Clone> BasePass<C> {
111 fn new() -> Self {
112 BasePass {
113 commands: Vec::new(),
114 dynamic_offsets: Vec::new(),
115 string_data: Vec::new(),
116 }
117 }
118
119 #[cfg(feature = "trace")]
120 fn from_ref(base: BasePassRef<C>) -> Self {
121 BasePass {
122 commands: base.commands.to_vec(),
123 dynamic_offsets: base.dynamic_offsets.to_vec(),
124 string_data: base.string_data.to_vec(),
125 }
126 }
127
128 pub fn as_ref(&self) -> BasePassRef<C> {
129 BasePassRef {
130 commands: &self.commands,
131 dynamic_offsets: &self.dynamic_offsets,
132 string_data: &self.string_data,
133 }
134 }
135}
136
137impl<G: GlobalIdentityHandlerFactory> Global<G> {
138 pub fn command_encoder_finish<B: GfxBackend>(
139 &self,
140 encoder_id: id::CommandEncoderId,
141 _desc: &wgt::CommandBufferDescriptor,
142 ) -> id::CommandBufferId {
143 span!(_guard, INFO, "CommandEncoder::finish");
144
145 let hub = B::hub(self);
146 let mut token = Token::root();
147 let (swap_chain_guard, mut token) = hub.swap_chains.read(&mut token);
148 let (mut comb_guard, _) = hub.command_buffers.write(&mut token);
150 let comb = &mut comb_guard[encoder_id];
151 assert!(comb.is_recording, "Command buffer must be recording");
152 comb.is_recording = false;
153 if let Some((ref sc_id, _)) = comb.used_swap_chain {
155 let view_id = swap_chain_guard[sc_id.value]
156 .acquired_view_id
157 .as_ref()
158 .expect("Used swap chain frame has already presented");
159 comb.trackers.views.remove(view_id.value);
160 }
161 log::trace!("Command buffer {:?} {:#?}", encoder_id, comb.trackers);
162 encoder_id
163 }
164
165 pub fn command_encoder_push_debug_group<B: GfxBackend>(
166 &self,
167 encoder_id: id::CommandEncoderId,
168 label: &str,
169 ) {
170 span!(_guard, DEBUG, "CommandEncoder::push_debug_group");
171
172 let hub = B::hub(self);
173 let mut token = Token::root();
174
175 let (mut cmb_guard, _) = hub.command_buffers.write(&mut token);
176 let cmb = &mut cmb_guard[encoder_id];
177 let cmb_raw = cmb.raw.last_mut().unwrap();
178
179 unsafe {
180 cmb_raw.begin_debug_marker(label, 0);
181 }
182 }
183
184 pub fn command_encoder_insert_debug_marker<B: GfxBackend>(
185 &self,
186 encoder_id: id::CommandEncoderId,
187 label: &str,
188 ) {
189 span!(_guard, DEBUG, "CommandEncoder::insert_debug_marker");
190
191 let hub = B::hub(self);
192 let mut token = Token::root();
193
194 let (mut cmb_guard, _) = hub.command_buffers.write(&mut token);
195 let cmb = &mut cmb_guard[encoder_id];
196 let cmb_raw = cmb.raw.last_mut().unwrap();
197
198 unsafe {
199 cmb_raw.insert_debug_marker(label, 0);
200 }
201 }
202
203 pub fn command_encoder_pop_debug_group<B: GfxBackend>(&self, encoder_id: id::CommandEncoderId) {
204 span!(_guard, DEBUG, "CommandEncoder::pop_debug_marker");
205
206 let hub = B::hub(self);
207 let mut token = Token::root();
208
209 let (mut cmb_guard, _) = hub.command_buffers.write(&mut token);
210 let cmb = &mut cmb_guard[encoder_id];
211 let cmb_raw = cmb.raw.last_mut().unwrap();
212
213 unsafe {
214 cmb_raw.end_debug_marker();
215 }
216 }
217}