panfrost: Adjust the format for AFBC textures on Bifrost v7

On Bifrost v7, AFBC textures can't be used with a non-identity component
order. Let's patch the format so the component order is always RGB[A].
That means we're lying about the internal format, but that shouldn't be
a problem as long as we don't share the resource.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8125>
This commit is contained in:
Boris Brezillon 2020-12-18 10:42:07 +01:00
parent 256d4a3eee
commit 44217be921
5 changed files with 99 additions and 3 deletions

View File

@ -83,13 +83,20 @@ panfrost_mfbd_raw_format(unsigned bits)
}
static void
panfrost_mfbd_rt_init_format(struct pipe_surface *surf,
panfrost_mfbd_rt_init_format(const struct panfrost_device *dev,
struct pipe_surface *surf,
struct MALI_RENDER_TARGET *rt)
{
struct panfrost_resource *rsrc = pan_resource(surf->texture);
enum pipe_format format =
drm_is_afbc(rsrc->layout.modifier) ?
panfrost_afbc_format_fixup(dev, surf->format) :
surf->format;
/* Explode details on the format */
const struct util_format_description *desc =
util_format_description(surf->format);
util_format_description(format);
/* The swizzle for rendering is inverted from texturing */
@ -149,7 +156,7 @@ panfrost_mfbd_rt_set_buf(struct pipe_surface *surf,
else
rt->writeback_msaa = MALI_MSAA_SINGLE;
panfrost_mfbd_rt_init_format(surf, rt);
panfrost_mfbd_rt_init_format(dev, surf, rt);
if (rsrc->layout.modifier == DRM_FORMAT_MOD_LINEAR) {
if (version >= 7)

View File

@ -127,7 +127,18 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
rsc->checksummed = true;
}
/* If we import an AFBC resource, it should be in a format that's
* supported, otherwise we don't know if the fixup is expected to be
* applied or not. In practice that's not a problem if the buffer has
* been exported by the GPU because the same constraint applies to both
* ends, but we might have issues if the exporter is a different piece
* of hardware (VPU?) that supports the BGR variants.
*/
assert(!drm_is_afbc(whandle->modifier) ||
!panfrost_afbc_format_needs_fixup(dev, rsc->internal_format));
if (drm_is_afbc(whandle->modifier)) {
unsigned tile_w =
panfrost_block_dim(whandle->modifier, true, 0);
unsigned tile_h =
@ -163,6 +174,16 @@ panfrost_resource_get_handle(struct pipe_screen *pscreen,
struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
struct renderonly_scanout *scanout = rsrc->scanout;
/* If we export an AFBC resource, it should be in a format that's
* supported, otherwise the importer has no clue about the format fixup
* done internally. In practice that shouldn't be an issue for GPU
* buffers because the same constraint applies to both ends, but we
* might have issues if the importer is a different piece of hardware
* that supports BGR variants.
*/
assert(!drm_is_afbc(rsrc->layout.modifier) ||
!panfrost_afbc_format_needs_fixup(dev, rsrc->internal_format));
handle->modifier = rsrc->layout.modifier;
rsrc->modifier_constant = true;
@ -519,6 +540,14 @@ panfrost_should_afbc(struct panfrost_device *dev, const struct panfrost_resource
if (pres->base.width0 <= 16 && pres->base.height0 <= 16)
return false;
/* AFBC(BGR) is not natively supported on Bifrost v7+. When we don't
* share the buffer we can fake those formats since we're in control
* of the format/swizzle we apply to the textures/RTs.
*/
if (panfrost_afbc_format_needs_fixup(dev, pres->internal_format) &&
(pres->base.bind & (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)))
return false;
/* Otherwise, we'd prefer AFBC as it is dramatically more efficient
* than linear or usually even u-interleaved */
return true;

View File

@ -140,3 +140,51 @@ panfrost_afbc_can_ytr(enum pipe_format format)
/* The fourth channel if it exists doesn't matter */
return desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB;
}
bool
panfrost_afbc_format_needs_fixup(const struct panfrost_device *dev,
enum pipe_format format)
{
if (dev->arch < 7)
return false;
const struct util_format_description *desc =
util_format_description(format);
bool identity_swizzle = true;
for (unsigned c = 0; c < desc->nr_channels; c++) {
if (desc->swizzle[c] != c) {
identity_swizzle = false;
break;
}
}
if (identity_swizzle ||
desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS)
return false;
return true;
}
enum pipe_format
panfrost_afbc_format_fixup(const struct panfrost_device *dev,
enum pipe_format format)
{
if (!panfrost_afbc_format_needs_fixup(dev, format))
return format;
const struct util_format_description *desc =
util_format_description(format);
switch (format) {
case PIPE_FORMAT_B8G8R8_UNORM:
return PIPE_FORMAT_R8G8B8_UNORM;
case PIPE_FORMAT_B5G6R5_UNORM:
return PIPE_FORMAT_R5G6B5_UNORM;
default:
if (util_format_is_rgba8_variant(desc))
return PIPE_FORMAT_R8G8B8A8_UNORM;
unreachable("Invalid format");
}
}

View File

@ -414,6 +414,10 @@ panfrost_new_texture(const struct panfrost_device *dev,
const struct panfrost_ptr *payload)
{
unsigned swizzle = panfrost_translate_swizzle_4(user_swizzle);
if (drm_is_afbc(layout->modifier))
format = panfrost_afbc_format_fixup(dev, format);
const struct util_format_description *desc =
util_format_description(format);

View File

@ -112,6 +112,14 @@ panfrost_afbc_header_size(unsigned width, unsigned height);
bool
panfrost_afbc_can_ytr(enum pipe_format format);
bool
panfrost_afbc_format_needs_fixup(const struct panfrost_device *dev,
enum pipe_format format);
enum pipe_format
panfrost_afbc_format_fixup(const struct panfrost_device *dev,
enum pipe_format format);
unsigned
panfrost_block_dim(uint64_t modifier, bool width, unsigned plane);