xref: /aosp_15_r20/external/mesa3d/src/nouveau/nil/tiling.rs (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 // Copyright © 2024 Collabora, Ltd.
2 // SPDX-License-Identifier: MIT
3 
4 use crate::extent::{units, Extent4D};
5 use crate::format::Format;
6 use crate::image::{
7     ImageDim, ImageUsageFlags, SampleLayout, IMAGE_USAGE_2D_VIEW_BIT,
8     IMAGE_USAGE_LINEAR_BIT,
9 };
10 use crate::ILog2Ceil;
11 
12 pub const GOB_WIDTH_B: u32 = 64;
13 pub const GOB_DEPTH: u32 = 1;
14 
gob_height(gob_height_is_8: bool) -> u3215 pub fn gob_height(gob_height_is_8: bool) -> u32 {
16     if gob_height_is_8 {
17         8
18     } else {
19         4
20     }
21 }
22 
23 #[derive(Clone, Debug, Default, Copy, PartialEq)]
24 #[repr(C)]
25 pub struct Tiling {
26     pub is_tiled: bool,
27     /// Whether the GOB height is 4 or 8
28     pub gob_height_is_8: bool,
29     /// log2 of the X tile dimension in GOBs
30     pub x_log2: u8,
31     /// log2 of the Y tile dimension in GOBs
32     pub y_log2: u8,
33     /// log2 of the z tile dimension in GOBs
34     pub z_log2: u8,
35 }
36 
37 impl Tiling {
38     /// Clamps the tiling to less than 2x the given extent in each dimension.
39     ///
40     /// This operation is done by the hardware at each LOD.
clamp(&self, extent_B: Extent4D<units::Bytes>) -> Self41     pub fn clamp(&self, extent_B: Extent4D<units::Bytes>) -> Self {
42         let mut tiling = *self;
43 
44         if !self.is_tiled {
45             return tiling;
46         }
47 
48         let tiling_extent_B = self.extent_B();
49 
50         if extent_B.width < tiling_extent_B.width
51             || extent_B.height < tiling_extent_B.height
52             || extent_B.depth < tiling_extent_B.depth
53         {
54             tiling.x_log2 = 0;
55         }
56 
57         let extent_GOB = extent_B.to_GOB(tiling.gob_height_is_8);
58 
59         let ceil_h = extent_GOB.height.ilog2_ceil() as u8;
60         let ceil_d = extent_GOB.depth.ilog2_ceil() as u8;
61 
62         tiling.y_log2 = std::cmp::min(tiling.y_log2, ceil_h);
63         tiling.z_log2 = std::cmp::min(tiling.z_log2, ceil_d);
64         tiling
65     }
66 
size_B(&self) -> u3267     pub fn size_B(&self) -> u32 {
68         let extent_B = self.extent_B();
69         extent_B.width * extent_B.height * extent_B.depth * extent_B.array_len
70     }
71 
72     #[no_mangle]
nil_tiling_size_B(&self) -> u3273     pub extern "C" fn nil_tiling_size_B(&self) -> u32 {
74         self.size_B()
75     }
76 
extent_B(&self) -> Extent4D<units::Bytes>77     pub fn extent_B(&self) -> Extent4D<units::Bytes> {
78         if self.is_tiled {
79             Extent4D::new(
80                 GOB_WIDTH_B << self.x_log2,
81                 gob_height(self.gob_height_is_8) << self.y_log2,
82                 GOB_DEPTH << self.z_log2,
83                 1,
84             )
85         } else {
86             // We handle linear images in Image::new()
87             Extent4D::new(1, 1, 1, 1)
88         }
89     }
90 }
91 
sparse_block_extent_el( format: Format, dim: ImageDim, ) -> Extent4D<units::Elements>92 pub fn sparse_block_extent_el(
93     format: Format,
94     dim: ImageDim,
95 ) -> Extent4D<units::Elements> {
96     let bits = format.el_size_B() * 8;
97 
98     // Taken from Vulkan 1.3.279 spec section entitled "Standard Sparse
99     // Image Block Shapes".
100     match dim {
101         ImageDim::_2D => match bits {
102             8 => Extent4D::new(256, 256, 1, 1),
103             16 => Extent4D::new(256, 128, 1, 1),
104             32 => Extent4D::new(128, 128, 1, 1),
105             64 => Extent4D::new(128, 64, 1, 1),
106             128 => Extent4D::new(64, 64, 1, 1),
107             other => panic!("Invalid texel size {other}"),
108         },
109         ImageDim::_3D => match bits {
110             8 => Extent4D::new(64, 32, 32, 1),
111             16 => Extent4D::new(32, 32, 32, 1),
112             32 => Extent4D::new(32, 32, 16, 1),
113             64 => Extent4D::new(32, 16, 16, 1),
114             128 => Extent4D::new(16, 16, 16, 1),
115             _ => panic!("Invalid texel size"),
116         },
117         _ => panic!("Invalid sparse image dimension"),
118     }
119 }
120 
sparse_block_extent_px( format: Format, dim: ImageDim, sample_layout: SampleLayout, ) -> Extent4D<units::Pixels>121 pub fn sparse_block_extent_px(
122     format: Format,
123     dim: ImageDim,
124     sample_layout: SampleLayout,
125 ) -> Extent4D<units::Pixels> {
126     sparse_block_extent_el(format, dim)
127         .to_sa(format)
128         .to_px(sample_layout)
129 }
130 
sparse_block_extent_B( format: Format, dim: ImageDim, ) -> Extent4D<units::Bytes>131 pub fn sparse_block_extent_B(
132     format: Format,
133     dim: ImageDim,
134 ) -> Extent4D<units::Bytes> {
135     sparse_block_extent_el(format, dim).to_B(format)
136 }
137 
138 #[no_mangle]
nil_sparse_block_extent_px( format: Format, dim: ImageDim, sample_layout: SampleLayout, ) -> Extent4D<units::Pixels>139 pub extern "C" fn nil_sparse_block_extent_px(
140     format: Format,
141     dim: ImageDim,
142     sample_layout: SampleLayout,
143 ) -> Extent4D<units::Pixels> {
144     sparse_block_extent_px(format, dim, sample_layout)
145 }
146 
147 impl Tiling {
sparse(format: Format, dim: ImageDim) -> Self148     pub fn sparse(format: Format, dim: ImageDim) -> Self {
149         let sparse_block_extent_B = sparse_block_extent_B(format, dim);
150 
151         assert!(sparse_block_extent_B.width.is_power_of_two());
152         assert!(sparse_block_extent_B.height.is_power_of_two());
153         assert!(sparse_block_extent_B.depth.is_power_of_two());
154 
155         let gob_height_is_8 = true;
156         let sparse_block_extent_gob =
157             sparse_block_extent_B.to_GOB(gob_height_is_8);
158 
159         Self {
160             is_tiled: true,
161             gob_height_is_8,
162             x_log2: sparse_block_extent_gob.width.ilog2().try_into().unwrap(),
163             y_log2: sparse_block_extent_gob.height.ilog2().try_into().unwrap(),
164             z_log2: sparse_block_extent_gob.depth.ilog2().try_into().unwrap(),
165         }
166     }
167 
choose( extent_px: Extent4D<units::Pixels>, format: Format, sample_layout: SampleLayout, usage: ImageUsageFlags, ) -> Tiling168     pub fn choose(
169         extent_px: Extent4D<units::Pixels>,
170         format: Format,
171         sample_layout: SampleLayout,
172         usage: ImageUsageFlags,
173     ) -> Tiling {
174         if (usage & IMAGE_USAGE_LINEAR_BIT) != 0 {
175             return Default::default();
176         }
177 
178         let mut tiling = Tiling {
179             is_tiled: true,
180             gob_height_is_8: true,
181             x_log2: 0,
182             y_log2: 5,
183             z_log2: 5,
184         };
185 
186         if (usage & IMAGE_USAGE_2D_VIEW_BIT) != 0 {
187             tiling.z_log2 = 0;
188         }
189 
190         tiling.clamp(extent_px.to_B(format, sample_layout))
191     }
192 }
193