1use alloc::{
8 sync::{Arc, Weak},
9 vec::Vec,
10};
11
12use hal::BufferBarrier;
13use wgt::{strict_assert, strict_assert_eq, BufferUses};
14
15use super::{PendingTransition, TrackerIndex};
16use crate::{
17 resource::{Buffer, Trackable},
18 snatch::SnatchGuard,
19 track::{
20 invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
21 ResourceUsageCompatibilityError, ResourceUses,
22 },
23};
24
25impl ResourceUses for BufferUses {
26 const EXCLUSIVE: Self = Self::EXCLUSIVE;
27
28 type Selector = ();
29
30 fn bits(self) -> u16 {
31 Self::bits(&self)
32 }
33
34 fn any_exclusive(self) -> bool {
35 self.intersects(Self::EXCLUSIVE)
36 }
37}
38
39#[derive(Debug)]
41pub(crate) struct BufferBindGroupState {
42 buffers: Vec<(Arc<Buffer>, BufferUses)>,
43}
44impl BufferBindGroupState {
45 pub fn new() -> Self {
46 Self {
47 buffers: Vec::new(),
48 }
49 }
50
51 pub(crate) fn optimize(&mut self) {
56 self.buffers
57 .sort_unstable_by_key(|(b, _)| b.tracker_index());
58 }
59
60 pub fn used_resources(&self) -> impl Iterator<Item = &Arc<Buffer>> {
62 self.buffers.iter().map(|(b, _)| b)
63 }
64
65 pub fn insert_single(&mut self, buffer: Arc<Buffer>, state: BufferUses) {
67 self.buffers.push((buffer, state));
68 }
69}
70
71#[derive(Debug)]
73pub(crate) struct BufferUsageScope {
74 state: Vec<BufferUses>,
75 metadata: ResourceMetadata<Arc<Buffer>>,
76 ordered_uses_mask: BufferUses,
77}
78
79impl Default for BufferUsageScope {
80 fn default() -> Self {
81 Self {
82 state: Vec::new(),
83 metadata: ResourceMetadata::new(),
84 ordered_uses_mask: BufferUses::empty(),
85 }
86 }
87}
88
89impl BufferUsageScope {
90 fn tracker_assert_in_bounds(&self, index: usize) {
91 strict_assert!(index < self.state.len());
92 self.metadata.tracker_assert_in_bounds(index);
93 }
94 pub fn clear(&mut self) {
95 self.state.clear();
96 self.metadata.clear();
97 }
98
99 pub fn set_size(&mut self, size: usize) {
104 self.state.resize(size, BufferUses::empty());
105 self.metadata.set_size(size);
106 }
107
108 pub fn set_ordered_uses_mask(&mut self, ordered_uses_mask: BufferUses) {
109 self.ordered_uses_mask = ordered_uses_mask;
110 }
111
112 fn allow_index(&mut self, index: usize) {
114 if index >= self.state.len() {
115 self.set_size(index + 1);
116 }
117 }
118
119 pub unsafe fn merge_bind_group(
132 &mut self,
133 bind_group: &BufferBindGroupState,
134 ) -> Result<(), ResourceUsageCompatibilityError> {
135 for &(ref resource, state) in bind_group.buffers.iter() {
136 let index = resource.tracker_index().as_usize();
137
138 unsafe {
139 self.insert_or_merge(
140 index as _,
141 index,
142 BufferStateProvider::Direct { state },
143 ResourceMetadataProvider::Direct { resource },
144 )?
145 };
146 }
147
148 Ok(())
149 }
150
151 pub fn merge_usage_scope(
159 &mut self,
160 scope: &Self,
161 ) -> Result<(), ResourceUsageCompatibilityError> {
162 let incoming_size = scope.state.len();
163 if incoming_size > self.state.len() {
164 self.set_size(incoming_size);
165 }
166
167 for index in scope.metadata.owned_indices() {
168 self.tracker_assert_in_bounds(index);
169 scope.tracker_assert_in_bounds(index);
170
171 unsafe {
172 self.insert_or_merge(
173 index as u32,
174 index,
175 BufferStateProvider::Indirect {
176 state: &scope.state,
177 },
178 ResourceMetadataProvider::Indirect {
179 metadata: &scope.metadata,
180 },
181 )?;
182 };
183 }
184
185 Ok(())
186 }
187
188 pub fn merge_single(
196 &mut self,
197 buffer: &Arc<Buffer>,
198 new_state: BufferUses,
199 ) -> Result<(), ResourceUsageCompatibilityError> {
200 let index = buffer.tracker_index().as_usize();
201
202 self.allow_index(index);
203
204 self.tracker_assert_in_bounds(index);
205
206 unsafe {
207 self.insert_or_merge(
208 index as _,
209 index,
210 BufferStateProvider::Direct { state: new_state },
211 ResourceMetadataProvider::Direct { resource: buffer },
212 )?;
213 }
214
215 Ok(())
216 }
217
218 #[inline(always)]
228 unsafe fn insert_or_merge(
229 &mut self,
230 index32: u32,
231 index: usize,
232 state_provider: BufferStateProvider<'_>,
233 metadata_provider: ResourceMetadataProvider<'_, Arc<Buffer>>,
234 ) -> Result<(), ResourceUsageCompatibilityError> {
235 let currently_owned = unsafe { self.metadata.contains_unchecked(index) };
236
237 if !currently_owned {
238 unsafe {
239 insert(
240 None,
241 &mut self.state,
242 &mut self.metadata,
243 index,
244 state_provider,
245 None,
246 metadata_provider,
247 )
248 };
249 return Ok(());
250 }
251
252 unsafe {
253 merge(
254 &mut self.state,
255 index32,
256 index,
257 state_provider,
258 metadata_provider,
259 )
260 }
261 }
262
263 pub fn remove_usage(&mut self, buffer: &Buffer, usage: BufferUses) {
269 let index = buffer.tracker_index().as_usize();
270 if self.metadata.contains(index) {
271 unsafe {
274 *self.state.get_unchecked_mut(index) &= !usage;
275 }
276 }
277 }
278}
279
280pub(crate) struct BufferTracker {
282 start: Vec<BufferUses>,
283 end: Vec<BufferUses>,
284
285 metadata: ResourceMetadata<Arc<Buffer>>,
286
287 temp: Vec<PendingTransition<BufferUses>>,
288
289 ordered_uses_mask: BufferUses,
290}
291
292impl BufferTracker {
293 pub fn new(ordered_uses_mask: BufferUses) -> Self {
294 Self {
295 start: Vec::new(),
296 end: Vec::new(),
297
298 metadata: ResourceMetadata::new(),
299
300 temp: Vec::new(),
301
302 ordered_uses_mask,
303 }
304 }
305
306 fn tracker_assert_in_bounds(&self, index: usize) {
307 strict_assert!(index < self.start.len());
308 strict_assert!(index < self.end.len());
309 self.metadata.tracker_assert_in_bounds(index);
310 }
311
312 pub fn set_size(&mut self, size: usize) {
317 self.start.resize(size, BufferUses::empty());
318 self.end.resize(size, BufferUses::empty());
319
320 self.metadata.set_size(size);
321 }
322
323 fn allow_index(&mut self, index: usize) {
325 if index >= self.start.len() {
326 self.set_size(index + 1);
327 }
328 }
329
330 pub fn contains(&self, buffer: &Buffer) -> bool {
332 self.metadata.contains(buffer.tracker_index().as_usize())
333 }
334
335 pub fn used_resources(&self) -> impl Iterator<Item = &Arc<Buffer>> + '_ {
337 self.metadata.owned_resources()
338 }
339
340 pub fn drain_transitions<'a, 'b: 'a>(
342 &'b mut self,
343 snatch_guard: &'a SnatchGuard<'a>,
344 ) -> impl Iterator<Item = BufferBarrier<'a, dyn hal::DynBuffer>> {
345 let buffer_barriers = self.temp.drain(..).map(|pending| {
346 let buf = unsafe { self.metadata.get_resource_unchecked(pending.id as _) };
347 pending.into_hal(buf, snatch_guard)
348 });
349 buffer_barriers
350 }
351
352 pub fn set_single(
360 &mut self,
361 buffer: &Arc<Buffer>,
362 state: BufferUses,
363 ) -> Option<PendingTransition<BufferUses>> {
364 let index: usize = buffer.tracker_index().as_usize();
365
366 self.allow_index(index);
367
368 self.tracker_assert_in_bounds(index);
369
370 unsafe {
371 self.insert_or_barrier_update(
372 index,
373 BufferStateProvider::Direct { state },
374 None,
375 ResourceMetadataProvider::Direct { resource: buffer },
376 )
377 };
378
379 strict_assert!(self.temp.len() <= 1);
380
381 self.temp.pop()
382 }
383
384 pub fn set_from_tracker(&mut self, tracker: &Self) {
393 let incoming_size = tracker.start.len();
394 if incoming_size > self.start.len() {
395 self.set_size(incoming_size);
396 }
397
398 for index in tracker.metadata.owned_indices() {
399 self.tracker_assert_in_bounds(index);
400 tracker.tracker_assert_in_bounds(index);
401 unsafe {
402 self.insert_or_barrier_update(
403 index,
404 BufferStateProvider::Indirect {
405 state: &tracker.start,
406 },
407 Some(BufferStateProvider::Indirect {
408 state: &tracker.end,
409 }),
410 ResourceMetadataProvider::Indirect {
411 metadata: &tracker.metadata,
412 },
413 )
414 }
415 }
416 }
417
418 pub fn set_from_usage_scope(&mut self, scope: &BufferUsageScope) {
427 let incoming_size = scope.state.len();
428 if incoming_size > self.start.len() {
429 self.set_size(incoming_size);
430 }
431
432 for index in scope.metadata.owned_indices() {
433 self.tracker_assert_in_bounds(index);
434 scope.tracker_assert_in_bounds(index);
435 unsafe {
436 self.insert_or_barrier_update(
437 index,
438 BufferStateProvider::Indirect {
439 state: &scope.state,
440 },
441 None,
442 ResourceMetadataProvider::Indirect {
443 metadata: &scope.metadata,
444 },
445 )
446 }
447 }
448 }
449
450 pub fn set_and_remove_from_usage_scope_sparse(
469 &mut self,
470 scope: &mut BufferUsageScope,
471 index_source: impl IntoIterator<Item = TrackerIndex>,
472 ) {
473 let incoming_size = scope.state.len();
474 if incoming_size > self.start.len() {
475 self.set_size(incoming_size);
476 }
477
478 for index in index_source {
479 let index = index.as_usize();
480
481 scope.tracker_assert_in_bounds(index);
482
483 if unsafe { !scope.metadata.contains_unchecked(index) } {
484 continue;
485 }
486
487 unsafe {
490 self.insert_or_barrier_update(
491 index,
492 BufferStateProvider::Indirect {
493 state: &scope.state,
494 },
495 None,
496 ResourceMetadataProvider::Indirect {
497 metadata: &scope.metadata,
498 },
499 )
500 };
501
502 unsafe { scope.metadata.remove(index) };
503 }
504 }
505
506 #[inline(always)]
525 unsafe fn insert_or_barrier_update(
526 &mut self,
527 index: usize,
528 start_state_provider: BufferStateProvider<'_>,
529 end_state_provider: Option<BufferStateProvider<'_>>,
530 metadata_provider: ResourceMetadataProvider<'_, Arc<Buffer>>,
531 ) {
532 let currently_owned = unsafe { self.metadata.contains_unchecked(index) };
533
534 if !currently_owned {
535 unsafe {
536 insert(
537 Some(&mut self.start),
538 &mut self.end,
539 &mut self.metadata,
540 index,
541 start_state_provider,
542 end_state_provider,
543 metadata_provider,
544 )
545 };
546 return;
547 }
548
549 let update_state_provider =
550 end_state_provider.unwrap_or_else(|| start_state_provider.clone());
551 unsafe {
552 barrier(
553 &mut self.end,
554 index,
555 start_state_provider,
556 &mut self.temp,
557 self.ordered_uses_mask,
558 )
559 };
560
561 unsafe { update(&mut self.end, index, update_state_provider) };
562 }
563}
564
565pub(crate) struct DeviceBufferTracker {
567 current_states: Vec<BufferUses>,
568 metadata: ResourceMetadata<Weak<Buffer>>,
569 temp: Vec<PendingTransition<BufferUses>>,
570 ordered_uses_mask: BufferUses,
571}
572
573impl DeviceBufferTracker {
574 pub fn new(ordered_uses_mask: BufferUses) -> Self {
575 Self {
576 current_states: Vec::new(),
577 metadata: ResourceMetadata::new(),
578 temp: Vec::new(),
579 ordered_uses_mask,
580 }
581 }
582
583 fn tracker_assert_in_bounds(&self, index: usize) {
584 strict_assert!(index < self.current_states.len());
585 self.metadata.tracker_assert_in_bounds(index);
586 }
587
588 fn allow_index(&mut self, index: usize) {
590 if index >= self.current_states.len() {
591 self.current_states.resize(index + 1, BufferUses::empty());
592 self.metadata.set_size(index + 1);
593 }
594 }
595
596 pub fn used_resources(&self) -> impl Iterator<Item = &Weak<Buffer>> + '_ {
598 self.metadata.owned_resources()
599 }
600
601 pub fn insert_single(&mut self, buffer: &Arc<Buffer>, state: BufferUses) {
605 let index = buffer.tracker_index().as_usize();
606
607 self.allow_index(index);
608
609 self.tracker_assert_in_bounds(index);
610
611 unsafe {
612 insert(
613 None,
614 &mut self.current_states,
615 &mut self.metadata,
616 index,
617 BufferStateProvider::Direct { state },
618 None,
619 ResourceMetadataProvider::Direct {
620 resource: &Arc::downgrade(buffer),
621 },
622 )
623 }
624 }
625
626 pub fn set_single(
631 &mut self,
632 buffer: &Arc<Buffer>,
633 state: BufferUses,
634 ) -> Option<PendingTransition<BufferUses>> {
635 let index: usize = buffer.tracker_index().as_usize();
636
637 self.tracker_assert_in_bounds(index);
638
639 let start_state_provider = BufferStateProvider::Direct { state };
640
641 unsafe {
642 barrier(
643 &mut self.current_states,
644 index,
645 start_state_provider.clone(),
646 &mut self.temp,
647 self.ordered_uses_mask,
648 )
649 };
650 unsafe { update(&mut self.current_states, index, start_state_provider) };
651
652 strict_assert!(self.temp.len() <= 1);
653
654 self.temp.pop()
655 }
656
657 pub fn set_from_tracker_and_drain_transitions<'a, 'b: 'a>(
662 &'a mut self,
663 tracker: &'a BufferTracker,
664 snatch_guard: &'b SnatchGuard<'b>,
665 ) -> impl Iterator<Item = BufferBarrier<'a, dyn hal::DynBuffer>> {
666 for index in tracker.metadata.owned_indices() {
667 self.tracker_assert_in_bounds(index);
668
669 let start_state_provider = BufferStateProvider::Indirect {
670 state: &tracker.start,
671 };
672 let end_state_provider = BufferStateProvider::Indirect {
673 state: &tracker.end,
674 };
675 unsafe {
676 barrier(
677 &mut self.current_states,
678 index,
679 start_state_provider,
680 &mut self.temp,
681 self.ordered_uses_mask,
682 )
683 };
684 unsafe { update(&mut self.current_states, index, end_state_provider) };
685 }
686
687 self.temp.drain(..).map(|pending| {
688 let buf = unsafe { tracker.metadata.get_resource_unchecked(pending.id as _) };
689 pending.into_hal(buf, snatch_guard)
690 })
691 }
692}
693
694#[derive(Debug, Clone)]
696enum BufferStateProvider<'a> {
697 Direct { state: BufferUses },
699 Indirect { state: &'a [BufferUses] },
701}
702impl BufferStateProvider<'_> {
703 #[inline(always)]
709 unsafe fn get_state(&self, index: usize) -> BufferUses {
710 match *self {
711 BufferStateProvider::Direct { state } => state,
712 BufferStateProvider::Indirect { state } => {
713 strict_assert!(index < state.len());
714 *unsafe { state.get_unchecked(index) }
715 }
716 }
717 }
718}
719
720#[inline(always)]
721unsafe fn insert<T: Clone>(
722 start_states: Option<&mut [BufferUses]>,
723 current_states: &mut [BufferUses],
724 resource_metadata: &mut ResourceMetadata<T>,
725 index: usize,
726 start_state_provider: BufferStateProvider<'_>,
727 end_state_provider: Option<BufferStateProvider<'_>>,
728 metadata_provider: ResourceMetadataProvider<'_, T>,
729) {
730 let new_start_state = unsafe { start_state_provider.get_state(index) };
731 let new_end_state =
732 end_state_provider.map_or(new_start_state, |p| unsafe { p.get_state(index) });
733
734 strict_assert_eq!(invalid_resource_state(new_start_state), false);
737 strict_assert_eq!(invalid_resource_state(new_end_state), false);
738
739 unsafe {
740 if let Some(&mut ref mut start_state) = start_states {
741 *start_state.get_unchecked_mut(index) = new_start_state;
742 }
743 *current_states.get_unchecked_mut(index) = new_end_state;
744
745 let resource = metadata_provider.get(index);
746 resource_metadata.insert(index, resource.clone());
747 }
748}
749
750#[inline(always)]
751unsafe fn merge(
752 current_states: &mut [BufferUses],
753 _index32: u32,
754 index: usize,
755 state_provider: BufferStateProvider<'_>,
756 metadata_provider: ResourceMetadataProvider<'_, Arc<Buffer>>,
757) -> Result<(), ResourceUsageCompatibilityError> {
758 let current_state = unsafe { current_states.get_unchecked_mut(index) };
759 let new_state = unsafe { state_provider.get_state(index) };
760
761 let merged_state = *current_state | new_state;
762
763 if invalid_resource_state(merged_state) {
764 return Err(ResourceUsageCompatibilityError::from_buffer(
765 unsafe { metadata_provider.get(index) },
766 *current_state,
767 new_state,
768 ));
769 }
770
771 *current_state = merged_state;
772
773 Ok(())
774}
775
776#[inline(always)]
777unsafe fn barrier(
778 current_states: &mut [BufferUses],
779 index: usize,
780 state_provider: BufferStateProvider<'_>,
781 barriers: &mut Vec<PendingTransition<BufferUses>>,
782 ordered_uses_mask: BufferUses,
783) {
784 let current_state = unsafe { *current_states.get_unchecked(index) };
785 let new_state = unsafe { state_provider.get_state(index) };
786
787 if skip_barrier(current_state, ordered_uses_mask, new_state) {
788 return;
789 }
790
791 barriers.push(PendingTransition {
792 id: index as _,
793 selector: (),
794 usage: hal::StateTransition {
795 from: current_state,
796 to: new_state,
797 },
798 });
799}
800
801#[inline(always)]
802unsafe fn update(
803 current_states: &mut [BufferUses],
804 index: usize,
805 state_provider: BufferStateProvider<'_>,
806) {
807 let current_state = unsafe { current_states.get_unchecked_mut(index) };
808 let new_state = unsafe { state_provider.get_state(index) };
809
810 *current_state = new_state;
811}