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    /// # Panics
616    ///
617    /// If a resource in `bind_group_state` is not found in the usage scope.
618    pub fn set_and_remove_from_usage_scope_sparse(
619        &mut self,
620        scope: &mut TextureUsageScope,
621        bind_group_state: &TextureViewBindGroupState,
622    ) {
623        let incoming_size = scope.set.size();
624        if incoming_size > self.start_set.size() {
625            self.set_size(incoming_size);
626        }
627
628        for (view, _) in bind_group_state.views.iter() {
629            let index = view.parent.tracker_index().as_usize();
630            scope.tracker_assert_in_bounds(index);
631
632            if unsafe { !scope.metadata.contains_unchecked(index) } {
633                continue;
634            }
635            let texture_selector = &view.parent.full_range;
636            // SAFETY: we checked that the index is in bounds for the scope, and
637            // called `set_size` to ensure it is valid for `self`.
638            unsafe {
639                insert_or_barrier_update(
640                    texture_selector,
641                    Some(&mut self.start_set),
642                    &mut self.end_set,
643                    &mut self.metadata,
644                    index,
645                    TextureStateProvider::TextureSet { set: &scope.set },
646                    None,
647                    ResourceMetadataProvider::Indirect {
648                        metadata: &scope.metadata,
649                    },
650                    &mut self.temp,
651                )
652            };
653
654            unsafe { scope.metadata.remove(index) };
655        }
656    }
657}
658
659impl TextureTrackerSetSingle for TextureTracker {
660    fn set_single(
661        &mut self,
662        texture: &Arc<Texture>,
663        selector: TextureSelector,
664        new_state: TextureUses,
665    ) -> Drain<'_, PendingTransition<TextureUses>> {
666        self.set_single(texture, selector, new_state)
667    }
668}
669
670/// Stores all texture state within a device.
671pub(crate) struct DeviceTextureTracker {
672    current_state_set: TextureStateSet,
673    metadata: ResourceMetadata<Weak<Texture>>,
674    temp: Vec<PendingTransition<TextureUses>>,
675}
676
677impl DeviceTextureTracker {
678    pub fn new() -> Self {
679        Self {
680            current_state_set: TextureStateSet::new(),
681            metadata: ResourceMetadata::new(),
682            temp: Vec::new(),
683        }
684    }
685
686    fn tracker_assert_in_bounds(&self, index: usize) {
687        self.metadata.tracker_assert_in_bounds(index);
688        self.current_state_set.tracker_assert_in_bounds(index);
689    }
690
691    /// Extend the vectors to let the given index be valid.
692    fn allow_index(&mut self, index: usize) {
693        if index >= self.current_state_set.size() {
694            self.current_state_set.set_size(index + 1);
695            self.metadata.set_size(index + 1);
696        }
697    }
698
699    /// Returns a list of all textures tracked.
700    pub fn used_resources(&self) -> impl Iterator<Item = &Weak<Texture>> + '_ {
701        self.metadata.owned_resources()
702    }
703
704    /// Inserts a single texture and a state into the resource tracker.
705    ///
706    /// If the resource already exists in the tracker, it will be overwritten.
707    pub fn insert_single(&mut self, texture: &Arc<Texture>, usage: TextureUses) {
708        let index = texture.tracker_index().as_usize();
709
710        self.allow_index(index);
711
712        self.tracker_assert_in_bounds(index);
713
714        unsafe {
715            insert(
716                None,
717                None,
718                &mut self.current_state_set,
719                &mut self.metadata,
720                index,
721                TextureStateProvider::KnownSingle { state: usage },
722                None,
723                ResourceMetadataProvider::Direct {
724                    resource: &Arc::downgrade(texture),
725                },
726            )
727        };
728    }
729
730    /// Sets the state of a single texture.
731    ///
732    /// If a transition is needed to get the texture into the given state, that transition
733    /// is returned.
734    pub fn set_single(
735        &mut self,
736        texture: &Arc<Texture>,
737        selector: TextureSelector,
738        new_state: TextureUses,
739    ) -> Drain<'_, PendingTransition<TextureUses>> {
740        let index = texture.tracker_index().as_usize();
741
742        self.allow_index(index);
743
744        self.tracker_assert_in_bounds(index);
745
746        let start_state_provider = TextureStateProvider::Selector {
747            selector,
748            state: new_state,
749        };
750        unsafe {
751            barrier(
752                &texture.full_range,
753                &self.current_state_set,
754                index,
755                start_state_provider.clone(),
756                &mut self.temp,
757            )
758        };
759        unsafe {
760            update(
761                &texture.full_range,
762                None,
763                &mut self.current_state_set,
764                index,
765                start_state_provider,
766            )
767        };
768
769        self.temp.drain(..)
770    }
771
772    /// Sets the given state for all texture in the given tracker.
773    ///
774    /// If a transition is needed to get the texture into the needed state,
775    /// those transitions are returned.
776    pub fn set_from_tracker_and_drain_transitions<'a, 'b: 'a>(
777        &'a mut self,
778        tracker: &'a TextureTracker,
779        snatch_guard: &'b SnatchGuard<'b>,
780    ) -> impl Iterator<Item = TextureBarrier<'a, dyn hal::DynTexture>> {
781        for index in tracker.metadata.owned_indices() {
782            self.tracker_assert_in_bounds(index);
783
784            let start_state_provider = TextureStateProvider::TextureSet {
785                set: &tracker.start_set,
786            };
787            let end_state_provider = TextureStateProvider::TextureSet {
788                set: &tracker.end_set,
789            };
790            unsafe {
791                let texture_selector = &tracker.metadata.get_resource_unchecked(index).full_range;
792                barrier(
793                    texture_selector,
794                    &self.current_state_set,
795                    index,
796                    start_state_provider,
797                    &mut self.temp,
798                );
799                update(
800                    texture_selector,
801                    None,
802                    &mut self.current_state_set,
803                    index,
804                    end_state_provider,
805                );
806            }
807        }
808
809        self.temp.drain(..).map(|pending| {
810            let tex = unsafe { tracker.metadata.get_resource_unchecked(pending.id as _) };
811            let tex = tex.try_raw(snatch_guard).unwrap();
812            pending.into_hal(tex)
813        })
814    }
815
816    /// Sets the given state for all textures in the given UsageScope.
817    ///
818    /// If a transition is needed to get the textures into the needed state,
819    /// those transitions are returned.
820    pub fn set_from_usage_scope_and_drain_transitions<'a, 'b: 'a>(
821        &'a mut self,
822        scope: &'a TextureUsageScope,
823        snatch_guard: &'b SnatchGuard<'b>,
824    ) -> impl Iterator<Item = TextureBarrier<'a, dyn hal::DynTexture>> {
825        for index in scope.metadata.owned_indices() {
826            self.tracker_assert_in_bounds(index);
827
828            let start_state_provider = TextureStateProvider::TextureSet { set: &scope.set };
829            unsafe {
830                let texture_selector = &scope.metadata.get_resource_unchecked(index).full_range;
831                barrier(
832                    texture_selector,
833                    &self.current_state_set,
834                    index,
835                    start_state_provider.clone(),
836                    &mut self.temp,
837                );
838                update(
839                    texture_selector,
840                    None,
841                    &mut self.current_state_set,
842                    index,
843                    start_state_provider,
844                );
845            }
846        }
847
848        self.temp.drain(..).map(|pending| {
849            let tex = unsafe { scope.metadata.get_resource_unchecked(pending.id as _) };
850            let tex = tex.try_raw(snatch_guard).unwrap();
851            pending.into_hal(tex)
852        })
853    }
854}
855
856impl TextureTrackerSetSingle for DeviceTextureTracker {
857    fn set_single(
858        &mut self,
859        texture: &Arc<Texture>,
860        selector: TextureSelector,
861        new_state: TextureUses,
862    ) -> Drain<'_, PendingTransition<TextureUses>> {
863        self.set_single(texture, selector, new_state)
864    }
865}
866
867/// An iterator adapter that can store two different iterator types.
868#[derive(Clone)]
869enum EitherIter<L, R> {
870    Left(L),
871    Right(R),
872}
873
874impl<L, R, D> Iterator for EitherIter<L, R>
875where
876    L: Iterator<Item = D>,
877    R: Iterator<Item = D>,
878{
879    type Item = D;
880
881    fn next(&mut self) -> Option<Self::Item> {
882        match *self {
883            EitherIter::Left(ref mut inner) => inner.next(),
884            EitherIter::Right(ref mut inner) => inner.next(),
885        }
886    }
887}
888
889/// Container that signifies storing both different things
890/// if there is a single state or many different states
891/// involved in the operation.
892#[derive(Debug, Clone)]
893enum SingleOrManyStates<S, M> {
894    Single(S),
895    Many(M),
896}
897
898/// A source of texture state.
899#[derive(Clone)]
900enum TextureStateProvider<'a> {
901    /// Comes directly from a single state.
902    KnownSingle { state: TextureUses },
903    /// Comes from a selector and a single state.
904    Selector {
905        selector: TextureSelector,
906        state: TextureUses,
907    },
908    /// Comes from another texture set.
909    TextureSet { set: &'a TextureStateSet },
910}
911impl<'a> TextureStateProvider<'a> {
912    /// Convenience function turning `Option<Selector>` into this enum.
913    fn from_option(selector: Option<TextureSelector>, state: TextureUses) -> Self {
914        match selector {
915            Some(selector) => Self::Selector { selector, state },
916            None => Self::KnownSingle { state },
917        }
918    }
919
920    /// Get the state provided by this.
921    ///
922    /// # Panics
923    ///
924    /// Panics if texture_selector is None and this uses a Selector source.
925    ///
926    /// # Safety
927    ///
928    /// - The index must be in bounds of the state set if this uses an TextureSet source.
929    #[inline(always)]
930    unsafe fn get_state(
931        self,
932        texture_selector: Option<&TextureSelector>,
933        index: usize,
934    ) -> SingleOrManyStates<
935        TextureUses,
936        impl Iterator<Item = (TextureSelector, TextureUses)> + Clone + 'a,
937    > {
938        match self {
939            TextureStateProvider::KnownSingle { state } => SingleOrManyStates::Single(state),
940            TextureStateProvider::Selector { selector, state } => {
941                // We check if the selector given is actually for the full resource,
942                // and if it is we promote to a simple state. This allows upstream
943                // code to specify selectors willy nilly, and all that are really
944                // single states are promoted here.
945                if *texture_selector.unwrap() == selector {
946                    SingleOrManyStates::Single(state)
947                } else {
948                    SingleOrManyStates::Many(EitherIter::Left(iter::once((selector, state))))
949                }
950            }
951            TextureStateProvider::TextureSet { set } => match unsafe { set.get_unchecked(index) } {
952                SingleOrManyStates::Single(single) => SingleOrManyStates::Single(single),
953                SingleOrManyStates::Many(complex) => {
954                    SingleOrManyStates::Many(EitherIter::Right(complex.to_selector_state_iter()))
955                }
956            },
957        }
958    }
959}
960
961/// Does an insertion operation if the index isn't tracked
962/// in the current metadata, otherwise merges the given state
963/// with the current state. If the merging would cause
964/// a conflict, returns that usage conflict.
965///
966/// # Safety
967///
968/// Indexes must be valid indexes into all arrays passed in
969/// to this function, either directly or via metadata or provider structs.
970#[inline(always)]
971unsafe fn insert_or_merge(
972    texture_selector: &TextureSelector,
973    current_state_set: &mut TextureStateSet,
974    resource_metadata: &mut ResourceMetadata<Arc<Texture>>,
975    index: usize,
976    state_provider: TextureStateProvider<'_>,
977    metadata_provider: ResourceMetadataProvider<'_, Arc<Texture>>,
978) -> Result<(), ResourceUsageCompatibilityError> {
979    let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
980
981    if !currently_owned {
982        unsafe {
983            insert(
984                Some(texture_selector),
985                None,
986                current_state_set,
987                resource_metadata,
988                index,
989                state_provider,
990                None,
991                metadata_provider,
992            )
993        };
994        return Ok(());
995    }
996
997    unsafe {
998        merge(
999            texture_selector,
1000            current_state_set,
1001            index,
1002            state_provider,
1003            metadata_provider,
1004        )
1005    }
1006}
1007
1008/// If the resource isn't tracked
1009/// - Inserts the given resource.
1010/// - Uses the `start_state_provider` to populate `start_states`
1011/// - Uses either `end_state_provider` or `start_state_provider`
1012///   to populate `current_states`.
1013///
1014/// If the resource is tracked
1015/// - Inserts barriers from the state in `current_states`
1016///   to the state provided by `start_state_provider`.
1017/// - Updates the `current_states` with either the state from
1018///   `end_state_provider` or `start_state_provider`.
1019///
1020/// Any barriers are added to the barrier vector.
1021///
1022/// # Safety
1023///
1024/// Indexes must be valid indexes into all arrays passed in
1025/// to this function, either directly or via metadata or provider structs.
1026#[inline(always)]
1027unsafe fn insert_or_barrier_update(
1028    texture_selector: &TextureSelector,
1029    start_state: Option<&mut TextureStateSet>,
1030    current_state_set: &mut TextureStateSet,
1031    resource_metadata: &mut ResourceMetadata<Arc<Texture>>,
1032    index: usize,
1033    start_state_provider: TextureStateProvider<'_>,
1034    end_state_provider: Option<TextureStateProvider<'_>>,
1035    metadata_provider: ResourceMetadataProvider<'_, Arc<Texture>>,
1036    barriers: &mut Vec<PendingTransition<TextureUses>>,
1037) {
1038    let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
1039
1040    if !currently_owned {
1041        unsafe {
1042            insert(
1043                Some(texture_selector),
1044                start_state,
1045                current_state_set,
1046                resource_metadata,
1047                index,
1048                start_state_provider,
1049                end_state_provider,
1050                metadata_provider,
1051            )
1052        };
1053        return;
1054    }
1055
1056    let update_state_provider = end_state_provider.unwrap_or_else(|| start_state_provider.clone());
1057    unsafe {
1058        barrier(
1059            texture_selector,
1060            current_state_set,
1061            index,
1062            start_state_provider,
1063            barriers,
1064        )
1065    };
1066    unsafe {
1067        update(
1068            texture_selector,
1069            start_state,
1070            current_state_set,
1071            index,
1072            update_state_provider,
1073        )
1074    };
1075}
1076
1077#[inline(always)]
1078unsafe fn insert<T: Clone>(
1079    texture_selector: Option<&TextureSelector>,
1080    start_state: Option<&mut TextureStateSet>,
1081    end_state: &mut TextureStateSet,
1082    resource_metadata: &mut ResourceMetadata<T>,
1083    index: usize,
1084    start_state_provider: TextureStateProvider<'_>,
1085    end_state_provider: Option<TextureStateProvider<'_>>,
1086    metadata_provider: ResourceMetadataProvider<'_, T>,
1087) {
1088    let start_layers = unsafe { start_state_provider.get_state(texture_selector, index) };
1089    match start_layers {
1090        SingleOrManyStates::Single(state) => {
1091            // This should only ever happen with a wgpu bug, but let's just double
1092            // check that resource states don't have any conflicts.
1093            strict_assert_eq!(invalid_resource_state(state), false);
1094
1095            if let Some(start_state) = start_state {
1096                unsafe { start_state.insert_simple_unchecked(index, state) };
1097            }
1098
1099            // We only need to insert ourselves the end state if there is no end state provider.
1100            if end_state_provider.is_none() {
1101                unsafe { end_state.insert_simple_unchecked(index, state) };
1102            }
1103        }
1104        SingleOrManyStates::Many(state_iter) => {
1105            let full_range = texture_selector.unwrap().clone();
1106
1107            let complex =
1108                unsafe { ComplexTextureState::from_selector_state_iter(full_range, state_iter) };
1109
1110            if let Some(start_state) = start_state {
1111                unsafe { start_state.insert_complex_unchecked(index, complex.clone()) };
1112            }
1113
1114            // We only need to insert ourselves the end state if there is no end state provider.
1115            if end_state_provider.is_none() {
1116                unsafe { end_state.insert_complex_unchecked(index, complex) };
1117            }
1118        }
1119    }
1120
1121    if let Some(end_state_provider) = end_state_provider {
1122        match unsafe { end_state_provider.get_state(texture_selector, index) } {
1123            SingleOrManyStates::Single(state) => {
1124                // This should only ever happen with a wgpu bug, but let's just double
1125                // check that resource states don't have any conflicts.
1126                strict_assert_eq!(invalid_resource_state(state), false);
1127
1128                // We only need to insert into the end, as there is guaranteed to be
1129                // a start state provider.
1130                unsafe { end_state.insert_simple_unchecked(index, state) };
1131            }
1132            SingleOrManyStates::Many(state_iter) => {
1133                let full_range = texture_selector.unwrap().clone();
1134
1135                let complex = unsafe {
1136                    ComplexTextureState::from_selector_state_iter(full_range, state_iter)
1137                };
1138
1139                // We only need to insert into the end, as there is guaranteed to be
1140                // a start state provider.
1141                unsafe { end_state.insert_complex_unchecked(index, complex) };
1142            }
1143        }
1144    }
1145
1146    unsafe {
1147        let resource = metadata_provider.get(index);
1148        resource_metadata.insert(index, resource.clone());
1149    }
1150}
1151
1152#[inline(always)]
1153unsafe fn merge(
1154    texture_selector: &TextureSelector,
1155    current_state_set: &mut TextureStateSet,
1156    index: usize,
1157    state_provider: TextureStateProvider<'_>,
1158    metadata_provider: ResourceMetadataProvider<'_, Arc<Texture>>,
1159) -> Result<(), ResourceUsageCompatibilityError> {
1160    let current_state = unsafe { current_state_set.get_mut_unchecked(index) };
1161
1162    let new_state = unsafe { state_provider.get_state(Some(texture_selector), index) };
1163
1164    match (current_state, new_state) {
1165        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Single(new_simple)) => {
1166            let merged_state = *current_simple | new_simple;
1167
1168            if invalid_resource_state(merged_state) {
1169                return Err(ResourceUsageCompatibilityError::from_texture(
1170                    unsafe { metadata_provider.get(index) },
1171                    texture_selector.clone(),
1172                    *current_simple,
1173                    new_simple,
1174                ));
1175            }
1176
1177            *current_simple = merged_state;
1178        }
1179        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Many(new_many)) => {
1180            // Because we are now demoting this simple state to a complex state,
1181            // we actually need to make a whole new complex state for us to use
1182            // as there wasn't one before.
1183            let mut new_complex = unsafe {
1184                ComplexTextureState::from_selector_state_iter(
1185                    texture_selector.clone(),
1186                    iter::once((texture_selector.clone(), *current_simple)),
1187                )
1188            };
1189
1190            for (selector, new_state) in new_many {
1191                let merged_state = *current_simple | new_state;
1192
1193                if invalid_resource_state(merged_state) {
1194                    return Err(ResourceUsageCompatibilityError::from_texture(
1195                        unsafe { metadata_provider.get(index) },
1196                        selector,
1197                        *current_simple,
1198                        new_state,
1199                    ));
1200                }
1201
1202                for mip in
1203                    &mut new_complex.mips[selector.mips.start as usize..selector.mips.end as usize]
1204                {
1205                    for &mut (_, ref mut current_layer_state) in
1206                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1207                    {
1208                        *current_layer_state = merged_state;
1209                    }
1210
1211                    mip.coalesce();
1212                }
1213            }
1214
1215            unsafe { current_state_set.make_complex_unchecked(index, new_complex) };
1216        }
1217        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Single(new_simple)) => {
1218            for (mip_id, mip) in current_complex.mips.iter_mut().enumerate() {
1219                let mip_id = mip_id as u32;
1220
1221                for &mut (ref layers, ref mut current_layer_state) in mip.iter_mut() {
1222                    let merged_state = *current_layer_state | new_simple;
1223
1224                    // Once we remove unknown, this will never be empty, as
1225                    // simple states are never unknown.
1226                    let merged_state = merged_state - TextureUses::UNKNOWN;
1227
1228                    if invalid_resource_state(merged_state) {
1229                        return Err(ResourceUsageCompatibilityError::from_texture(
1230                            unsafe { metadata_provider.get(index) },
1231                            TextureSelector {
1232                                mips: mip_id..mip_id + 1,
1233                                layers: layers.clone(),
1234                            },
1235                            *current_layer_state,
1236                            new_simple,
1237                        ));
1238                    }
1239
1240                    *current_layer_state = merged_state;
1241                }
1242
1243                mip.coalesce();
1244            }
1245        }
1246        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Many(new_many)) => {
1247            for (selector, new_state) in new_many {
1248                for mip_id in selector.mips {
1249                    strict_assert!((mip_id as usize) < current_complex.mips.len());
1250
1251                    let mip = unsafe { current_complex.mips.get_unchecked_mut(mip_id as usize) };
1252
1253                    for &mut (ref layers, ref mut current_layer_state) in
1254                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1255                    {
1256                        let merged_state = *current_layer_state | new_state;
1257                        let merged_state = merged_state - TextureUses::UNKNOWN;
1258
1259                        if merged_state.is_empty() {
1260                            // We know nothing about this state, lets just move on.
1261                            continue;
1262                        }
1263
1264                        if invalid_resource_state(merged_state) {
1265                            return Err(ResourceUsageCompatibilityError::from_texture(
1266                                unsafe { metadata_provider.get(index) },
1267                                TextureSelector {
1268                                    mips: mip_id..mip_id + 1,
1269                                    layers: layers.clone(),
1270                                },
1271                                *current_layer_state,
1272                                new_state,
1273                            ));
1274                        }
1275                        *current_layer_state = merged_state;
1276                    }
1277
1278                    mip.coalesce();
1279                }
1280            }
1281        }
1282    }
1283    Ok(())
1284}
1285
1286#[inline(always)]
1287unsafe fn barrier(
1288    texture_selector: &TextureSelector,
1289    current_state_set: &TextureStateSet,
1290    index: usize,
1291    state_provider: TextureStateProvider<'_>,
1292    barriers: &mut Vec<PendingTransition<TextureUses>>,
1293) {
1294    let current_state = unsafe { current_state_set.get_unchecked(index) };
1295
1296    let new_state = unsafe { state_provider.get_state(Some(texture_selector), index) };
1297
1298    match (current_state, new_state) {
1299        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Single(new_simple)) => {
1300            if skip_barrier(current_simple, new_simple) {
1301                return;
1302            }
1303
1304            barriers.push(PendingTransition {
1305                id: index as _,
1306                selector: texture_selector.clone(),
1307                usage: hal::StateTransition {
1308                    from: current_simple,
1309                    to: new_simple,
1310                },
1311            });
1312        }
1313        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Many(new_many)) => {
1314            for (selector, new_state) in new_many {
1315                if new_state == TextureUses::UNKNOWN {
1316                    continue;
1317                }
1318
1319                if skip_barrier(current_simple, new_state) {
1320                    continue;
1321                }
1322
1323                barriers.push(PendingTransition {
1324                    id: index as _,
1325                    selector,
1326                    usage: hal::StateTransition {
1327                        from: current_simple,
1328                        to: new_state,
1329                    },
1330                });
1331            }
1332        }
1333        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Single(new_simple)) => {
1334            for (mip_id, mip) in current_complex.mips.iter().enumerate() {
1335                let mip_id = mip_id as u32;
1336
1337                for &(ref layers, current_layer_state) in mip.iter() {
1338                    if current_layer_state == TextureUses::UNKNOWN {
1339                        continue;
1340                    }
1341
1342                    if skip_barrier(current_layer_state, new_simple) {
1343                        continue;
1344                    }
1345
1346                    barriers.push(PendingTransition {
1347                        id: index as _,
1348                        selector: TextureSelector {
1349                            mips: mip_id..mip_id + 1,
1350                            layers: layers.clone(),
1351                        },
1352                        usage: hal::StateTransition {
1353                            from: current_layer_state,
1354                            to: new_simple,
1355                        },
1356                    });
1357                }
1358            }
1359        }
1360        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Many(new_many)) => {
1361            for (selector, new_state) in new_many {
1362                for mip_id in selector.mips {
1363                    strict_assert!((mip_id as usize) < current_complex.mips.len());
1364
1365                    let mip = unsafe { current_complex.mips.get_unchecked(mip_id as usize) };
1366
1367                    for (layers, current_layer_state) in mip.iter_filter(&selector.layers) {
1368                        if *current_layer_state == TextureUses::UNKNOWN
1369                            || new_state == TextureUses::UNKNOWN
1370                        {
1371                            continue;
1372                        }
1373
1374                        if skip_barrier(*current_layer_state, new_state) {
1375                            continue;
1376                        }
1377
1378                        barriers.push(PendingTransition {
1379                            id: index as _,
1380                            selector: TextureSelector {
1381                                mips: mip_id..mip_id + 1,
1382                                layers,
1383                            },
1384                            usage: hal::StateTransition {
1385                                from: *current_layer_state,
1386                                to: new_state,
1387                            },
1388                        });
1389                    }
1390                }
1391            }
1392        }
1393    }
1394}
1395
1396#[inline(always)]
1397unsafe fn update(
1398    texture_selector: &TextureSelector,
1399    start_state_set: Option<&mut TextureStateSet>,
1400    current_state_set: &mut TextureStateSet,
1401    index: usize,
1402    state_provider: TextureStateProvider<'_>,
1403) {
1404    // We only ever need to update the start state here if the state is complex.
1405    //
1406    // If the state is simple, the first insert to the tracker would cover it.
1407    let mut start_complex = start_state_set.and_then(|start_state_set| {
1408        match unsafe { start_state_set.get_mut_unchecked(index) } {
1409            SingleOrManyStates::Single(_) => None,
1410            SingleOrManyStates::Many(complex) => Some(complex),
1411        }
1412    });
1413
1414    let current_state = unsafe { current_state_set.get_mut_unchecked(index) };
1415
1416    let new_state = unsafe { state_provider.get_state(Some(texture_selector), index) };
1417
1418    match (current_state, new_state) {
1419        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Single(new_simple)) => {
1420            *current_simple = new_simple;
1421        }
1422        (SingleOrManyStates::Single(current_simple), SingleOrManyStates::Many(new_many)) => {
1423            // Because we are now demoting this simple state to a complex state,
1424            // we actually need to make a whole new complex state for us to use
1425            // as there wasn't one before.
1426            let mut new_complex = unsafe {
1427                ComplexTextureState::from_selector_state_iter(
1428                    texture_selector.clone(),
1429                    iter::once((texture_selector.clone(), *current_simple)),
1430                )
1431            };
1432
1433            for (selector, mut new_state) in new_many {
1434                if new_state == TextureUses::UNKNOWN {
1435                    new_state = *current_simple;
1436                }
1437                for mip in
1438                    &mut new_complex.mips[selector.mips.start as usize..selector.mips.end as usize]
1439                {
1440                    for &mut (_, ref mut current_layer_state) in
1441                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1442                    {
1443                        *current_layer_state = new_state;
1444                    }
1445
1446                    mip.coalesce();
1447                }
1448            }
1449
1450            unsafe { current_state_set.make_complex_unchecked(index, new_complex) };
1451        }
1452        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Single(new_single)) => {
1453            for (mip_id, mip) in current_complex.mips.iter().enumerate() {
1454                for &(ref layers, current_layer_state) in mip.iter() {
1455                    // If this state is unknown, that means that the start is _also_ unknown.
1456                    if current_layer_state == TextureUses::UNKNOWN {
1457                        if let Some(&mut ref mut start_complex) = start_complex {
1458                            strict_assert!(mip_id < start_complex.mips.len());
1459
1460                            let start_mip = unsafe { start_complex.mips.get_unchecked_mut(mip_id) };
1461
1462                            for &mut (_, ref mut current_start_state) in
1463                                start_mip.isolate(layers, TextureUses::UNKNOWN)
1464                            {
1465                                strict_assert_eq!(*current_start_state, TextureUses::UNKNOWN);
1466                                *current_start_state = new_single;
1467                            }
1468
1469                            start_mip.coalesce();
1470                        }
1471                    }
1472                }
1473            }
1474
1475            unsafe { current_state_set.make_simple_unchecked(index, new_single) };
1476        }
1477        (SingleOrManyStates::Many(current_complex), SingleOrManyStates::Many(new_many)) => {
1478            for (selector, new_state) in new_many {
1479                if new_state == TextureUses::UNKNOWN {
1480                    // We know nothing new
1481                    continue;
1482                }
1483
1484                for mip_id in selector.mips {
1485                    let mip_id = mip_id as usize;
1486                    strict_assert!(mip_id < current_complex.mips.len());
1487
1488                    let mip = unsafe { current_complex.mips.get_unchecked_mut(mip_id) };
1489
1490                    for &mut (ref layers, ref mut current_layer_state) in
1491                        mip.isolate(&selector.layers, TextureUses::UNKNOWN)
1492                    {
1493                        if *current_layer_state == TextureUses::UNKNOWN
1494                            && new_state != TextureUses::UNKNOWN
1495                        {
1496                            // We now know something about this subresource that
1497                            // we didn't before so we should go back and update
1498                            // the start state.
1499                            //
1500                            // We know we must have starter state be complex,
1501                            // otherwise we would know about this state.
1502                            strict_assert!(start_complex.is_some());
1503
1504                            let start_complex =
1505                                unsafe { start_complex.as_deref_mut().unwrap_unchecked() };
1506
1507                            strict_assert!(mip_id < start_complex.mips.len());
1508
1509                            let start_mip = unsafe { start_complex.mips.get_unchecked_mut(mip_id) };
1510
1511                            for &mut (_, ref mut current_start_state) in
1512                                start_mip.isolate(layers, TextureUses::UNKNOWN)
1513                            {
1514                                strict_assert_eq!(*current_start_state, TextureUses::UNKNOWN);
1515                                *current_start_state = new_state;
1516                            }
1517
1518                            start_mip.coalesce();
1519                        }
1520
1521                        *current_layer_state = new_state;
1522                    }
1523
1524                    mip.coalesce();
1525                }
1526            }
1527        }
1528    }
1529}