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