1use alloc::{
2 sync::Arc,
3 vec::{Drain, Vec},
4};
5use core::ops::Range;
6
7use hashbrown::hash_map::Entry;
8
9use crate::{
10 device::{Device, DeviceError},
11 init_tracker::*,
12 resource::{ParentDevice, RawResourceAccess, Texture, Trackable},
13 snatch::SnatchGuard,
14 track::{DeviceTracker, TextureTracker},
15 FastHashMap,
16};
17
18use super::{clear_texture, BakedCommands, ClearError};
19
20#[derive(Clone)]
23pub(crate) struct TextureSurfaceDiscard {
24 pub texture: Arc<Texture>,
25 pub mip_level: u32,
26 pub layer: u32,
27}
28
29pub(crate) type SurfacesInDiscardState = Vec<TextureSurfaceDiscard>;
30
31#[derive(Default)]
32pub(crate) struct CommandBufferTextureMemoryActions {
33 init_actions: Vec<TextureInitTrackerAction>,
36 discards: Vec<TextureSurfaceDiscard>,
40}
41
42impl CommandBufferTextureMemoryActions {
43 pub(crate) fn drain_init_actions(&mut self) -> Drain<'_, TextureInitTrackerAction> {
44 self.init_actions.drain(..)
45 }
46
47 pub(crate) fn discard(&mut self, discard: TextureSurfaceDiscard) {
48 self.discards.push(discard);
49 }
50
51 #[must_use]
55 pub(crate) fn register_init_action(
56 &mut self,
57 action: &TextureInitTrackerAction,
58 ) -> SurfacesInDiscardState {
59 let mut immediately_necessary_clears = SurfacesInDiscardState::new();
60
61 self.init_actions.extend(
69 action
70 .texture
71 .initialization_status
72 .read()
73 .check_action(action),
74 );
75
76 let init_actions = &mut self.init_actions;
80 self.discards.retain(|discarded_surface| {
81 if discarded_surface.texture.is_equal(&action.texture)
82 && action.range.layer_range.contains(&discarded_surface.layer)
83 && action
84 .range
85 .mip_range
86 .contains(&discarded_surface.mip_level)
87 {
88 if let MemoryInitKind::NeedsInitializedMemory = action.kind {
89 immediately_necessary_clears.push(discarded_surface.clone());
90
91 init_actions.push(TextureInitTrackerAction {
95 texture: discarded_surface.texture.clone(),
96 range: TextureInitRange {
97 mip_range: discarded_surface.mip_level
98 ..(discarded_surface.mip_level + 1),
99 layer_range: discarded_surface.layer..(discarded_surface.layer + 1),
100 },
101 kind: MemoryInitKind::ImplicitlyInitialized,
102 });
103 }
104 false
105 } else {
106 true
107 }
108 });
109
110 immediately_necessary_clears
111 }
112
113 pub(crate) fn register_implicit_init(
116 &mut self,
117 texture: &Arc<Texture>,
118 range: TextureInitRange,
119 ) {
120 let must_be_empty = self.register_init_action(&TextureInitTrackerAction {
121 texture: texture.clone(),
122 range,
123 kind: MemoryInitKind::ImplicitlyInitialized,
124 });
125 assert!(must_be_empty.is_empty());
126 }
127}
128
129pub(crate) fn fixup_discarded_surfaces<InitIter: Iterator<Item = TextureSurfaceDiscard>>(
134 inits: InitIter,
135 encoder: &mut dyn hal::DynCommandEncoder,
136 texture_tracker: &mut TextureTracker,
137 device: &Device,
138 snatch_guard: &SnatchGuard<'_>,
139) {
140 for init in inits {
141 clear_texture(
142 &init.texture,
143 TextureInitRange {
144 mip_range: init.mip_level..(init.mip_level + 1),
145 layer_range: init.layer..(init.layer + 1),
146 },
147 encoder,
148 texture_tracker,
149 &device.alignments,
150 device.zero_buffer.as_ref(),
151 snatch_guard,
152 device.instance_flags,
153 )
154 .unwrap();
155 }
156}
157
158impl BakedCommands {
159 pub(crate) fn initialize_buffer_memory(
171 &mut self,
172 device_tracker: &mut DeviceTracker,
173 snatch_guard: &SnatchGuard<'_>,
174 ) {
175 profiling::scope!("initialize_buffer_memory");
176
177 let mut uninitialized_ranges_per_buffer = FastHashMap::default();
181 for buffer_use in self.buffer_memory_init_actions.drain(..) {
182 let mut initialization_status = buffer_use.buffer.initialization_status.write();
183
184 let end_remainder = buffer_use.range.end % wgt::COPY_BUFFER_ALIGNMENT;
186 let end = if end_remainder == 0 {
187 buffer_use.range.end
188 } else {
189 buffer_use.range.end + wgt::COPY_BUFFER_ALIGNMENT - end_remainder
190 };
191 let uninitialized_ranges = initialization_status.drain(buffer_use.range.start..end);
192
193 match buffer_use.kind {
194 MemoryInitKind::ImplicitlyInitialized => {}
195 MemoryInitKind::NeedsInitializedMemory => {
196 match uninitialized_ranges_per_buffer.entry(buffer_use.buffer.tracker_index()) {
197 Entry::Vacant(e) => {
198 e.insert((
199 buffer_use.buffer.clone(),
200 uninitialized_ranges.collect::<Vec<Range<wgt::BufferAddress>>>(),
201 ));
202 }
203 Entry::Occupied(mut e) => {
204 e.get_mut().1.extend(uninitialized_ranges);
205 }
206 }
207 }
208 }
209 }
210
211 for (buffer, mut ranges) in uninitialized_ranges_per_buffer.into_values() {
212 ranges.sort_by_key(|r| r.start);
214 for i in (1..ranges.len()).rev() {
215 assert!(ranges[i - 1].end <= ranges[i].start);
217 if ranges[i].start == ranges[i - 1].end {
218 ranges[i - 1].end = ranges[i].end;
219 ranges.swap_remove(i); }
221 }
222
223 let transition = device_tracker
229 .buffers
230 .set_single(&buffer, wgt::BufferUses::COPY_DST);
231
232 let raw_buf = buffer
233 .try_raw(snatch_guard)
234 .expect("attempt to initialize a destroyed buffer");
235
236 unsafe {
237 self.encoder.raw.transition_buffers(
238 transition
239 .map(|pending| pending.into_hal(&buffer, snatch_guard))
240 .as_slice(),
241 );
242 }
243
244 for range in ranges.iter() {
245 assert!(
246 range.start % wgt::COPY_BUFFER_ALIGNMENT == 0,
247 "Buffer {:?} has an uninitialized range with a start \
248 not aligned to 4 (start was {})",
249 raw_buf,
250 range.start
251 );
252 assert!(
253 range.end % wgt::COPY_BUFFER_ALIGNMENT == 0,
254 "Buffer {:?} has an uninitialized range with an end \
255 not aligned to 4 (end was {})",
256 raw_buf,
257 range.end
258 );
259
260 unsafe {
261 self.encoder.raw.clear_buffer(raw_buf, range.clone());
262 }
263 }
264 }
265 }
266
267 pub(crate) fn initialize_texture_memory(
284 &mut self,
285 device_tracker: &mut DeviceTracker,
286 device: &Device,
287 snatch_guard: &SnatchGuard<'_>,
288 ) -> Result<(), ClearError> {
289 profiling::scope!("initialize_texture_memory");
290
291 let mut ranges: Vec<TextureInitRange> = Vec::new();
292 for texture_use in self.texture_memory_actions.drain_init_actions() {
293 let mut initialization_status = texture_use.texture.initialization_status.write();
294 let use_range = texture_use.range;
295 let affected_mip_trackers = initialization_status
296 .mips
297 .iter_mut()
298 .enumerate()
299 .skip(use_range.mip_range.start as usize)
300 .take((use_range.mip_range.end - use_range.mip_range.start) as usize);
301
302 match texture_use.kind {
303 MemoryInitKind::ImplicitlyInitialized => {
304 for (_, mip_tracker) in affected_mip_trackers {
305 mip_tracker.drain(use_range.layer_range.clone());
306 }
307 }
308 MemoryInitKind::NeedsInitializedMemory => {
309 for (mip_level, mip_tracker) in affected_mip_trackers {
310 for layer_range in mip_tracker.drain(use_range.layer_range.clone()) {
311 ranges.push(TextureInitRange {
312 mip_range: (mip_level as u32)..(mip_level as u32 + 1),
313 layer_range,
314 });
315 }
316 }
317 }
318 }
319
320 for range in ranges.drain(..) {
322 let clear_result = clear_texture(
323 &texture_use.texture,
324 range,
325 self.encoder.raw.as_mut(),
326 &mut device_tracker.textures,
327 &device.alignments,
328 device.zero_buffer.as_ref(),
329 snatch_guard,
330 device.instance_flags,
331 );
332
333 if matches!(clear_result, Err(ClearError::DestroyedResource(_))) {
338 panic!("attempt to initialize a destroyed texture");
339 } else {
340 clear_result?;
341 }
342 }
343 }
344
345 for surface_discard in self.texture_memory_actions.discards.iter() {
349 surface_discard
350 .texture
351 .initialization_status
352 .write()
353 .discard(surface_discard.mip_level, surface_discard.layer);
354 }
355
356 Ok(())
357 }
358
359 pub(crate) fn process_deferred_query_set_resolves(
360 &mut self,
361 device: &Device,
362 snatch_guard: &SnatchGuard<'_>,
363 ) -> Result<(), DeviceError> {
364 profiling::scope!("process_deferred_query_set_resolves");
365
366 for mut resolve in self.deferred_query_set_resolves.drain(..).rev() {
367 let raw_dst = resolve.dst_buffer.try_raw(snatch_guard).unwrap();
368 let raw_query_set = resolve.query_set.try_raw(snatch_guard).unwrap();
369
370 let raw_encoder = self.encoder.open_pass(crate::hal_label(
371 Some("(wgpu internal) Deferred query set resolve"),
372 device.instance_flags,
373 ))?;
374
375 let initialized_slots_guard = resolve.query_set.initialized_slots.lock();
376 let initialized_slots =
377 if let Some(query_set_writes) = resolve.query_set_writes.as_mut() {
378 query_set_writes.or(&initialized_slots_guard);
379 &*query_set_writes
380 } else {
381 &*initialized_slots_guard
382 };
383
384 let mut start = resolve.start_query;
385 while start < resolve.end_query {
386 let is_initialized = initialized_slots[start as usize];
387 let end = (start + 1..resolve.end_query)
388 .find(|&i| initialized_slots[i as usize] != is_initialized)
389 .unwrap_or(resolve.end_query);
390
391 let byte_offset = resolve.destination_offset
392 + (start - resolve.start_query) as u64 * resolve.stride;
393 let byte_len = (end - start) as u64 * resolve.stride;
394
395 if is_initialized {
396 unsafe {
397 raw_encoder.copy_query_results(
398 raw_query_set,
399 start..end,
400 raw_dst,
401 byte_offset,
402 wgt::BufferSize::new_unchecked(resolve.stride),
403 );
404 }
405 } else {
406 unsafe {
407 raw_encoder.clear_buffer(raw_dst, byte_offset..byte_offset + byte_len);
408 }
409 }
410
411 start = end;
412 }
413 drop(initialized_slots_guard);
414
415 self.encoder.close_and_insert_at(resolve.insertion_point)?;
416 }
417
418 for query_set in self.trackers.query_sets.used_resources() {
420 if let Some(slots) = self.query_set_writes.get(&query_set.tracker_index()) {
421 let mut initialized = query_set.initialized_slots.lock();
422 initialized.or(slots);
423 }
424 }
425
426 Ok(())
427 }
428}