etnaviv: implement resource import with modifier
authorLucas Stach <l.stach@pengutronix.de>
Thu, 22 Jun 2017 10:49:17 +0000 (12:49 +0200)
committerLucas Stach <l.stach@pengutronix.de>
Wed, 19 Jul 2017 14:26:49 +0000 (16:26 +0200)
This implements resource import with modifier, deriving the correct
internal layout from the modifier and constructing a render compatible
base resource if needed.

This removes the special cases for DDX and renderonly scanout allocated
buffers, as the linear modifier is enough to trigger correct handling
of those buffers.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Wladimir J. van der Laan <laanwj@gmail.com>
Reviewed-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Acked-by: Daniel Stone <daniels@collabora.com>
src/gallium/drivers/etnaviv/etnaviv_resource.c

index e094737344b8e6cb3a08a617ba02e45b0cde53da..b1a814d4a398720c5a15898331c21379a3a988ce 100644 (file)
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 
+#include <drm_fourcc.h>
+
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
+#endif
+
+static enum etna_surface_layout modifier_to_layout(uint64_t modifier)
+{
+   switch (modifier) {
+   case DRM_FORMAT_MOD_VIVANTE_TILED:
+      return ETNA_LAYOUT_TILED;
+   case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
+      return ETNA_LAYOUT_SUPER_TILED;
+   case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
+      return ETNA_LAYOUT_MULTI_TILED;
+   case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
+      return ETNA_LAYOUT_MULTI_SUPERTILED;
+   case DRM_FORMAT_MOD_LINEAR:
+   default:
+      return ETNA_LAYOUT_LINEAR;
+   }
+}
+
 /* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status.
  * So, in a buffer of N pixels, there are N / (4 * 4) tiles.
  * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or
 /* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status.
  * So, in a buffer of N pixels, there are N / (4 * 4) tiles.
  * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or
@@ -141,6 +164,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
                     const struct pipe_resource *templat)
 {
    struct etna_screen *screen = etna_screen(pscreen);
                     const struct pipe_resource *templat)
 {
    struct etna_screen *screen = etna_screen(pscreen);
+   struct etna_resource *rsc;
    unsigned size;
 
    DBG_F(ETNA_DBG_RESOURCE_MSGS,
    unsigned size;
 
    DBG_F(ETNA_DBG_RESOURCE_MSGS,
@@ -183,8 +207,34 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
    if (templat->target != PIPE_BUFFER)
       etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
 
    if (templat->target != PIPE_BUFFER)
       etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
 
-   struct etna_resource *rsc = CALLOC_STRUCT(etna_resource);
+   if (templat->bind & PIPE_BIND_SCANOUT) {
+      struct pipe_resource scanout_templat = *templat;
+      struct renderonly_scanout *scanout;
+      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);
+
+      scanout = renderonly_scanout_for_resource(&scanout_templat,
+                                                screen->ro, &handle);
+      if (!scanout)
+         return NULL;
+
+      assert(handle.type == DRM_API_HANDLE_TYPE_FD);
+      rsc = etna_resource(pscreen->resource_from_handle(pscreen, templat,
+                                                        &handle,
+                                                        PIPE_HANDLE_USAGE_WRITE));
+      close(handle.handle);
+      if (!rsc)
+         return NULL;
+
+      rsc->scanout = scanout;
+
+      return &rsc->base;
+   }
 
 
+   rsc = CALLOC_STRUCT(etna_resource);
    if (!rsc)
       return NULL;
 
    if (!rsc)
       return NULL;
 
@@ -211,27 +261,6 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
    rsc->bo = bo;
    rsc->ts_bo = 0; /* TS is only created when first bound to surface */
 
    rsc->bo = bo;
    rsc->ts_bo = 0; /* TS is only created when first bound to surface */
 
-   if (templat->bind & PIPE_BIND_SCANOUT) {
-      struct pipe_resource scanout_templat = *templat;
-      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);
-
-      rsc->scanout = renderonly_scanout_for_resource(&scanout_templat,
-                                                     screen->ro, &handle);
-      if (!rsc->scanout)
-         goto free_rsc;
-
-      rsc->external = pscreen->resource_from_handle(pscreen, &rsc->base,
-                                                    &handle,
-                                                    PIPE_HANDLE_USAGE_WRITE);
-      close(handle.handle);
-      if (!rsc->external)
-         goto free_rsc;
-   }
-
    if (DBG_ENABLED(ETNA_DBG_ZERO)) {
       void *map = etna_bo_map(bo);
       memset(map, 0, size);
    if (DBG_ENABLED(ETNA_DBG_ZERO)) {
       void *map = etna_bo_map(bo);
       memset(map, 0, size);
@@ -368,15 +397,22 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
       goto fail;
 
    rsc->seqno = 1;
       goto fail;
 
    rsc->seqno = 1;
+   rsc->layout = modifier_to_layout(handle->modifier);
+   rsc->halign = TEXTURE_HALIGN_FOUR;
+
 
    level->width = tmpl->width0;
    level->height = tmpl->height0;
 
 
    level->width = tmpl->width0;
    level->height = tmpl->height0;
 
-   /* We will be using the RS to copy with this resource, so we must
-    * ensure that it is appropriately aligned for the RS requirements. */
-   level->padded_width = level->width;
-   level->padded_height = level->height;
-   etna_adjust_rs_align(&level->padded_width, &level->padded_height);
+   /* Determine padding of the imported resource. */
+   unsigned paddingX = 0, paddingY = 0;
+   etna_layout_multiple(rsc->layout, screen->specs.pixel_pipes,
+                        VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN),
+                        &paddingX, &paddingY, &rsc->halign);
+
+   etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
+   level->padded_width = align(level->width, paddingX);
+   level->padded_height = align(level->height, paddingY);
 
    level->layer_stride = level->stride * util_format_get_nblocksy(prsc->format,
                                                                   level->padded_height);
 
    level->layer_stride = level->stride * util_format_get_nblocksy(prsc->format,
                                                                   level->padded_height);
@@ -393,12 +429,21 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
       goto fail;
    }
 
       goto fail;
    }
 
-   if (handle->type == DRM_API_HANDLE_TYPE_SHARED && tmpl->bind & PIPE_BIND_RENDER_TARGET) {
-      /* Render targets are linear in Xorg but must be tiled
-      * here. It would be nice if dri_drawable_get_format()
-      * set scanout for these buffers too. */
+   if (rsc->layout == ETNA_LAYOUT_LINEAR) {
+      /*
+       * Both sampler and pixel pipes can't handle linear, create a compatible
+       * base resource, where we can attach the imported buffer as an external
+       * resource.
+       */
+      struct pipe_resource tiled_templat = *tmpl;
+
+      /*
+       * Remove BIND_SCANOUT to avoid recursion, as etna_resource_create uses
+       * this function to import the scanout buffer and get a tiled resource.
+       */
+      tiled_templat.bind &= ~PIPE_BIND_SCANOUT;
 
 
-      ptiled = etna_resource_create(pscreen, tmpl);
+      ptiled = etna_resource_create(pscreen, &tiled_templat);
       if (!ptiled)
          goto fail;
 
       if (!ptiled)
          goto fail;