[Mesa-dev] [PATCH 3/3] panfrost: Add support for modifiers

Tomeu Vizoso tomeu.vizoso at collabora.com
Thu Jul 4 08:04:43 UTC 2019


Implement query_dmabuf_modifiers and resource_create_with_modifiers so
Wayland clients can share AFBC buffers with the compositor.

For now this is guarded behind the PAN_MESA_DEBUG=modifiers env var
because implementing those callbacks causes Weston to try to pass
modifiers to the Rockchip KMS driver, which currently doesn't support
modifiers, thus failing the modeset.

This has been fixed in Weston 6.0, so we can enable unconditionally once
we are confident that most people testing panfrost have upgraded.

This lays the ground for scanning out AFBC buffers, if the KMS driver
supports it.

Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
---
 src/gallium/drivers/panfrost/pan_drm.c      |  1 +
 src/gallium/drivers/panfrost/pan_resource.c | 74 ++++++++++++++++++---
 src/gallium/drivers/panfrost/pan_screen.c   | 37 +++++++++++
 src/gallium/drivers/panfrost/pan_util.h     |  7 ++
 4 files changed, 108 insertions(+), 11 deletions(-)

diff --git a/src/gallium/drivers/panfrost/pan_drm.c b/src/gallium/drivers/panfrost/pan_drm.c
index 9648ac1d452d..623793a84411 100644
--- a/src/gallium/drivers/panfrost/pan_drm.c
+++ b/src/gallium/drivers/panfrost/pan_drm.c
@@ -26,6 +26,7 @@
 #include <fcntl.h>
 #include <xf86drm.h>
 
+#include "drm-uapi/drm_fourcc.h"
 #include "drm-uapi/panfrost_drm.h"
 
 #include "util/u_memory.h"
diff --git a/src/gallium/drivers/panfrost/pan_resource.c b/src/gallium/drivers/panfrost/pan_resource.c
index 54497d3de2bb..d901d43168fb 100644
--- a/src/gallium/drivers/panfrost/pan_resource.c
+++ b/src/gallium/drivers/panfrost/pan_resource.c
@@ -34,6 +34,7 @@
 #include "drm-uapi/drm_fourcc.h"
 
 #include "state_tracker/winsys_handle.h"
+#include "util/u_drm.h"
 #include "util/u_format.h"
 #include "util/u_memory.h"
 #include "util/u_surface.h"
@@ -91,6 +92,18 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
 
 	rsc->bo = panfrost_drm_import_bo(screen, whandle->handle);
 
+	switch(whandle->modifier) {
+	case DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_ROCKCHIP):
+		rsc->layout = PAN_AFBC;
+		break;
+	case DRM_FORMAT_MOD_LINEAR:
+		rsc->layout = PAN_LINEAR;
+		break;
+	default:
+                fprintf(stderr, "unknown modifier: 0x%"PRIx64"\n", whandle->modifier);
+		assert(0);
+	}
+
         size_t bo_size;
         panfrost_setup_slices(rsc, &bo_size);
         assert(bo_size == rsc->bo->size);
@@ -106,6 +119,21 @@ panfrost_resource_from_handle(struct pipe_screen *pscreen,
         return prsc;
 }
 
+static uint64_t
+panfrost_resource_modifier(struct panfrost_resource *rsrc)
+{
+        switch (rsrc->layout) {
+        case PAN_AFBC:
+                return DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_ROCKCHIP);
+        case PAN_TILED:
+                return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
+        case PAN_LINEAR:
+                return DRM_FORMAT_MOD_LINEAR;
+        default:
+                return DRM_FORMAT_MOD_INVALID;
+        }
+}
+
 static boolean
 panfrost_resource_get_handle(struct pipe_screen *pscreen,
                              struct pipe_context *ctx,
@@ -117,7 +145,7 @@ panfrost_resource_get_handle(struct pipe_screen *pscreen,
         struct panfrost_resource *rsrc = (struct panfrost_resource *) pt;
         struct renderonly_scanout *scanout = rsrc->scanout;
 
-        handle->modifier = DRM_FORMAT_MOD_INVALID;
+        handle->modifier = panfrost_resource_modifier(rsrc);
 
 	if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
 		return FALSE;
@@ -341,7 +369,9 @@ panfrost_setup_slices(struct panfrost_resource *pres, size_t *bo_size)
 }
 
 static void
-panfrost_resource_create_bo(struct panfrost_screen *screen, struct panfrost_resource *pres)
+panfrost_resource_create_bo(struct panfrost_screen *screen,
+                            struct panfrost_resource *pres,
+                            const uint64_t *modifiers, int count)
 {
 	struct pipe_resource *res = &pres->base;
 
@@ -362,14 +392,19 @@ panfrost_resource_create_bo(struct panfrost_screen *screen, struct panfrost_reso
 
         /* Tiling textures is almost always faster, unless we only use it once */
 
+        bool can_afbc = panfrost_format_supports_afbc(res->format);
+        bool want_afbc = drm_find_modifier(DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_ROCKCHIP), modifiers, count);
+        bool want_linear = drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count);
+
 #define SCANOUT (PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET)
 
         bool is_scanout = (res->bind & SCANOUT);
         bool is_texture = (res->bind & PIPE_BIND_SAMPLER_VIEW);
+        bool is_renderable = (res->bind & PIPE_BIND_RENDER_TARGET);
         bool is_2d = res->depth0 == 1 && res->array_size == 1;
         bool is_streaming = (res->usage == PIPE_USAGE_STREAM);
 
-        bool should_tile = !is_streaming && is_texture && is_2d && !is_scanout;
+        bool should_tile = !is_streaming && is_texture && is_2d && !want_linear && !is_scanout;
 
         /* Depth/stencil can't be tiled, only linear or AFBC */
         should_tile &= !(res->bind & PIPE_BIND_DEPTH_STENCIL);
@@ -381,17 +416,20 @@ panfrost_resource_create_bo(struct panfrost_screen *screen, struct panfrost_reso
         pres->checksummed = can_checksum && should_checksum;
 
         /* Set the layout appropriately */
-        pres->layout = should_tile ? PAN_TILED : PAN_LINEAR;
+	if (want_afbc || (is_renderable && can_afbc && !is_texture))
+                pres->layout = PAN_AFBC;
+        else
+                pres->layout = should_tile ? PAN_TILED : PAN_LINEAR;
 
         size_t bo_size;
-
         panfrost_setup_slices(pres, &bo_size);
         pres->bo = panfrost_drm_create_bo(screen, bo_size, 0);
 }
 
 static struct pipe_resource *
-panfrost_resource_create(struct pipe_screen *screen,
-                         const struct pipe_resource *template)
+panfrost_resource_create_with_modifiers(struct pipe_screen *screen,
+                                        const struct pipe_resource *template,
+                                        const uint64_t *modifiers, int count)
 {
         /* Make sure we're familiar */
         switch (template->target) {
@@ -418,13 +456,16 @@ panfrost_resource_create(struct pipe_screen *screen,
 
         util_range_init(&so->valid_buffer_range);
 
-        panfrost_resource_create_bo(pscreen, so);
+        panfrost_resource_create_bo(pscreen, so, modifiers, count);
 
         /* Set up the "scanout resource" (the dmabuf export of our buffer to
          * the KMS handle) if the buffer might ever have
          * resource_get_handle(WINSYS_HANDLE_TYPE_KMS) called on it.
+         * create_with_modifiers() doesn't give us usage flags, so we have to
+         * assume that all calls with modifiers are scanout-possible.
          */
-        if (template->bind & PIPE_BIND_SCANOUT) {
+        if (((template->bind & PIPE_BIND_SCANOUT) ||
+             !(count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID))) {
                 so->scanout =
                         renderonly_scanout_for_resource(&so->base, pscreen->ro, NULL);
                 if (!so->scanout) {
@@ -436,6 +477,14 @@ panfrost_resource_create(struct pipe_screen *screen,
         return (struct pipe_resource *)so;
 }
 
+static struct pipe_resource *
+panfrost_resource_create(struct pipe_screen *screen,
+                         const struct pipe_resource *template)
+{
+	const uint64_t mod = DRM_FORMAT_MOD_INVALID;
+	return panfrost_resource_create_with_modifiers(screen, template, &mod, 1);
+}
+
 void
 panfrost_bo_reference(struct panfrost_bo *bo)
 {
@@ -779,8 +828,11 @@ static const struct u_transfer_vtbl transfer_vtbl = {
 void
 panfrost_resource_screen_init(struct panfrost_screen *pscreen)
 {
-        //pscreen->base.resource_create_with_modifiers =
-        //        panfrost_resource_create_with_modifiers;
+        if (pan_debug & PAN_DBG_MODIFIERS) {
+                pscreen->base.resource_create_with_modifiers =
+                        panfrost_resource_create_with_modifiers;
+        }
+
         pscreen->base.resource_create = u_transfer_helper_resource_create;
         pscreen->base.resource_destroy = u_transfer_helper_resource_destroy;
         pscreen->base.resource_from_handle = panfrost_resource_from_handle;
diff --git a/src/gallium/drivers/panfrost/pan_screen.c b/src/gallium/drivers/panfrost/pan_screen.c
index d53a906838eb..02b65e068c30 100644
--- a/src/gallium/drivers/panfrost/pan_screen.c
+++ b/src/gallium/drivers/panfrost/pan_screen.c
@@ -57,6 +57,7 @@
 static const struct debug_named_value debug_options[] = {
 	{"msgs",      PAN_DBG_MSGS,	"Print debug messages"},
 	{"trace",     PAN_DBG_TRACE,    "Trace the command stream"},
+	{"modifiers", PAN_DBG_MODIFIERS,"Enable modifiers support"},
 	DEBUG_NAMED_VALUE_END
 };
 
@@ -559,6 +560,38 @@ panfrost_screen_get_compiler_options(struct pipe_screen *pscreen,
         return &midgard_nir_options;
 }
 
+const uint64_t supported_modifiers[] = {
+   DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_ROCKCHIP),
+   DRM_FORMAT_MOD_LINEAR,
+};
+
+static void
+panfrost_query_dmabuf_modifiers(struct pipe_screen *pscreen,
+                                enum pipe_format format, int max,
+                                uint64_t *modifiers,
+                                unsigned int *external_only, int *count)
+{
+   int i, num_modifiers = 0;
+
+   if (max > ARRAY_SIZE(supported_modifiers))
+      max = ARRAY_SIZE(supported_modifiers);
+
+   if (!max) {
+      modifiers = NULL;
+      max = ARRAY_SIZE(supported_modifiers);
+   }
+
+   for (i = 0; num_modifiers < max; i++) {
+      if (modifiers)
+         modifiers[num_modifiers] = supported_modifiers[i];
+      if (external_only)
+         external_only[num_modifiers] = util_format_is_yuv(format) ? 1 : 0;
+      num_modifiers++;
+   }
+
+   *count = num_modifiers;
+}
+
 struct pipe_screen *
 panfrost_create_screen(int fd, struct renderonly *ro)
 {
@@ -599,6 +632,10 @@ panfrost_create_screen(int fd, struct renderonly *ro)
         screen->base.fence_reference = panfrost_fence_reference;
         screen->base.fence_finish = panfrost_fence_finish;
 
+        if (pan_debug & PAN_DBG_MODIFIERS) {
+                screen->base.query_dmabuf_modifiers = panfrost_query_dmabuf_modifiers;
+        }
+
 	screen->last_fragment_flushed = true;
         screen->last_job = NULL;
 
diff --git a/src/gallium/drivers/panfrost/pan_util.h b/src/gallium/drivers/panfrost/pan_util.h
index 8fd41420a486..a3a7ec3067e6 100644
--- a/src/gallium/drivers/panfrost/pan_util.h
+++ b/src/gallium/drivers/panfrost/pan_util.h
@@ -30,6 +30,7 @@
 
 #define PAN_DBG_MSGS		0x0001
 #define PAN_DBG_TRACE           0x0002
+#define PAN_DBG_MODIFIERS       0x0004
 
 extern int pan_debug;
 
@@ -38,4 +39,10 @@ extern int pan_debug;
 			fprintf(stderr, "%s:%d: "fmt, \
 				__FUNCTION__, __LINE__, ##__VA_ARGS__); } while (0)
 
+/* TODO: Pick these two up from kernel header */
+#define AFBC_FORMAT_MOD_ROCKCHIP (1ULL <<  20)
+
+#define DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED \
+       fourcc_mod_code(ARM, ((1ULL << 55) | 1))
+
 #endif /* PAN_UTIL_H */
-- 
2.20.1



More information about the mesa-dev mailing list