xref: /aosp_15_r20/external/mesa3d/src/nouveau/nil/image.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::modifiers::*;
7 use crate::tiling::Tiling;
8 use crate::Minify;
9 
10 use nil_rs_bindings::*;
11 use nvidia_headers::classes::{cl9097, clc597};
12 
13 pub const MAX_LEVELS: usize = 16;
14 
15 pub type ImageUsageFlags = u8;
16 pub const IMAGE_USAGE_2D_VIEW_BIT: ImageUsageFlags = 1 << 0;
17 pub const IMAGE_USAGE_LINEAR_BIT: ImageUsageFlags = 1 << 1;
18 pub const IMAGE_USAGE_SPARSE_RESIDENCY_BIT: ImageUsageFlags = 1 << 2;
19 
20 #[derive(Clone, Debug, Copy, PartialEq, Default)]
21 #[repr(u8)]
22 pub enum ImageDim {
23     #[default]
24     _1D = 1,
25     _2D = 2,
26     _3D = 3,
27 }
28 
29 #[derive(Clone, Debug, Copy, PartialEq, Default)]
30 #[repr(u8)]
31 pub enum SampleLayout {
32     _1x1 = 0,
33     _2x1 = 1,
34     _2x2 = 2,
35     _4x2 = 3,
36     _4x4 = 4,
37     #[default]
38     Invalid = 5,
39 }
40 
41 impl SampleLayout {
42     #[no_mangle]
nil_choose_sample_layout(samples: u32) -> SampleLayout43     pub extern "C" fn nil_choose_sample_layout(samples: u32) -> SampleLayout {
44         Self::choose_sample_layout(samples)
45     }
46 
choose_sample_layout(samples: u32) -> SampleLayout47     pub fn choose_sample_layout(samples: u32) -> SampleLayout {
48         match samples {
49             1 => SampleLayout::_1x1,
50             2 => SampleLayout::_2x1,
51             4 => SampleLayout::_2x2,
52             8 => SampleLayout::_4x2,
53             16 => SampleLayout::_4x4,
54             _ => SampleLayout::Invalid,
55         }
56     }
57 
px_extent_sa(&self) -> Extent4D<units::Samples>58     pub fn px_extent_sa(&self) -> Extent4D<units::Samples> {
59         match self {
60             SampleLayout::_1x1 => Extent4D::new(1, 1, 1, 1),
61             SampleLayout::_2x1 => Extent4D::new(2, 1, 1, 1),
62             SampleLayout::_2x2 => Extent4D::new(2, 2, 1, 1),
63             SampleLayout::_4x2 => Extent4D::new(4, 2, 1, 1),
64             SampleLayout::_4x4 => Extent4D::new(4, 4, 1, 1),
65             SampleLayout::Invalid => panic!("Invalid sample layout"),
66         }
67     }
68 
69     #[no_mangle]
nil_px_extent_sa(self) -> Extent4D<units::Samples>70     pub extern "C" fn nil_px_extent_sa(self) -> Extent4D<units::Samples> {
71         self.px_extent_sa()
72     }
73 }
74 
75 #[derive(Clone, Debug, Copy, PartialEq)]
76 #[repr(C)]
77 pub struct ImageInitInfo {
78     pub dim: ImageDim,
79     pub format: Format,
80     pub extent_px: Extent4D<units::Pixels>,
81     pub levels: u32,
82     pub samples: u32,
83     pub usage: ImageUsageFlags,
84     pub modifier: u64,
85     pub explicit_row_stride_B: u32,
86 }
87 
88 /// Represents the data layout of a single slice (level + lod) of an image.
89 #[repr(C)]
90 #[derive(Clone, Debug, Copy, PartialEq, Default)]
91 pub struct ImageLevel {
92     pub offset_B: u64,
93     pub tiling: Tiling,
94     pub row_stride_B: u32,
95 }
96 
97 #[repr(C)]
98 #[derive(Clone, Debug, PartialEq)]
99 pub struct Image {
100     pub dim: ImageDim,
101     pub format: Format,
102     pub extent_px: Extent4D<units::Pixels>,
103     pub sample_layout: SampleLayout,
104     pub num_levels: u32,
105     pub mip_tail_first_lod: u32,
106     pub levels: [ImageLevel; MAX_LEVELS],
107     pub array_stride_B: u64,
108     pub align_B: u32,
109     pub size_B: u64,
110     pub compressed: bool,
111     pub tile_mode: u16,
112     pub pte_kind: u8,
113 }
114 
115 impl Image {
116     #[no_mangle]
nil_image_new( dev: &nil_rs_bindings::nv_device_info, info: &ImageInitInfo, ) -> Self117     pub extern "C" fn nil_image_new(
118         dev: &nil_rs_bindings::nv_device_info,
119         info: &ImageInitInfo,
120     ) -> Self {
121         Self::new(dev, info)
122     }
123 
new( dev: &nil_rs_bindings::nv_device_info, info: &ImageInitInfo, ) -> Self124     pub fn new(
125         dev: &nil_rs_bindings::nv_device_info,
126         info: &ImageInitInfo,
127     ) -> Self {
128         match info.dim {
129             ImageDim::_1D => {
130                 assert!(info.extent_px.height == 1);
131                 assert!(info.extent_px.depth == 1);
132                 assert!(info.samples == 1);
133             }
134             ImageDim::_2D => {
135                 assert!(info.extent_px.depth == 1);
136             }
137             ImageDim::_3D => {
138                 assert!(info.extent_px.array_len == 1);
139                 assert!(info.samples == 1);
140             }
141         }
142 
143         let sample_layout = SampleLayout::choose_sample_layout(info.samples);
144 
145         let tiling = if info.modifier != DRM_FORMAT_MOD_INVALID {
146             assert!((info.usage & IMAGE_USAGE_SPARSE_RESIDENCY_BIT) == 0);
147             assert!(info.dim == ImageDim::_2D);
148             assert!(sample_layout == SampleLayout::_1x1);
149             if info.modifier == DRM_FORMAT_MOD_LINEAR {
150                 Tiling::default()
151             } else {
152                 let bl_mod =
153                     BlockLinearModifier::try_from(info.modifier).unwrap();
154 
155                 // We don't support compression yet
156                 assert!(bl_mod.compression_type() == CompressionType::None);
157 
158                 bl_mod
159                     .tiling()
160                     .clamp(info.extent_px.to_B(info.format, sample_layout))
161             }
162         } else if (info.usage & IMAGE_USAGE_SPARSE_RESIDENCY_BIT) != 0 {
163             Tiling::sparse(info.format, info.dim)
164         } else {
165             Tiling::choose(
166                 info.extent_px,
167                 info.format,
168                 sample_layout,
169                 info.usage,
170             )
171         };
172 
173         let mut image = Self {
174             dim: info.dim,
175             format: info.format,
176             extent_px: info.extent_px,
177             sample_layout,
178             num_levels: info.levels,
179             levels: [ImageLevel::default(); MAX_LEVELS as usize],
180             array_stride_B: 0,
181             align_B: 0,
182             size_B: 0,
183             compressed: false,
184             tile_mode: 0,
185             pte_kind: 0,
186             mip_tail_first_lod: 0,
187         };
188 
189         if (info.usage & IMAGE_USAGE_SPARSE_RESIDENCY_BIT) != 0 {
190             image.mip_tail_first_lod = info.levels;
191         }
192 
193         let mut layer_size_B = 0;
194         for level in 0..info.levels {
195             let mut lvl_ext_B = image.level_extent_B(level);
196 
197             // NVIDIA images are layed out as an array of 1/2/3D images, each of
198             // which may have multiple miplevels.  For the purposes of computing
199             // the size of a miplevel, we don't care about arrays.
200             lvl_ext_B.array_len = 1;
201 
202             if tiling.is_tiled {
203                 let lvl_tiling = tiling.clamp(lvl_ext_B);
204 
205                 if tiling != lvl_tiling {
206                     image.mip_tail_first_lod =
207                         std::cmp::min(image.mip_tail_first_lod, level);
208                 }
209 
210                 // Align the size to tiles
211                 let lvl_tiling_ext_B = lvl_tiling.extent_B();
212                 lvl_ext_B = lvl_ext_B.align(&lvl_tiling_ext_B);
213                 assert!(
214                     info.explicit_row_stride_B == 0
215                         || info.explicit_row_stride_B == lvl_ext_B.width
216                 );
217 
218                 image.levels[level as usize] = ImageLevel {
219                     offset_B: layer_size_B,
220                     tiling: lvl_tiling,
221                     row_stride_B: lvl_ext_B.width,
222                 };
223 
224                 layer_size_B += lvl_ext_B.size_B();
225             } else {
226                 // Linear images need to be 2D
227                 assert!(image.dim == ImageDim::_2D);
228                 // Linear images can't be arrays
229                 assert!(image.extent_px.array_len == 1);
230                 // NVIDIA can't do linear and mipmapping
231                 assert!(image.num_levels == 1);
232                 // NVIDIA can't do linear and multisampling
233                 assert!(image.sample_layout == SampleLayout::_1x1);
234 
235                 let row_stride_B = if info.explicit_row_stride_B > 0 {
236                     assert!(info.modifier == DRM_FORMAT_MOD_LINEAR);
237                     assert!(info.explicit_row_stride_B % 128 == 0);
238                     info.explicit_row_stride_B
239                 } else {
240                     // Row stride needs to be aligned to 128B for render to work
241                     lvl_ext_B.width.next_multiple_of(128)
242                 };
243 
244                 image.levels[level as usize] = ImageLevel {
245                     offset_B: layer_size_B,
246                     tiling,
247                     row_stride_B,
248                 };
249 
250                 layer_size_B +=
251                     u64::from(row_stride_B) * u64::from(lvl_ext_B.height);
252             }
253         }
254 
255         // We use the tiling for level 0 instead of the tiling selected above
256         // because, in the case of sparse residency with small images, level 0 may
257         // have a smaller tiling than what we tried to use. However, the level 0
258         // tiling is the one we program in the hardware so that's the one we need
259         // to use for array stride calculations and the like.
260 
261         let lvl0_tiling_size_B = image.levels[0].tiling.size_B();
262 
263         // The array stride has to be aligned to the size of a level 0 tile
264         image.array_stride_B =
265             layer_size_B.next_multiple_of(lvl0_tiling_size_B.into());
266 
267         image.size_B =
268             image.array_stride_B * u64::from(image.extent_px.array_len);
269         image.align_B = lvl0_tiling_size_B;
270 
271         // If the client requested sparse residency, we need a 64K alignment
272         // or else sparse binding may fail.  This is true regardless of
273         // whether or not we actually select a 64K tile format.
274         if (info.usage & IMAGE_USAGE_SPARSE_RESIDENCY_BIT) != 0 {
275             image.align_B = std::cmp::max(image.align_B, 1 << 16);
276         }
277 
278         if image.levels[0].tiling.is_tiled {
279             image.pte_kind = Self::choose_pte_kind(
280                 dev,
281                 info.format,
282                 info.samples,
283                 image.compressed,
284             );
285 
286             if info.modifier != DRM_FORMAT_MOD_INVALID {
287                 let bl_mod =
288                     BlockLinearModifier::try_from(info.modifier).unwrap();
289                 assert!(bl_mod.pte_kind() == image.pte_kind);
290             }
291         }
292 
293         if image.levels[0].tiling.is_tiled {
294             image.tile_mode = u16::from(image.levels[0].tiling.y_log2) << 4
295                 | u16::from(image.levels[0].tiling.z_log2) << 8;
296 
297             image.align_B = std::cmp::max(image.align_B, 4096);
298             if image.pte_kind >= 0xb && image.pte_kind <= 0xe {
299                 image.align_B = std::cmp::max(image.align_B, 1 << 16);
300             }
301         } else {
302             // Linear images need to be aligned to 128B for render to work
303             image.align_B = std::cmp::max(image.align_B, 128);
304         }
305 
306         image.size_B = image.size_B.next_multiple_of(image.align_B.into());
307 
308         image
309     }
310 
311     /// The size in bytes of an extent at a given level.
level_extent_B(&self, level: u32) -> Extent4D<units::Bytes>312     fn level_extent_B(&self, level: u32) -> Extent4D<units::Bytes> {
313         self.level_extent_px(level)
314             .to_B(self.format, self.sample_layout)
315     }
316 
317     #[no_mangle]
nil_image_level_extent_px( &self, level: u32, ) -> Extent4D<units::Pixels>318     pub extern "C" fn nil_image_level_extent_px(
319         &self,
320         level: u32,
321     ) -> Extent4D<units::Pixels> {
322         self.level_extent_px(level)
323     }
324 
level_extent_px(&self, level: u32) -> Extent4D<units::Pixels>325     pub fn level_extent_px(&self, level: u32) -> Extent4D<units::Pixels> {
326         assert!(level == 0 || self.sample_layout == SampleLayout::_1x1);
327         self.extent_px.minify(level)
328     }
329 
330     #[no_mangle]
nil_image_level_layer_offset_B( &self, level: u32, layer: u32, ) -> u64331     pub extern "C" fn nil_image_level_layer_offset_B(
332         &self,
333         level: u32,
334         layer: u32,
335     ) -> u64 {
336         self.level_layer_offset_B(level, layer)
337     }
338 
level_layer_offset_B(&self, level: u32, layer: u32) -> u64339     pub fn level_layer_offset_B(&self, level: u32, layer: u32) -> u64 {
340         assert!(level < self.num_levels);
341         assert!(layer < self.extent_px.array_len);
342         self.levels[level as usize].offset_B
343             + u64::from(layer) * self.array_stride_B
344     }
345 
346     #[no_mangle]
nil_image_mip_tail_offset_B(&self) -> u64347     pub extern "C" fn nil_image_mip_tail_offset_B(&self) -> u64 {
348         self.mip_tail_offset_B()
349     }
350 
mip_tail_offset_B(&self) -> u64351     pub fn mip_tail_offset_B(&self) -> u64 {
352         assert!(self.mip_tail_first_lod > 0);
353         self.levels[self.mip_tail_first_lod as usize].offset_B
354     }
355 
356     #[no_mangle]
nil_image_mip_tail_size_B(&self) -> u32357     pub extern "C" fn nil_image_mip_tail_size_B(&self) -> u32 {
358         self.mip_tail_size_B()
359     }
360 
mip_tail_size_B(&self) -> u32361     pub fn mip_tail_size_B(&self) -> u32 {
362         (self.array_stride_B - self.mip_tail_offset_B())
363             .try_into()
364             .unwrap()
365     }
366 
367     #[no_mangle]
nil_image_level_extent_sa( &self, level: u32, ) -> Extent4D<units::Samples>368     pub extern "C" fn nil_image_level_extent_sa(
369         &self,
370         level: u32,
371     ) -> Extent4D<units::Samples> {
372         self.level_extent_sa(level)
373     }
374 
level_extent_sa(&self, level: u32) -> Extent4D<units::Samples>375     pub fn level_extent_sa(&self, level: u32) -> Extent4D<units::Samples> {
376         self.level_extent_px(level).to_sa(self.sample_layout)
377     }
378 
379     #[no_mangle]
nil_image_level_size_B(&self, level: u32) -> u64380     pub extern "C" fn nil_image_level_size_B(&self, level: u32) -> u64 {
381         self.level_size_B(level)
382     }
383 
level_size_B(&self, level: u32) -> u64384     pub fn level_size_B(&self, level: u32) -> u64 {
385         assert!(level < self.num_levels);
386         let lvl_ext_B = self.level_extent_B(level);
387         let level = &self.levels[level as usize];
388 
389         if level.tiling.is_tiled {
390             let lvl_tiling_ext_B = level.tiling.extent_B();
391             let mut lvl_ext_B = lvl_ext_B.align(&lvl_tiling_ext_B);
392 
393             let array_len = lvl_ext_B.array_len;
394             lvl_ext_B.array_len = 1;
395 
396             self.array_stride_B * u64::from(array_len - 1) + lvl_ext_B.size_B()
397         } else {
398             assert!(lvl_ext_B.depth == 1);
399             assert!(lvl_ext_B.array_len == 1);
400             u64::from(level.row_stride_B) * u64::from(lvl_ext_B.height - 1)
401                 + u64::from(lvl_ext_B.width)
402         }
403     }
404 
405     #[no_mangle]
nil_image_level_depth_stride_B(&self, level: u32) -> u64406     pub extern "C" fn nil_image_level_depth_stride_B(&self, level: u32) -> u64 {
407         self.level_depth_stride_B(level)
408     }
409 
level_depth_stride_B(&self, level: u32) -> u64410     pub fn level_depth_stride_B(&self, level: u32) -> u64 {
411         assert!(level < self.num_levels);
412 
413         let lvl_ext_B = self.level_extent_B(level);
414         let level = &self.levels[level as usize];
415         let lvl_tiling_ext_B = level.tiling.extent_B();
416         let lvl_ext_B = lvl_ext_B.align(&lvl_tiling_ext_B);
417 
418         (lvl_ext_B.width * lvl_ext_B.height).into()
419     }
420 
421     #[no_mangle]
nil_image_for_level( &self, level: u32, offset_in_bytes_out: &mut u64, ) -> Self422     pub extern "C" fn nil_image_for_level(
423         &self,
424         level: u32,
425         offset_in_bytes_out: &mut u64,
426     ) -> Self {
427         self.image_for_level(level, offset_in_bytes_out)
428     }
429 
image_for_level( &self, level: u32, offset_in_bytes_out: &mut u64, ) -> Self430     pub fn image_for_level(
431         &self,
432         level: u32,
433         offset_in_bytes_out: &mut u64,
434     ) -> Self {
435         assert!(level < self.num_levels);
436         let lvl_extent_px = self.level_extent_px(level);
437         let lvl = self.levels[level as usize];
438         let align_B = lvl.tiling.size_B();
439 
440         let mut size_B = self.size_B - lvl.offset_B;
441         if (level + 1) < self.num_levels {
442             // This assumes levels are sequential, tightly packed and that each
443             // level has a higher alignment than the next one. All of this is
444             // currently true.
445             let next_lvl_offset_in_bytes =
446                 self.levels[level as usize + 1].offset_B;
447             assert!(next_lvl_offset_in_bytes > lvl.offset_B);
448             size_B -= next_lvl_offset_in_bytes - lvl.offset_B;
449         }
450 
451         let mut levels: [ImageLevel; MAX_LEVELS as usize] = Default::default();
452         levels[0] = lvl;
453 
454         *offset_in_bytes_out = lvl.offset_B;
455         levels[0].offset_B = 0;
456 
457         Self {
458             extent_px: lvl_extent_px,
459             num_levels: 1,
460             levels,
461             align_B,
462             size_B,
463             mip_tail_first_lod: if level < self.mip_tail_first_lod {
464                 1
465             } else {
466                 0
467             },
468             ..*self
469         }
470     }
471 
472     #[no_mangle]
nil_image_level_as_uncompressed( &self, level: u32, offset_in_bytes_out: &mut u64, ) -> Self473     pub extern "C" fn nil_image_level_as_uncompressed(
474         &self,
475         level: u32,
476         offset_in_bytes_out: &mut u64,
477     ) -> Self {
478         self.level_as_uncompressed(level, offset_in_bytes_out)
479     }
480 
level_as_uncompressed( &self, level: u32, offset_in_bytes_out: &mut u64, ) -> Self481     pub fn level_as_uncompressed(
482         &self,
483         level: u32,
484         offset_in_bytes_out: &mut u64,
485     ) -> Self {
486         assert!(self.sample_layout == SampleLayout::_1x1);
487 
488         // Format is arbitrary. Pick one that has the right number of bits.
489         let uc_format = match self.format.el_size_B() {
490             4 => PIPE_FORMAT_R32_UINT,
491             8 => PIPE_FORMAT_R32G32_UINT,
492             16 => PIPE_FORMAT_R32G32B32A32_UINT,
493             _ => panic!("No compressed PIPE_FORMAT with this size"),
494         };
495 
496         let lvl_image = self.image_for_level(level, offset_in_bytes_out);
497         let mut image_out = lvl_image.clone();
498 
499         image_out.format = uc_format.try_into().unwrap();
500         image_out.extent_px = lvl_image
501             .extent_px
502             .to_el(lvl_image.format, lvl_image.sample_layout)
503             .cast_units();
504 
505         image_out
506     }
507 
508     #[no_mangle]
nil_image_3d_level_as_2d_array( &self, level: u32, offset_in_bytes_out: &mut u64, ) -> Self509     pub extern "C" fn nil_image_3d_level_as_2d_array(
510         &self,
511         level: u32,
512         offset_in_bytes_out: &mut u64,
513     ) -> Self {
514         self._3d_level_as_2d_array(level, offset_in_bytes_out)
515     }
516 
_3d_level_as_2d_array( &self, level: u32, offset_in_bytes_out: &mut u64, ) -> Self517     pub fn _3d_level_as_2d_array(
518         &self,
519         level: u32,
520         offset_in_bytes_out: &mut u64,
521     ) -> Self {
522         assert!(self.dim == ImageDim::_3D);
523         assert!(self.extent_px.array_len == 1);
524         assert!(self.sample_layout == SampleLayout::_1x1);
525 
526         let mut image_2d_out = self.image_for_level(level, offset_in_bytes_out);
527         let lvl0 = &image_2d_out.levels[0];
528 
529         assert!(image_2d_out.num_levels == 1);
530         assert!(!lvl0.tiling.is_tiled || lvl0.tiling.z_log2 == 0);
531 
532         let lvl_tiling_ext_B = lvl0.tiling.extent_B();
533         let lvl_ext_B = image_2d_out.level_extent_B(0);
534         let lvl_ext_B = lvl_ext_B.align(&lvl_tiling_ext_B);
535         let z_stride = u64::from(lvl_ext_B.width * lvl_ext_B.height);
536 
537         image_2d_out.dim = ImageDim::_2D;
538         image_2d_out.extent_px.array_len = image_2d_out.extent_px.depth;
539         image_2d_out.extent_px.depth = 1;
540         image_2d_out.array_stride_B = z_stride;
541 
542         image_2d_out
543     }
544 
choose_pte_kind( dev: &nil_rs_bindings::nv_device_info, format: Format, samples: u32, compressed: bool, ) -> u8545     pub fn choose_pte_kind(
546         dev: &nil_rs_bindings::nv_device_info,
547         format: Format,
548         samples: u32,
549         compressed: bool,
550     ) -> u8 {
551         if dev.cls_eng3d >= clc597::TURING_A {
552             Self::tu102_choose_pte_kind(format, compressed)
553         } else if dev.cls_eng3d >= cl9097::FERMI_A {
554             Self::nvc0_choose_pte_kind(format, samples, compressed)
555         } else {
556             panic!("Unsupported 3d engine class")
557         }
558     }
559 
tu102_choose_pte_kind(format: Format, compressed: bool) -> u8560     fn tu102_choose_pte_kind(format: Format, compressed: bool) -> u8 {
561         use nvidia_headers::hwref::tu102::mmu::*;
562         match pipe_format::from(format) {
563             PIPE_FORMAT_Z16_UNORM => {
564                 if compressed {
565                     NV_MMU_PTE_KIND_Z16_COMPRESSIBLE_DISABLE_PLC
566                 } else {
567                     NV_MMU_PTE_KIND_Z16
568                 }
569             }
570             PIPE_FORMAT_X8Z24_UNORM
571             | PIPE_FORMAT_S8X24_UINT
572             | PIPE_FORMAT_S8_UINT_Z24_UNORM => {
573                 if compressed {
574                     NV_MMU_PTE_KIND_Z24S8_COMPRESSIBLE_DISABLE_PLC
575                 } else {
576                     NV_MMU_PTE_KIND_Z24S8
577                 }
578             }
579             PIPE_FORMAT_X24S8_UINT
580             | PIPE_FORMAT_Z24X8_UNORM
581             | PIPE_FORMAT_Z24_UNORM_S8_UINT => {
582                 if compressed {
583                     NV_MMU_PTE_KIND_S8Z24_COMPRESSIBLE_DISABLE_PLC
584                 } else {
585                     NV_MMU_PTE_KIND_S8Z24
586                 }
587             }
588             PIPE_FORMAT_X32_S8X24_UINT | PIPE_FORMAT_Z32_FLOAT_S8X24_UINT => {
589                 if compressed {
590                     NV_MMU_PTE_KIND_ZF32_X24S8_COMPRESSIBLE_DISABLE_PLC
591                 } else {
592                     NV_MMU_PTE_KIND_ZF32_X24S8
593                 }
594             }
595             PIPE_FORMAT_Z32_FLOAT => NV_MMU_PTE_KIND_GENERIC_MEMORY,
596             PIPE_FORMAT_S8_UINT => {
597                 if compressed {
598                     NV_MMU_PTE_KIND_S8_COMPRESSIBLE_DISABLE_PLC
599                 } else {
600                     NV_MMU_PTE_KIND_S8
601                 }
602             }
603             _ => NV_MMU_PTE_KIND_GENERIC_MEMORY,
604         }
605         .try_into()
606         .unwrap()
607     }
608 
nvc0_choose_pte_kind( format: Format, samples: u32, compressed: bool, ) -> u8609     fn nvc0_choose_pte_kind(
610         format: Format,
611         samples: u32,
612         compressed: bool,
613     ) -> u8 {
614         use nvidia_headers::hwref::gp100::mmu::*;
615         let ms = samples.ilog2();
616         match pipe_format::from(format) {
617             PIPE_FORMAT_Z16_UNORM => {
618                 if compressed {
619                     NV_MMU_PTE_KIND_Z16_2C + ms
620                 } else {
621                     NV_MMU_PTE_KIND_Z16
622                 }
623             }
624             PIPE_FORMAT_X8Z24_UNORM
625             | PIPE_FORMAT_S8X24_UINT
626             | PIPE_FORMAT_S8_UINT_Z24_UNORM => {
627                 if compressed {
628                     NV_MMU_PTE_KIND_Z24S8_2CZ + ms
629                 } else {
630                     NV_MMU_PTE_KIND_Z24S8
631                 }
632             }
633             PIPE_FORMAT_X24S8_UINT
634             | PIPE_FORMAT_Z24X8_UNORM
635             | PIPE_FORMAT_Z24_UNORM_S8_UINT => {
636                 if compressed {
637                     NV_MMU_PTE_KIND_S8Z24_2CZ + ms
638                 } else {
639                     NV_MMU_PTE_KIND_S8Z24
640                 }
641             }
642             PIPE_FORMAT_Z32_FLOAT => {
643                 if compressed {
644                     NV_MMU_PTE_KIND_ZF32_2CZ + ms
645                 } else {
646                     NV_MMU_PTE_KIND_ZF32
647                 }
648             }
649             PIPE_FORMAT_X32_S8X24_UINT | PIPE_FORMAT_Z32_FLOAT_S8X24_UINT => {
650                 if compressed {
651                     NV_MMU_PTE_KIND_ZF32_X24S8_2CSZV + ms
652                 } else {
653                     NV_MMU_PTE_KIND_ZF32_X24S8
654                 }
655             }
656             PIPE_FORMAT_S8_UINT => NV_MMU_PTE_KIND_S8,
657             _ => {
658                 let blocksize_bits = format.el_size_B() * 8;
659                 match blocksize_bits {
660                     128 => {
661                         if compressed {
662                             match samples {
663                                 1 => NV_MMU_PTE_KIND_C128_2C,
664                                 2 => NV_MMU_PTE_KIND_C128_MS2_2C,
665                                 4 => NV_MMU_PTE_KIND_C128_MS4_2C,
666                                 8 | 16 => NV_MMU_PTE_KIND_C128_MS8_MS16_2C,
667                                 _ => panic!("Unsupported sample count"),
668                             }
669                         } else {
670                             NV_MMU_PTE_KIND_GENERIC_16BX2
671                         }
672                     }
673                     64 => {
674                         if compressed {
675                             match samples {
676                                 1 => NV_MMU_PTE_KIND_C64_2C,
677                                 2 => NV_MMU_PTE_KIND_C64_MS2_2C,
678                                 4 => NV_MMU_PTE_KIND_C64_MS4_2C,
679                                 8 | 16 => NV_MMU_PTE_KIND_C64_MS8_MS16_2C,
680                                 _ => panic!("Unsupported sample count"),
681                             }
682                         } else {
683                             NV_MMU_PTE_KIND_GENERIC_16BX2
684                         }
685                     }
686                     32 => {
687                         if compressed {
688                             match samples {
689                                 1 => NV_MMU_PTE_KIND_C32_2C,
690                                 2 => NV_MMU_PTE_KIND_C32_MS2_2C,
691                                 4 => NV_MMU_PTE_KIND_C32_MS4_2C,
692                                 8 | 16 => NV_MMU_PTE_KIND_C32_MS8_MS16_2C,
693                                 _ => panic!("Unsupported sample count"),
694                             }
695                         } else {
696                             NV_MMU_PTE_KIND_GENERIC_16BX2
697                         }
698                     }
699                     16 | 8 => NV_MMU_PTE_KIND_GENERIC_16BX2,
700                     _ => NV_MMU_PTE_KIND_PITCH,
701                 }
702             }
703         }
704         .try_into()
705         .unwrap()
706     }
707 
708     #[no_mangle]
nil_msaa_image_as_sa(&self) -> Self709     pub extern "C" fn nil_msaa_image_as_sa(&self) -> Self {
710         self.msaa_as_samples()
711     }
712 
713     /// For a multisampled image, returns an image of samples
714     ///
715     /// The resulting image is supersampled with each pixel in the original
716     /// consuming some number pixels in the supersampled images according to the
717     /// original image's sample layout
msaa_as_samples(&self) -> Self718     pub fn msaa_as_samples(&self) -> Self {
719         assert!(self.dim == ImageDim::_2D);
720         assert!(self.num_levels == 1);
721 
722         let extent_sa = self.extent_px.to_sa(self.sample_layout);
723         let mut out = self.clone();
724         out.extent_px = extent_sa.cast_units();
725         out.sample_layout = SampleLayout::_1x1;
726         out
727     }
728 
729     #[no_mangle]
nil_image_level_z_offset_B( &self, level: u32, z: u32, ) -> u64730     pub extern "C" fn nil_image_level_z_offset_B(
731         &self,
732         level: u32,
733         z: u32,
734     ) -> u64 {
735         self.level_z_offset_B(level, z)
736     }
737 
level_z_offset_B(&self, level: u32, z: u32) -> u64738     pub fn level_z_offset_B(&self, level: u32, z: u32) -> u64 {
739         assert!(level < self.num_levels);
740         let lvl_extent_px = self.level_extent_px(level);
741         assert!(z < lvl_extent_px.depth);
742 
743         let lvl_tiling = &self.levels[level as usize].tiling;
744         let z_tl = z >> lvl_tiling.z_log2;
745         let z_gob = z & ((1 << lvl_tiling.z_log2) - 1);
746 
747         let lvl_extent_tl =
748             lvl_extent_px.to_tl(lvl_tiling, self.format, self.sample_layout);
749         let offset_B = u64::from(
750             lvl_extent_tl.width
751                 * lvl_extent_tl.height
752                 * z_tl
753                 * lvl_tiling.size_B(),
754         );
755 
756         let tiling_extent_B = lvl_tiling.extent_B();
757         let offset_B = offset_B
758             + u64::from(tiling_extent_B.width * tiling_extent_B.height * z_gob);
759         offset_B
760     }
761 }
762 
763 #[allow(dead_code)]
764 #[derive(Clone, Debug, Copy, PartialEq)]
765 #[repr(u8)]
766 pub enum ViewType {
767     _1D,
768     _2D,
769     _3D,
770     _3DSliced,
771     Cube,
772     _1DArray,
773     _2DArray,
774     CubeArray,
775 }
776 
777 #[repr(C)]
778 #[derive(Debug, Clone, PartialEq)]
779 pub struct View {
780     pub view_type: ViewType,
781 
782     /// The format to use in the view
783     ///
784     /// This may differ from the format of the actual isl_surf but must have the
785     /// same block size.
786     pub format: Format,
787 
788     pub base_level: u32,
789     pub num_levels: u32,
790 
791     /// Base array layer
792     ///
793     /// For cube maps, both base_array_layer and array_len should be specified in
794     /// terms of 2-D layers and must be a multiple of 6.
795     pub base_array_layer: u32,
796 
797     /// Array Length
798     ///
799     /// Indicates the number of array elements starting at  Base Array Layer.
800     pub array_len: u32,
801 
802     pub swizzle: [nil_rs_bindings::pipe_swizzle; 4],
803 
804     // VK_EXT_image_view_min_lod
805     pub min_lod_clamp: f32,
806 }
807