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