1 /*
2 * Copyright 2021 Intel Corporation
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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <gtest/gtest.h>
25 #include <inttypes.h>
26
27 #include "util/u_math.h"
28 #include "isl/isl.h"
29 #include "isl/isl_priv.h"
30
31 #define LIN_OFF(y, tw, x) ((y * tw) + x)
32 #define IMAGE_FORMAT ISL_FORMAT_R32G32B32_UINT
33 #define TILEW_IMAGE_FORMAT ISL_FORMAT_R8_UINT
34
35 enum TILE_CONV {LIN_TO_TILE, TILE_TO_LIN};
36
37 typedef uint8_t *(*swizzle_func_t)(const uint8_t *base_addr, uint32_t pitch, uint32_t x_B, uint32_t y_px);
38
39 #define TILE_COORDINATES \
40 /* x1, x2, y1, y2 */ \
41 std::make_tuple( 0, 1, 0, 1), \
42 std::make_tuple( 0, 2, 0, 1), \
43 std::make_tuple( 0, 4, 0, 1), \
44 std::make_tuple( 0, 8, 0, 8), \
45 std::make_tuple( 0, 128, 0, 32), \
46 std::make_tuple( 19, 20, 25, 32), \
47 std::make_tuple( 59, 83, 13, 32), \
48 std::make_tuple( 10, 12, 5, 8), \
49 std::make_tuple( 64, 65, 16, 17), \
50 std::make_tuple(128, 129, 0, 32), \
51 std::make_tuple(245, 521, 5, 8)
52
53 #define FULL_TILEX_COORDINATES \
54 std::make_tuple( 0, 32, 0, 8), \
55 std::make_tuple( 0, 64, 0, 16), \
56 std::make_tuple( 0, 64, 0, 32)
57
58 #define FULL_TILEY_COORDINATES \
59 std::make_tuple( 0, 8, 0, 32), \
60 std::make_tuple( 0, 16, 0, 32), \
61 std::make_tuple( 0, 16, 0, 64)
62
63 #define FULL_TILEW_COORDINATES \
64 std::make_tuple( 0, 64, 0, 64), \
65 std::make_tuple( 0, 128, 0, 64), \
66 std::make_tuple( 0, 128, 0,128)
67
68 struct tile_swizzle_ops {
69 enum isl_tiling tiling;
70 swizzle_func_t linear_to_tile_swizzle;
71 };
72
swizzle_bitops(uint32_t num,uint8_t field,uint8_t curr_ind,uint8_t swizzle_ind)73 uint32_t swizzle_bitops(uint32_t num, uint8_t field, uint8_t curr_ind, uint8_t swizzle_ind)
74 {
75 uint32_t bitmask = (1 << field) - 1;
76 uint32_t maskednum = num & (bitmask << curr_ind);
77 uint32_t bits = maskednum >> curr_ind;
78 return bits << swizzle_ind;
79 }
80
linear_to_tileY_swizzle(const uint8_t * base_addr,uint32_t pitch,uint32_t x_B,uint32_t y_px)81 uint8_t *linear_to_tileY_swizzle(const uint8_t *base_addr, uint32_t pitch, uint32_t x_B, uint32_t y_px)
82 {
83 const uint32_t cu = 7, cv = 5;
84 const uint32_t tile_id = (y_px >> cv) * (pitch >> cu) + (x_B >> cu);
85
86 /* The table below represents the mapping from coordinate (x_B, y_px) to
87 * byte offset in a 128x32px 1Bpp image:
88 *
89 * Bit ind : 11 10 9 8 7 6 5 4 3 2 1 0
90 * Tile-Y : u6 u5 u4 v4 v3 v2 v1 v0 u3 u2 u1 u0
91 */
92 uint32_t tiled_off;
93
94 tiled_off = tile_id * 4096 |
95 swizzle_bitops(x_B, 4, 0, 0) |
96 swizzle_bitops(y_px, 5, 0, 4) |
97 swizzle_bitops(x_B, 3, 4, 9);
98
99 return (uint8_t *)(base_addr + tiled_off);
100 }
101
linear_to_tile4_swizzle(const uint8_t * base_addr,uint32_t pitch,uint32_t x_B,uint32_t y_px)102 uint8_t *linear_to_tile4_swizzle(const uint8_t * base_addr, uint32_t pitch, uint32_t x_B, uint32_t y_px)
103 {
104 const uint32_t cu = 7, cv = 5;
105 const uint32_t tile_id = (y_px >> cv) * (pitch >> cu) + (x_B >> cu);
106
107 /* The table below represents the mapping from coordinate (x_B, y_px) to
108 * byte offset in a 128x32px 1Bpp image:
109 *
110 * Bit ind : 11 10 9 8 7 6 5 4 3 2 1 0
111 * Tile-Y : v4 v3 u6 v2 u5 u4 v1 v0 u3 u2 u1 u0
112 */
113 uint32_t tiled_off;
114
115 tiled_off = tile_id * 4096 |
116 swizzle_bitops(x_B, 4, 0, 0) |
117 swizzle_bitops(y_px, 2, 0, 4) |
118 swizzle_bitops(x_B, 2, 4, 6) |
119 swizzle_bitops(y_px, 1, 2, 8) |
120 swizzle_bitops(x_B, 1, 6, 9) |
121 swizzle_bitops(y_px, 2, 3, 10);
122
123 return (uint8_t *) (base_addr + tiled_off);
124 }
125
linear_to_tileX_swizzle(const uint8_t * base_addr,uint32_t pitch,uint32_t x_B,uint32_t y_px)126 uint8_t *linear_to_tileX_swizzle(const uint8_t * base_addr, uint32_t pitch, uint32_t x_B, uint32_t y_px)
127 {
128 const uint32_t cu = 9, cv = 3;
129 const uint32_t tile_id = (y_px >> cv) * (pitch >> cu) + (x_B >> cu);
130
131 /* The table below represents the mapping from coordinate (x_B, y_px) to
132 * byte offset in a 512x8px 1Bpp image:
133 *
134 * Bit ind : 11 10 9 8 7 6 5 4 3 2 1 0
135 * Tile-X : v2 v1 v0 u8 u7 u6 u5 u4 u3 u2 u1 u0
136 */
137 uint32_t tiled_off;
138
139 tiled_off = tile_id * 4096 |
140 swizzle_bitops(x_B, 9, 0, 0) |
141 swizzle_bitops(y_px, 3, 0, 9);
142
143 return (uint8_t *) (base_addr + tiled_off);
144 }
145
linear_to_tileW_swizzle(const uint8_t * base_addr,uint32_t pitch,uint32_t x_B,uint32_t y_px)146 uint8_t *linear_to_tileW_swizzle(const uint8_t *base_addr, uint32_t pitch, uint32_t x_B, uint32_t y_px)
147 {
148 /* TileW is a special case with doubled physical tile width due to HW
149 * programming requirements (see isl_tiling_get_info() in
150 * src/intel/isl/isl.c)
151 */
152 pitch /= 2;
153
154 const uint32_t cu = 6, cv = 6;
155 const uint32_t tile_id = (y_px >> cv) * (pitch >> cu) + (x_B >> cu);
156
157 /* The table below represents the mapping from coordinate (x_B, y_px) to
158 * byte offset in a 64x64px 1Bpp image:
159 *
160 * Bit ind : 11 10 9 8 7 6 5 4 3 2 1 0
161 * Tile-W : u5 u4 u3 v5 v4 v3 v2 u2 v1 u1 v0 u0
162 */
163 uint32_t tiled_off;
164
165 tiled_off = tile_id * 4096 |
166 swizzle_bitops(x_B, 1, 0, 0) |
167 swizzle_bitops(y_px, 1, 0, 1) |
168 swizzle_bitops(x_B, 1, 1, 2) |
169 swizzle_bitops(y_px, 1, 1, 3) |
170 swizzle_bitops(x_B, 1, 2, 4) |
171 swizzle_bitops(y_px, 4, 2, 5) |
172 swizzle_bitops(x_B, 3, 3, 9);
173
174 return (uint8_t *) (base_addr + tiled_off);
175 }
176
177 struct tile_swizzle_ops swizzle_opers[] = {
178 {ISL_TILING_Y0, linear_to_tileY_swizzle},
179 {ISL_TILING_4, linear_to_tile4_swizzle},
180 {ISL_TILING_X, linear_to_tileX_swizzle},
181 {ISL_TILING_W, linear_to_tileW_swizzle},
182 };
183
184 class tileTFixture: public ::testing::Test {
185
186 protected:
187 uint32_t x_max_el;
188 uint32_t y_max_el;
189
190 uint8_t *buf_dst;
191 uint8_t *buf_src;
192 uint32_t buf_dst_size_B;
193 uint32_t buf_src_size_B;
194
195 uint32_t tiled_pitch_B, tiled_height;
196 uint32_t tiled_size_B;
197 uint32_t linear_pitch_B;
198 uint32_t linear_sz;
199 uint32_t fmt_bs; /* format bytes per block */
200 TILE_CONV conv;
201 struct tile_swizzle_ops ops;
202 bool print_results;
203 struct isl_tile_info tile_info;
204
205 public:
206 void test_setup(TILE_CONV convert, enum isl_tiling tiling_fmt,
207 enum isl_format format,
208 uint32_t max_width, uint32_t max_height);
209 void TearDown();
210 uint32_t swizzle_bitops(uint32_t num, uint8_t field,
211 uint8_t curr_ind, uint8_t swizzle_ind);
212 void bounded_byte_fill(uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2);
213 void hex_oword_print(const uint8_t *buf, uint32_t size);
214 void convert_texture(uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2);
215 void compare_conv_result(uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2);
216 void run_test(uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2);
217 };
218
219 class tileYFixture : public tileTFixture,
220 public ::testing::WithParamInterface<std::tuple<int, int,
221 int, int>>
222 {};
223
224 class tile4Fixture : public tileTFixture,
225 public ::testing::WithParamInterface<std::tuple<int, int,
226 int, int>>
227 {};
228
229 class tileXFixture : public tileTFixture,
230 public ::testing::WithParamInterface<std::tuple<int, int,
231 int, int>>
232 {};
233
234 class tileWFixture : public tileTFixture,
235 public ::testing::WithParamInterface<std::tuple<int, int,
236 int, int>>
237 {};
238
test_setup(TILE_CONV convert,enum isl_tiling tiling_fmt,enum isl_format format,uint32_t max_width,uint32_t max_height)239 void tileTFixture::test_setup(TILE_CONV convert,
240 enum isl_tiling tiling_fmt,
241 enum isl_format format,
242 uint32_t max_width,
243 uint32_t max_height)
244 {
245 print_results = debug_get_bool_option("ISL_TEST_DEBUG", false);
246
247 const struct isl_format_layout *fmtl = isl_format_get_layout(format);
248 conv = convert;
249 fmt_bs = fmtl->bpb / 8;
250 ops.tiling = tiling_fmt;
251
252 isl_tiling_get_info(tiling_fmt, ISL_SURF_DIM_2D, ISL_MSAA_LAYOUT_NONE,
253 fmtl->bpb, 1 , &tile_info);
254
255 x_max_el = align(max_width, tile_info.logical_extent_el.w);
256 y_max_el = align(max_height, tile_info.logical_extent_el.h);
257
258 tiled_pitch_B = (x_max_el * (fmt_bs / (tile_info.format_bpb / 8)) /
259 tile_info.logical_extent_el.w) *
260 tile_info.phys_extent_B.w;
261 tiled_height = y_max_el / tile_info.logical_extent_el.h *
262 tile_info.phys_extent_B.h;
263 tiled_size_B = tiled_pitch_B * tiled_height;
264
265 linear_pitch_B = x_max_el * fmt_bs;
266 linear_sz = linear_pitch_B * y_max_el;
267
268 buf_dst_size_B = convert == LIN_TO_TILE ? tiled_size_B : linear_sz;
269 buf_src_size_B = convert == LIN_TO_TILE ? linear_sz : tiled_size_B;
270
271 buf_src = (uint8_t *) calloc(buf_src_size_B, sizeof(uint8_t));
272 ASSERT_TRUE(buf_src != nullptr);
273
274 buf_dst = (uint8_t *) calloc(buf_dst_size_B, sizeof(uint8_t));
275 ASSERT_TRUE(buf_src != nullptr);
276
277 for (uint8_t i = 0; i < ARRAY_SIZE(swizzle_opers); i++)
278 if (ops.tiling == swizzle_opers[i].tiling)
279 ops.linear_to_tile_swizzle = swizzle_opers[i].linear_to_tile_swizzle;
280
281 memset(buf_src, 0xcc, buf_src_size_B);
282 memset(buf_dst, 0xcc, buf_dst_size_B);
283 }
284
TearDown()285 void tileTFixture::TearDown()
286 {
287 free(buf_src);
288 buf_src = nullptr;
289
290 free(buf_dst);
291 buf_dst = nullptr;
292 }
293
bounded_byte_fill(uint32_t x1_el,uint32_t x2_el,uint32_t y1_el,uint32_t y2_el)294 void tileTFixture::bounded_byte_fill(uint32_t x1_el, uint32_t x2_el,
295 uint32_t y1_el, uint32_t y2_el)
296 {
297 for(auto y_el = y1_el; y_el < y2_el; y_el++)
298 for (auto x_b = x1_el * fmt_bs; x_b < x2_el * fmt_bs; x_b++)
299 if (conv == LIN_TO_TILE) {
300 *(buf_src + LIN_OFF(y_el, linear_pitch_B, x_b)) = LIN_OFF(y_el, linear_pitch_B, x_b)%16;
301 } else {
302 *(ops.linear_to_tile_swizzle(buf_src, tiled_pitch_B, x_b, y_el)) =
303 LIN_OFF(y_el, linear_pitch_B, x_b)%16;
304 }
305 }
306
hex_oword_print(const uint8_t * buf,uint32_t size)307 void tileTFixture::hex_oword_print(const uint8_t *buf, uint32_t size)
308 {
309 uint64_t *itr;
310 uint32_t i;
311
312 for (itr = (uint64_t *)buf, i=0; itr < (uint64_t *)(buf + size); i++) {
313 fprintf(stdout, "%.16" PRIx64 "%.16" PRIx64, util_bswap64(*(itr)), util_bswap64(*(itr+1)));
314
315 itr = itr+2;
316
317 if((i+1) % 8 == 0 && i > 0)
318 printf("\n");
319 else
320 printf(" ");
321 }
322 }
323
convert_texture(uint32_t x1_el,uint32_t x2_el,uint32_t y1_el,uint32_t y2_el)324 void tileTFixture::convert_texture(uint32_t x1_el, uint32_t x2_el, uint32_t y1_el, uint32_t y2_el)
325 {
326 if (print_results) {
327 printf("/************** Printing src ***************/\n");
328 hex_oword_print((const uint8_t *)buf_src, buf_src_size_B);
329 }
330
331 uint32_t linear_offset_B = LIN_OFF(y1_el, linear_pitch_B, x1_el * fmt_bs);
332
333 if (conv == LIN_TO_TILE)
334 isl_memcpy_linear_to_tiled(x1_el * fmt_bs, x2_el * fmt_bs, y1_el, y2_el,
335 (char *)buf_dst,
336 (const char *)buf_src + linear_offset_B,
337 tiled_pitch_B, linear_pitch_B,
338 0, ops.tiling, ISL_MEMCPY);
339 else
340 isl_memcpy_tiled_to_linear(x1_el * fmt_bs, x2_el * fmt_bs, y1_el, y2_el,
341 (char *)buf_dst + linear_offset_B,
342 (const char *)buf_src,
343 linear_pitch_B, tiled_pitch_B,
344 0, ops.tiling, ISL_MEMCPY);
345
346 if (print_results) {
347 printf("/************** Printing dest **************/\n");
348 hex_oword_print((const uint8_t *) buf_dst, buf_dst_size_B);
349 }
350 }
351
compare_conv_result(uint32_t x1_el,uint32_t x2_el,uint32_t y1_el,uint32_t y2_el)352 void tileTFixture::compare_conv_result(uint32_t x1_el, uint32_t x2_el,
353 uint32_t y1_el, uint32_t y2_el)
354 {
355 for (uint32_t y_el = 0; y_el < y_max_el; y_el++) {
356 for (uint32_t x_el = 0; x_el < x_max_el; x_el++) {
357 for (uint32_t b = 0; b < fmt_bs; b++) {
358 uint32_t x_b = x_el * fmt_bs + b;
359
360 if (x_el < x1_el || x_el >= x2_el || y_el < y1_el || y_el >= y2_el) {
361 if (conv == LIN_TO_TILE) {
362 EXPECT_EQ(*(buf_src + LIN_OFF(y_el, linear_pitch_B, x_b)), 0xcc)
363 << "Not matching for x:" << x_el << " and y:" << y_el << std::endl;
364 } else {
365 EXPECT_EQ(*(buf_dst + LIN_OFF(y_el, linear_pitch_B, x_b)), 0xcc)
366 << "Not matching for x:" << x_el << " and y:" << y_el << std::endl;
367 }
368 } else {
369 if (conv == LIN_TO_TILE) {
370 EXPECT_EQ(*(buf_src + LIN_OFF(y_el, linear_pitch_B, x_b)),
371 *(ops.linear_to_tile_swizzle(buf_dst, tiled_pitch_B, x_b, y_el)))
372 << "Not matching for x:" << x_el << " and y:" << y_el << std::endl;
373 } else {
374 EXPECT_EQ(*(buf_dst + LIN_OFF(y_el, linear_pitch_B, x_b)),
375 *(ops.linear_to_tile_swizzle(buf_src, tiled_pitch_B, x_b, y_el)))
376 << "Not matching for x:" << x_el << " and y:" << y_el << std::endl;
377 }
378 }
379 }
380 }
381 }
382 }
383
run_test(uint32_t x1,uint32_t x2,uint32_t y1,uint32_t y2)384 void tileTFixture::run_test(uint32_t x1, uint32_t x2,
385 uint32_t y1, uint32_t y2)
386 {
387 bounded_byte_fill(x1, x2, y1, y2);
388 convert_texture(x1, x2, y1, y2);
389 compare_conv_result(x1, x2, y1, y2);
390 }
391
TEST_P(tileYFixture,lintotile)392 TEST_P(tileYFixture, lintotile)
393 {
394 auto [x1, x2, y1, y2] = GetParam();
395 test_setup(LIN_TO_TILE, ISL_TILING_Y0, IMAGE_FORMAT, x2, y2);
396 if (print_results)
397 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
398 run_test(x1, x2, y1, y2);
399 }
400
TEST_P(tileYFixture,tiletolin)401 TEST_P(tileYFixture, tiletolin)
402 {
403 auto [x1, x2, y1, y2] = GetParam();
404 test_setup(TILE_TO_LIN, ISL_TILING_Y0, IMAGE_FORMAT, x2, y2);
405 if (print_results)
406 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
407 run_test(x1, x2, y1, y2);
408 }
409
TEST_P(tile4Fixture,lintotile)410 TEST_P(tile4Fixture, lintotile)
411 {
412 auto [x1, x2, y1, y2] = GetParam();
413 test_setup(LIN_TO_TILE, ISL_TILING_4, IMAGE_FORMAT, x2, y2);
414 if (print_results)
415 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
416 run_test(x1, x2, y1, y2);
417 }
418
TEST_P(tile4Fixture,tiletolin)419 TEST_P(tile4Fixture, tiletolin)
420 {
421 auto [x1, x2, y1, y2] = GetParam();
422 test_setup(TILE_TO_LIN, ISL_TILING_4, IMAGE_FORMAT, x2, y2);
423 if (print_results)
424 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
425 run_test(x1, x2, y1, y2);
426 }
427
TEST_P(tileXFixture,lintotile)428 TEST_P(tileXFixture, lintotile)
429 {
430 auto [x1, x2, y1, y2] = GetParam();
431 test_setup(LIN_TO_TILE, ISL_TILING_X, IMAGE_FORMAT, x2, y2);
432 if (print_results)
433 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
434 run_test(x1, x2, y1, y2);
435 }
436
TEST_P(tileXFixture,tiletolin)437 TEST_P(tileXFixture, tiletolin)
438 {
439 auto [x1, x2, y1, y2] = GetParam();
440 test_setup(TILE_TO_LIN, ISL_TILING_X, IMAGE_FORMAT, x2, y2);
441 if (print_results)
442 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
443 run_test(x1, x2, y1, y2);
444 }
445
TEST_P(tileWFixture,lintotile)446 TEST_P(tileWFixture, lintotile)
447 {
448 auto [x1, x2, y1, y2] = GetParam();
449 test_setup(LIN_TO_TILE, ISL_TILING_W, TILEW_IMAGE_FORMAT, x2, y2);
450 if (print_results)
451 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
452 run_test(x1, x2, y1, y2);
453 }
454
TEST_P(tileWFixture,tiletolin)455 TEST_P(tileWFixture, tiletolin)
456 {
457 auto [x1, x2, y1, y2] = GetParam();
458 test_setup(TILE_TO_LIN, ISL_TILING_W, TILEW_IMAGE_FORMAT, x2, y2);
459 if (print_results)
460 printf("Coordinates: x1=%d x2=%d y1=%d y2=%d \n", x1, x2, y1, y2);
461 run_test(x1, x2, y1, y2);
462 }
463
464
465 INSTANTIATE_TEST_SUITE_P(tileY, tileYFixture, testing::Values(TILE_COORDINATES,
466 FULL_TILEY_COORDINATES));
467 INSTANTIATE_TEST_SUITE_P(tile4, tile4Fixture, testing::Values(TILE_COORDINATES,
468 FULL_TILEY_COORDINATES));
469 INSTANTIATE_TEST_SUITE_P(tileX, tileXFixture, testing::Values(TILE_COORDINATES,
470 FULL_TILEX_COORDINATES));
471 INSTANTIATE_TEST_SUITE_P(tileW, tileWFixture, testing::Values(TILE_COORDINATES,
472 FULL_TILEW_COORDINATES));
473