[Mesa-dev] [RFC] egl: Add DRI3 support to the EGL backend.

Joonas Lahtinen joonas.lahtinen at linux.intel.com
Wed Oct 22 11:17:26 PDT 2014


Hi,

This patch introduced DRI3 support to the EGL backend.

Patch is on top of current master. With the patch you can observe
reduced CPU stress when many glViewport calls are made.

Notice that the DRI3 extension is only exposed if the DRI3 interface is
found working too instead of just existing. So you need to enable DRI3
from all three; Mesa, X driver and X server, to get the benefit.

Regards, Joonas

PS. Will be traveling over the weekend, so will react to comments on
Monday.

>From c945e777e0aaf77a5ec450cdec1cf4db89ef0c8d Mon Sep 17 00:00:00 2001
From: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Date: Wed, 22 Oct 2014 21:05:31 +0300
Subject: [PATCH] egl: Add DRI3 support to the EGL backend.

DRI3 support is needed to avoid excess buffer invalidations, because
the XCB interface doesn't supply that information through DRI2.

Signed-off-by: Daniel van der Wath <danielx.j.van.der.wath at intel.com>
Signed-off-by: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
---
 configure.ac                            |    4 +
 include/GL/internal/dri_interface.h     |    8 +
 src/egl/drivers/dri2/egl_dri2.c         |    9 +
 src/egl/drivers/dri2/egl_dri2.h         |   39 +++-
 src/egl/drivers/dri2/platform_x11.c     |  340 ++++++++++++++++++++++++++++++-
 src/egl/main/Makefile.am                |    4 +
 src/mesa/drivers/dri/common/dri_util.c  |    2 +
 src/mesa/drivers/dri/common/dri_util.h  |    1 +
 src/mesa/drivers/dri/i965/brw_context.c |   12 +-
 9 files changed, 406 insertions(+), 13 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0ed9325..308fddf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,6 +43,7 @@ VDPAU_REQUIRED=0.4.1
 WAYLAND_REQUIRED=1.2.0
 XCB_REQUIRED=1.9.3
 XCBDRI2_REQUIRED=1.8
+XCBDRI3_REQUIRED=1.8
 XCBGLX_REQUIRED=1.8.1
 XSHMFENCE_REQUIRED=1.1
 XVMC_REQUIRED=1.0.6
@@ -1557,6 +1558,9 @@ for plat in $egl_platforms; do
 
 	x11)
 		PKG_CHECK_MODULES([XCB_DRI2], [x11-xcb xcb xcb-dri2 >= $XCBDRI2_REQUIRED xcb-xfixes])
+		if test x"$enable_dri3" = "xyes"; then
+			PKG_CHECK_MODULES([XCB_DRI3], [xcb-dri3 >= $XCBDRI3_REQUIRED xcb-present])
+		fi
 		;;
 
 	drm)
diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
index 8c5ceb9..3bd9d18 100644
--- a/include/GL/internal/dri_interface.h
+++ b/include/GL/internal/dri_interface.h
@@ -83,6 +83,7 @@ typedef struct __DRIswrastExtensionRec		__DRIswrastExtension;
 typedef struct __DRIbufferRec			__DRIbuffer;
 typedef struct __DRIdri2ExtensionRec		__DRIdri2Extension;
 typedef struct __DRIdri2LoaderExtensionRec	__DRIdri2LoaderExtension;
+typedef struct __DRIdri3ExtensionRec		__DRIdri3Extension;
 typedef struct __DRI2flushExtensionRec	__DRI2flushExtension;
 typedef struct __DRI2throttleExtensionRec	__DRI2throttleExtension;
 
@@ -999,6 +1000,13 @@ struct __DRIdri2ExtensionRec {
    __DRIcreateNewScreen2Func            createNewScreen2;
 };
 
+#define __DRI_DRI3 "DRI_DRI3"
+#define __DRI_DRI3_VERSION 1
+
+struct __DRIdri3ExtensionRec {
+   __DRIextension base;
+};
+
 
 /**
  * This extension provides functionality to enable various EGLImage
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 20a7243..6024cb3 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -55,6 +55,12 @@ const __DRIuseInvalidateExtension use_invalidate = {
    .base = { __DRI_USE_INVALIDATE, 1 }
 };
 
+#ifdef HAVE_DRI3
+const __DRIdri3Extension dri3_extension = {
+   .base = { __DRI_DRI3, 1 }
+};
+#endif
+
 EGLint dri2_to_egl_attribute_map[] = {
    0,
    EGL_BUFFER_SIZE,		/* __DRI_ATTRIB_BUFFER_SIZE */
@@ -600,6 +606,9 @@ dri2_create_screen(_EGLDisplay *disp)
 	 if (strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0) {
 	    dri2_dpy->config = (__DRI2configQueryExtension *) extensions[i];
 	 }
+         if (strcmp(extensions[i]->name, __DRI_DRI3) == 0) {
+            dri2_dpy->dri3 = (__DRIdri3Extension *) extensions[i];
+         }
       }
    } else {
       assert(dri2_dpy->swrast);
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index 52f05fb..d8713df 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -35,6 +35,11 @@
 #include <X11/Xlib-xcb.h>
 #endif
 
+#ifdef HAVE_DRI3
+#include <xcb/dri3.h>
+#include <xcb/present.h>
+#endif
+
 #ifdef HAVE_WAYLAND_PLATFORM
 #include <wayland-client.h>
 #include "wayland-egl-priv.h"
@@ -74,6 +79,7 @@
 #include "eglimage.h"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define DRI2_EGL_SURFACE_NUM_BUFFERS 5
 
 struct wl_buffer;
 
@@ -150,12 +156,17 @@ struct dri2_egl_display
 
    int                       dri2_major;
    int                       dri2_minor;
+#ifdef HAVE_DRI3
+   int                       dri3_major;
+   int                       dri3_minor;
+#endif
    __DRIscreen              *dri_screen;
    int                       own_dri_screen;
    const __DRIconfig       **driver_configs;
    void                     *driver;
    const __DRIcoreExtension       *core;
    const __DRIdri2Extension       *dri2;
+   const __DRIdri3Extension       *dri3;
    const __DRIswrastExtension     *swrast;
    const __DRI2flushExtension     *flush;
    const __DRItexBufferExtension  *tex_buffer;
@@ -163,6 +174,7 @@ struct dri2_egl_display
    const __DRIrobustnessExtension *robustness;
    const __DRI2configQueryExtension *config;
    int                       fd;
+   int                       dri3_present_and_working;
 
    int                       own_device;
    int                       swap_available;
@@ -218,7 +230,7 @@ struct dri2_egl_surface
 {
    _EGLSurface          base;
    __DRIdrawable       *dri_drawable;
-   __DRIbuffer          buffers[5];
+   __DRIbuffer          buffers[DRI2_EGL_SURFACE_NUM_BUFFERS];
    int                  buffer_count;
    int                  have_fake_front;
 
@@ -229,6 +241,28 @@ struct dri2_egl_surface
    int                  bytes_per_pixel;
    xcb_gcontext_t       gc;
    xcb_gcontext_t       swapgc;
+#ifdef HAVE_DRI3
+   xcb_special_event_t *special_event;
+   xcb_present_event_t eid;
+   uint32_t *stamp;
+   uint8_t is_pixmap;
+   uint8_t flipping;
+
+   /* SBC numbers are tracked by using the serial numbers
+    * in the present request and complete events
+    */
+   uint64_t send_sbc;
+   uint64_t recv_sbc;
+
+   /* Last received UST/MSC values */
+   uint64_t ust, msc;
+
+   int num_back;
+
+   /* Serial numbers for tracking wait_for_msc events */
+   uint32_t send_msc_serial;
+   uint32_t recv_msc_serial;
+#endif
 #endif
 
 #ifdef HAVE_WAYLAND_PLATFORM
@@ -293,6 +327,9 @@ _EGL_DRIVER_TYPECAST(dri2_egl_image, _EGLImage, obj)
 
 extern const __DRIimageLookupExtension image_lookup_extension;
 extern const __DRIuseInvalidateExtension use_invalidate;
+#ifdef HAVE_DRI3
+extern const __DRIdri3Extension dri3_extension;
+#endif
 
 EGLBoolean
 dri2_load_driver(_EGLDisplay *disp);
diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
index f8c4b70..3bf0c96 100644
--- a/src/egl/drivers/dri2/platform_x11.c
+++ b/src/egl/drivers/dri2/platform_x11.c
@@ -188,6 +188,240 @@ get_xcb_screen(xcb_screen_iterator_t iter, int screen)
     return NULL;
 }
 
+#ifdef HAVE_DRI3
+/** dri3_open
+ *
+ * Wrapper around xcb_dri3_open
+ */
+static int
+dri3_open(struct dri2_egl_display *dri2_dpy,
+          Window root,
+          uint32_t provider)
+{
+   xcb_dri3_open_cookie_t       cookie;
+   xcb_dri3_open_reply_t        *reply;
+   xcb_connection_t             *c = dri2_dpy->conn;
+   int                          fd;
+
+   cookie = xcb_dri3_open(c,
+                          root,
+                          provider);
+
+   reply = xcb_dri3_open_reply(c, cookie, NULL);
+   if (!reply)
+      return -1;
+
+   if (reply->nfd != 1) {
+      free(reply);
+      return -1;
+   }
+
+   fd = xcb_dri3_open_reply_fds(c, reply)[0];
+
+   fcntl(fd, F_SETFD, FD_CLOEXEC);
+   return fd;
+}
+
+/* from glx. Called by the XCB_PRESENT_COMPLETE_NOTIFY case.
+ */
+static void
+dri3_update_num_back(struct dri2_egl_surface *priv)
+{
+   priv->num_back = 1;
+   if (priv->flipping)
+      priv->num_back++;
+   if (priv->base.SwapInterval == 0)
+      priv->num_back++;
+}
+
+/** dri3_free_render_buffer
+ *
+ * In the glx version there's some more clean up, but here we can just call releaseBuffer().
+ */
+static void
+dri3_free_render_buffer(struct dri2_egl_surface *pdraw, __DRIbuffer *buffer)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(pdraw->base.Resource.Display);
+
+   (*dri2_dpy->dri2->releaseBuffer)(dri2_dpy->dri_screen, buffer);
+}
+
+/*
+ * Process one Present event
+ */
+static void
+dri3_handle_present_event(struct dri2_egl_surface *priv, xcb_present_generic_event_t *ge)
+{
+   switch (ge->evtype) {
+   case XCB_PRESENT_CONFIGURE_NOTIFY: {
+      xcb_present_configure_notify_event_t *ce = (void *) ge;
+
+      priv->base.Width = ce->width;
+      priv->base.Height = ce->height;
+      break;
+   }
+   case XCB_PRESENT_COMPLETE_NOTIFY: {
+      xcb_present_complete_notify_event_t *ce = (void *) ge;
+
+      /* Compute the processed SBC number from the received 32-bit serial number merged
+       * with the upper 32-bits of the sent 64-bit serial number while checking for
+       * wrap
+       */
+      if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
+         priv->recv_sbc = (priv->send_sbc & 0xffffffff00000000LL) | ce->serial;
+         if (priv->recv_sbc > priv->send_sbc)
+            priv->recv_sbc -= 0x100000000;
+         switch (ce->mode) {
+         case XCB_PRESENT_COMPLETE_MODE_FLIP:
+            priv->flipping = true;
+            break;
+         case XCB_PRESENT_COMPLETE_MODE_COPY:
+            priv->flipping = false;
+            break;
+         }
+         dri3_update_num_back(priv);
+      } else {
+         priv->recv_msc_serial = ce->serial;
+      }
+      priv->ust = ce->ust;
+      priv->msc = ce->msc;
+      break;
+   }
+   case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
+      xcb_present_idle_notify_event_t *ie = (void *) ge;
+      int b;
+
+      for (b = 0; b < sizeof (priv->buffers) / sizeof (priv->buffers[0]); b++) {
+         __DRIbuffer        *buf = &priv->buffers[b];
+
+         if (buf && buf->name == ie->pixmap) {
+            /* busy is used in the glx version (in dri3_find_back()) but isn't required here */
+            //buf->busy = 0;
+
+            /* slight change from glx, these buffers are not dynamically allocated so don't 
+             * need to be NULL'd.
+             */
+            if (priv->num_back <= b && b < DRI2_EGL_SURFACE_NUM_BUFFERS) {
+               dri3_free_render_buffer(priv, buf);
+            }
+            break;
+         }
+      }
+      break;
+   }
+   default:
+      break;
+   }
+   free(ge);
+}
+
+/** dri3_flush_present_events
+ *
+ * Process any present events that have been received from the X server
+ *
+ * From glx, we additionally invalidate the drawable here if there has a been a special event.
+ */
+static void
+dri3_flush_present_events(struct dri2_egl_display *dri2_dpy, struct dri2_egl_surface *priv)
+{
+   xcb_connection_t     *c = dri2_dpy->conn;
+
+   /* Check to see if any configuration changes have occurred
+    * since we were last invoked
+    */
+   if (priv->special_event) {
+      xcb_generic_event_t    *ev;
+
+      while ((ev = xcb_poll_for_special_event(c, priv->special_event)) != NULL) {
+         xcb_present_generic_event_t *ge = (void *) ev;
+         dri3_handle_present_event(priv, ge);
+         _eglLog(_EGL_INFO, "DRI3: Invalidating buffer 0x%x\n", priv->dri_drawable);
+         (*dri2_dpy->flush->invalidate)(priv->dri_drawable);
+      }
+   }
+}
+
+/** dri3_update_drawable
+ *
+ * from glx
+ * Called the first time we use the drawable and then
+ * after we receive present configure notify events to
+ * track the geometry of the drawable
+ */
+static int
+dri3_update_drawable(struct dri2_egl_display *dri2_dpy, __DRIdrawable *driDrawable, void *loaderPrivate)
+{
+   struct dri2_egl_surface *priv = loaderPrivate;
+   xcb_connection_t     *c = dri2_dpy->conn;
+
+   /* First time through, go get the current drawable geometry
+    */
+   if (priv->base.Width == 0 || priv->base.Height == 0 || priv->depth == 0) {
+      xcb_get_geometry_cookie_t                 geom_cookie;
+      xcb_get_geometry_reply_t                  *geom_reply;
+      xcb_void_cookie_t                         cookie;
+      xcb_generic_error_t                       *error;
+
+      /* Try to select for input on the window.
+       *
+       * If the drawable is a window, this will get our events
+       * delivered.
+       *
+       * Otherwise, we'll get a BadWindow error back from this request which
+       * will let us know that the drawable is a pixmap instead.
+       */
+
+
+      cookie = xcb_present_select_input_checked(c,
+                                                (priv->eid = xcb_generate_id(c)),
+                                                priv->drawable,
+                                                XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY|
+                                                XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY|
+                                                XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
+
+      /* Create an XCB event queue to hold present events outside of the usual
+       * application event queue
+       */
+      priv->special_event = xcb_register_for_special_xge(c,
+                                                         &xcb_present_id,
+                                                         priv->eid,
+                                                         priv->stamp);
+
+      geom_cookie = xcb_get_geometry(c, priv->drawable);
+
+      geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL);
+
+      if (!geom_reply)
+         return false;
+
+      priv->base.Width = geom_reply->width;
+      priv->base.Height = geom_reply->height;
+      priv->depth = geom_reply->depth;
+      priv->is_pixmap = false;
+
+      free(geom_reply);
+
+      /* Check to see if our select input call failed. If it failed with a
+       * BadWindow error, then assume the drawable is a pixmap. Destroy the
+       * special event queue created above and mark the drawable as a pixmap
+       */
+
+      error = xcb_request_check(c, cookie);
+
+      if (error) {
+         if (error->error_code != BadWindow) {
+            free(error);
+            return false;
+         }
+         priv->is_pixmap = true;
+         xcb_unregister_for_special_event(c, priv->special_event);
+         priv->special_event = NULL;
+      }
+   }
+   dri3_flush_present_events(dri2_dpy, priv);
+   return true;
+}
+#endif
 
 /**
  * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
@@ -212,7 +446,10 @@ dri2_x11_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
 
    (void) drv;
 
-   dri2_surf = malloc(sizeof *dri2_surf);
+   /* dri2_surf->special_event needs to be initialised as NULL
+    * so calloc makes sense here
+    */
+   dri2_surf = calloc(1, sizeof *dri2_surf);
    if (!dri2_surf) {
       _eglError(EGL_BAD_ALLOC, "dri2_create_surface");
       return NULL;
@@ -360,6 +597,17 @@ dri2_x11_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
    if (surf->Type == EGL_PBUFFER_BIT)
       xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable);
 
