mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-30 05:40:13 +01:00
pan/layout: Test WSI import behavior on all supported format/mods
Instead of picking random formats/extents, iterate over all supported <format,modifier> for each architecture, and make sure pan_image_layout_init() fails/suceeds when it's supposed to. On success, we also make sure pan_image_layout_get_wsi_layout() returns values that match the import. Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com> Tested-by: Eric R. Smith <eric.smith@collabora.com> Reviewed-by: Eric R. Smith <eric.smith@collabora.com> Reviewed-by: Mary Guillemard <mary.guillemard@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35015>
This commit is contained in:
parent
f28b2c9e8d
commit
916f75a2a6
1 changed files with 349 additions and 73 deletions
|
|
@ -22,7 +22,10 @@
|
|||
*/
|
||||
|
||||
#include "pan_afbc.h"
|
||||
#include "pan_afrc.h"
|
||||
#include "pan_format.h"
|
||||
#include "pan_image.h"
|
||||
#include "pan_layout.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
|
@ -221,79 +224,6 @@ TEST(AFBCStride, Tiled)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
row_stride_from_wsi_pitch(unsigned row_pitch_B, unsigned width_px,
|
||||
enum pipe_format fmt, uint64_t mod)
|
||||
{
|
||||
const struct pan_image_wsi_layout wsi_l = {
|
||||
.row_pitch_B = row_pitch_B,
|
||||
.strict = true,
|
||||
};
|
||||
struct pan_image_props p = {
|
||||
.modifier = mod,
|
||||
.format = fmt,
|
||||
.extent_px = {
|
||||
.width = width_px,
|
||||
.height = 1,
|
||||
.depth = 1,
|
||||
},
|
||||
.nr_samples = 1,
|
||||
.dim = MALI_TEXTURE_DIMENSION_2D,
|
||||
.nr_slices = 1,
|
||||
.array_size = 1,
|
||||
};
|
||||
struct pan_image_layout l = {};
|
||||
|
||||
pan_image_layout_init(0, &p, &wsi_l, &l);
|
||||
|
||||
return l.slices[0].row_stride_B;
|
||||
}
|
||||
|
||||
TEST(WSI, FromWSILinear)
|
||||
{
|
||||
EXPECT_EQ(
|
||||
row_stride_from_wsi_pitch(1920 * 4, 1920, PIPE_FORMAT_R8G8B8A8_UINT,
|
||||
DRM_FORMAT_MOD_LINEAR),
|
||||
1920 * 4);
|
||||
EXPECT_EQ(row_stride_from_wsi_pitch(64, 53, PIPE_FORMAT_R8_SNORM,
|
||||
DRM_FORMAT_MOD_LINEAR),
|
||||
64);
|
||||
EXPECT_EQ(row_stride_from_wsi_pitch(64, 32, PIPE_FORMAT_ETC2_RGB8,
|
||||
DRM_FORMAT_MOD_LINEAR),
|
||||
64);
|
||||
}
|
||||
|
||||
TEST(WSI, FromWSIInterleaved)
|
||||
{
|
||||
EXPECT_EQ(
|
||||
row_stride_from_wsi_pitch(1920 * 4, 1920, PIPE_FORMAT_R8G8B8A8_UINT,
|
||||
DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED),
|
||||
1920 * 4 * 16);
|
||||
|
||||
EXPECT_EQ(
|
||||
row_stride_from_wsi_pitch(64, 53, PIPE_FORMAT_R8_SNORM,
|
||||
DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED),
|
||||
64 * 16);
|
||||
|
||||
EXPECT_EQ(
|
||||
row_stride_from_wsi_pitch(64, 32, PIPE_FORMAT_ETC2_RGB8,
|
||||
DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED),
|
||||
64 * 4);
|
||||
}
|
||||
|
||||
TEST(WSI, FromWSIAFBC)
|
||||
{
|
||||
uint64_t modifier =
|
||||
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
|
||||
AFBC_FORMAT_MOD_SPARSE | AFBC_FORMAT_MOD_YTR);
|
||||
|
||||
EXPECT_EQ(row_stride_from_wsi_pitch(1920 * 4, 1920,
|
||||
PIPE_FORMAT_R8G8B8A8_UINT, modifier),
|
||||
60 * 16);
|
||||
EXPECT_EQ(row_stride_from_wsi_pitch(64, 64, PIPE_FORMAT_R8_SNORM, modifier),
|
||||
2 * 16);
|
||||
}
|
||||
|
||||
/* dEQP-GLES3.functional.texture.format.compressed.etc1_2d_pot */
|
||||
TEST(Layout, ImplicitLayoutInterleavedETC2)
|
||||
{
|
||||
|
|
@ -562,3 +492,349 @@ TEST(AFBCLayout, Tiled16x16Minimal)
|
|||
EXPECT_EQ(l.slices[0].surface_stride_B, 4096 + (32 * 8 * 8 * 8));
|
||||
EXPECT_EQ(l.slices[0].size_B, 4096 + (32 * 8 * 8 * 8));
|
||||
}
|
||||
|
||||
static unsigned archs[] = {4, 5, 6, 7, 9, 12, 13};
|
||||
|
||||
#define IMAGE_WIDTH 4096
|
||||
#define IMAGE_HEIGHT 512
|
||||
#define IMAGE_FORMAT \
|
||||
(PAN_BIND_DEPTH_STENCIL | PAN_BIND_RENDER_TARGET | PAN_BIND_SAMPLER_VIEW | \
|
||||
PAN_BIND_STORAGE_IMAGE)
|
||||
|
||||
#define EXPECT_IMPORT_SUCCESS(__arch, __iprops, __plane, __wsi_layout, \
|
||||
__out_layout, __test_desc) \
|
||||
do { \
|
||||
bool __result = \
|
||||
pan_image_layout_init(__arch, __iprops, __wsi_layout, __out_layout); \
|
||||
EXPECT_TRUE(__result) \
|
||||
<< __test_desc \
|
||||
<< " for <format=" << util_format_name((__iprops)->format) \
|
||||
<< ",plane=" << __plane << ",mod=" << std::hex \
|
||||
<< (__iprops)->modifier << std::dec << "> rejected (arch=" << __arch \
|
||||
<< ")"; \
|
||||
\
|
||||
if (!__result) \
|
||||
break; \
|
||||
\
|
||||
struct pan_image_wsi_layout __export_wsi_layout = \
|
||||
pan_image_layout_get_wsi_layout(&iprops, &layout, 0); \
|
||||
EXPECT_TRUE(__export_wsi_layout.row_pitch_B == \
|
||||
(__wsi_layout)->row_pitch_B && \
|
||||
__export_wsi_layout.offset_B == (__wsi_layout)->offset_B) \
|
||||
<< " mismatch between import and export for <format=" \
|
||||
<< util_format_name(iprops.format) << ",plane=" << __plane \
|
||||
<< ",mod=" << std::hex << (__iprops)->modifier << std::dec \
|
||||
<< "> (arch=" << __arch << ")"; \
|
||||
} while (0)
|
||||
|
||||
#define EXPECT_IMPORT_FAIL(__arch, __iprops, __plane, __wsi_layout, \
|
||||
__out_layout, __test_desc) \
|
||||
EXPECT_FALSE( \
|
||||
pan_image_layout_init(__arch, __iprops, __wsi_layout, __out_layout)) \
|
||||
<< __test_desc \
|
||||
<< " for <format=" << util_format_name((__iprops)->format) \
|
||||
<< ",plane=" << __plane << ",mod=" << std::hex << (__iprops)->modifier \
|
||||
<< std::dec << "> not rejected (arch=" << __arch << ")"
|
||||
|
||||
static bool
|
||||
format_can_do_mod(unsigned arch, enum pipe_format format, unsigned plane_idx,
|
||||
uint64_t modifier)
|
||||
{
|
||||
if (drm_is_afbc(modifier)) {
|
||||
return pan_afbc_format(arch, format) != PAN_AFBC_MODE_INVALID;
|
||||
} else if (drm_is_afrc(modifier)) {
|
||||
return arch >= 10 && pan_format_supports_afrc(format);
|
||||
} else {
|
||||
assert(modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
|
||||
modifier == DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
get_plane_blocksize(enum pipe_format format, unsigned plane_idx)
|
||||
{
|
||||
switch (format) {
|
||||
case PIPE_FORMAT_R8G8_R8B8_UNORM:
|
||||
case PIPE_FORMAT_G8R8_B8R8_UNORM:
|
||||
case PIPE_FORMAT_R8B8_R8G8_UNORM:
|
||||
case PIPE_FORMAT_B8R8_G8R8_UNORM:
|
||||
return 2;
|
||||
case PIPE_FORMAT_R8_G8B8_420_UNORM:
|
||||
case PIPE_FORMAT_R8_B8G8_420_UNORM:
|
||||
case PIPE_FORMAT_R8_G8B8_422_UNORM:
|
||||
case PIPE_FORMAT_R8_B8G8_422_UNORM:
|
||||
return plane_idx ? 2 : 1;
|
||||
case PIPE_FORMAT_R10_G10B10_420_UNORM:
|
||||
case PIPE_FORMAT_R10_G10B10_422_UNORM:
|
||||
return plane_idx ? 10 : 5;
|
||||
case PIPE_FORMAT_R8_G8_B8_420_UNORM:
|
||||
case PIPE_FORMAT_R8_B8_G8_420_UNORM:
|
||||
return 1;
|
||||
default:
|
||||
assert(util_format_get_num_planes(format) == 1);
|
||||
return util_format_get_blocksize(format);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
offset_align_for_mod(unsigned arch, const struct pan_image_props *iprops,
|
||||
unsigned plane_idx)
|
||||
{
|
||||
uint64_t modifier = iprops->modifier;
|
||||
enum pipe_format format = iprops->format;
|
||||
|
||||
if (drm_is_afbc(modifier)) {
|
||||
return pan_afbc_header_align(arch, modifier);
|
||||
} else if (drm_is_afrc(modifier)) {
|
||||
return pan_afrc_buffer_alignment_from_modifier(modifier);
|
||||
} else {
|
||||
assert(modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
|
||||
modifier == DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
if (arch < 7)
|
||||
return 64;
|
||||
|
||||
switch (format) {
|
||||
/* For v7+, NV12/NV21/I420 have a looser alignment requirement of 16 bytes
|
||||
*/
|
||||
case PIPE_FORMAT_R8_G8B8_420_UNORM:
|
||||
case PIPE_FORMAT_G8_B8R8_420_UNORM:
|
||||
case PIPE_FORMAT_R8_G8_B8_420_UNORM:
|
||||
case PIPE_FORMAT_R8_B8_G8_420_UNORM:
|
||||
case PIPE_FORMAT_R8_G8B8_422_UNORM:
|
||||
case PIPE_FORMAT_R8_B8G8_422_UNORM:
|
||||
return 16;
|
||||
/* the 10 bit formats have even looser alignment */
|
||||
case PIPE_FORMAT_R10_G10B10_420_UNORM:
|
||||
case PIPE_FORMAT_R10_G10B10_422_UNORM:
|
||||
return 1;
|
||||
default:
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
row_align_for_mod(unsigned arch, const struct pan_image_props *iprops,
|
||||
unsigned plane_idx)
|
||||
{
|
||||
uint64_t modifier = iprops->modifier;
|
||||
enum pipe_format format = iprops->format;
|
||||
|
||||
if (drm_is_afbc(modifier)) {
|
||||
unsigned hdr_row_align =
|
||||
pan_afbc_header_row_stride_align(arch, format, modifier);
|
||||
unsigned ntiles = hdr_row_align / AFBC_HEADER_BYTES_PER_TILE;
|
||||
unsigned sb_width_el = pan_afbc_superblock_width(modifier) /
|
||||
util_format_get_blockwidth(format);
|
||||
|
||||
assert(pan_afbc_superblock_width(modifier) %
|
||||
util_format_get_blockwidth(format) ==
|
||||
0);
|
||||
return ntiles * sb_width_el * get_plane_blocksize(format, plane_idx);
|
||||
} else if (drm_is_afrc(modifier)) {
|
||||
unsigned row_align = pan_afrc_buffer_alignment_from_modifier(modifier);
|
||||
struct pan_image_block_size tile_size_px =
|
||||
pan_afrc_tile_size(format, modifier);
|
||||
|
||||
assert(row_align % tile_size_px.height == 0);
|
||||
return row_align / tile_size_px.height;
|
||||
} else {
|
||||
assert(modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
|
||||
modifier == DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
unsigned tile_height_el = modifier == DRM_FORMAT_MOD_LINEAR ? 1
|
||||
: util_format_is_compressed(format) ? 4
|
||||
: 16;
|
||||
|
||||
return DIV_ROUND_UP(offset_align_for_mod(arch, iprops, plane_idx),
|
||||
tile_height_el);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
default_wsi_row_pitch(unsigned arch, const struct pan_image_props *iprops,
|
||||
unsigned plane_idx)
|
||||
{
|
||||
uint64_t modifier = iprops->modifier;
|
||||
enum pipe_format format = iprops->format;
|
||||
unsigned fmt_blksz_B = get_plane_blocksize(format, plane_idx);
|
||||
unsigned width_px =
|
||||
util_format_get_plane_width(format, plane_idx, iprops->extent_px.width);
|
||||
|
||||
assert(width_px % util_format_get_blockwidth(format) == 0);
|
||||
|
||||
if (drm_is_afbc(modifier)) {
|
||||
unsigned sb_width_el = pan_afbc_superblock_width(modifier) /
|
||||
util_format_get_blockwidth(format);
|
||||
unsigned sb_height_el = pan_afbc_superblock_height(modifier) /
|
||||
util_format_get_blockheight(format);
|
||||
unsigned ntiles =
|
||||
DIV_ROUND_UP(width_px, pan_afbc_superblock_width(modifier));
|
||||
unsigned tile_row_size_B =
|
||||
sb_width_el * sb_height_el * fmt_blksz_B * ntiles;
|
||||
|
||||
assert(pan_afbc_superblock_width(modifier) %
|
||||
util_format_get_blockwidth(format) ==
|
||||
0);
|
||||
assert(pan_afbc_superblock_height(modifier) %
|
||||
util_format_get_blockheight(format) ==
|
||||
0);
|
||||
assert(tile_row_size_B % pan_afbc_superblock_height(modifier) == 0);
|
||||
return tile_row_size_B / pan_afbc_superblock_height(modifier);
|
||||
} else if (drm_is_afrc(modifier)) {
|
||||
struct pan_image_block_size tile_size =
|
||||
pan_afrc_tile_size(format, modifier);
|
||||
unsigned afrc_row_stride_B =
|
||||
pan_afrc_row_stride(format, modifier, width_px);
|
||||
|
||||
assert(afrc_row_stride_B % tile_size.height == 0);
|
||||
|
||||
return afrc_row_stride_B / tile_size.height;
|
||||
} else {
|
||||
assert(modifier == DRM_FORMAT_MOD_LINEAR ||
|
||||
modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED);
|
||||
|
||||
unsigned row_pitch_B =
|
||||
(width_px / util_format_get_blockwidth(format)) * fmt_blksz_B;
|
||||
struct pan_image_block_size tile_size_el = {1, 1};
|
||||
|
||||
if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
|
||||
if (util_format_is_compressed(format)) {
|
||||
tile_size_el.width = 4;
|
||||
tile_size_el.height = 4;
|
||||
} else {
|
||||
tile_size_el.width = 16;
|
||||
tile_size_el.height = 16;
|
||||
}
|
||||
}
|
||||
|
||||
assert(width_px %
|
||||
(util_format_get_blockwidth(format) * tile_size_el.width) ==
|
||||
0);
|
||||
|
||||
return row_pitch_B;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(WSI, Import)
|
||||
{
|
||||
/* We don't want to spam stderr with failure messages caused by our
|
||||
* EXPECT_FALSE() cases. */
|
||||
setenv("MESA_LOG", "null", 0);
|
||||
|
||||
struct pan_image_layout layout;
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(archs); i++) {
|
||||
unsigned arch = archs[i];
|
||||
const struct pan_format *ftable = pan_format_table(arch);
|
||||
PAN_SUPPORTED_MODIFIERS(mods);
|
||||
|
||||
for (unsigned m = 0; m < ARRAY_SIZE(mods); m++) {
|
||||
for (unsigned fmt = PIPE_FORMAT_NONE + 1; fmt < PIPE_FORMAT_COUNT;
|
||||
fmt++) {
|
||||
if (!(ftable[fmt].bind & IMAGE_FORMAT))
|
||||
continue;
|
||||
|
||||
|
||||
struct pan_image_props iprops = {
|
||||
.modifier = mods[m],
|
||||
.format = (enum pipe_format)fmt,
|
||||
.extent_px = {
|
||||
.width = IMAGE_WIDTH,
|
||||
.height = IMAGE_HEIGHT,
|
||||
},
|
||||
.nr_samples = 1,
|
||||
.dim = MALI_TEXTURE_DIMENSION_2D,
|
||||
.nr_slices = 1,
|
||||
.array_size = 1,
|
||||
.crc = false,
|
||||
};
|
||||
|
||||
/* YUV import is broken. Will be fixed once we make
|
||||
* pan_image_layout a per-plane thing and pass the
|
||||
* plane index to pan_image_layout_init(). */
|
||||
if (pan_format_is_yuv(iprops.format))
|
||||
continue;
|
||||
|
||||
bool supported = true;
|
||||
for (unsigned p = 0; p < util_format_get_num_planes(iprops.format);
|
||||
p++) {
|
||||
if (!format_can_do_mod(arch, iprops.format, p,
|
||||
iprops.modifier)) {
|
||||
supported = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!supported)
|
||||
continue;
|
||||
|
||||
if (util_format_is_compressed(iprops.format)) {
|
||||
/* We multiply the image extent by the block extent to make sure
|
||||
* things are always aligned on a block. */
|
||||
iprops.extent_px.width *=
|
||||
util_format_get_blockwidth(iprops.format);
|
||||
iprops.extent_px.height *=
|
||||
util_format_get_blockheight(iprops.format);
|
||||
}
|
||||
|
||||
for (unsigned p = 0; p < util_format_get_num_planes(iprops.format);
|
||||
p++) {
|
||||
unsigned row_align_req_B =
|
||||
row_align_for_mod(arch, &iprops, p);
|
||||
unsigned offset_align_req_B =
|
||||
offset_align_for_mod(arch, &iprops, p);
|
||||
unsigned default_row_pitch_B =
|
||||
default_wsi_row_pitch(arch, &iprops, p);
|
||||
|
||||
assert(default_row_pitch_B > row_align_req_B);
|
||||
|
||||
if (row_align_req_B > 1) {
|
||||
struct pan_image_wsi_layout wsi_layout = {
|
||||
.row_pitch_B = default_row_pitch_B + 1,
|
||||
.strict = true,
|
||||
};
|
||||
|
||||
EXPECT_IMPORT_FAIL(arch, &iprops, p, &wsi_layout, &layout,
|
||||
"unaligned WSI row pitch");
|
||||
}
|
||||
|
||||
if (offset_align_req_B > 1) {
|
||||
struct pan_image_wsi_layout wsi_layout = {
|
||||
.offset_B = 1,
|
||||
.row_pitch_B = default_row_pitch_B,
|
||||
.strict = true,
|
||||
};
|
||||
|
||||
EXPECT_IMPORT_FAIL(arch, &iprops, p, &wsi_layout, &layout,
|
||||
"unaligned WSI offset");
|
||||
}
|
||||
|
||||
/* Exact match. */
|
||||
struct pan_image_wsi_layout wsi_layout = {
|
||||
.row_pitch_B = default_row_pitch_B,
|
||||
.strict = true,
|
||||
};
|
||||
|
||||
EXPECT_IMPORT_SUCCESS(arch, &iprops, p, &wsi_layout, &layout,
|
||||
"tightly packed lines");
|
||||
|
||||
wsi_layout.row_pitch_B = default_row_pitch_B + row_align_req_B;
|
||||
EXPECT_IMPORT_SUCCESS(arch, &iprops, p, &wsi_layout, &layout,
|
||||
"lines with padding");
|
||||
|
||||
wsi_layout.row_pitch_B = default_row_pitch_B - row_align_req_B;
|
||||
EXPECT_IMPORT_FAIL(arch, &iprops, p, &wsi_layout, &layout,
|
||||
"partially aliased lines");
|
||||
|
||||
wsi_layout.row_pitch_B = default_row_pitch_B;
|
||||
wsi_layout.offset_B = offset_align_req_B;
|
||||
EXPECT_IMPORT_SUCCESS(arch, &iprops, p, &wsi_layout, &layout,
|
||||
"properly aligned offset");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue