1/* 2 * Copyright (C) 2022 Collabora, Ltd. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include "pan_texture.h" 25 26#include <gtest/gtest.h> 27 28TEST(BlockSize, Linear) 29{ 30 enum pipe_format format[] = { 31 PIPE_FORMAT_R32G32B32_FLOAT, 32 PIPE_FORMAT_R8G8B8_UNORM, 33 PIPE_FORMAT_ETC2_RGB8, 34 PIPE_FORMAT_ASTC_5x5 35 }; 36 37 for (unsigned i = 0; i < ARRAY_SIZE(format); ++i) { 38 struct pan_block_size blk = panfrost_block_size(DRM_FORMAT_MOD_LINEAR, format[i]); 39 40 EXPECT_EQ(blk.width, 1); 41 EXPECT_EQ(blk.height, 1); 42 } 43} 44 45TEST(BlockSize, UInterleavedRegular) 46{ 47 enum pipe_format format[] = { 48 PIPE_FORMAT_R32G32B32_FLOAT, 49 PIPE_FORMAT_R8G8B8_UNORM, 50 }; 51 52 for (unsigned i = 0; i < ARRAY_SIZE(format); ++i) { 53 struct pan_block_size blk = panfrost_block_size(DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED, format[i]); 54 55 EXPECT_EQ(blk.width, 16); 56 EXPECT_EQ(blk.height, 16); 57 } 58} 59 60TEST(BlockSize, UInterleavedBlockCompressed) 61{ 62 enum pipe_format format[] = { 63 PIPE_FORMAT_ETC2_RGB8, 64 PIPE_FORMAT_ASTC_5x5 65 }; 66 67 for (unsigned i = 0; i < ARRAY_SIZE(format); ++i) { 68 struct pan_block_size blk = panfrost_block_size(DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED, format[i]); 69 70 EXPECT_EQ(blk.width, 4); 71 EXPECT_EQ(blk.height, 4); 72 } 73} 74 75TEST(BlockSize, AFBCFormatInvariant16x16) 76{ 77 enum pipe_format format[] = { 78 PIPE_FORMAT_R32G32B32_FLOAT, 79 PIPE_FORMAT_R8G8B8_UNORM, 80 PIPE_FORMAT_ETC2_RGB8, 81 PIPE_FORMAT_ASTC_5x5 82 }; 83 84 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC( 85 AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 86 AFBC_FORMAT_MOD_SPARSE | 87 AFBC_FORMAT_MOD_YTR); 88 89 for (unsigned i = 0; i < ARRAY_SIZE(format); ++i) { 90 struct pan_block_size blk = panfrost_block_size(modifier, format[i]); 91 92 EXPECT_EQ(blk.width, 16); 93 EXPECT_EQ(blk.height, 16); 94 } 95} 96 97TEST(BlockSize, AFBCFormatInvariant32x8) 98{ 99 enum pipe_format format[] = { 100 PIPE_FORMAT_R32G32B32_FLOAT, 101 PIPE_FORMAT_R8G8B8_UNORM, 102 PIPE_FORMAT_ETC2_RGB8, 103 PIPE_FORMAT_ASTC_5x5 104 }; 105 106 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC( 107 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 108 AFBC_FORMAT_MOD_SPARSE | 109 AFBC_FORMAT_MOD_YTR); 110 111 for (unsigned i = 0; i < ARRAY_SIZE(format); ++i) { 112 struct pan_block_size blk = panfrost_block_size(modifier, format[i]); 113 114 EXPECT_EQ(blk.width, 32); 115 EXPECT_EQ(blk.height, 8); 116 } 117} 118 119TEST(BlockSize, AFBCSuperblock16x16) 120{ 121 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC( 122 AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 123 AFBC_FORMAT_MOD_SPARSE | 124 AFBC_FORMAT_MOD_YTR); 125 126 EXPECT_EQ(panfrost_afbc_superblock_size(modifier).width, 16); 127 EXPECT_EQ(panfrost_afbc_superblock_width(modifier), 16); 128 129 EXPECT_EQ(panfrost_afbc_superblock_size(modifier).height, 16); 130 EXPECT_EQ(panfrost_afbc_superblock_height(modifier), 16); 131 132 EXPECT_FALSE(panfrost_afbc_is_wide(modifier)); 133} 134 135TEST(BlockSize, AFBCSuperblock32x8) 136{ 137 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC( 138 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 139 AFBC_FORMAT_MOD_SPARSE); 140 141 EXPECT_EQ(panfrost_afbc_superblock_size(modifier).width, 32); 142 EXPECT_EQ(panfrost_afbc_superblock_width(modifier), 32); 143 144 EXPECT_EQ(panfrost_afbc_superblock_size(modifier).height, 8); 145 EXPECT_EQ(panfrost_afbc_superblock_height(modifier), 8); 146 147 EXPECT_TRUE(panfrost_afbc_is_wide(modifier)); 148} 149 150TEST(BlockSize, AFBCSuperblock64x4) 151{ 152 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC( 153 AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 | 154 AFBC_FORMAT_MOD_SPARSE); 155 156 EXPECT_EQ(panfrost_afbc_superblock_size(modifier).width, 64); 157 EXPECT_EQ(panfrost_afbc_superblock_width(modifier), 64); 158 159 EXPECT_EQ(panfrost_afbc_superblock_size(modifier).height, 4); 160 EXPECT_EQ(panfrost_afbc_superblock_height(modifier), 4); 161 162 EXPECT_TRUE(panfrost_afbc_is_wide(modifier)); 163} 164 165/* Calculate Bifrost line stride, since we have reference formulas for Bifrost 166 * stride calculations. 167 */ 168static uint32_t pan_afbc_line_stride(uint64_t modifier, uint32_t width) 169{ 170 return pan_afbc_stride_blocks(modifier, pan_afbc_row_stride(modifier, width)); 171} 172 173/* Which form of the stride we specify is hardware specific (row stride for 174 * Valhall, line stride for Bifrost). However, the layout code is hardware 175 * independent, so we test both row stride and line stride calculations. 176 */ 177TEST(AFBCStride, Linear) 178{ 179 uint64_t modifiers[] = { 180 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 181 AFBC_FORMAT_MOD_SPARSE), 182 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 183 AFBC_FORMAT_MOD_SPARSE), 184 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 | 185 AFBC_FORMAT_MOD_SPARSE), 186 }; 187 188 for (unsigned m = 0; m < ARRAY_SIZE(modifiers); ++m) { 189 uint64_t modifier = modifiers[m]; 190 191 uint32_t sw = panfrost_afbc_superblock_width(modifier); 192 uint32_t cases[] = { 1, 4, 17, 39 }; 193 194 for (unsigned i = 0; i < ARRAY_SIZE(cases); ++i) { 195 uint32_t width = sw * cases[i]; 196 197 EXPECT_EQ(pan_afbc_row_stride(modifier, width), 198 16 * DIV_ROUND_UP(width, sw)); 199 200 EXPECT_EQ(pan_afbc_line_stride(modifier, width), 201 DIV_ROUND_UP(width, sw)); 202 } 203 } 204} 205 206TEST(AFBCStride, Tiled) 207{ 208 uint64_t modifiers[] = { 209 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 210 AFBC_FORMAT_MOD_TILED | 211 AFBC_FORMAT_MOD_SPARSE), 212 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 213 AFBC_FORMAT_MOD_TILED | 214 AFBC_FORMAT_MOD_SPARSE), 215 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 | 216 AFBC_FORMAT_MOD_TILED | 217 AFBC_FORMAT_MOD_SPARSE), 218 }; 219 220 for (unsigned m = 0; m < ARRAY_SIZE(modifiers); ++m) { 221 uint64_t modifier = modifiers[m]; 222 223 uint32_t sw = panfrost_afbc_superblock_width(modifier); 224 uint32_t cases[] = { 1, 4, 17, 39 }; 225 226 for (unsigned i = 0; i < ARRAY_SIZE(cases); ++i) { 227 uint32_t width = sw * 8 * cases[i]; 228 229 EXPECT_EQ(pan_afbc_row_stride(modifier, width), 230 16 * DIV_ROUND_UP(width, (sw * 8)) * 8 * 8); 231 232 EXPECT_EQ(pan_afbc_line_stride(modifier, width), 233 DIV_ROUND_UP(width, sw * 8) * 8); 234 } 235 } 236} 237 238TEST(LegacyStride, FromLegacyLinear) 239{ 240 EXPECT_EQ(panfrost_from_legacy_stride(1920 * 4, PIPE_FORMAT_R8G8B8A8_UINT, DRM_FORMAT_MOD_LINEAR), 1920 * 4); 241 EXPECT_EQ(panfrost_from_legacy_stride(53, PIPE_FORMAT_R8_SNORM, DRM_FORMAT_MOD_LINEAR), 53); 242 EXPECT_EQ(panfrost_from_legacy_stride(60, PIPE_FORMAT_ETC2_RGB8, DRM_FORMAT_MOD_LINEAR), 60); 243} 244 245TEST(LegacyStride, FromLegacyInterleaved) 246{ 247 EXPECT_EQ(panfrost_from_legacy_stride(1920 * 4, PIPE_FORMAT_R8G8B8A8_UINT, 248 DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED), 249 1920 * 4 * 16); 250 251 EXPECT_EQ(panfrost_from_legacy_stride(53, PIPE_FORMAT_R8_SNORM, 252 DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED), 53 * 16); 253 254 EXPECT_EQ(panfrost_from_legacy_stride(60, PIPE_FORMAT_ETC2_RGB8, 255 DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED), 60 * 4); 256} 257 258TEST(LegacyStride, FromLegacyAFBC) 259{ 260 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC( 261 AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 | 262 AFBC_FORMAT_MOD_SPARSE | 263 AFBC_FORMAT_MOD_YTR); 264 265 EXPECT_EQ(panfrost_from_legacy_stride(1920 * 4, PIPE_FORMAT_R8G8B8A8_UINT, modifier), 60 * 16); 266 EXPECT_EQ(panfrost_from_legacy_stride(64, PIPE_FORMAT_R8_SNORM, modifier), 2 * 16); 267} 268 269/* dEQP-GLES3.functional.texture.format.compressed.etc1_2d_pot */ 270TEST(Layout, ImplicitLayoutInterleavedETC2) 271{ 272 struct pan_image_layout l = { 273 .modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED, 274 .format = PIPE_FORMAT_ETC2_RGB8, 275 .width = 128, 276 .height = 128, 277 .depth = 1, 278 .nr_samples = 1, 279 .dim = MALI_TEXTURE_DIMENSION_2D, 280 .nr_slices = 8 281 }; 282 283 unsigned offsets[9] = { 284 0, 8192, 10240, 10752, 10880, 11008, 11136, 11264, 11392 285 }; 286 287 ASSERT_TRUE(pan_image_layout_init(&l, NULL)); 288 289 for (unsigned i = 0; i < 8; ++i) { 290 unsigned size = (offsets[i + 1] - offsets[i]); 291 EXPECT_EQ(l.slices[i].offset, offsets[i]); 292 293 if (size == 64) 294 EXPECT_TRUE(l.slices[i].size < 64); 295 else 296 EXPECT_EQ(l.slices[i].size, size); 297 } 298} 299 300TEST(Layout, ImplicitLayoutInterleavedASTC5x5) 301{ 302 struct pan_image_layout l = { 303 .modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED, 304 .format = PIPE_FORMAT_ASTC_5x5, 305 .width = 50, 306 .height = 50, 307 .depth = 1, 308 .nr_samples = 1, 309 .dim = MALI_TEXTURE_DIMENSION_2D, 310 .nr_slices = 1 311 }; 312 313 ASSERT_TRUE(pan_image_layout_init(&l, NULL)); 314 315 /* The image is 50x50 pixels, with 5x5 blocks. So it is a 10x10 grid of ASTC 316 * blocks. 4x4 tiles of ASTC blocks are u-interleaved, so we have to round up 317 * to a 12x12 grid. So we need space for 144 ASTC blocks. Each ASTC block is 318 * 16 bytes (128-bits), so we require 2304 bytes, with a row stride of 12 * 319 * 16 * 4 = 192 bytes. 320 */ 321 EXPECT_EQ(l.slices[0].offset, 0); 322 EXPECT_EQ(l.slices[0].row_stride, 768); 323 EXPECT_EQ(l.slices[0].surface_stride, 2304); 324 EXPECT_EQ(l.slices[0].size, 2304); 325} 326 327TEST(Layout, ImplicitLayoutLinearASTC5x5) 328{ 329 struct pan_image_layout l = { 330 .modifier = DRM_FORMAT_MOD_LINEAR, 331 .format = PIPE_FORMAT_ASTC_5x5, 332 .width = 50, 333 .height = 50, 334 .depth = 1, 335 .nr_samples = 1, 336 .dim = MALI_TEXTURE_DIMENSION_2D, 337 .nr_slices = 1 338 }; 339 340 ASSERT_TRUE(pan_image_layout_init(&l, NULL)); 341 342 /* The image is 50x50 pixels, with 5x5 blocks. So it is a 10x10 grid of ASTC 343 * blocks. Each ASTC block is 16 bytes, so the row stride is 160 bytes, 344 * rounded up to the cache line (192 bytes). There are 10 rows, so we have 345 * 1920 bytes total. 346 */ 347 EXPECT_EQ(l.slices[0].offset, 0); 348 EXPECT_EQ(l.slices[0].row_stride, 192); 349 EXPECT_EQ(l.slices[0].surface_stride, 1920); 350 EXPECT_EQ(l.slices[0].size, 1920); 351} 352 353/* dEQP-GLES3.functional.texture.format.unsized.rgba_unsigned_byte_3d_pot */ 354TEST(AFBCLayout, Linear3D) 355{ 356 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 357 AFBC_FORMAT_MOD_SPARSE); 358 359 struct pan_image_layout l = { 360 .modifier = modifier, 361 .format = PIPE_FORMAT_R8G8B8A8_UNORM, 362 .width = 8, 363 .height = 32, 364 .depth = 16, 365 .nr_samples = 1, 366 .dim = MALI_TEXTURE_DIMENSION_3D, 367 .nr_slices = 1 368 }; 369 370 ASSERT_TRUE(pan_image_layout_init(&l, NULL)); 371 372 /* AFBC Surface stride is bytes between consecutive surface headers, which is 373 * the header size since this is a 3D texture. At superblock size 16x16, the 8x32 374 * layer has 1x2 superblocks, so the header size is 2 * 16 = 32 bytes, 375 * rounded up to cache line 64. 376 * 377 * There is only 1 superblock per row, so the row stride is the bytes per 1 378 * header block = 16. 379 * 380 * There are 16 layers of size 64 so afbc.header_size = 16 * 64 = 1024. 381 * 382 * Each 16x16 superblock consumes 16 * 16 * 4 = 1024 bytes. There are 2 * 1 * 383 * 16 superblocks in the image, so body size is 32768. 384 */ 385 EXPECT_EQ(l.slices[0].offset, 0); 386 EXPECT_EQ(l.slices[0].row_stride, 16); 387 EXPECT_EQ(l.slices[0].afbc.header_size, 1024); 388 EXPECT_EQ(l.slices[0].afbc.body_size, 32768); 389 EXPECT_EQ(l.slices[0].afbc.surface_stride, 64); 390 EXPECT_EQ(l.slices[0].surface_stride, 2048); /* XXX: Not meaningful? */ 391 EXPECT_EQ(l.slices[0].size, 32768); /* XXX: Not used by anything and wrong */ 392} 393 394TEST(AFBCLayout, Tiled16x16) 395{ 396 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 397 AFBC_FORMAT_MOD_TILED | 398 AFBC_FORMAT_MOD_SPARSE); 399 400 struct pan_image_layout l = { 401 .modifier = modifier, 402 .format = PIPE_FORMAT_R8G8B8A8_UNORM, 403 .width = 917, 404 .height = 417, 405 .depth = 1, 406 .nr_samples = 1, 407 .dim = MALI_TEXTURE_DIMENSION_2D, 408 .nr_slices = 1 409 }; 410 411 ASSERT_TRUE(pan_image_layout_init(&l, NULL)); 412 413 /* The image is 917x417. Superblocks are 16x16, so there are 58x27 414 * superblocks. Superblocks are grouped into 8x8 tiles, so there are 8x4 415 * tiles of superblocks. So the row stride is 16 * 8 * 8 * 8 = 8192 bytes. 416 * There are 4 tiles vertically, so the header is 8192 * 4 = 32768 bytes. 417 * This is already 4096-byte aligned. 418 * 419 * Each tile of superblock contains 128x128 pixels and each pixel is 4 bytes, 420 * so tiles are 65536 bytes, meaning the payload is 8 * 4 * 65536 = 2097152 421 * bytes. 422 * 423 * In total, the AFBC surface is 32768 + 2097152 = 2129920 bytes. 424 */ 425 EXPECT_EQ(l.slices[0].offset, 0); 426 EXPECT_EQ(l.slices[0].row_stride, 8192); 427 EXPECT_EQ(l.slices[0].afbc.header_size, 32768); 428 EXPECT_EQ(l.slices[0].afbc.body_size, 2097152); 429 EXPECT_EQ(l.slices[0].surface_stride, 2129920); 430 EXPECT_EQ(l.slices[0].size, 2129920); 431} 432 433TEST(AFBCLayout, Linear16x16Minimal) 434{ 435 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 436 AFBC_FORMAT_MOD_SPARSE); 437 438 struct pan_image_layout l = { 439 .modifier = modifier, 440 .format = PIPE_FORMAT_R8_UNORM, 441 .width = 1, 442 .height = 1, 443 .depth = 1, 444 .nr_samples = 1, 445 .dim = MALI_TEXTURE_DIMENSION_2D, 446 .nr_slices = 1 447 }; 448 449 ASSERT_TRUE(pan_image_layout_init(&l, NULL)); 450 451 /* Image is 1x1 to test for correct alignment everywhere. */ 452 EXPECT_EQ(l.slices[0].offset, 0); 453 EXPECT_EQ(l.slices[0].row_stride, 16); 454 EXPECT_EQ(l.slices[0].afbc.header_size, 64); 455 EXPECT_EQ(l.slices[0].afbc.body_size, 32 * 8); 456 EXPECT_EQ(l.slices[0].surface_stride, 64 + (32 * 8)); 457 EXPECT_EQ(l.slices[0].size, 64 + (32 * 8)); 458} 459 460TEST(AFBCLayout, Tiled16x16Minimal) 461{ 462 uint64_t modifier = DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 463 AFBC_FORMAT_MOD_TILED | 464 AFBC_FORMAT_MOD_SPARSE); 465 466 struct pan_image_layout l = { 467 .modifier = modifier, 468 .format = PIPE_FORMAT_R8_UNORM, 469 .width = 1, 470 .height = 1, 471 .depth = 1, 472 .nr_samples = 1, 473 .dim = MALI_TEXTURE_DIMENSION_2D, 474 .nr_slices = 1 475 }; 476 477 ASSERT_TRUE(pan_image_layout_init(&l, NULL)); 478 479 /* Image is 1x1 to test for correct alignment everywhere. */ 480 EXPECT_EQ(l.slices[0].offset, 0); 481 EXPECT_EQ(l.slices[0].row_stride, 16 * 8 * 8); 482 EXPECT_EQ(l.slices[0].afbc.header_size, 4096); 483 EXPECT_EQ(l.slices[0].afbc.body_size, 32 * 8 * 8 * 8); 484 EXPECT_EQ(l.slices[0].surface_stride, 4096 + (32 * 8 * 8 * 8)); 485 EXPECT_EQ(l.slices[0].size, 4096 + (32 * 8 * 8 * 8)); 486} 487