wgpu_core/init_tracker/
texture.rs

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