wgpu_core/init_tracker/
texture.rs

1use super::{InitTracker, MemoryInitKind};
2use crate::resource::Texture;
3use alloc::{sync::Arc, vec::Vec};
4use arrayvec::ArrayVec;
5use core::ops::Range;
6use wgt::TextureSelector;
7
8#[derive(Debug, Clone)]
9pub(crate) struct TextureInitRange {
10    pub(crate) mip_range: Range<u32>,
11    // Strictly array layers. We do *not* track volume slices separately.
12    pub(crate) layer_range: Range<u32>,
13}
14
15// Returns true if a copy operation doesn't fully cover the texture init
16// tracking granularity. I.e. if this function returns true for a pending copy
17// operation, the target texture needs to be ensured to be initialized first!
18pub(crate) fn has_copy_partial_init_tracker_coverage<T>(
19    copy_size: &wgt::Extent3d,
20    copy_info: &wgt::TexelCopyTextureInfo<T>,
21    desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
22) -> bool {
23    let target_size = desc.mip_level_size(copy_info.mip_level).unwrap();
24    copy_size.width != target_size.width
25        || copy_size.height != target_size.height
26        || (desc.dimension == wgt::TextureDimension::D3
27            && copy_size.depth_or_array_layers != target_size.depth_or_array_layers)
28        || copy_info.aspect != wgt::TextureAspect::All
29}
30
31impl From<TextureSelector> for TextureInitRange {
32    fn from(selector: TextureSelector) -> Self {
33        TextureInitRange {
34            mip_range: selector.mips,
35            layer_range: selector.layers,
36        }
37    }
38}
39
40#[derive(Debug, Clone)]
41pub(crate) struct TextureInitTrackerAction {
42    pub(crate) texture: Arc<Texture>,
43    pub(crate) range: TextureInitRange,
44    pub(crate) kind: MemoryInitKind,
45}
46
47pub(crate) type TextureLayerInitTracker = InitTracker<u32>;
48
49#[derive(Debug)]
50pub(crate) struct TextureInitTracker {
51    pub mips: ArrayVec<TextureLayerInitTracker, { hal::MAX_MIP_LEVELS as usize }>,
52}
53
54impl TextureInitTracker {
55    pub(crate) fn new(mip_level_count: u32, depth_or_array_layers: u32) -> Self {
56        TextureInitTracker {
57            mips: core::iter::repeat_n(
58                TextureLayerInitTracker::new(depth_or_array_layers),
59                mip_level_count as usize,
60            )
61            .collect(),
62        }
63    }
64
65    pub(crate) fn check_action(
66        &self,
67        action: &TextureInitTrackerAction,
68    ) -> Option<TextureInitTrackerAction> {
69        let mut mip_range_start = usize::MAX;
70        let mut mip_range_end = usize::MIN;
71        let mut layer_range_start = u32::MAX;
72        let mut layer_range_end = u32::MIN;
73
74        for (i, mip_tracker) in self
75            .mips
76            .iter()
77            .enumerate()
78            .take(action.range.mip_range.end as usize)
79            .skip(action.range.mip_range.start as usize)
80        {
81            if let Some(uninitialized_layer_range) =
82                mip_tracker.check(action.range.layer_range.clone())
83            {
84                mip_range_start = mip_range_start.min(i);
85                mip_range_end = i + 1;
86                layer_range_start = layer_range_start.min(uninitialized_layer_range.start);
87                layer_range_end = layer_range_end.max(uninitialized_layer_range.end);
88            };
89        }
90
91        if mip_range_start < mip_range_end && layer_range_start < layer_range_end {
92            Some(TextureInitTrackerAction {
93                texture: action.texture.clone(),
94                range: TextureInitRange {
95                    mip_range: mip_range_start as u32..mip_range_end as u32,
96                    layer_range: layer_range_start..layer_range_end,
97                },
98                kind: action.kind,
99            })
100        } else {
101            None
102        }
103    }
104
105    pub(crate) fn discard(&mut self, mip_level: u32, layer: u32) {
106        self.mips[mip_level as usize].discard(layer);
107    }
108}