104ba72547
based on the panfrost tests. Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27616>
239 lines
7.5 KiB
C++
239 lines
7.5 KiB
C++
/*
|
|
* Copyright 2024 Alyssa Rosenzweig
|
|
* Copyright 2022 Collabora, Ltd.
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
*/
|
|
|
|
#include "layout.h"
|
|
|
|
#include "util/format/u_format.h"
|
|
#include <gtest/gtest.h>
|
|
|
|
/*
|
|
* Reference tiling algorithm, written for clarity rather than performance. See
|
|
* docs/drivers/asahi.rst for details on the format.
|
|
*/
|
|
|
|
static unsigned
|
|
z_order(unsigned x, unsigned y)
|
|
{
|
|
unsigned out = 0;
|
|
|
|
for (unsigned i = 0; i < 8; ++i) {
|
|
unsigned bit = (1 << (2 * i));
|
|
|
|
if (x & (1 << i))
|
|
out |= bit;
|
|
|
|
if (y & (1 << i))
|
|
out |= bit << 1;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
/* x/y are in blocks */
|
|
static unsigned
|
|
tiled_offset_el(struct ail_layout *layout, unsigned level, unsigned x_el,
|
|
unsigned y_el)
|
|
{
|
|
unsigned x_tl = x_el / layout->tilesize_el[level].width_el;
|
|
unsigned y_tl = y_el / layout->tilesize_el[level].height_el;
|
|
|
|
unsigned offs_x_el = x_el % layout->tilesize_el[level].width_el;
|
|
unsigned offs_y_el = y_el % layout->tilesize_el[level].height_el;
|
|
|
|
unsigned offs_in_tile_el = z_order(offs_x_el, offs_y_el);
|
|
|
|
unsigned offs_row_el =
|
|
y_tl *
|
|
align(layout->stride_el[level], layout->tilesize_el[level].width_el) *
|
|
layout->tilesize_el[level].height_el;
|
|
|
|
unsigned offs_col_el = x_tl * layout->tilesize_el[level].width_el *
|
|
layout->tilesize_el[level].height_el;
|
|
|
|
return offs_row_el + offs_col_el + offs_in_tile_el;
|
|
}
|
|
|
|
static unsigned
|
|
linear_offset_B(unsigned x_el, unsigned y_el, unsigned stride_B,
|
|
unsigned blocksize_B)
|
|
{
|
|
return (stride_B * y_el) + (x_el * blocksize_B);
|
|
}
|
|
|
|
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)
|
|
{
|
|
unsigned blocksize_B = util_format_get_blocksize(layout->format);
|
|
|
|
unsigned w_el = util_format_get_nblocksx(layout->format, w_px);
|
|
unsigned h_el = util_format_get_nblocksy(layout->format, h_px);
|
|
|
|
unsigned region_x_el = util_format_get_nblocksx(layout->format, region_x_px);
|
|
unsigned region_y_el = util_format_get_nblocksy(layout->format, region_y_px);
|
|
|
|
for (unsigned linear_y_el = 0; linear_y_el < h_el; ++linear_y_el) {
|
|
for (unsigned linear_x_el = 0; linear_x_el < w_el; ++linear_x_el) {
|
|
unsigned tiled_x_el = region_x_el + linear_x_el;
|
|
unsigned tiled_y_el = region_y_el + linear_y_el;
|
|
|
|
uint8_t *linear_ptr =
|
|
linear + linear_offset_B(linear_x_el, linear_y_el, linear_stride_B,
|
|
blocksize_B);
|
|
|
|
uint8_t *tiled_ptr =
|
|
tiled +
|
|
(blocksize_B * tiled_offset_el(layout, 0, tiled_x_el, tiled_y_el));
|
|
|
|
if (dst_is_tiled) {
|
|
memcpy(tiled_ptr, linear_ptr, blocksize_B);
|
|
} else {
|
|
memcpy(linear_ptr, tiled_ptr, blocksize_B);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Helper to build test cases for tiled texture access. This test suite compares
|
|
* the above reference tiling algorithm to the optimized algorithm used in
|
|
* production.
|
|
*/
|
|
static void
|
|
test(unsigned width, unsigned height, unsigned rx, unsigned ry, unsigned rw,
|
|
unsigned rh, unsigned linear_stride, enum pipe_format format, bool store)
|
|
{
|
|
unsigned bpp = util_format_get_blocksize(format);
|
|
struct ail_layout layout = {
|
|
.width_px = width,
|
|
.height_px = height,
|
|
.depth_px = 1,
|
|
.sample_count_sa = 1,
|
|
.levels = 1,
|
|
.tiling = AIL_TILING_TWIDDLED,
|
|
.format = format,
|
|
};
|
|
|
|
ail_make_miptree(&layout);
|
|
|
|
uint8_t *tiled = (uint8_t *)calloc(bpp, layout.size_B);
|
|
uint8_t *linear = (uint8_t *)calloc(bpp, rh * linear_stride);
|
|
uint8_t *ref =
|
|
(uint8_t *)calloc(bpp, store ? layout.size_B : (rh * linear_stride));
|
|
|
|
if (store) {
|
|
for (unsigned i = 0; i < bpp * rh * linear_stride; ++i) {
|
|
linear[i] = (i & 0xFF);
|
|
}
|
|
|
|
ail_tile(tiled, linear, &layout, 0, linear_stride, rx, ry, rw, rh);
|
|
ref_access_tiled(ref, linear, &layout, rx, ry, rw, rh, linear_stride,
|
|
true);
|
|
|
|
EXPECT_EQ(memcmp(ref, tiled, layout.size_B), 0);
|
|
} else {
|
|
for (unsigned i = 0; i < layout.size_B; ++i) {
|
|
tiled[i] = (i & 0xFF);
|
|
}
|
|
|
|
ail_detile(tiled, linear, &layout, 0, linear_stride, rx, ry, rw, rh);
|
|
ref_access_tiled(tiled, ref, &layout, rx, ry, rw, rh, linear_stride,
|
|
false);
|
|
|
|
EXPECT_EQ(memcmp(ref, linear, bpp * rh * linear_stride), 0);
|
|
}
|
|
|
|
free(ref);
|
|
free(tiled);
|
|
free(linear);
|
|
}
|
|
|
|
static void
|
|
test_ldst(unsigned width, unsigned height, unsigned rx, unsigned ry,
|
|
unsigned rw, unsigned rh, unsigned linear_stride,
|
|
enum pipe_format format)
|
|
{
|
|
test(width, height, rx, ry, rw, rh, linear_stride, format, true);
|
|
test(width, height, rx, ry, rw, rh, linear_stride, format, false);
|
|
}
|
|
|
|
TEST(Twiddling, RegularFormats)
|
|
{
|
|
test_ldst(233, 173, 0, 0, 233, 173, 233, PIPE_FORMAT_R8_UINT);
|
|
test_ldst(233, 173, 0, 0, 233, 173, 233 * 2, PIPE_FORMAT_R8G8_UINT);
|
|
test_ldst(233, 173, 0, 0, 233, 173, 233 * 4, PIPE_FORMAT_R32_UINT);
|
|
test_ldst(173, 143, 0, 0, 173, 143, 173 * 8, PIPE_FORMAT_R32G32_UINT);
|
|
test_ldst(133, 143, 0, 0, 133, 143, 133 * 16, PIPE_FORMAT_R32G32B32A32_UINT);
|
|
}
|
|
|
|
TEST(Twiddling, UnpackedStrides)
|
|
{
|
|
test_ldst(213, 17, 0, 0, 213, 17, 369 * 1, PIPE_FORMAT_R8_SINT);
|
|
test_ldst(213, 17, 0, 0, 213, 17, 369 * 2, PIPE_FORMAT_R8G8_SINT);
|
|
test_ldst(213, 17, 0, 0, 213, 17, 369 * 4, PIPE_FORMAT_R32_SINT);
|
|
test_ldst(213, 17, 0, 0, 213, 17, 369 * 8, PIPE_FORMAT_R32G32_SINT);
|
|
test_ldst(213, 17, 0, 0, 213, 17, 369 * 16, PIPE_FORMAT_R32G32B32A32_SINT);
|
|
}
|
|
|
|
TEST(Twiddling, PartialAccess)
|
|
{
|
|
test_ldst(283, 171, 3, 1, 131, 7, 369 * 1, PIPE_FORMAT_R8_UNORM);
|
|
test_ldst(283, 171, 3, 1, 131, 7, 369 * 2, PIPE_FORMAT_R8G8_UNORM);
|
|
test_ldst(283, 171, 3, 1, 131, 7, 369 * 4, PIPE_FORMAT_R32_UNORM);
|
|
test_ldst(283, 171, 3, 1, 131, 7, 369 * 8, PIPE_FORMAT_R32G32_UNORM);
|
|
test_ldst(283, 171, 3, 1, 131, 7, 369 * 16, PIPE_FORMAT_R32G32B32A32_UNORM);
|
|
}
|
|
|
|
TEST(Twiddling, ETC)
|
|
{
|
|
/* Block alignment assumed */
|
|
test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_ETC1_RGB8);
|
|
test_ldst(32, 256, 0, 0, 32, 256, 512, PIPE_FORMAT_ETC2_RGB8A1);
|
|
test_ldst(32, 512, 0, 0, 32, 512, 512, PIPE_FORMAT_ETC2_RG11_SNORM);
|
|
}
|
|
|
|
TEST(Twiddling, PartialETC)
|
|
{
|
|
/* Block alignment assumed */
|
|
test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_ETC1_RGB8);
|
|
test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_ETC2_RGB8A1);
|
|
test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_ETC2_RG11_SNORM);
|
|
}
|
|
|
|
TEST(Twiddling, DXT)
|
|
{
|
|
/* Block alignment assumed */
|
|
test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_DXT1_RGB);
|
|
test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_DXT3_RGBA);
|
|
test_ldst(32, 32, 0, 0, 32, 32, 512, PIPE_FORMAT_DXT5_RGBA);
|
|
}
|
|
|
|
TEST(Twiddling, PartialDXT)
|
|
{
|
|
/* Block alignment assumed */
|
|
test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_DXT1_RGB);
|
|
test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_DXT3_RGBA);
|
|
test_ldst(32, 32, 4, 8, 16, 12, 512, PIPE_FORMAT_DXT5_RGBA);
|
|
}
|
|
|
|
TEST(Twiddling, ASTC)
|
|
{
|
|
/* Block alignment assumed */
|
|
test_ldst(40, 40, 0, 0, 40, 40, 512, PIPE_FORMAT_ASTC_4x4);
|
|
test_ldst(50, 40, 0, 0, 50, 40, 512, PIPE_FORMAT_ASTC_5x4);
|
|
test_ldst(50, 50, 0, 0, 50, 50, 512, PIPE_FORMAT_ASTC_5x5);
|
|
}
|
|
|
|
TEST(Twiddling, PartialASTC)
|
|
{
|
|
/* Block alignment assumed */
|
|
test_ldst(40, 40, 4, 4, 16, 8, 512, PIPE_FORMAT_ASTC_4x4);
|
|
test_ldst(50, 40, 5, 4, 10, 8, 512, PIPE_FORMAT_ASTC_5x4);
|
|
test_ldst(50, 50, 5, 5, 10, 10, 512, PIPE_FORMAT_ASTC_5x5);
|
|
}
|