mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-06-04 02:18:16 +02:00
etnaviv: blt: Add BLT format conversion support
Until now the BLT engine only handled same-format blits. Teach it to convert between the UNORM formats it can represent, so format-converting blits no longer fall back to the 3D blitter. The supported formats are A8R8G8B8, X8R8G8B8, A4R4G4B4, A1R5G5B5, R5G6B5, R8G8, R8 and A2R10G10B10. The BLT format names are BGRA-based, matching the PE-internal byte order, so an identity swizzle is correct for all of these except A2R10G10B10. That one the PE keeps in RGBA order, so pipe R lands in the BLT B position and vice versa. blt_conversion_needs_channel_swap() captures this and find_blt_conversion() derives the per-image swizzle. SRGB variants share the BLT format of their UNORM sibling. For example R8G8B8A8_UNORM and R8G8B8A8_SRGB both map to BLT_FORMAT_A8R8G8B8, and the sRGB handling is carried separately via img->srgb. No regressions in dEQP-GLES3.functional.fbo.blit.conversion.*. Signed-off-by: Christian Gmeiner <cgmeiner@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39879>
This commit is contained in:
parent
4e5363a66c
commit
99400f272d
1 changed files with 119 additions and 25 deletions
|
|
@ -49,6 +49,82 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
static const uint32_t blt_conversion_formats[] = {
|
||||
BLT_FORMAT_A8R8G8B8,
|
||||
BLT_FORMAT_X8R8G8B8,
|
||||
BLT_FORMAT_A4R4G4B4,
|
||||
BLT_FORMAT_A1R5G5B5,
|
||||
BLT_FORMAT_R5G6B5,
|
||||
BLT_FORMAT_R8G8,
|
||||
BLT_FORMAT_R8,
|
||||
BLT_FORMAT_A2R10G10B10,
|
||||
};
|
||||
|
||||
static inline bool
|
||||
blt_conversion_needs_channel_swap(uint32_t blt_fmt)
|
||||
{
|
||||
/* Not the PE_FORMAT_RB_SWAP property: RB_SWAP formats are stored BGRA and
|
||||
* already match the BGRA-named BLT formats (identity), and R8/R8G8 have no
|
||||
* R/B pair. A2R10G10B10 is the only whitelist format stored RGBA against a
|
||||
* BGRA-named BLT format, so it alone needs the swap.
|
||||
*/
|
||||
return blt_fmt == BLT_FORMAT_A2R10G10B10;
|
||||
}
|
||||
|
||||
struct blt_conv_swizzle {
|
||||
uint8_t src_swizzle[4];
|
||||
uint8_t dst_swizzle[4];
|
||||
};
|
||||
|
||||
static bool
|
||||
find_blt_conversion(enum pipe_format src_pipe, enum pipe_format dst_pipe,
|
||||
struct blt_conv_swizzle *swizzle)
|
||||
{
|
||||
const uint32_t src_blt = translate_blt_format(src_pipe);
|
||||
const uint32_t dst_blt = translate_blt_format(dst_pipe);
|
||||
|
||||
if (src_blt == ETNA_NO_MATCH || dst_blt == ETNA_NO_MATCH)
|
||||
return false;
|
||||
|
||||
bool src_found = false, dst_found = false;
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(blt_conversion_formats); i++) {
|
||||
if (blt_conversion_formats[i] == src_blt) src_found = true;
|
||||
if (blt_conversion_formats[i] == dst_blt) dst_found = true;
|
||||
}
|
||||
|
||||
if (!src_found || !dst_found)
|
||||
return false;
|
||||
|
||||
static const uint8_t ident[] = {0, 1, 2, 3};
|
||||
static const uint8_t rb_swap[] = {2, 1, 0, 3};
|
||||
|
||||
memcpy(swizzle->src_swizzle,
|
||||
blt_conversion_needs_channel_swap(src_blt) ? rb_swap : ident, 4);
|
||||
memcpy(swizzle->dst_swizzle,
|
||||
blt_conversion_needs_channel_swap(dst_blt) ? rb_swap : ident, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* do_blit_framebuffer(..) only sets non-identity swizzle for channels
|
||||
* missing from src - shared channels stay identity.
|
||||
*/
|
||||
static inline void
|
||||
blt_assert_swizzle_compatible(ASSERTED const struct pipe_blit_info *info)
|
||||
{
|
||||
if (!info->swizzle_enable)
|
||||
return;
|
||||
|
||||
/* Only channels present in both src and dst must be identity. */
|
||||
ASSERTED unsigned n =
|
||||
MIN2(util_format_get_nr_components(info->src.format),
|
||||
util_format_get_nr_components(info->dst.format));
|
||||
|
||||
assert(info->swizzle[0] == PIPE_SWIZZLE_X);
|
||||
assert(n < 2 || info->swizzle[1] == PIPE_SWIZZLE_Y);
|
||||
assert(n < 3 || info->swizzle[2] == PIPE_SWIZZLE_Z);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
etna_compatible_blt_format(enum pipe_format fmt)
|
||||
{
|
||||
|
|
@ -678,35 +754,46 @@ etna_try_blt_blit(struct pipe_context *pctx,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Only support same format (used tiling/detiling) blits for now.
|
||||
* TODO: figure out which different-format blits are possible and test them
|
||||
* - need to use correct swizzle
|
||||
* - set sRGB bits correctly
|
||||
* - avoid trying to convert between float/int formats?
|
||||
*/
|
||||
if (blit_info->src.format != blit_info->dst.format) {
|
||||
DBG("non matching formats: %s vs %s",
|
||||
util_format_short_name(blit_info->src.format),
|
||||
util_format_short_name(blit_info->dst.format));
|
||||
return false;
|
||||
struct blt_conv_swizzle conv_swizzle;
|
||||
bool has_conversion = false;
|
||||
enum pipe_format src_fmt = blit_info->src.format;
|
||||
enum pipe_format dst_fmt = blit_info->dst.format;
|
||||
|
||||
if (src_fmt != dst_fmt) {
|
||||
has_conversion = find_blt_conversion(src_fmt, dst_fmt, &conv_swizzle);
|
||||
|
||||
if (!has_conversion) {
|
||||
DBG("format conversion not supported: %s -> %s",
|
||||
util_format_short_name(src_fmt),
|
||||
util_format_short_name(dst_fmt));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
blt_assert_swizzle_compatible(blit_info);
|
||||
}
|
||||
|
||||
const enum pipe_format fmt = translate_format_128bit_to_64bit(blit_info->dst.format);
|
||||
src_fmt = translate_format_128bit_to_64bit(src_fmt);
|
||||
dst_fmt = translate_format_128bit_to_64bit(dst_fmt);
|
||||
|
||||
/* try to find a exact format match first */
|
||||
uint32_t format = translate_blt_format(fmt);
|
||||
/* try to find an exact format match first */
|
||||
uint32_t src_format = translate_blt_format(src_fmt);
|
||||
uint32_t dst_format = translate_blt_format(dst_fmt);
|
||||
/* When not resolving MSAA, but only doing a layout conversion, we can get
|
||||
* away with a fallback format of matching size.
|
||||
*/
|
||||
if (format == ETNA_NO_MATCH && !downsample_x && !downsample_y)
|
||||
format = etna_compatible_blt_format(fmt);
|
||||
if (format == ETNA_NO_MATCH) {
|
||||
DBG("format not supported: %s", util_format_short_name(fmt));
|
||||
if (src_format == ETNA_NO_MATCH && !downsample_x && !downsample_y)
|
||||
src_format = etna_compatible_blt_format(src_fmt);
|
||||
if (dst_format == ETNA_NO_MATCH && !downsample_x && !downsample_y)
|
||||
dst_format = etna_compatible_blt_format(dst_fmt);
|
||||
if (src_format == ETNA_NO_MATCH || dst_format == ETNA_NO_MATCH) {
|
||||
DBG("format not supported: %s -> %s",
|
||||
util_format_short_name(src_fmt), util_format_short_name(dst_fmt));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blit_info->scissor_enable ||
|
||||
blit_info->swizzle_enable ||
|
||||
(blit_info->swizzle_enable && !has_conversion) ||
|
||||
blit_info->dst.box.depth != blit_info->src.box.depth ||
|
||||
blit_info->dst.box.depth != 1) {
|
||||
return false;
|
||||
|
|
@ -758,18 +845,22 @@ etna_try_blt_blit(struct pipe_context *pctx,
|
|||
} else {
|
||||
/* Copy op */
|
||||
struct blt_imgcopy_op op = {};
|
||||
static const uint8_t ident[] = {0, 1, 2, 3};
|
||||
|
||||
op.src.addr.bo = src->bo;
|
||||
op.src.addr.offset = src_lev->offset + blit_info->src.box.z * src_lev->layer_stride;
|
||||
op.src.addr.flags = ETNA_RELOC_READ;
|
||||
op.src.bpp = util_format_get_blocksize(blit_info->src.format);
|
||||
op.src.format = format;
|
||||
op.src.format = src_format;
|
||||
op.src.srgb = util_format_is_srgb(src_fmt);
|
||||
op.src.stride = src_lev->stride;
|
||||
op.src.tiling = src->layout;
|
||||
op.src.downsample_x = downsample_x;
|
||||
op.src.downsample_y = downsample_y;
|
||||
for (unsigned x=0; x<4; ++x)
|
||||
op.src.swizzle[x] = x;
|
||||
if (has_conversion)
|
||||
memcpy(op.src.swizzle, conv_swizzle.src_swizzle, 4);
|
||||
else
|
||||
memcpy(op.src.swizzle, ident, 4);
|
||||
|
||||
if (etna_resource_level_ts_valid(src_lev)) {
|
||||
op.src.use_ts = 1;
|
||||
|
|
@ -785,11 +876,14 @@ etna_try_blt_blit(struct pipe_context *pctx,
|
|||
op.dest.addr.bo = dst->bo;
|
||||
op.dest.addr.offset = dst_lev->offset + blit_info->dst.box.z * dst_lev->layer_stride;
|
||||
op.dest.addr.flags = ETNA_RELOC_WRITE;
|
||||
op.dest.format = format;
|
||||
op.dest.format = dst_format;
|
||||
op.dest.srgb = util_format_is_srgb(dst_fmt);
|
||||
op.dest.stride = dst_lev->stride;
|
||||
op.dest.tiling = dst->layout;
|
||||
for (unsigned x=0; x<4; ++x)
|
||||
op.dest.swizzle[x] = x;
|
||||
if (has_conversion)
|
||||
memcpy(op.dest.swizzle, conv_swizzle.dst_swizzle, 4);
|
||||
else
|
||||
memcpy(op.dest.swizzle, ident, 4);
|
||||
|
||||
/* Apply R<->B swizzle when needed:
|
||||
* - Transfer blits (CPU access): swap on the linear side to convert
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue