wgpu_core/track/
texture.rs

1//! Texture Trackers
2//!
3//! Texture trackers are significantly more complicated than
4//! the buffer trackers because textures can be in a "complex"
5//! state where each individual subresource can potentially be
6//! in a different state from every other subtresource. These
7//! complex states are stored separately from the simple states
8//! because they are signifignatly more difficult to track and
9//! most resources spend the vast majority of their lives in
10//! simple states.
11//!
12//! There are two special texture usages: `UNKNOWN` and `UNINITIALIZED`.
13//! - `UNKNOWN` is only used in complex states and is used to signify
14//!   that the complex state does not know anything about those subresources.
15//!   It cannot leak into transitions, it is invalid to transition into UNKNOWN
16//!   state.
17//! - `UNINITIALIZED` is used in both simple and complex states to mean the texture
18//!   is known to be in some undefined state. Any transition away from UNINITIALIZED
19//!   will treat the contents as junk.
20
21use super::{range::RangedStates, PendingTransition, PendingTransitionList};
22use crate::{
23    resource::{RawResourceAccess, Texture, TextureInner, TextureView, Trackable},
24    snatch::SnatchGuard,
25    track::{
26        invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
27        ResourceUsageCompatibilityError, ResourceUses,
28    },
29};
30use hal::TextureBarrier;
31
32use arrayvec::ArrayVec;
33use naga::FastHashMap;
34
35use wgt::{strict_assert, strict_assert_eq, TextureSelector, TextureUses};
36
37use alloc::{
38    sync::{Arc, Weak},
39    vec::{Drain, Vec},
40};
41use core::iter;
42
43impl ResourceUses for TextureUses {
44    const EXCLUSIVE: Self = Self::EXCLUSIVE;
45
46    type Selector = TextureSelector;
47
48    fn bits(self) -> u16 {
49        Self::bits(&self)
50    }
51
52    fn all_ordered(self) -> bool {
53        Self::ORDERED.contains(self)
54    }
55
56    fn any_exclusive(self) -> bool {
57        self.intersects(Self::EXCLUSIVE)
58    }
59}
60
61/// Represents the complex state of textures where every subresource is potentially
62/// in a different state.
63#[derive(Clone, Debug, Default, PartialEq)]
64struct ComplexTextureState {
65    mips: ArrayVec<RangedStates<u32, TextureUses>, { hal::MAX_MIP_LEVELS as usize }>,
66}
67
68impl ComplexTextureState {
69    /// Creates complex texture state for the given sizes.
70    ///
71    /// This state will be initialized with the UNKNOWN state, a special state
72    /// which means the trakcer knows nothing about the state.
73    fn new(mip_level_count: u32, array_layer_count: u32) -> Self {
74        Self {
75            mips: iter::repeat_with(|| {
76                RangedStates::from_range(0..array_layer_count, TextureUses::UNKNOWN)
77            })
78            .take(mip_level_count as usize)
79            .collect(),
80        }
81    }
82
83    /// Initialize a complex state from a selector representing the full size of the texture
84    /// and an iterator of a selector and a texture use, specifying a usage for a specific
85    /// set of subresources.
86    ///
87    /// [`Self::to_selector_state_iter`] can be used to create such an iterator.
88    ///
89    /// # Safety
90    ///
91    /// All selectors in the iterator must be inside of the full_range selector.
92    ///
93    /// The full range selector must have mips and layers start at 0.
94    unsafe fn from_selector_state_iter(
95        full_range: TextureSelector,
96        state_iter: impl Iterator<Item = (TextureSelector, TextureUses)>,
97    ) -> Self {
98        strict_assert_eq!(full_range.layers.start, 0);
99        strict_assert_eq!(full_range.mips.start, 0);
100
101        let mut complex =
102            ComplexTextureState::new(full_range.mips.len() as u32, full_range.layers.len() as u32);
103        for (selector, desired_state) in state_iter {
104            strict_assert!(selector.layers.end <= full_range.layers.end);
105            strict_assert!(selector.mips.end <= full_range.mips.end);
106
107            // This should only ever happen with a wgpu bug, but let's just double
108            // check that resource states don't have any conflicts.
109            strict_assert_eq!(invalid_resource_state(desired_state), false);
110
111            let mips = selector.mips.start as usize..selector.mips.end as usize;
112            for mip in unsafe { complex.mips.get_unchecked_mut(mips) } {
113                for &mut (_, ref mut state) in mip.isolate(&selector.layers, TextureUses::UNKNOWN) {
114                    *state = desired_state;
115                }
116            }
117        }
118        complex
119    }
120
121    /// Convert a complex state into an iterator over all states stored.
122    ///
123    /// [`Self::from_selector_state_iter`] can be used to consume such an iterator.
124    fn to_selector_state_iter(
125        &self,
126    ) -> impl Iterator<Item = (TextureSelector, TextureUses)> + Clone + '_ {
127        self.mips.iter().enumerate().flat_map(|(mip, inner)| {
128            let mip = mip as u32;
129            {
130                inner.iter().map(move |&(ref layers, inner)| {
131                    (
132                        TextureSelector {
133                            mips: mip..mip + 1,
134                            layers: layers.clone(),
135                        },
136                        inner,
137                    )
138                })
139            }
140        })
141    }
142}
143
144/// Stores a bind group's texture views + their usages (within the bind group).
145#[derive(Debug)]
146pub(crate) struct TextureViewBindGroupState {
147    views: Vec<(Arc<TextureView>, TextureUses)>,
148}
149impl TextureViewBindGroupState {
150    pub fn new() -> Self {
151        Self { views: Vec::new() }
152    }
153
154    /// Optimize the texture bind group state by sorting it by ID.
155    ///
156    /// When this list of states is merged into a tracker, the memory
157    /// accesses will be in a constant ascending order.
158    pub(crate) fn optimize(&mut self) {
159        self.views
160            .sort_unstable_by_key(|(view, _)| view.parent.tracker_index());
161    }
162
163    /// Adds the given resource with the given state.
164    pub fn insert_single(&mut self, view: Arc<TextureView>, usage: TextureUses) {
165        self.views.push((view, usage));
166    }
167}
168
169/// Container for corresponding simple and complex texture states.
170#[derive(Debug)]
171pub(crate) struct TextureStateSet {
172    simple: Vec<TextureUses>,
173    complex: FastHashMap<usize, ComplexTextureState>,
174}
175
176impl TextureStateSet {
177    fn new() -> Self {
178        Self {
179            simple: Vec::new(),
180            complex: FastHashMap::default(),
181        }
182    }
183
184    fn clear(&mut self) {
185        self.simple.clear();
186        self.complex.clear();
187    }
188
189    fn set_size(&mut self, size: usize) {
190        self.simple.resize(size, TextureUses::UNINITIALIZED);
191    }
192
193    fn size(&self) -> usize {
194        self.simple.len()
195    }
196
197    /// SAFETY: `index` must be in bounds.
198    unsafe fn get_unchecked(
199        &self,
200        index: usize,
201    ) -> SingleOrManyStates<TextureUses, &ComplexTextureState> {
202        let simple = unsafe { *self.simple.get_unchecked(index) };
203        if simple == TextureUses::COMPLEX {
204            SingleOrManyStates::Many(unsafe { self.complex.get(&index).unwrap_unchecked() })
205        } else {
206            SingleOrManyStates::Single(simple)
207        }
208    }
209
210    /// # Safety
211    ///
212    /// The `index` must be in bounds.
213    unsafe fn get_mut_unchecked(
214        &mut self,
215        index: usize,
216    ) -> SingleOrManyStates<&mut TextureUses, &mut ComplexTextureState> {
217        let simple = unsafe { self.simple.get_unchecked_mut(index) };
218        if *simple == TextureUses::COMPLEX {
219            SingleOrManyStates::Many(unsafe { self.complex.get_mut(&index).unwrap_unchecked() })
220        } else {
221            SingleOrManyStates::Single(simple)
222        }
223    }
224
225    /// # Safety
226    ///
227    /// The `index` must be in bounds.
228    unsafe fn insert_simple_unchecked(&mut self, index: usize, simple: TextureUses) {
229        unsafe { *self.simple.get_unchecked_mut(index) = simple };
230    }
231
232    /// # Safety
233    ///
234    /// The `index` must be in bounds.
235    unsafe fn insert_complex_unchecked(&mut self, index: usize, complex: ComplexTextureState) {
236        unsafe { *self.simple.get_unchecked_mut(index) = TextureUses::COMPLEX };
237        self.complex.insert(index, complex);
238    }
239
240    /// # Safety
241    ///
242    /// The `index` must be in bounds.
243    unsafe fn make_simple_unchecked(&mut self, index: usize, simple: TextureUses) {
244        unsafe { *self.simple.get_unchecked_mut(index) = simple };
245        unsafe { self.complex.remove(&index).unwrap_unchecked() };
246    }
247
248    /// # Safety
249    ///
250    /// The `index` must be in bounds.
251    unsafe fn make_complex_unchecked(&mut self, index: usize, complex: ComplexTextureState) {
252        unsafe { *self.simple.get_unchecked_mut(index) = TextureUses::COMPLEX };
253        self.complex.insert(index, complex);
254    }
255
256    fn tracker_assert_in_bounds(&self, index: usize) {
257        strict_assert!(index < self.size());
258    }
259}
260
261/// Stores all texture state within a single usage scope.
262#[derive(Debug)]
263pub(crate) struct TextureUsageScope {
264    set: TextureStateSet,
265    metadata: ResourceMetadata<Arc<Texture>>,
266}
267
268impl Default for TextureUsageScope {
269    fn default() -> Self {
270        Self {
271            set: TextureStateSet::new(),
272            metadata: ResourceMetadata::new(),
273        }
274    }
275}
276
277impl TextureUsageScope {
278    fn tracker_assert_in_bounds(&self, index: usize) {
279        self.metadata.tracker_assert_in_bounds(index);
280        self.set.tracker_assert_in_bounds(index);
281    }
282
283    pub fn clear(&mut self) {
284        self.set.clear();
285        self.metadata.clear();
286    }
287
288    /// Sets the size of all the vectors inside the tracker.
289    ///
290    /// Must be called with the highest possible Texture ID before
291    /// all unsafe functions are called.
292    pub fn set_size(&mut self, size: usize) {
293        self.set.set_size(size);
294        self.metadata.set_size(size);
295    }
296
297    /// Returns true if the tracker owns no resources.
298    ///
299    /// This is a O(n) operation.
300    pub(crate) fn is_empty(&self) -> bool {
301        self.metadata.is_empty()
302    }
303
304    /// Merge the list of texture states in the given usage scope into this UsageScope.
305    ///
306    /// If any of the resulting states is invalid, stops the merge and returns a usage
307    /// conflict with the details of the invalid state.
308    ///
309    /// If the given tracker uses IDs higher than the length of internal vectors,
310    /// the vectors will be extended. A call to set_size is not needed.
311    pub fn merge_usage_scope(
312        &mut self,
313        scope: &Self,
314    ) -> Result<(), ResourceUsageCompatibilityError> {
315        let incoming_size = scope.set.size();
316        if incoming_size > self.set.size() {
317            self.set_size(incoming_size);
318        }
319
320        for index in scope.metadata.owned_indices() {
321            self.tracker_assert_in_bounds(index);
322            scope.tracker_assert_in_bounds(index);
323
324            let texture_selector =
325                unsafe { &scope.metadata.get_resource_unchecked(index).full_range };
326            unsafe {
327                insert_or_merge(
328                    texture_selector,
329                    &mut self.set,
330                    &mut self.metadata,
331                    index,
332                    TextureStateProvider::TextureSet { set: &scope.set },
333                    ResourceMetadataProvider::Indirect {
334                        metadata: &scope.metadata,
335                    },
336                )?
337            };
338        }
339
340        Ok(())
341    }
342
343    /// Merge the list of texture states in the given bind group into this usage scope.
344    ///
345    /// If any of the resulting states is invalid, stops the merge and returns a usage
346    /// conflict with the details of the invalid state.
347    ///
348    /// Because bind groups do not check if the union of all their states is valid,
349    /// this method is allowed to return Err on the first bind group bound.
350    ///
351    /// # Safety
352    ///
353    /// [`Self::set_size`] must be called with the maximum possible Buffer ID before this
354    /// method is called.
355    pub unsafe fn merge_bind_group(
356        &mut self,
357        bind_group: &TextureViewBindGroupState,
358    ) -> Result<(), ResourceUsageCompatibilityError> {
359        for (view, usage) in bind_group.views.iter() {
360            unsafe { self.merge_single(&view.parent, Some(view.selector.clone()), *usage)? };
361        }
362
363        Ok(())
364    }
365
366    /// Merge a single state into the UsageScope.
367    ///
368    /// If the resulting state is invalid, returns a usage
369    /// conflict with the details of the invalid state.
370    ///
371    /// # Safety
372    ///
373    /// Unlike other trackers whose merge_single is safe, this method is only
374    /// called where there is already other unsafe tracking functions active,
375    /// so we can prove this unsafe "for free".
376    ///
377    /// [`Self::set_size`] must be called with the maximum possible Buffer ID before this
378    /// method is called.
379    pub unsafe fn merge_single(
380        &mut self,
381        texture: &Arc<Texture>,
382        selector: Option<TextureSelector>,
383        new_state: TextureUses,
384    ) -> Result<(), ResourceUsageCompatibilityError> {
385        let index = texture.tracker_index().as_usize();
386
387        self.tracker_assert_in_bounds(index);
388
389        let texture_selector = &texture.full_range;
390        unsafe {
391            insert_or_merge(
392                texture_selector,
393                &mut self.set,
394                &mut self.metadata,
395                index,
396                TextureStateProvider::from_option(selector, new_state),
397                ResourceMetadataProvider::Direct { resource: texture },
398            )?
399        };
400
401        Ok(())
402    }
403}
404
405pub(crate) trait TextureTrackerSetSingle {
406    fn set_single(
407        &mut self,
408        texture: &Arc<Texture>,
409        selector: TextureSelector,
410        new_state: TextureUses,
411    ) -> Drain<'_, PendingTransition<TextureUses>>;
412}
413
414/// Stores all texture state within a command buffer.
415pub(crate) struct TextureTracker {
416    start_set: TextureStateSet,
417    end_set: TextureStateSet,
418
419    metadata: ResourceMetadata<Arc<Texture>>,
420
421    temp: Vec<PendingTransition<TextureUses>>,
422}
423
424impl TextureTracker {
425    pub fn new() -> Self {
426        Self {
427            start_set: TextureStateSet::new(),
428            end_set: TextureStateSet::new(),
429
430            metadata: ResourceMetadata::new(),
431
432            temp: Vec::new(),
433        }
434    }
435
436    fn tracker_assert_in_bounds(&self, index: usize) {
437        self.metadata.tracker_assert_in_bounds(index);
438        self.start_set.tracker_assert_in_bounds(index);
439        self.end_set.tracker_assert_in_bounds(index);
440    }
441
442    /// Sets the size of all the vectors inside the tracker.
443    ///
444    /// Must be called with the highest possible Texture ID before
445    /// all unsafe functions are called.
446    pub fn set_size(&mut self, size: usize) {
447        self.start_set.set_size(size);
448        self.end_set.set_size(size);
449
450        self.metadata.set_size(size);
451    }
452
453    /// Extend the vectors to let the given index be valid.
454    fn allow_index(&mut self, index: usize) {
455        if index >= self.start_set.size() {
456            self.set_size(index + 1);
457        }
458    }
459
460    /// Returns true if the tracker owns the given texture.
461    pub fn contains(&self, texture: &Texture) -> bool {
462        self.metadata.contains(texture.tracker_index().as_usize())
463    }
464
465    /// Returns a list of all textures tracked.
466    pub fn used_resources(&self) -> impl Iterator<Item = &Arc<Texture>> + '_ {
467        self.metadata.owned_resources()
468    }
469    /// Drain all currently pending transitions.
470    pub fn drain_transitions<'a>(
471        &'a mut self,
472        snatch_guard: &'a SnatchGuard<'a>,
473    ) -> (PendingTransitionList, Vec<Option<&'a TextureInner>>) {
474        let mut textures = Vec::new();
475        let transitions = self
476            .temp
477            .drain(..)
478            .inspect(|pending| {
479                let tex = unsafe { self.metadata.get_resource_unchecked(pending.id as _) };
480                textures.push(tex.inner.get(snatch_guard));
481            })
482            .collect();
483        (transitions, textures)
484    }
485
486    /// Sets the state of a single texture.
487    ///
488    /// If a transition is needed to get the texture into the given state, that transition
489    /// is returned.
490    ///
491    /// If the ID is higher than the length of internal vectors,
492    /// the vectors will be extended. A call to set_size is not needed.
493    pub fn set_single(
494        &mut self,
495        texture: &Arc<Texture>,
496        selector: TextureSelector,
497        new_state: TextureUses,
498    ) -> Drain<'_, PendingTransition<TextureUses>> {
499        let index = texture.tracker_index().as_usize();
500
501        self.allow_index(index);
502
503        self.tracker_assert_in_bounds(index);
504
505        unsafe {
506            insert_or_barrier_update(
507                &texture.full_range,
508                Some(&mut self.start_set),
509                &mut self.end_set,
510                &mut self.metadata,
511                index,
512                TextureStateProvider::Selector {
513                    selector,
514                    state: new_state,
515                },
516                None,
517                ResourceMetadataProvider::Direct { resource: texture },
518                &mut self.temp,
519            )
520        }
521
522        self.temp.drain(..)
523    }
524
525    /// Sets the given state for all texture in the given tracker.
526    ///
527    /// If a transition is needed to get the texture into the needed state,
528    /// those transitions are stored within the tracker. A subsequent
529    /// call to [`Self::drain_transitions`] is needed to get those transitions.
530    ///
531    /// If the ID is higher than the length of internal vectors,
532    /// the vectors will be extended. A call to set_size is not needed.
533    pub fn set_from_tracker(&mut self, tracker: &Self) {
534        let incoming_size = tracker.start_set.size();
535        if incoming_size > self.start_set.size() {
536            self.set_size(incoming_size);
537        }
538
539        for index in tracker.metadata.owned_indices() {
540            self.tracker_assert_in_bounds(index);
541            tracker.tracker_assert_in_bounds(index);
542            unsafe {
543                let texture_selector = &tracker.metadata.get_resource_unchecked(index).full_range;
544                insert_or_barrier_update(
545                    texture_selector,
546                    Some(&mut self.start_set),
547                    &mut self.end_set,
548                    &mut self.metadata,
549                    index,
550                    TextureStateProvider::TextureSet {
551                        set: &tracker.start_set,
552                    },
553                    Some(TextureStateProvider::TextureSet {
554                        set: &tracker.end_set,
555                    }),
556                    ResourceMetadataProvider::Indirect {
557                        metadata: &tracker.metadata,
558                    },
559                    &mut self.temp,
560                );
561            }
562        }
563    }
564
565    /// Sets the given state for all textures in the given UsageScope.
566    ///
567    /// If a transition is needed to get the textures into the needed state,
568    /// those transitions are stored within the tracker. A subsequent
569    /// call to [`Self::drain_transitions`] is needed to get those transitions.
570    ///
571    /// If the ID is higher than the length of internal vectors,
572    /// the vectors will be extended. A call to set_size is not needed.
573    pub fn set_from_usage_scope(&mut self, scope: &TextureUsageScope) {
574        let incoming_size = scope.set.size();
575        if incoming_size > self.start_set.size() {
576            self.set_size(incoming_size);
577        }
578
579        for index in scope.metadata.owned_indices() {
580            self.tracker_assert_in_bounds(index);
581            scope.tracker_assert_in_bounds(index);
582            unsafe {
583                let texture_selector = &scope.metadata.get_resource_unchecked(index).full_range;
584                insert_or_barrier_update(
585                    texture_selector,
586                    Some(&mut self.start_set),
587                    &mut self.end_set,
588                    &mut self.metadata,
589                    index,
590                    TextureStateProvider::TextureSet { set: &scope.set },
591                    None,
592                    ResourceMetadataProvider::Indirect {
593                        metadata: &scope.metadata,
594                    },
595                    &mut self.temp,
596                );
597            }
598        }
599    }
600
601    /// Iterates through all textures in the given bind group and adopts
602    /// the state given for those textures in the UsageScope. It also
603    /// removes all touched textures from the usage scope.
604    ///
605    /// If a transition is needed to get the textures into the needed state,
606    /// those transitions are stored within the tracker. A subsequent
607    /// call to [`Self::drain_transitions`] is needed to get those transitions.
608    ///
609    /// This is a really funky method used by Compute Passes to generate
610    /// barriers after a call to dispatch without needing to iterate
611    /// over all elements in the usage scope. We use each the
612    /// bind group as a source of which IDs to look at. The bind groups
613    /// must have first been added to the usage scope.
614    ///
615    /// # Safety
616    ///
617    /// [`Self::set_size`] must be called with the maximum possible Buffer ID before this
618    /// method is called.
619    pub unsafe fn set_and_remove_from_usage_scope_sparse(
620        &mut self,
621        scope: &mut TextureUsageScope,
622        bind_group_state: &TextureViewBindGroupState,
623    ) {
624        let incoming_size = scope.set.size();
625        if incoming_size > self.start_set.size() {
626            self.set_size(incoming_size);
627        }
628
629        for (view, _) in bind_group_state.views.iter() {
630            let index = view.parent.tracker_index().as_usize();
631            scope.tracker_assert_in_bounds(index);
632
633            if unsafe { !scope.metadata.contains_unchecked(index) } {
634                continue;
635            }
636            let texture_selector = &view.parent.full_range;
637            unsafe {
638                insert_or_barrier_update(
639                    texture_selector,
640                    Some(&mut self.start_set),
641                    &mut self.end_set,
642                    &mut self.metadata,
643                    index,
644                    TextureStateProvider::TextureSet { set: &scope.set },
645                    None,
646                    ResourceMetadataProvider::Indirect {
647                        metadata: &scope.metadata,
648                    },
649                    &mut self.temp,
650                )
651            };
652
653            unsafe { scope.metadata.remove(index) };
654        }
655    }
656}
657
658impl TextureTrackerSetSingle for TextureTracker {
659    fn set_single(
660        &mut self,
661        texture: &Arc<Texture>,
662        selector: TextureSelector,
663        new_state: TextureUses,
664    ) -> Drain<'_, PendingTransition<TextureUses>> {
665        self.set_single(texture, selector, new_state)
666    }
667}
668
669/// Stores all texture state within a device.
670pub(crate) struct DeviceTextureTracker {
671    current_state_set: TextureStateSet,
672    metadata: ResourceMetadata<Weak<Texture>>,
673    temp: Vec<PendingTransition<TextureUses>>,
674}
675
676impl DeviceTextureTracker {
677    pub fn new() -> Self {
678        Self {
679            current_state_set: TextureStateSet::new(),
680            metadata: ResourceMetadata::new(),
681            temp: Vec::new(),
682        }
683    }
684
685    fn tracker_assert_in_bounds(&self, index: usize) {
686        self.metadata.tracker_assert_in_bounds(index);
687        self.current_state_set.tracker_assert_in_bounds(index);
688    }
689
690    /// Extend the vectors to let the given index be valid.
691    fn allow_index(&mut self, index: usize) {
692        if index >= self.current_state_set.size() {
693            self.current_state_set.set_size(index + 1);
694            self.metadata.set_size(index + 1);
695        }
696    }
697
698    /// Returns a list of all textures tracked.
699    pub fn used_resources(&self) -> impl Iterator<Item = &Weak<Texture>> + '_ {
700        self.metadata.owned_resources()
701    }
702
703    /// Inserts a single texture and a state into the resource tracker.
704    ///
705    /// If the resource already exists in the tracker, it will be overwritten.
706    pub fn insert_single(&mut self, texture: &Arc<Texture>, usage: TextureUses) {
707        let index = texture.tracker_index().as_usize();
708
709        self.allow_index(index);
710
711        self.tracker_assert_in_bounds(index);
712
713        unsafe {
714            insert(
715                None,
716                None,
717                &mut self.current_state_set,
718                &mut self.metadata,
719                index,
720                TextureStateProvider::KnownSingle { state: usage },
721                None,
722                ResourceMetadataProvider::Direct {
723                    resource: &Arc::downgrade(texture),
724                },
725            )
726        };
727    }
728
729    /// Sets the state of a single texture.
730    ///
731    /// If a transition is needed to get the texture into the given state, that transition
732    /// is returned.
733    pub fn set_single(
734        &mut self,
735        texture: &Arc<Texture>,
736        selector: TextureSelector,
737        new_state: TextureUses,
738    ) -> Drain<'_, PendingTransition<TextureUses>> {
739        let index = texture.tracker_index().as_usize();
740
741        self.allow_index(index);
742
743        self.tracker_assert_in_bounds(index);
744
745        let start_state_provider = TextureStateProvider::Selector {
746            selector,
747            state: new_state,
748        };
749        unsafe {
750            barrier(
751                &texture.full_range,
752                &self.current_state_set,
753                index,
754                start_state_provider.clone(),
755                &mut self.temp,
756            )
757        };
758        unsafe {
759            update(
760                &texture.full_range,
761                None,
762                &mut self.current_state_set,
763                index,
764                start_state_provider,
765            )
766        };
767
768        self.temp.drain(..)
769    }
770
771    /// Sets the given state for all texture in the given tracker.
772    ///
773    /// If a transition is needed to get the texture into the needed state,
774    /// those transitions are returned.
775    pub fn set_from_tracker_and_drain_transitions<'a, 'b: 'a>(
776        &'a mut self,
777        tracker: &'a TextureTracker,
778        snatch_guard: &'b SnatchGuard<'b>,
779    ) -> impl Iterator<Item = TextureBarrier<'a, dyn hal::DynTexture>> {
780        for index in tracker.metadata.owned_indices() {
781            self.tracker_assert_in_bounds(index);
782
783            let start_state_provider = TextureStateProvider::TextureSet {
784                set: &tracker.start_set,
785            };
786            let end_state_provider = TextureStateProvider::TextureSet {
787                set: &tracker.end_set,
788            };
789            unsafe {
790                let texture_selector = &tracker.metadata.get_resource_unchecked(index).full_range;
791                barrier(
792                    texture_selector,
793                    &self.current_state_set,
794                    index,
795                    start_state_provider,
796                    &mut self.temp,
797                );
798                update(
799                    texture_selector,
800                    None,
801                    &mut self.current_state_set,
802                    index,
803                    end_state_provider,
804                );
805            }
806        }
807
808        self.temp.drain(..).map(|pending| {
809            let tex = unsafe { tracker.metadata.get_resource_unchecked(pending.id as _) };
810            let tex = tex.try_raw(snatch_guard).unwrap();
811            pending.into_hal(tex)
812        })
813    }
814
815    /// Sets the given state for all textures in the given UsageScope.
816    ///
817    /// If a transition is needed to get the textures into the needed state,
818    /// those transitions are returned.
819    pub fn set_from_usage_scope_and_drain_transitions<'a, 'b: 'a>(
820        &'a mut self,
821        scope: &'a TextureUsageScope,
822        snatch_guard: &'b SnatchGuard<'b>,
823    ) -> impl Iterator<Item = TextureBarrier<'a, dyn hal::DynTexture>> {
824        for index in scope.metadata.owned_indices() {
825            self.tracker_assert_in_bounds(index);
826
827            let start_state_provider = TextureStateProvider::TextureSet { set: &scope.set };
828            unsafe {
829                let texture_selector = &scope.metadata.get_resource_unchecked(index).full_range;
830                barrier(
831                    texture_selector,
832                    &self.current_state_set,
833                    index,
834                    start_state_provider.clone(),
835                    &mut self.temp,
836                );
837                update(
838                    texture_selector,
839                    None,
840                    &mut self.current_state_set,
841                    index,
842                    start_state_provider,
843                );
844            }
845        }
846
847        self.temp.drain(..).map(|pending| {
848            let tex = unsafe { scope.metadata.get_resource_unchecked(pending.id as _) };
849            let tex = tex.try_raw(snatch_guard).unwrap();
850            pending.into_hal(tex)
851        })
852    }
853}
854
855impl TextureTrackerSetSingle for DeviceTextureTracker {
856    fn set_single(
857        &mut self,
858        texture: &Arc<Texture>,
859        selector: TextureSelector,
860        new_state: TextureUses,
861    ) -> Drain<'_, PendingTransition<TextureUses>> {
862        self.set_single(texture, selector, new_state)
863    }
864}
865
866/// An iterator adapter that can store two different iterator types.
867#[derive(Clone)]
868enum EitherIter<L, R> {
869    Left(L),
870    Right(R),
871}
872
873impl<L, R, D> Iterator for EitherIter<L, R>
874where
875    L: Iterator<Item = D>,
876    R: Iterator<Item = D>,
877{
878    type Item = D;
879
880    fn next(&mut self) -> Option<Self::Item> {
881        match *self {
882            EitherIter::Left(ref mut inner) => inner.next(),
883            EitherIter::Right(ref mut inner) => inner.next(),
884        }
885    }
886}
887
888/// Container that signifies storing both different things
889/// if there is a single state or many different states
890/// involved in the operation.
891#[derive(Debug, Clone)]
892enum SingleOrManyStates<S, M> {
893    Single(S),
894    Many(M),
895}
896
897/// A source of texture state.
898#[derive(Clone)]
899enum TextureStateProvider<'a> {
900    /// Comes directly from a single state.
901    KnownSingle { state: TextureUses },
902    /// Comes from a selector and a single state.
903    Selector {
904        selector: TextureSelector,
905        state: TextureUses,
906    },
907    /// Comes from another texture set.
908    TextureSet { set: &'a TextureStateSet },
909}
910impl<'a> TextureStateProvider<'a> {
911    /// Convenience function turning `Option<Selector>` into this enum.
912    fn from_option(selector: Option<TextureSelector>, state: TextureUses) -> Self {
913        match selector {
914            Some(selector) => Self::Selector { selector, state },
915            None => Self::KnownSingle { state },
916        }
917    }
918
919    /// Get the state provided by this.
920    ///
921    /// # Panics
922    ///
923    /// Panics if texture_selector is None and this uses a Selector source.
924    ///
925    /// # Safety
926    ///
927    /// - The index must be in bounds of the state set if this uses an TextureSet source.
928    #[inline(always)]
929    unsafe fn get_state(
930        self,
931        texture_selector: Option<&TextureSelector>,
932        index: usize,
933    ) -> SingleOrManyStates<
934        TextureUses,
935        impl Iterator<Item = (TextureSelector, TextureUses)> + Clone + 'a,
936    > {
937        match self {
938            TextureStateProvider::KnownSingle { state } => SingleOrManyStates::Single(state),
939            TextureStateProvider::Selector { selector, state } => {
940                // We check if the selector given is actually for the full resource,
941                // and if it is we promote to a simple state. This allows upstream
942                // code to specify selectors willy nilly, and all that are really
943                // single states are promoted here.
944                if *texture_selector.unwrap() == selector {
945                    SingleOrManyStates::Single(state)
946                } else {
947                    SingleOrManyStates::Many(EitherIter::Left(iter::once((selector, state))))
948                }
949            }
950            TextureStateProvider::TextureSet { set } => match unsafe { set.get_unchecked(index) } {
951                SingleOrManyStates::Single(single) => SingleOrManyStates::Single(single),
952                SingleOrManyStates::Many(complex) => {
953                    SingleOrManyStates::Many(EitherIter::Right(complex.to_selector_state_iter()))
954                }
955            },
956        }
957    }
958}
959
960/// Does an insertion operation if the index isn't tracked
961/// in the current metadata, otherwise merges the given state
962/// with the current state. If the merging would cause
963/// a conflict, returns that usage conflict.
964///
965/// # Safety
966///
967/// Indexes must be valid indexes into all arrays passed in
968/// to this function, either directly or via metadata or provider structs.
969#[inline(always)]
970unsafe fn insert_or_merge(
971    texture_selector: &TextureSelector,
972    current_state_set: &mut TextureStateSet,
973    resource_metadata: &mut ResourceMetadata<Arc<Texture>>,
974    index: usize,
975    state_provider: TextureStateProvider<'_>,
976    metadata_provider: ResourceMetadataProvider<'_, Arc<Texture>>,
977) -> Result<(), ResourceUsageCompatibilityError> {
978    let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
979
980    if !currently_owned {
981        unsafe {
982            insert(
983                Some(texture_selector),
984                None,
985                current_state_set,
986                resource_metadata,
987                index,
988                state_provider,
989                None,
990                metadata_provider,
991            )
992        };
993        return Ok(());
994    }
995
996    unsafe {
997        merge(
998            texture_selector,
999            current_state_set,
1000            index,
1001            state_provider,
1002            metadata_provider,
1003        )
1004    }
1005}
1006
1007/// If the resource isn't tracked
1008/// - Inserts the given resource.
1009/// - Uses the `start_state_provider` to populate `start_states`
1010/// - Uses either `end_state_provider` or `start_state_provider`
1011///   to populate `current_states`.
1012///
1013/// If the resource is tracked
1014/// - Inserts barriers from the state in `current_states`
1015///   to the state provided by `start_state_provider`.
1016/// - Updates the `current_states` with either the state from
1017///   `end_state_provider` or `start_state_provider`.
1018///
1019/// Any barriers are added to the barrier vector.
1020///
1021/// # Safety
1022///
1023/// Indexes must be valid indexes into all arrays passed in
1024/// to this function, either directly or via metadata or provider structs.
1025#[inline(always)]
1026unsafe fn insert_or_barrier_update(
1027    texture_selector: &TextureSelector,
1028    start_state: Option<&mut TextureStateSet>,
1029    current_state_set: &mut TextureStateSet,
1030    resource_metadata: &mut ResourceMetadata<Arc<Texture>>,
1031    index: usize,
1032    start_state_provider: TextureStateProvider<'_>,
1033    end_state_provider: Option<TextureStateProvider<'_>>,
1034    metadata_provider: ResourceMetadataProvider<'_, Arc<Texture>>,
1035    barriers: &mut Vec<PendingTransition<TextureUses>>,
1036) {
1037    let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
1038
1039    if !currently_owned {
1040        unsafe {
1041            insert(
1042                Some(texture_selector),
1043                start_state,
1044                current_state_set,
1045                resource_metadata,
1046                index,
1047                start_state_provider,
1048                end_state_provider,
1049                metadata_provider,
1050            )
1051        };
1052        return;
1053    }
1054
1055    let update_state_provider = end_state_provider.unwrap_or_else(|| start_state_provider.clone());
1056    unsafe {
1057        barrier(
1058            texture_selector,
1059            current_state_set,
1060            index,
1061            start_state_provider,
1062            barriers,
1063        )
1064    };
1065    unsafe {
1066        update(
1067            texture_selector,
1068            start_state,
1069            current_state_set,
1070            index,
1071            update_state_provider,
1072        )
1073    };
1074}
1075
1076#[inline(always)]
1077unsafe fn insert<T: Clone>(
1078    texture_selector: Option<&TextureSelector>,
1079    start_state: Option<&mut TextureStateSet>,
1080    end_state: &mut TextureStateSet,
1081    resource_metadata: &mut ResourceMetadata<T>,
1082    index: usize,
1083    start_state_provider: TextureStateProvider<'_>,
1084    end_state_provider: Option<TextureStateProvider<'_>>,
1085    metadata_provider: ResourceMetadataProvider<'_, T>,
1086) {
1087    let start_layers = unsafe { start_state_provider.get_state(texture_selector, index) };
1088    match start_layers {
1089        SingleOrManyStates::Single(state) => {
1090            // This should only ever happen with a wgpu bug, but let's just double
1091            // check that resource states don't have any conflicts.
1092            strict_assert_eq!(invalid_resource_state(state), false);
1093
1094            if let Some(start_state) = start_state {
1095                unsafe { start_state.insert_simple_unchecked(index, state) };
1096            }
1097
1098            // We only need to insert ourselves the end state if there is no end state provider.
1099            if end_state_provider.is_none() {
1100                unsafe { end_state.insert_simple_unchecked(index, state) };
1101            }
1102        }
1103        SingleOrManyStates::Many(state_iter) => {
1104            let full_range = texture_selector.unwrap().clone();
1105
1106            let complex =
1107                unsafe { ComplexTextureState::from_selector_state_iter(full_range, state_iter) };
1108
1109            if let Some(start_state) = start_state {
1110                unsafe { start_state.insert_complex_unchecked(index, complex.clone()) };
1111            }
1112
1113            // We only need to insert ourselves the end state if there is no end state provider.
1114            if end_state_provider.is_none() {
1115                unsafe { end_state.insert_complex_unchecked(index, complex) };
1116            }
1117        }
1118    }
1119
1120    if let Some(end_state_provider) = end_state_provider {
1121        match unsafe { end_state_provider.get_state(texture_selector, index) } {
1122            SingleOrManyStates::Single(state) => {
1123                // This should only ever happen with a wgpu bug, but let's just double
1124                // check that resource states don't have any conflicts.
1125                strict_assert_eq!(invalid_resource_state(state), false);
1126
1127                // We only need to insert into the end, as there is guaranteed to be
1128                // a start state provider.
1129                unsafe { end_state.insert_simple_unchecked(index, state) };
1130            }
1131            SingleOrManyStates::Many(state_iter) => {
1132                let full_range = texture_selector.unwrap().clone();
1133
1134                let complex = unsafe {
1135                    ComplexTextureState::from_selector_state_iter(full_range, state_iter)
1136                };
1137
1138                // We only need to insert into the end, as there is guaranteed to be
1139                // a start state provider.
1140                unsafe { end_state.insert_complex_unchecked(index, complex) };
1141            }
1142        }
1143    }
1144
1145    unsafe {
1146        let resource = metadata_provider.get(index);
1147        resource_metadata.insert(index, resource.clone());
1148    }
1149}
1150
1151#[inline(always)]
1152unsafe fn merge(
1153    texture_selector: &TextureSelector,
1154    current_state_set: &mut TextureStateSet,
1155    index: usize,
1156    state_provider: TextureStateProvider<'_>,
1157    metadata_provider: ResourceMetadataProvider<'_, Arc<Texture>>,
1158) -> Result<(), ResourceUsageCompatibilityError> {
1159    let current_state = unsafe { current_state_set.get_mut_unchecked(index) };
1160
1161    let new_state = unsafe { state_provider.get_state(Some(texture_selector), index) };
1162
1163    match (current_state, new_state) {
1164        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Single(new_simple)) => {
1165            let merged_state = *current_simple | new_simple;
1166
1167            if invalid_resource_state(merged_state) {
1168                return Err(ResourceUsageCompatibilityError::from_texture(
1169                    unsafe { metadata_provider.get(index) },
1170                    texture_selector.clone(),
1171                    *current_simple,
1172                    new_simple,
1173                ));
1174            }
1175
1176            *current_simple = merged_state;
1177        }
1178        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Many(new_many)) => {
1179            // Because we are now demoting this simple state to a complex state,
1180            // we actually need to make a whole new complex state for us to use
1181            // as there wasn't one before.
1182            let mut new_complex = unsafe {
1183                ComplexTextureState::from_selector_state_iter(
1184                    texture_selector.clone(),
1185                    iter::once((texture_selector.clone(), *current_simple)),
1186                )
1187            };
1188
1189            for (selector, new_state) in new_many {
1190                let merged_state = *current_simple | new_state;
1191
1192                if invalid_resource_state(merged_state) {
1193                    return Err(ResourceUsageCompatibilityError::from_texture(
1194                        unsafe { metadata_provider.get(index) },
1195                        selector,
1196                        *current_simple,
1197                        new_state,
1198                    ));
1199                }
1200
1201                for mip in
1202                    &mut new_complex.mips[selector.mips.start as usize..selector.mips.end as usize]
1203                {
1204                    for &mut (_, ref mut current_layer_state) in
1205                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1206                    {
1207                        *current_layer_state = merged_state;
1208                    }
1209
1210                    mip.coalesce();
1211                }
1212            }
1213
1214            unsafe { current_state_set.make_complex_unchecked(index, new_complex) };
1215        }
1216        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Single(new_simple)) => {
1217            for (mip_id, mip) in current_complex.mips.iter_mut().enumerate() {
1218                let mip_id = mip_id as u32;
1219
1220                for &mut (ref layers, ref mut current_layer_state) in mip.iter_mut() {
1221                    let merged_state = *current_layer_state | new_simple;
1222
1223                    // Once we remove unknown, this will never be empty, as
1224                    // simple states are never unknown.
1225                    let merged_state = merged_state - TextureUses::UNKNOWN;
1226
1227                    if invalid_resource_state(merged_state) {
1228                        return Err(ResourceUsageCompatibilityError::from_texture(
1229                            unsafe { metadata_provider.get(index) },
1230                            TextureSelector {
1231                                mips: mip_id..mip_id + 1,
1232                                layers: layers.clone(),
1233                            },
1234                            *current_layer_state,
1235                            new_simple,
1236                        ));
1237                    }
1238
1239                    *current_layer_state = merged_state;
1240                }
1241
1242                mip.coalesce();
1243            }
1244        }
1245        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Many(new_many)) => {
1246            for (selector, new_state) in new_many {
1247                for mip_id in selector.mips {
1248                    strict_assert!((mip_id as usize) < current_complex.mips.len());
1249
1250                    let mip = unsafe { current_complex.mips.get_unchecked_mut(mip_id as usize) };
1251
1252                    for &mut (ref layers, ref mut current_layer_state) in
1253                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1254                    {
1255                        let merged_state = *current_layer_state | new_state;
1256                        let merged_state = merged_state - TextureUses::UNKNOWN;
1257
1258                        if merged_state.is_empty() {
1259                            // We know nothing about this state, lets just move on.
1260                            continue;
1261                        }
1262
1263                        if invalid_resource_state(merged_state) {
1264                            return Err(ResourceUsageCompatibilityError::from_texture(
1265                                unsafe { metadata_provider.get(index) },
1266                                TextureSelector {
1267                                    mips: mip_id..mip_id + 1,
1268                                    layers: layers.clone(),
1269                                },
1270                                *current_layer_state,
1271                                new_state,
1272                            ));
1273                        }
1274                        *current_layer_state = merged_state;
1275                    }
1276
1277                    mip.coalesce();
1278                }
1279            }
1280        }
1281    }
1282    Ok(())
1283}
1284
1285#[inline(always)]
1286unsafe fn barrier(
1287    texture_selector: &TextureSelector,
1288    current_state_set: &TextureStateSet,
1289    index: usize,
1290    state_provider: TextureStateProvider<'_>,
1291    barriers: &mut Vec<PendingTransition<TextureUses>>,
1292) {
1293    let current_state = unsafe { current_state_set.get_unchecked(index) };
1294
1295    let new_state = unsafe { state_provider.get_state(Some(texture_selector), index) };
1296
1297    match (current_state, new_state) {
1298        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Single(new_simple)) => {
1299            if skip_barrier(current_simple, new_simple) {
1300                return;
1301            }
1302
1303            barriers.push(PendingTransition {
1304                id: index as _,
1305                selector: texture_selector.clone(),
1306                usage: hal::StateTransition {
1307                    from: current_simple,
1308                    to: new_simple,
1309                },
1310            });
1311        }
1312        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Many(new_many)) => {
1313            for (selector, new_state) in new_many {
1314                if new_state == TextureUses::UNKNOWN {
1315                    continue;
1316                }
1317
1318                if skip_barrier(current_simple, new_state) {
1319                    continue;
1320                }
1321
1322                barriers.push(PendingTransition {
1323                    id: index as _,
1324                    selector,
1325                    usage: hal::StateTransition {
1326                        from: current_simple,
1327                        to: new_state,
1328                    },
1329                });
1330            }
1331        }
1332        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Single(new_simple)) => {
1333            for (mip_id, mip) in current_complex.mips.iter().enumerate() {
1334                let mip_id = mip_id as u32;
1335
1336                for &(ref layers, current_layer_state) in mip.iter() {
1337                    if current_layer_state == TextureUses::UNKNOWN {
1338                        continue;
1339                    }
1340
1341                    if skip_barrier(current_layer_state, new_simple) {
1342                        continue;
1343                    }
1344
1345                    barriers.push(PendingTransition {
1346                        id: index as _,
1347                        selector: TextureSelector {
1348                            mips: mip_id..mip_id + 1,
1349                            layers: layers.clone(),
1350                        },
1351                        usage: hal::StateTransition {
1352                            from: current_layer_state,
1353                            to: new_simple,
1354                        },
1355                    });
1356                }
1357            }
1358        }
1359        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Many(new_many)) => {
1360            for (selector, new_state) in new_many {
1361                for mip_id in selector.mips {
1362                    strict_assert!((mip_id as usize) < current_complex.mips.len());
1363
1364                    let mip = unsafe { current_complex.mips.get_unchecked(mip_id as usize) };
1365
1366                    for (layers, current_layer_state) in mip.iter_filter(&selector.layers) {
1367                        if *current_layer_state == TextureUses::UNKNOWN
1368                            || new_state == TextureUses::UNKNOWN
1369                        {
1370                            continue;
1371                        }
1372
1373                        if skip_barrier(*current_layer_state, new_state) {
1374                            continue;
1375                        }
1376
1377                        barriers.push(PendingTransition {
1378                            id: index as _,
1379                            selector: TextureSelector {
1380                                mips: mip_id..mip_id + 1,
1381                                layers,
1382                            },
1383                            usage: hal::StateTransition {
1384                                from: *current_layer_state,
1385                                to: new_state,
1386                            },
1387                        });
1388                    }
1389                }
1390            }
1391        }
1392    }
1393}
1394
1395#[inline(always)]
1396unsafe fn update(
1397    texture_selector: &TextureSelector,
1398    start_state_set: Option<&mut TextureStateSet>,
1399    current_state_set: &mut TextureStateSet,
1400    index: usize,
1401    state_provider: TextureStateProvider<'_>,
1402) {
1403    // We only ever need to update the start state here if the state is complex.
1404    //
1405    // If the state is simple, the first insert to the tracker would cover it.
1406    let mut start_complex = start_state_set.and_then(|start_state_set| {
1407        match unsafe { start_state_set.get_mut_unchecked(index) } {
1408            SingleOrManyStates::Single(_) => None,
1409            SingleOrManyStates::Many(complex) => Some(complex),
1410        }
1411    });
1412
1413    let current_state = unsafe { current_state_set.get_mut_unchecked(index) };
1414
1415    let new_state = unsafe { state_provider.get_state(Some(texture_selector), index) };
1416
1417    match (current_state, new_state) {
1418        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Single(new_simple)) => {
1419            *current_simple = new_simple;
1420        }
1421        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Many(new_many)) => {
1422            // Because we are now demoting this simple state to a complex state,
1423            // we actually need to make a whole new complex state for us to use
1424            // as there wasn't one before.
1425            let mut new_complex = unsafe {
1426                ComplexTextureState::from_selector_state_iter(
1427                    texture_selector.clone(),
1428                    iter::once((texture_selector.clone(), *current_simple)),
1429                )
1430            };
1431
1432            for (selector, mut new_state) in new_many {
1433                if new_state == TextureUses::UNKNOWN {
1434                    new_state = *current_simple;
1435                }
1436                for mip in
1437                    &mut new_complex.mips[selector.mips.start as usize..selector.mips.end as usize]
1438                {
1439                    for &mut (_, ref mut current_layer_state) in
1440                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1441                    {
1442                        *current_layer_state = new_state;
1443                    }
1444
1445                    mip.coalesce();
1446                }
1447            }
1448
1449            unsafe { current_state_set.make_complex_unchecked(index, new_complex) };
1450        }
1451        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Single(new_single)) => {
1452            for (mip_id, mip) in current_complex.mips.iter().enumerate() {
1453                for &(ref layers, current_layer_state) in mip.iter() {
1454                    // If this state is unknown, that means that the start is _also_ unknown.
1455                    if current_layer_state == TextureUses::UNKNOWN {
1456                        if let Some(&mut ref mut start_complex) = start_complex {
1457                            strict_assert!(mip_id < start_complex.mips.len());
1458
1459                            let start_mip = unsafe { start_complex.mips.get_unchecked_mut(mip_id) };
1460
1461                            for &mut (_, ref mut current_start_state) in
1462                                start_mip.isolate(layers, TextureUses::UNKNOWN)
1463                            {
1464                                strict_assert_eq!(*current_start_state, TextureUses::UNKNOWN);
1465                                *current_start_state = new_single;
1466                            }
1467
1468                            start_mip.coalesce();
1469                        }
1470                    }
1471                }
1472            }
1473
1474            unsafe { current_state_set.make_simple_unchecked(index, new_single) };
1475        }
1476        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Many(new_many)) => {
1477            for (selector, new_state) in new_many {
1478                if new_state == TextureUses::UNKNOWN {
1479                    // We know nothing new
1480                    continue;
1481                }
1482
1483                for mip_id in selector.mips {
1484                    let mip_id = mip_id as usize;
1485                    strict_assert!(mip_id < current_complex.mips.len());
1486
1487                    let mip = unsafe { current_complex.mips.get_unchecked_mut(mip_id) };
1488
1489                    for &mut (ref layers, ref mut current_layer_state) in
1490                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1491                    {
1492                        if *current_layer_state == TextureUses::UNKNOWN
1493                            && new_state != TextureUses::UNKNOWN
1494                        {
1495                            // We now know something about this subresource that
1496                            // we didn't before so we should go back and update
1497                            // the start state.
1498                            //
1499                            // We know we must have starter state be complex,
1500                            // otherwise we would know about this state.
1501                            strict_assert!(start_complex.is_some());
1502
1503                            let start_complex =
1504                                unsafe { start_complex.as_deref_mut().unwrap_unchecked() };
1505
1506                            strict_assert!(mip_id < start_complex.mips.len());
1507
1508                            let start_mip = unsafe { start_complex.mips.get_unchecked_mut(mip_id) };
1509
1510                            for &mut (_, ref mut current_start_state) in
1511                                start_mip.isolate(layers, TextureUses::UNKNOWN)
1512                            {
1513                                strict_assert_eq!(*current_start_state, TextureUses::UNKNOWN);
1514                                *current_start_state = new_state;
1515                            }
1516
1517                            start_mip.coalesce();
1518                        }
1519
1520                        *current_layer_state = new_state;
1521                    }
1522
1523                    mip.coalesce();
1524                }
1525            }
1526        }
1527    }
1528}