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