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