etnaviv: implement resource creation with modifier
authorLucas Stach <l.stach@pengutronix.de>
Thu, 22 Jun 2017 13:14:31 +0000 (15:14 +0200)
committerLucas Stach <l.stach@pengutronix.de>
Wed, 19 Jul 2017 14:26:50 +0000 (16:26 +0200)
This allows to create buffers with a specific tiling layout, which is primarily
used by GBM to allocate the EGL back buffers with the correct tiling/modifier
for use with the scanout engines.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
src/gallium/drivers/etnaviv/etnaviv_resource.c
src/gallium/drivers/etnaviv/etnaviv_resource.h
src/gallium/drivers/etnaviv/etnaviv_texture.c
src/gallium/drivers/etnaviv/etnaviv_transfer.c

index 63ed8bacf0a76edab5bad7290c0c59bbb2ca7814..d6cccd2dbb16fef960f9eb8c1b59a6dcb573d7b1 100644 (file)
@@ -179,7 +179,7 @@ setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY,
 /* Create a new resource object, using the given template info */
 struct pipe_resource *
 etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
-                    const struct pipe_resource *templat)
+                    uint64_t modifier, const struct pipe_resource *templat)
 {
    struct etna_screen *screen = etna_screen(pscreen);
    struct etna_resource *rsc;
@@ -231,8 +231,11 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
       struct winsys_handle handle;
 
       /* pad scanout buffer size to be compatible with the RS */
-      etna_adjust_rs_align(screen->specs.pixel_pipes,
-                           &scanout_templat.width0, &scanout_templat.height0);
+      if (modifier == DRM_FORMAT_MOD_LINEAR)
+         etna_adjust_rs_align(screen->specs.pixel_pipes, &paddingX, &paddingY);
+
+      scanout_templat.width0 = align(scanout_templat.width0, paddingX);
+      scanout_templat.height0 = align(scanout_templat.height0, paddingY);
 
       scanout = renderonly_scanout_for_resource(&scanout_templat,
                                                 screen->ro, &handle);
@@ -240,6 +243,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
          return NULL;
 
       assert(handle.type == DRM_API_HANDLE_TYPE_FD);
+      handle.modifier = modifier;
       rsc = etna_resource(pscreen->resource_from_handle(pscreen, templat,
                                                         &handle,
                                                         PIPE_HANDLE_USAGE_WRITE));
@@ -344,7 +348,89 @@ etna_resource_create(struct pipe_screen *pscreen,
    if (templat->target == PIPE_TEXTURE_3D)
       layout = ETNA_LAYOUT_LINEAR;
 
-   return etna_resource_alloc(pscreen, layout, templat);
+   /* modifier is only used for scanout surfaces, so safe to use LINEAR here */
+   return etna_resource_alloc(pscreen, layout, DRM_FORMAT_MOD_LINEAR, templat);
+}
+
+enum modifier_priority {
+   MODIFIER_PRIORITY_INVALID = 0,
+   MODIFIER_PRIORITY_LINEAR,
+   MODIFIER_PRIORITY_SPLIT_TILED,
+   MODIFIER_PRIORITY_SPLIT_SUPER_TILED,
+   MODIFIER_PRIORITY_TILED,
+   MODIFIER_PRIORITY_SUPER_TILED,
+};
+
+const uint64_t priority_to_modifier[] = {
+   [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID,
+   [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR,
+   [MODIFIER_PRIORITY_SPLIT_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED,
+   [MODIFIER_PRIORITY_SPLIT_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED,
+   [MODIFIER_PRIORITY_TILED] = DRM_FORMAT_MOD_VIVANTE_TILED,
+   [MODIFIER_PRIORITY_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
+};
+
+static uint64_t
+select_best_modifier(const struct etna_screen * screen,
+                     const uint64_t *modifiers, const unsigned count)
+{
+   enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
+
+   for (int i = 0; i < count; i++) {
+      switch (modifiers[i]) {
+      case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+         if ((screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) ||
+             !screen->specs.can_supertile)
+            break;
+         prio = MAX2(prio, MODIFIER_PRIORITY_SUPER_TILED);
+         break;
+      case DRM_FORMAT_MOD_VIVANTE_TILED:
+         if (screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer)
+            break;
+         prio = MAX2(prio, MODIFIER_PRIORITY_TILED);
+         break;
+      case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
+         if ((screen->specs.pixel_pipes < 2) || !screen->specs.can_supertile)
+            break;
+         prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_SUPER_TILED);
+         break;
+      case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
+         if (screen->specs.pixel_pipes < 2)
+            break;
+         prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_TILED);
+         break;
+      case DRM_FORMAT_MOD_LINEAR:
+         prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR);
+         break;
+      case DRM_FORMAT_MOD_INVALID:
+      default:
+         break;
+      }
+   }
+
+   return priority_to_modifier[prio];
+}
+
+static struct pipe_resource *
+etna_resource_create_modifiers(struct pipe_screen *pscreen,
+                               const struct pipe_resource *templat,
+                               const uint64_t *modifiers, int count)
+{
+   struct etna_screen *screen = etna_screen(pscreen);
+   struct pipe_resource tmpl = *templat;
+   uint64_t modifier = select_best_modifier(screen, modifiers, count);
+
+   if (modifier == DRM_FORMAT_MOD_INVALID)
+      return NULL;
+
+   /*
+    * We currently assume that all buffers allocated through this interface
+    * should be scanout enabled.
+    */
+   tmpl.bind |= PIPE_BIND_SCANOUT;
+
+   return etna_resource_alloc(pscreen, modifier_to_layout(modifier),
+                              modifier, &tmpl);
 }
 
 static void
@@ -542,6 +628,7 @@ etna_resource_screen_init(struct pipe_screen *pscreen)
 {
    pscreen->can_create_resource = etna_screen_can_create_resource;
    pscreen->resource_create = etna_resource_create;
+   pscreen->resource_create_with_modifiers = etna_resource_create_modifiers;
    pscreen->resource_from_handle = etna_resource_from_handle;
    pscreen->resource_get_handle = etna_resource_get_handle;
    pscreen->resource_changed = etna_resource_changed;
index 5f563c06adcfcc7bef7e86797990d311e856bf5a..0b135e2373b6e12c284564c73615430e3b1c1d3d 100644 (file)
@@ -151,7 +151,7 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
 
 struct pipe_resource *
 etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
-                    const struct pipe_resource *templat);
+                    uint64_t modifier, const struct pipe_resource *templat);
 
 void
 etna_resource_screen_init(struct pipe_screen *pscreen);
index 954daea7ba57c06453c57c53e5bee7e861985540..b8ebab60822eb4919a3971f9802df25f83f12f68 100644 (file)
@@ -36,6 +36,8 @@
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 
+#include <drm_fourcc.h>
+
 static void *
 etna_create_sampler_state(struct pipe_context *pipe,
                           const struct pipe_sampler_state *ss)
@@ -187,7 +189,8 @@ etna_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *prsc,
          templat.bind &= ~(PIPE_BIND_DEPTH_STENCIL | PIPE_BIND_RENDER_TARGET |
                            PIPE_BIND_BLENDABLE);
          res->texture =
-            etna_resource_alloc(pctx->screen, ETNA_LAYOUT_TILED, &templat);
+            etna_resource_alloc(pctx->screen, ETNA_LAYOUT_TILED,
+                                DRM_FORMAT_MOD_LINEAR, &templat);
       }
 
       if (!res->texture) {
index 27e1be19579a3c16bf08db55012040430901af18..6c1edd483541d5417e03b0f13e4cc1947842ae3f 100644 (file)
@@ -39,6 +39,8 @@
 #include "util/u_surface.h"
 #include "util/u_transfer.h"
 
+#include <drm_fourcc.h>
+
 /* Compute offset into a 1D/2D/3D buffer of a certain box.
  * This box must be aligned to the block width and height of the
  * underlying format. */
@@ -203,7 +205,8 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
       templ.nr_samples = 0;
       templ.bind = PIPE_BIND_RENDER_TARGET;
 
-      trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR, &templ);
+      trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR,
+                                       DRM_FORMAT_MOD_LINEAR, &templ);
       if (!trans->rsc) {
          slab_free(&ctx->transfer_pool, trans);
          return NULL;