From: Louis-Francis Ratté-Boulianne <l...@collabora.com>

If PresentCompleteNotify event says the pixmap was presented
with mode PresentCompleteModeSuboptimalCopy, it means the pixmap
could possibly have been flipped instead if allocated with a
different format/modifier.

Signed-off-by: Louis-Francis Ratté-Boulianne <l...@collabora.com>
Reviewed-by: Daniel Stone <dani...@collabora.com>
Signed-off-by: Daniel Stone <dani...@collabora.com>
---
 src/egl/drivers/dri2/egl_dri2.c          |  2 ++
 src/egl/drivers/dri2/egl_dri2.h          |  2 ++
 src/egl/drivers/dri2/platform_x11_dri3.c |  3 +++
 src/glx/dri3_glx.c                       |  4 ++-
 src/loader/loader_dri3_helper.c          | 43 +++++++++++++++++++++++++++-----
 src/loader/loader_dri3_helper.h          |  1 +
 6 files changed, 48 insertions(+), 7 deletions(-)

diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 9a7e43bafb6..921d1a52931 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -885,6 +885,8 @@ dri2_setup_extensions(_EGLDisplay *disp)
    dri2_dpy->multibuffers_available =
       (dri2_dpy->dri3_major_version > 1 || (dri2_dpy->dri3_major_version == 1 
&&
                                             dri2_dpy->dri3_minor_version >= 
1)) &&
+      (dri2_dpy->present_major_version > 1 || (dri2_dpy->present_major_version 
== 1 &&
+                                               dri2_dpy->present_minor_version 
>= 1)) &&
       (dri2_dpy->image && dri2_dpy->image->base.version >= 15);
 #endif
 
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 00c4768d421..bd637f73c9d 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -202,6 +202,8 @@ struct dri2_egl_display
    bool                     multibuffers_available;
    int                      dri3_major_version;
    int                      dri3_minor_version;
+   int                      present_major_version;
+   int                      present_minor_version;
    struct loader_dri3_extensions loader_dri3_ext;
 #endif
 #endif
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c 
b/src/egl/drivers/dri2/platform_x11_dri3.c
index aee6b0cfdcc..bd328f09a09 100644
--- a/src/egl/drivers/dri2/platform_x11_dri3.c
+++ b/src/egl/drivers/dri2/platform_x11_dri3.c
@@ -569,6 +569,9 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
       free(error);
       return EGL_FALSE;
    }
+
+   dri2_dpy->present_major_version = present_query->major_version;
+   dri2_dpy->present_minor_version = present_query->minor_version;
    free(present_query);
 
    dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
index 933d5b5e181..7955da83e91 100644
--- a/src/glx/dri3_glx.c
+++ b/src/glx/dri3_glx.c
@@ -372,7 +372,9 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
    pdraw->base.psc = &psc->base;
 
    if ((psc->image && psc->image->base.version >= 15) &&
-       (pdp->dri3Major > 1 || (pdp->dri3Major == 1 && pdp->dri3Minor >= 1)))
+       (pdp->dri3Major > 1 || (pdp->dri3Major == 1 && pdp->dri3Minor >= 1)) &&
+       (pdp->presentMajor > 1 ||
+        (pdp->presentMajor == 1 && pdp->presentMinor >= 1)))
       has_multibuffer = true;
 
    (void) __glXInitialize(psc->base.dpy);
diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
index fdb3e72f3b0..8116f7ab291 100644
--- a/src/loader/loader_dri3_helper.c
+++ b/src/loader/loader_dri3_helper.c
@@ -374,6 +374,31 @@ dri3_handle_present_event(struct loader_dri3_drawable 
*draw,
          if (draw->recv_sbc > draw->send_sbc)
             draw->recv_sbc -= 0x100000000;
 
+         /* When moving from flip to copy, we assume that we can allocate in
+          * a more optimal way if we don't need to cater for the display
+          * controller.
+          */
+         if (ce->mode == XCB_PRESENT_COMPLETE_MODE_COPY &&
+             draw->last_present_mode == XCB_PRESENT_COMPLETE_MODE_FLIP) {
+            for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) {
+               if (draw->buffers[b])
+                  draw->buffers[b]->reallocate = true;
+            }
+         }
+
+#if XCB_PRESENT_MAJOR_VERSION > 1 || (XCB_PRESENT_MAJOR_VERSION == 1 && 
XCB_PRESENT_MINOR_VERSION >= 1)
+        /* If the server tells us that our allocation is suboptimal, we
+          * reallocate once.
+          */
+         if (ce->mode == XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY &&
+             draw->last_present_mode != ce->mode) {
+            for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) {
+               if (draw->buffers[b])
+                  draw->buffers[b]->reallocate = true;
+            }
+         }
+#endif
+
          draw->last_present_mode = ce->mode;
 
          if (draw->vtable->show_fps)
@@ -397,9 +422,9 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw,
          if (buf && buf->pixmap == ie->pixmap)
             buf->busy = 0;
 
-         if (buf && draw->num_back <= b && b < LOADER_DRI3_MAX_BACK &&
-             draw->cur_blit_source != b &&
-             !buf->busy) {
+         if (buf && draw->cur_blit_source != b && !buf->busy &&
+             (buf->reallocate ||
+             (draw->num_back <= b && b < LOADER_DRI3_MAX_BACK))) {
             dri3_free_render_buffer(draw, buf);
             draw->buffers[b] = NULL;
          }
@@ -881,6 +906,11 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable 
*draw,
       if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1)
          options |= XCB_PRESENT_OPTION_COPY;
 
+#if XCB_PRESENT_MAJOR_VERSION > 1 || (XCB_PRESENT_MAJOR_VERSION == 1 && 
XCB_PRESENT_MINOR_VERSION >= 1)
+      if (draw->multiplanes_available)
+         options  |= XCB_PRESENT_OPTION_SUBOPTIMAL;
+#endif
+
       back->busy = 1;
       back->last_swap = draw->send_sbc;
       xcb_present_pixmap(draw->conn,
@@ -1637,11 +1667,12 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
 
    buffer = draw->buffers[buf_id];
 
-   /* Allocate a new buffer if there isn't an old one, or if that
-    * old one is the wrong size
+   /* Allocate a new buffer if there isn't an old one, if that
+    * old one is the wrong size, or if it's suboptimal
     */
    if (!buffer || buffer->width != draw->width ||
-       buffer->height != draw->height) {
+       buffer->height != draw->height ||
+       buffer->reallocate) {
       struct loader_dri3_buffer *new_buffer;
 
       /* Allocate the new buffers
diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h
index def70426431..6d3ebe12ff2 100644
--- a/src/loader/loader_dri3_helper.h
+++ b/src/loader/loader_dri3_helper.h
@@ -61,6 +61,7 @@ struct loader_dri3_buffer {
    struct xshmfence *shm_fence; /* pointer to xshmfence object */
    bool         busy;           /* Set on swap, cleared on IdleNotify */
    bool         own_pixmap;     /* We allocated the pixmap ID, free on destroy 
*/
+   bool         reallocate;     /* Buffer should be reallocated and not reused 
*/
 
    uint32_t     num_planes;
    uint32_t     size;
-- 
2.14.3

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to