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