xref: /aosp_15_r20/external/mesa3d/src/asahi/layout/tests/test-twiddling.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2024 Alyssa Rosenzweig
3  * Copyright 2022 Collabora, Ltd.
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #include "layout.h"
9 
10 #include "util/format/u_format.h"
11 #include <gtest/gtest.h>
12 
13 /*
14  * Reference tiling algorithm, written for clarity rather than performance. See
15  * docs/drivers/asahi.rst for details on the format.
16  */
17 
18 static unsigned
z_order(unsigned x,unsigned y)19 z_order(unsigned x, unsigned y)
20 {
21    unsigned out = 0;
22 
23    for (unsigned i = 0; i < 8; ++i) {
24       unsigned bit = (1 << (2 * i));
25 
26       if (x & (1 << i))
27          out |= bit;
28 
29       if (y & (1 << i))
30          out |= bit << 1;
31    }
32 
33    return out;
34 }
35 
36 /* x/y are in blocks */
37 static unsigned
tiled_offset_el(struct ail_layout * layout,unsigned level,unsigned x_el,unsigned y_el)38 tiled_offset_el(struct ail_layout *layout, unsigned level, unsigned x_el,
39                 unsigned y_el)
40 {
41    unsigned x_tl = x_el / layout->tilesize_el[level].width_el;
42    unsigned y_tl = y_el / layout->tilesize_el[level].height_el;
43 
44    unsigned offs_x_el = x_el % layout->tilesize_el[level].width_el;
45    unsigned offs_y_el = y_el % layout->tilesize_el[level].height_el;
46 
47    unsigned offs_in_tile_el = z_order(offs_x_el, offs_y_el);
48 
49    unsigned offs_row_el =
50       y_tl *
51       align(layout->stride_el[level], layout->tilesize_el[level].width_el) *
52       layout->tilesize_el[level].height_el;
53 
54    unsigned offs_col_el = x_tl * layout->tilesize_el[level].width_el *
55                           layout->tilesize_el[level].height_el;
56 
57    return offs_row_el + offs_col_el + offs_in_tile_el;
58 }
59 
60 static unsigned
linear_offset_B(unsigned x_el,unsigned y_el,unsigned stride_B,unsigned blocksize_B)61 linear_offset_B(unsigned x_el, unsigned y_el, unsigned stride_B,
62                 unsigned blocksize_B)
63 {
64    return (stride_B * y_el) + (x_el * blocksize_B);
65 }
66 
67 static void
ref_access_tiled(uint8_t * tiled,uint8_t * linear,struct ail_layout * layout,unsigned region_x_px,unsigned region_y_px,unsigned w_px,unsigned h_px,uint32_t linear_stride_B,bool dst_is_tiled)68 ref_access_tiled(uint8_t *tiled, uint8_t *linear, struct ail_layout *layout,
69                  unsigned region_x_px, unsigned region_y_px, unsigned w_px,
70                  unsigned h_px, uint32_t linear_stride_B, bool dst_is_tiled)
71 {
72    unsigned blocksize_B = util_format_get_blocksize(layout->format);
73 
74    unsigned w_el = util_format_get_nblocksx(layout->format, w_px);
75    unsigned h_el = util_format_get_nblocksy(layout->format, h_px);
76 
77    unsigned region_x_el = util_format_get_nblocksx(layout->format, region_x_px);
78    unsigned region_y_el = util_format_get_nblocksy(layout->format, region_y_px);
79 
80    for (unsigned linear_y_el = 0; linear_y_el < h_el; ++linear_y_el) {
81       for (unsigned linear_x_el = 0; linear_x_el < w_el; ++linear_x_el) {
82          unsigned tiled_x_el = region_x_el + linear_x_el;
83          unsigned tiled_y_el = region_y_el + linear_y_el;
84 
85          uint8_t *linear_ptr =
86             linear + linear_offset_B(linear_x_el, linear_y_el, linear_stride_B,
87                                      blocksize_B);
88 
89          uint8_t *tiled_ptr =
90             tiled +
91             (blocksize_B * tiled_offset_el(layout, 0, tiled_x_el, tiled_y_el));
92 
93          if (dst_is_tiled) {
94             memcpy(tiled_ptr, linear_ptr, blocksize_B);
95          } else {
96             memcpy(linear_ptr, tiled_ptr, blocksize_B);
97          }
98       }
99    }
100 }
101 
102 /*
103  * Helper to build test cases for tiled texture access. This test suite compares
104  * the above reference tiling algorithm to the optimized algorithm used in
105  * production.
106  */
107 static void
test(unsigned width,unsigned height,unsigned rx,unsigned ry,unsigned rw,unsigned rh,unsigned linear_stride,enum pipe_format format,bool store)108 test(unsigned width, unsigned height, unsigned rx, unsigned ry, unsigned rw,
109      unsigned rh, unsigned linear_stride, enum pipe_format format, bool store)
110 {
111    unsigned bpp = util_format_get_blocksize(format);
112    struct ail_layout layout = {
113       .width_px = width,
114       .height_px = height,
115       .depth_px = 1,
116       .sample_count_sa = 1,
117       .levels = 1,
118       .tiling = AIL_TILING_TWIDDLED,
119       .format = format,
120    };
121 
122    ail_make_miptree(&layout);
123 
124    uint8_t *tiled = (uint8_t *)calloc(bpp, layout.size_B);
125    uint8_t *linear = (uint8_t *)calloc(bpp, rh * linear_stride);
126    uint8_t *ref =
127       (uint8_t *)calloc(bpp, store ? layout.size_B : (rh * linear_stride));
128 
129    if (store) {
130       for (unsigned i = 0; i < bpp * rh * linear_stride; ++i) {
131          linear[i] = (i & 0xFF);
132       }
133 
134       ail_tile(tiled, linear, &layout, 0, linear_stride, rx, ry, rw, rh);
135       ref_access_tiled(ref, linear, &layout, rx, ry, rw, rh, linear_stride,
136                        true);
137 
138       EXPECT_EQ(memcmp(ref, tiled, layout.size_B), 0);
139    } else {
140       for (unsigned i = 0; i < layout.size_B; ++i) {
141          tiled[i] = (i & 0xFF);
142       }
143 
144       ail_detile(tiled, linear, &layout, 0, linear_stride, rx, ry, rw, rh);
145       ref_access_tiled(tiled, ref, &layout, rx, ry, rw, rh, linear_stride,
146                        false);
147 
148       EXPECT_EQ(memcmp(ref, linear, bpp * rh * linear_stride), 0);
149    }
150 
151    free(ref);
152    free(tiled);
153    free(linear);
154 }
155 
156 static void
test_ldst(unsigned width,unsigned height,unsigned rx,unsigned ry,unsigned rw,unsigned rh,unsigned linear_stride,enum pipe_format format)157 test_ldst(unsigned width, unsigned height, unsigned rx, unsigned ry,
158           unsigned rw, unsigned rh, unsigned linear_stride,
159           enum pipe_format format)
160 {
161    test(width, height, rx, ry, rw, rh, linear_stride, format, true);
162    test(width, height, rx, ry, rw, rh, linear_stride, format, false);
163 }
164 
TEST(Twiddling,RegularFormats)165 TEST(Twiddling, RegularFormats)
166 {
167    test_ldst(233, 173, 0, 0, 233, 173, 233, PIPE_FORMAT_R8_UINT);
168    test_ldst(233, 173, 0, 0, 233, 173, 233 * 2, PIPE_FORMAT_R8G8_UINT);
169    test_ldst(233, 173, 0, 0, 233, 173, 233 * 4, PIPE_FORMAT_R32_UINT);
170    test_ldst(173, 143, 0, 0, 173, 143, 173 * 8, PIPE_FORMAT_R32G32_UINT);
171    test_ldst(133, 143, 0, 0, 133, 143, 133 * 16, PIPE_FORMAT_R32G32B32A32_UINT);
172 }
173 
TEST(Twiddling,UnpackedStrides)174 TEST(Twiddling, UnpackedStrides)
175 {
176    test_ldst(213, 17, 0, 0, 213, 17, 369 * 1, PIPE_FORMAT_R8_SINT);
177    test_ldst(213, 17, 0, 0, 213, 17, 369 * 2, PIPE_FORMAT_R8G8_SINT);
178    test_ldst(213, 17, 0, 0, 213, 17, 369 * 4, PIPE_FORMAT_R32_SINT);
179    test_ldst(213, 17, 0, 0, 213, 17, 369 * 8, PIPE_FORMAT_R32G32_SINT);
180    test_ldst(213, 17, 0, 0, 213, 17, 369 * 16, PIPE_FORMAT_R32G32B32A32_SINT);
181 }
182 
TEST(Twiddling,PartialAccess)183 TEST(Twiddling, PartialAccess)
184 {
185    test_ldst(283, 171, 3, 1, 131, 7, 369 * 1, PIPE_FORMAT_R8_UNORM);
186    test_ldst(283, 171, 3, 1, 131, 7, 369 * 2, PIPE_FORMAT_R8G8_UNORM);
187    test_ldst(283, 171, 3, 1, 131, 7, 369 * 4, PIPE_FORMAT_R32_UNORM);
188    test_ldst(283, 171, 3, 1, 131, 7, 369 * 8, PIPE_FORMAT_R32G32_UNORM);
189    test_ldst(283, 171, 3, 1, 131, 7, 369 * 16, PIPE_FORMAT_R32G32B32A32_UNORM);
190 }
191 
TEST(Twiddling,ETC)192 TEST(Twiddling, ETC)
193 {
194    /* Block alignment assumed */
195    test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_ETC1_RGB8);
196    test_ldst(32, 256, 0, 0, 32, 256, 512, PIPE_FORMAT_ETC2_RGB8A1);
197    test_ldst(32, 512, 0, 0, 32, 512, 512, PIPE_FORMAT_ETC2_RG11_SNORM);
198 }
199 
TEST(Twiddling,PartialETC)200 TEST(Twiddling, PartialETC)
201 {
202    /* Block alignment assumed */
203    test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_ETC1_RGB8);
204    test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_ETC2_RGB8A1);
205    test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_ETC2_RG11_SNORM);
206 }
207 
TEST(Twiddling,DXT)208 TEST(Twiddling, DXT)
209 {
210    /* Block alignment assumed */
211    test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_DXT1_RGB);
212    test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_DXT3_RGBA);
213    test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_DXT5_RGBA);
214 }
215 
TEST(Twiddling,PartialDXT)216 TEST(Twiddling, PartialDXT)
217 {
218    /* Block alignment assumed */
219    test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_DXT1_RGB);
220    test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_DXT3_RGBA);
221    test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_DXT5_RGBA);
222 }
223 
TEST(Twiddling,ASTC)224 TEST(Twiddling, ASTC)
225 {
226    /* Block alignment assumed */
227    test_ldst(40, 40, 0, 0, 40, 40, 512, PIPE_FORMAT_ASTC_4x4);
228    test_ldst(50, 40, 0, 0, 50, 40, 512, PIPE_FORMAT_ASTC_5x4);
229    test_ldst(50, 50, 0, 0, 50, 50, 512, PIPE_FORMAT_ASTC_5x5);
230 }
231 
TEST(Twiddling,PartialASTC)232 TEST(Twiddling, PartialASTC)
233 {
234    /* Block alignment assumed */
235    test_ldst(40, 40, 4, 4, 16, 8, 512, PIPE_FORMAT_ASTC_4x4);
236    test_ldst(50, 40, 5, 4, 10, 8, 512, PIPE_FORMAT_ASTC_5x4);
237    test_ldst(50, 50, 5, 5, 10, 10, 512, PIPE_FORMAT_ASTC_5x5);
238 }
239