Mesa (main): egl/wayland: use surface dma-buf feedback to allocate surface buffers

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Nov 26 20:00:50 UTC 2021


Module: Mesa
Branch: main
Commit: b5848b2dac1464f5364dc2a76bd11cac0cb5769b
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=b5848b2dac1464f5364dc2a76bd11cac0cb5769b

Author: Leandro Ribeiro <leandro.ribeiro at collabora.com>
Date:   Mon Jul 26 17:53:24 2021 -0300

egl/wayland: use surface dma-buf feedback to allocate surface buffers

As explained in "egl/wayland: add initial dma-buf feedback support", we
still don't use the per-surface dma-buf feedback. In this patch we start
to use it.

If per-surface dma-buf feedback is advertised, use it to allocate
surface buffers. Also, the dma-buf protocol states that the feedback is
resent only when the client is using a suboptimal format/modifier pair.
So listen for new per-surface feedback events and reallocate the surface
buffers based on them. We can't change the format of a buffer, but we
can pick a new modifier.

This patch is based on previous work of Scott Anderson (@ascent).

Signed-off-by: Scott Anderson <scott.anderson at collabora.com>
Signed-off-by: Leandro Ribeiro <leandro.ribeiro at collabora.com>
Reviewed-by: Daniel Stone <daniels at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11248>

---

 src/egl/drivers/dri2/egl_dri2.h         |  1 +
 src/egl/drivers/dri2/platform_wayland.c | 81 +++++++++++++++++++++++++++++++--
 2 files changed, 78 insertions(+), 4 deletions(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 948c9acb89e..c466ff83c53 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -332,6 +332,7 @@ struct dri2_egl_surface
    bool compositor_using_another_device;
    int format;
    bool resized;
+   bool received_dmabuf_feedback;
 #endif
 
 #ifdef HAVE_DRM_PLATFORM
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index b4b4325fa68..87751ada684 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -558,6 +558,13 @@ surface_dmabuf_feedback_done(void *data,
 {
    struct dri2_egl_surface *dri2_surf = data;
 
+   /* The dma-buf feedback protocol states that surface dma-buf feedback should
+    * be sent by the compositor only if its buffers are using a suboptimal pair
+    * of format and modifier. We can't change the buffer format, but we can
+    * reallocate with another modifier. So we raise this flag in order to force
+    * buffer reallocation based on the dma-buf feedback sent. */
+   dri2_surf->received_dmabuf_feedback = true;
+
    dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback);
    dri2_surf->dmabuf_feedback = dri2_surf->pending_dmabuf_feedback;
    dmabuf_feedback_init(&dri2_surf->pending_dmabuf_feedback);
@@ -878,6 +885,68 @@ create_dri_image_diff_gpu(struct dri2_egl_surface *dri2_surf,
                               &linear_mod, 1, NULL);
 }
 
+static void
+create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf,
+                                      unsigned int dri_image_format, uint32_t use_flags)
+{
+   struct dri2_egl_display *dri2_dpy =
+      dri2_egl_display(dri2_surf->base.Resource.Display);
+   int visual_idx;
+   uint64_t *modifiers;
+   unsigned int num_modifiers;
+   uint32_t flags;
+
+   /* We don't have valid dma-buf feedback, so return */
+   if (dri2_surf->dmabuf_feedback.main_device == 0)
+      return;
+
+   visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
+   assert(visual_idx != -1);
+
+   /* Iterates through the dma-buf feedback to pick a new set of modifiers. The
+    * tranches are sent in descending order of preference by the compositor, so
+    * the first set that we can pick is the best one. For now we still can't
+    * specify the target device in order to make the render device try its best
+    * to allocate memory that can be directly scanned out by the KMS device. But
+    * in the future this may change (newer versions of
+    * createImageWithModifiers). Also, we are safe to pick modifiers from
+    * tranches whose target device differs from the main device, as compositors
+    * do not expose (in dma-buf feedback tranches) formats/modifiers that are
+    * incompatible with the main device. */
+   util_dynarray_foreach(&dri2_surf->dmabuf_feedback.tranches,
+                         struct dmabuf_feedback_tranche, tranche) {
+      /* Ignore tranches that do not contain dri2_surf->format */
+      if (!BITSET_TEST(tranche->formats.formats_bitmap, visual_idx))
+         continue;
+      modifiers = util_dynarray_begin(&tranche->formats.modifiers[visual_idx]);
+      num_modifiers = util_dynarray_num_elements(&tranche->formats.modifiers[visual_idx],
+                                                 uint64_t);
+
+      /* For the purposes of this function, an INVALID modifier on
+       * its own means the modifiers aren't supported. */
+      if (num_modifiers == 0 ||
+          (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
+         num_modifiers = 0;
+         modifiers = NULL;
+      }
+
+      flags = use_flags;
+      if (tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT)
+         flags |= __DRI_IMAGE_USE_SCANOUT;
+
+      dri2_surf->back->dri_image =
+         loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
+                                 dri2_surf->base.Width,
+                                 dri2_surf->base.Height,
+                                 dri_image_format,
+                                 dri2_dpy->is_different_gpu ? 0 : flags,
+                                 modifiers, num_modifiers, NULL);
+
+      if (dri2_surf->back->dri_image)
+         return;
+   }
+}
+
 static void
 create_dri_image(struct dri2_egl_surface *dri2_surf,
                  unsigned int dri_image_format, uint32_t use_flags)
@@ -987,7 +1056,10 @@ get_back_bo(struct dri2_egl_surface *dri2_surf)
    }
 
    if (dri2_surf->back->dri_image == NULL) {
-      create_dri_image(dri2_surf, dri_image_format, use_flags);
+      if (dri2_surf->wl_dmabuf_feedback)
+         create_dri_image_from_dmabuf_feedback(dri2_surf, dri_image_format, use_flags);
+      if (dri2_surf->back->dri_image == NULL)
+         create_dri_image(dri2_surf, dri_image_format, use_flags);
       dri2_surf->back->age = 0;
    }
 
@@ -1036,9 +1108,10 @@ update_buffers(struct dri2_egl_surface *dri2_surf)
       dri2_surf->dy = dri2_surf->wl_win->dy;
    }
 
-   if (dri2_surf->resized) {
-       dri2_wl_release_buffers(dri2_surf);
-       dri2_surf->resized = false;
+   if (dri2_surf->resized || dri2_surf->received_dmabuf_feedback) {
+      dri2_wl_release_buffers(dri2_surf);
+      dri2_surf->resized = false;
+      dri2_surf->received_dmabuf_feedback = false;
    }
 
    if (get_back_bo(dri2_surf) < 0) {



More information about the mesa-commit mailing list