diff --git a/src/gallium/drivers/panfrost/pan_mfbd.c b/src/gallium/drivers/panfrost/pan_mfbd.c index 299f993ae4e..289dfa8eedb 100644 --- a/src/gallium/drivers/panfrost/pan_mfbd.c +++ b/src/gallium/drivers/panfrost/pan_mfbd.c @@ -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) diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c index 0353497f553..aafb0a9c474 100644 --- a/src/gallium/drivers/panfrost/pan_resource.c +++ b/src/gallium/drivers/panfrost/pan_resource.c @@ -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; diff --git a/src/panfrost/lib/pan_afbc.c b/src/panfrost/lib/pan_afbc.c index 7b1bfb32d9d..50b379daed6 100644 --- a/src/panfrost/lib/pan_afbc.c +++ b/src/panfrost/lib/pan_afbc.c @@ -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"); + } +} diff --git a/src/panfrost/lib/pan_texture.c b/src/panfrost/lib/pan_texture.c index 5075774d8fa..16dfc5b5783 100644 --- a/src/panfrost/lib/pan_texture.c +++ b/src/panfrost/lib/pan_texture.c @@ -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); diff --git a/src/panfrost/lib/pan_texture.h b/src/panfrost/lib/pan_texture.h index db7f90c70c9..ba6f3fbf648 100644 --- a/src/panfrost/lib/pan_texture.h +++ b/src/panfrost/lib/pan_texture.h @@ -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);