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