panfrost: Fix WRITES_GLOBAL bit
[mesa.git] / src / gallium / drivers / panfrost / pan_resource.c
index 8226b4b3c3e279b64d7d0d6292c0cdbfc547ac01..a34656b5bdfa3a96516b4b043731ae068cd68b75 100644 (file)
@@ -218,10 +218,42 @@ panfrost_create_scanout_res(struct pipe_screen *screen,
                             uint64_t modifier)
 {
         struct panfrost_device *dev = pan_device(screen);
-        struct pipe_resource scanout_templat = *template;
         struct renderonly_scanout *scanout;
         struct winsys_handle handle;
         struct pipe_resource *res;
+        struct pipe_resource scanout_templat = *template;
+
+        /* Tiled formats need to be tile aligned */
+        if (modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) {
+                scanout_templat.width0 = ALIGN_POT(template->width0, 16);
+                scanout_templat.height0 = ALIGN_POT(template->height0, 16);
+        }
+
+        /* AFBC formats need a header. Thankfully we don't care about the
+         * stride so we can just use wonky dimensions as long as the right
+         * number of bytes are allocated at the end of the day... this implies
+         * that stride/pitch is invalid for AFBC buffers */
+
+        if (drm_is_afbc(modifier)) {
+                /* Space for the header. We need to keep vaguely similar
+                 * dimensions because... reasons... to allocate with renderonly
+                 * as a dumb buffer. To do so, after the usual 16x16 alignment,
+                 * we add on extra rows for the header. The order of operations
+                 * matters here, the extra rows of padding can in fact be
+                 * needed and missing them can lead to faults. */
+
+                unsigned header_size = panfrost_afbc_header_size(
+                                template->width0, template->height0);
+
+                unsigned pitch = ALIGN_POT(template->width0, 16) *
+                        util_format_get_blocksize(template->format);
+
+                unsigned header_rows =
+                        DIV_ROUND_UP(header_size, pitch);
+
+                scanout_templat.width0 = ALIGN_POT(template->width0, 16);
+                scanout_templat.height0 = ALIGN_POT(template->height0, 16) + header_rows;
+        }
 
         scanout = renderonly_scanout_for_resource(&scanout_templat,
                         dev->ro, &handle);
@@ -277,7 +309,7 @@ panfrost_setup_slices(struct panfrost_resource *pres, size_t *bo_size)
         bool afbc = drm_is_afbc(pres->modifier);
         bool tiled = pres->modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
         bool linear = pres->modifier == DRM_FORMAT_MOD_LINEAR;
-        bool should_align = renderable || tiled;
+        bool should_align = renderable || tiled || afbc;
 
         /* We don't know how to specify a 2D stride for 3D textures */
 
@@ -382,7 +414,9 @@ panfrost_setup_slices(struct panfrost_resource *pres, size_t *bo_size)
  * that the contents frequently change, tiling will be a loss.
  *
  * Due to incomplete information on some platforms, we may need to force tiling
- * in some cases */
+ * in some cases.
+ *
+ * On platforms where it is supported, AFBC is even better. */
 
 static bool
 panfrost_can_linear(struct panfrost_device *dev, const struct panfrost_resource *pres)
@@ -392,6 +426,53 @@ panfrost_can_linear(struct panfrost_device *dev, const struct panfrost_resource
                 (dev->quirks & (MIDGARD_SFBD | IS_BIFROST)));
 }
 
+static bool
+panfrost_should_afbc(struct panfrost_device *dev, const struct panfrost_resource *pres)
+{
+        /* AFBC resources may be rendered to, textured from, or shared across
+         * processes, but may not be used as e.g buffers */
+        const unsigned valid_binding =
+                PIPE_BIND_DEPTH_STENCIL |
+                PIPE_BIND_RENDER_TARGET |
+                PIPE_BIND_BLENDABLE |
+                PIPE_BIND_SAMPLER_VIEW |
+                PIPE_BIND_DISPLAY_TARGET |
+                PIPE_BIND_SCANOUT |
+                PIPE_BIND_SHARED;
+
+        if (pres->base.bind & ~valid_binding)
+                return false;
+
+        /* AFBC introduced with Mali T760 */
+        if (dev->quirks & MIDGARD_NO_AFBC)
+                return false;
+
+        /* AFBC<-->staging is expensive */
+        if (pres->base.usage == PIPE_USAGE_STREAM)
+                return false;
+
+        /* Only a small selection of formats are AFBC'able */
+        if (!panfrost_format_supports_afbc(pres->internal_format))
+                return false;
+
+        /* AFBC does not support layered (GLES3 style) multisampling. Use
+         * EXT_multisampled_render_to_texture instead */
+        if (pres->base.nr_samples > 1)
+                return false;
+
+        /* TODO: Is AFBC of 3D textures possible? */
+        if ((pres->base.target != PIPE_TEXTURE_2D) && (pres->base.target != PIPE_TEXTURE_RECT))
+                return false;
+
+        /* For one tile, AFBC is a loss compared to u-interleaved */
+        if (pres->base.width0 <= 16 && pres->base.height0 <= 16)
+                return false;
+
+        /* Otherwise, we'd prefer AFBC as it is dramatically more efficient
+         * than linear or usually even u-interleaved */
+        return true;
+}
+
 static bool
 panfrost_should_tile(struct panfrost_device *dev, const struct panfrost_resource *pres)
 {
@@ -400,7 +481,9 @@ panfrost_should_tile(struct panfrost_device *dev, const struct panfrost_resource
                 PIPE_BIND_RENDER_TARGET |
                 PIPE_BIND_BLENDABLE |
                 PIPE_BIND_SAMPLER_VIEW |
-                PIPE_BIND_DISPLAY_TARGET;
+                PIPE_BIND_DISPLAY_TARGET |
+                PIPE_BIND_SCANOUT |
+                PIPE_BIND_SHARED;
 
         unsigned bpp = util_format_get_blocksizebits(pres->internal_format);
 
@@ -425,7 +508,16 @@ static uint64_t
 panfrost_best_modifier(struct panfrost_device *dev,
                 const struct panfrost_resource *pres)
 {
-        if (panfrost_should_tile(dev, pres))
+        if (panfrost_should_afbc(dev, pres)) {
+                uint64_t afbc =
+                        AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+                        AFBC_FORMAT_MOD_SPARSE;
+
+                if (panfrost_afbc_can_ytr(pres->base.format))
+                        afbc |= AFBC_FORMAT_MOD_YTR;
+
+                return DRM_FORMAT_MOD_ARM_AFBC(afbc);
+        } else if (panfrost_should_tile(dev, pres))
                 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
         else
                 return DRM_FORMAT_MOD_LINEAR;