• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #[repr(u8)]
13 #[derive(Clone, Copy, Debug, Default, PartialEq)]
14 pub enum GOBType {
15     #[default]
16     Linear,
17     Fermi8,
18 }
19 
20 impl GOBType {
extent_B(&self) -> Extent4D<units::Bytes>21     pub fn extent_B(&self) -> Extent4D<units::Bytes> {
22         match self {
23             GOBType::Linear => Extent4D::new(1, 1, 1, 1),
24             GOBType::Fermi8 => Extent4D::new(64, 8, 1, 1),
25         }
26     }
27 
28     #[no_mangle]
nil_gob_type_height(self) -> u3229     pub extern "C" fn nil_gob_type_height(self) -> u32 {
30         self.extent_B().height
31     }
32 }
33 
34 #[derive(Clone, Debug, Default, Copy, PartialEq)]
35 #[repr(C)]
36 pub struct Tiling {
37     /// GOB type
38     pub gob_type: GOBType,
39     /// log2 of the X tile dimension in GOBs
40     pub x_log2: u8,
41     /// log2 of the Y tile dimension in GOBs
42     pub y_log2: u8,
43     /// log2 of the z tile dimension in GOBs
44     pub z_log2: u8,
45 }
46 
47 impl Tiling {
48     /// Clamps the tiling to less than 2x the given extent in each dimension.
49     ///
50     /// This operation is done by the hardware at each LOD.
clamp(&self, extent_B: Extent4D<units::Bytes>) -> Self51     pub fn clamp(&self, extent_B: Extent4D<units::Bytes>) -> Self {
52         let mut tiling = *self;
53 
54         if !self.is_tiled() {
55             return tiling;
56         }
57 
58         let tiling_extent_B = self.extent_B();
59 
60         if extent_B.width < tiling_extent_B.width
61             || extent_B.height < tiling_extent_B.height
62             || extent_B.depth < tiling_extent_B.depth
63         {
64             tiling.x_log2 = 0;
65         }
66 
67         let extent_GOB = extent_B.to_GOB(tiling.gob_type);
68 
69         let ceil_h = extent_GOB.height.ilog2_ceil() as u8;
70         let ceil_d = extent_GOB.depth.ilog2_ceil() as u8;
71 
72         tiling.y_log2 = std::cmp::min(tiling.y_log2, ceil_h);
73         tiling.z_log2 = std::cmp::min(tiling.z_log2, ceil_d);
74         tiling
75     }
76 
size_B(&self) -> u3277     pub fn size_B(&self) -> u32 {
78         let extent_B = self.extent_B();
79         extent_B.width * extent_B.height * extent_B.depth * extent_B.array_len
80     }
81 
82     #[no_mangle]
nil_tiling_size_B(&self) -> u3283     pub extern "C" fn nil_tiling_size_B(&self) -> u32 {
84         self.size_B()
85     }
86 
extent_B(&self) -> Extent4D<units::Bytes>87     pub fn extent_B(&self) -> Extent4D<units::Bytes> {
88         let gob_extent_B = self.gob_type.extent_B();
89         debug_assert!(gob_extent_B.array_len == 1);
90         Extent4D::new(
91             gob_extent_B.width << self.x_log2,
92             gob_extent_B.height << self.y_log2,
93             gob_extent_B.depth << self.z_log2,
94             1,
95         )
96     }
97 }
98 
sparse_block_extent_el( format: Format, dim: ImageDim, ) -> Extent4D<units::Elements>99 pub fn sparse_block_extent_el(
100     format: Format,
101     dim: ImageDim,
102 ) -> Extent4D<units::Elements> {
103     let bits = format.el_size_B() * 8;
104 
105     // Taken from Vulkan 1.3.279 spec section entitled "Standard Sparse
106     // Image Block Shapes".
107     match dim {
108         ImageDim::_2D => match bits {
109             8 => Extent4D::new(256, 256, 1, 1),
110             16 => Extent4D::new(256, 128, 1, 1),
111             32 => Extent4D::new(128, 128, 1, 1),
112             64 => Extent4D::new(128, 64, 1, 1),
113             128 => Extent4D::new(64, 64, 1, 1),
114             other => panic!("Invalid texel size {other}"),
115         },
116         ImageDim::_3D => match bits {
117             8 => Extent4D::new(64, 32, 32, 1),
118             16 => Extent4D::new(32, 32, 32, 1),
119             32 => Extent4D::new(32, 32, 16, 1),
120             64 => Extent4D::new(32, 16, 16, 1),
121             128 => Extent4D::new(16, 16, 16, 1),
122             _ => panic!("Invalid texel size"),
123         },
124         _ => panic!("Invalid sparse image dimension"),
125     }
126 }
127 
sparse_block_extent_px( format: Format, dim: ImageDim, sample_layout: SampleLayout, ) -> Extent4D<units::Pixels>128 pub fn sparse_block_extent_px(
129     format: Format,
130     dim: ImageDim,
131     sample_layout: SampleLayout,
132 ) -> Extent4D<units::Pixels> {
133     sparse_block_extent_el(format, dim)
134         .to_sa(format)
135         .to_px(sample_layout)
136 }
137 
sparse_block_extent_B( format: Format, dim: ImageDim, ) -> Extent4D<units::Bytes>138 pub fn sparse_block_extent_B(
139     format: Format,
140     dim: ImageDim,
141 ) -> Extent4D<units::Bytes> {
142     sparse_block_extent_el(format, dim).to_B(format)
143 }
144 
145 #[no_mangle]
nil_sparse_block_extent_px( format: Format, dim: ImageDim, sample_layout: SampleLayout, ) -> Extent4D<units::Pixels>146 pub extern "C" fn nil_sparse_block_extent_px(
147     format: Format,
148     dim: ImageDim,
149     sample_layout: SampleLayout,
150 ) -> Extent4D<units::Pixels> {
151     sparse_block_extent_px(format, dim, sample_layout)
152 }
153 
154 impl Tiling {
sparse(format: Format, dim: ImageDim) -> Self155     pub fn sparse(format: Format, dim: ImageDim) -> Self {
156         let sparse_block_extent_B = sparse_block_extent_B(format, dim);
157 
158         assert!(sparse_block_extent_B.width.is_power_of_two());
159         assert!(sparse_block_extent_B.height.is_power_of_two());
160         assert!(sparse_block_extent_B.depth.is_power_of_two());
161 
162         let gob_type = GOBType::Fermi8;
163         let sparse_block_extent_gob = sparse_block_extent_B.to_GOB(gob_type);
164 
165         Self {
166             gob_type,
167             x_log2: sparse_block_extent_gob.width.ilog2().try_into().unwrap(),
168             y_log2: sparse_block_extent_gob.height.ilog2().try_into().unwrap(),
169             z_log2: sparse_block_extent_gob.depth.ilog2().try_into().unwrap(),
170         }
171     }
172 
choose( extent_px: Extent4D<units::Pixels>, format: Format, sample_layout: SampleLayout, usage: ImageUsageFlags, ) -> Tiling173     pub fn choose(
174         extent_px: Extent4D<units::Pixels>,
175         format: Format,
176         sample_layout: SampleLayout,
177         usage: ImageUsageFlags,
178     ) -> Tiling {
179         if (usage & IMAGE_USAGE_LINEAR_BIT) != 0 {
180             return Default::default();
181         }
182 
183         let mut tiling = Tiling {
184             gob_type: GOBType::Fermi8,
185             x_log2: 0,
186             y_log2: 5,
187             z_log2: 5,
188         };
189 
190         if (usage & IMAGE_USAGE_2D_VIEW_BIT) != 0 {
191             tiling.z_log2 = 0;
192         }
193 
194         tiling.clamp(extent_px.to_B(format, sample_layout))
195     }
196 
is_tiled(&self) -> bool197     pub fn is_tiled(&self) -> bool {
198         if self.gob_type == GOBType::Linear {
199             debug_assert!(self.x_log2 == 0);
200             debug_assert!(self.y_log2 == 0);
201             debug_assert!(self.z_log2 == 0);
202             false
203         } else {
204             true
205         }
206     }
207 }
208