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