+#ifdef HAVE_DRI3
+   /* from glx: dri3_destroy_drawable(). dri2_surf is not necessarily being
+    * destroyed so we need to NULL special_event after unregistering it
+    */ 
+   if (dri2_dpy->dri3_present_and_working && dri2_surf->special_event)
+   {
+      xcb_unregister_for_special_event(dri2_dpy->conn, dri2_surf->special_event);
+      dri2_surf->special_event = NULL;
+   }
+#endif
+
    free(surf);
 
    return EGL_TRUE;
@@ -427,6 +675,11 @@ dri2_x11_get_buffers(__DRIdrawable * driDrawable,
 
    (void) driDrawable;
 
+#ifdef HAVE_DRI3
+   if (dri2_dpy->dri3_present_and_working && !dri3_update_drawable(dri2_dpy, driDrawable, loaderPrivate))
+      return false;
+#endif
+
    cookie = xcb_dri2_get_buffers_unchecked (dri2_dpy->conn,
 					    dri2_surf->drawable,
 					    count, count, attachments);
@@ -461,6 +714,11 @@ dri2_x11_get_buffers_with_format(__DRIdrawable * driDrawable,
 
    (void) driDrawable;
 
+#ifdef HAVE_DRI3
+   if (dri2_dpy->dri3_present_and_working && !dri3_update_drawable(dri2_dpy, driDrawable, loaderPrivate))
+      return false;
+#endif
+
    format_attachments = (xcb_dri2_attach_format_t *) attachments;
    cookie = xcb_dri2_get_buffers_with_format_unchecked (dri2_dpy->conn,
 							dri2_surf->drawable,
@@ -500,12 +758,16 @@ dri2_x11_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
 }
 
 static EGLBoolean
-dri2_x11_connect(struct dri2_egl_display *dri2_dpy)
+dri2_x11_connect(struct dri2_egl_display *dri2_dpy, _EGLDisplay *disp)
 {
    xcb_xfixes_query_version_reply_t *xfixes_query;
    xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
    xcb_dri2_query_version_reply_t *dri2_query;
    xcb_dri2_query_version_cookie_t dri2_query_cookie;
+#ifdef HAVE_DRI3
+   xcb_dri3_query_version_reply_t *dri3_query;
+   xcb_dri3_query_version_cookie_t dri3_query_cookie;
+#endif
    xcb_dri2_connect_reply_t *connect;
    xcb_dri2_connect_cookie_t connect_cookie;
    xcb_generic_error_t *error;
@@ -525,6 +787,44 @@ dri2_x11_connect(struct dri2_egl_display *dri2_dpy)
    if (!(extension && extension->present))
       return EGL_FALSE;
 
+#ifdef HAVE_DRI3
+   xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
+   extension = xcb_get_extension_data (dri2_dpy->conn, &xcb_dri3_id);
+   if (extension && extension->present) {
+      dri3_query_cookie = xcb_dri3_query_version (dri2_dpy->conn,
+                                                  XCB_DRI3_MAJOR_VERSION,
+                                                  XCB_DRI3_MINOR_VERSION);
+      dri3_query =
+         xcb_dri3_query_version_reply (dri2_dpy->conn, dri3_query_cookie, &error);
+      if (dri3_query == NULL || error != NULL) {
+         _eglLog(_EGL_WARNING, "DRI2: failed to query DRI3 version");
+         free(error);
+         dri2_dpy->dri3_present_and_working = 0;
+      } else {
+         dri2_dpy->dri3_major = dri3_query->major_version;
+         dri2_dpy->dri3_minor = dri3_query->minor_version;
+         free(dri3_query);
+
+         dri2_dpy->fd = dri3_open(dri2_dpy, RootWindow(disp->PlatformDisplay, DefaultScreen(disp->PlatformDisplay)), None);
+         if(dri2_dpy->fd < 0)
+         {
+            dri2_dpy->dri3_present_and_working = 0;
+            _eglLog(_EGL_INFO, "DRI2: DRI3 extension not working\n");
+         } else {
+            dri2_dpy->dri3_present_and_working = 1;
+            _eglLog(_EGL_INFO, "DRI2: DRI3 present and working\n");
+            close(dri2_dpy->fd);
+            dri2_dpy->fd = -1;
+         }
+      }
+   } else {
+      dri2_dpy->dri3_present_and_working = 0;
+      _eglLog(_EGL_INFO, "DRI2: DRI3 extension not present\n");
+   }
+#else
+   dri2_dpy->dri3_present_and_working = 0;
+#endif
+
    xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,
 						  XCB_XFIXES_MAJOR_VERSION,
 						  XCB_XFIXES_MINOR_VERSION);
@@ -774,6 +1074,13 @@ dri2_x11_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
    if (dri2_dpy->flush)
       (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
 
+#ifdef HAVE_DRI3
+   /* Poll for special events and invalidate the surface if needed.
+    */
+   if(dri2_dpy->dri3_present_and_working)
+      dri3_flush_present_events(dri2_dpy, dri2_surf);
+#endif
+
    cookie = xcb_dri2_swap_buffers_unchecked(dri2_dpy->conn, dri2_surf->drawable,
                   msc_hi, msc_lo, divisor_hi, divisor_lo, remainder_hi, remainder_lo);
 
@@ -794,10 +1101,15 @@ dri2_x11_swap_buffers_msc(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw,
     * happened.  The driver should still be using the viewport hack to catch
     * window resizes.
     */
-   if (dri2_dpy->flush &&
-       dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate)
+   /* With DRI3 we ARE watching for the server's invalidate events like we're
+    * supposed to. They're handled in dri3_flush_present_events(), so if we've
+    * got DRI3 then we don't need to invalidate here.
+    */
+   if (!dri2_dpy->dri3_present_and_working && dri2_dpy->flush &&
+       dri2_dpy->flush->base.version >= 3 && dri2_dpy->flush->invalidate) {
+      _eglLog(_EGL_INFO, "DRI: Invalidating buffer 0x%x\n", dri2_surf->dri_drawable);
       (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
-
+   }
    return swap_count;
 }
 
@@ -807,6 +1119,14 @@ dri2_x11_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
 
+#ifdef HAVE_DRI3
+   /* from glx: dri3_swap_buffers(). Polls for special events and invalidates
+    * the surface if needed.
+    */
+   if(dri2_dpy->dri3_present_and_working)
+      dri3_flush_present_events(dri2_dpy, dri2_surf);
+#endif
+
    if (dri2_dpy->dri2) {
       return dri2_x11_swap_buffers_msc(drv, disp, draw, 0, 0, 0) != -1;
    } else {
@@ -1234,7 +1554,7 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
    }
 
    if (dri2_dpy->conn) {
-      if (!dri2_x11_connect(dri2_dpy))
+      if (!dri2_x11_connect(dri2_dpy, disp))
 	 goto cleanup_conn;
    }
 
@@ -1277,10 +1597,16 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp)
       dri2_dpy->dri2_loader_extension.flushFrontBuffer = dri2_x11_flush_front_buffer;
       dri2_dpy->dri2_loader_extension.getBuffersWithFormat = NULL;
    }
-      
+
    dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
    dri2_dpy->extensions[1] = &image_lookup_extension.base;
    dri2_dpy->extensions[2] = NULL;
+#ifdef HAVE_DRI3
+   if (dri2_dpy->dri3_present_and_working) {
+      dri2_dpy->extensions[2] = &dri3_extension.base;
+      dri2_dpy->extensions[3] = NULL;
+   }
+#endif
 
    dri2_dpy->swap_available = (dri2_dpy->dri2_minor >= 2);
    dri2_dpy->invalidate_available = (dri2_dpy->dri2_minor >= 3);
diff --git a/src/egl/main/Makefile.am b/src/egl/main/Makefile.am
index df8bf28..490930f 100644
--- a/src/egl/main/Makefile.am
+++ b/src/egl/main/Makefile.am
@@ -79,6 +79,10 @@ libEGL_la_LIBADD += ../drivers/dri2/libegl_dri2.la
 libEGL_la_LIBADD += $(DLOPEN_LIBS) $(LIBDRM_LIBS)
 endif
 
+if HAVE_DRI3
+libEGL_la_LIBADD += $(XCB_DRI3_LIBS)
+endif
+
 include $(top_srcdir)/install-lib-links.mk
 
 pkgconfigdir = $(libdir)/pkgconfig
diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c
index 6c78928..068d209 100644
--- a/src/mesa/drivers/dri/common/dri_util.c
+++ b/src/mesa/drivers/dri/common/dri_util.c
@@ -73,6 +73,8 @@ setupLoaderExtensions(__DRIscreen *psp,
     for (i = 0; extensions[i]; i++) {
 	if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
 	    psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
+	if (strcmp(extensions[i]->name, __DRI_DRI3) == 0)
+	    psp->dri2.dri3 = (__DRIdri3Extension *) extensions[i];
 	if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
 	    psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
 	if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
diff --git a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h
index 1138bf1..e64a049 100644
--- a/src/mesa/drivers/dri/common/dri_util.h
+++ b/src/mesa/drivers/dri/common/dri_util.h
@@ -175,6 +175,7 @@ struct __DRIscreenRec {
 	/* Flag to indicate that this is a DRI2 screen.  Many of the above
 	 * fields will not be valid or initializaed in that case. */
 	const __DRIdri2LoaderExtension *loader;
+	const __DRIdri3Extension *dri3;
 	const __DRIimageLookupExtension *image;
 	const __DRIuseInvalidateExtension *useInvalidate;
     } dri2;
diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index 8b3f45b..0b25dc8 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -148,6 +148,9 @@ intel_viewport(struct gl_context *ctx)
    __DRIcontext *driContext = brw->driContext;
 
    if (_mesa_is_winsys_fbo(ctx->DrawBuffer)) {
+      if (unlikely(INTEL_DEBUG & DEBUG_DRI))
+         fprintf(stderr, "invalidating drawables\n");
+
       dri2InvalidateDrawable(driContext->driDrawablePriv);
       dri2InvalidateDrawable(driContext->driReadablePriv);
    }
@@ -252,13 +255,12 @@ brw_init_driver_functions(struct brw_context *brw,
    _mesa_init_driver_functions(functions);
 
    /* GLX uses DRI2 invalidate events to handle window resizing.
-    * Unfortunately, EGL does not - libEGL is written in XCB (not Xlib),
-    * which doesn't provide a mechanism for snooping the event queues.
+    * EGL backend can only receive the events when DRI3 is present.
     *
-    * So EGL still relies on viewport hacks to handle window resizing.
-    * This should go away with DRI3000.
+    * So DRI2 relies on viewport hacks to handle window resizing.
     */
-   if (!brw->driContext->driScreenPriv->dri2.useInvalidate)
+   if (!brw->driContext->driScreenPriv->dri2.useInvalidate &&
+       !brw->driContext->driScreenPriv->dri2.dri3)
       functions->Viewport = intel_viewport;
 
    functions->Flush = intel_glFlush;
-- 
1.7.9.5



More information about the mesa-dev mailing list