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
TEST(BlockSize,Linear)28 TEST(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
TEST(BlockSize,UInterleavedRegular)45 TEST(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
TEST(BlockSize,UInterleavedBlockCompressed)60 TEST(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
TEST(BlockSize,AFBCFormatInvariant16x16)75 TEST(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
TEST(BlockSize,AFBCFormatInvariant32x8)97 TEST(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
TEST(BlockSize,AFBCSuperblock16x16)119 TEST(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
TEST(BlockSize,AFBCSuperblock32x8)135 TEST(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
TEST(BlockSize,AFBCSuperblock64x4)150 TEST(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 */
pan_afbc_line_stride(uint64_t modifier,uint32_t width)168 static 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 */
TEST(AFBCStride,Linear)177 TEST(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
TEST(AFBCStride,Tiled)206 TEST(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
TEST(LegacyStride,FromLegacyLinear)238 TEST(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
TEST(LegacyStride,FromLegacyInterleaved)245 TEST(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
TEST(LegacyStride,FromLegacyAFBC)258 TEST(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 */
TEST(Layout,ImplicitLayoutInterleavedETC2)270 TEST(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
TEST(Layout,ImplicitLayoutInterleavedASTC5x5)300 TEST(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
TEST(Layout,ImplicitLayoutLinearASTC5x5)327 TEST(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 */
TEST(AFBCLayout,Linear3D)354 TEST(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
TEST(AFBCLayout,Tiled16x16)394 TEST(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
TEST(AFBCLayout,Linear16x16Minimal)433 TEST(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
TEST(AFBCLayout,Tiled16x16Minimal)460 TEST(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