[PATCH 8/8] xephyr: Use GLX swap events to reduce repaints.

Eric Anholt eric at anholt.net
Mon Feb 3 10:36:49 PST 2014


If there's a swap already outstanding, don't bother queueing another
one until this one has completed.  The assumption here is that our
screen paints are cheap compared to everything else going on, so we
don't need to queue them up way ahead of time.  The swap events also
give us information we can use to avoid full screen repaints when the
swap is a copy.

Signed-off-by: Eric Anholt <eric at anholt.net>
---
 hw/kdrive/ephyr/ephyr.c            |  1 +
 hw/kdrive/ephyr/ephyr_glamor_glx.c | 95 +++++++++++++++++++++++++++++++++++++-
 hw/kdrive/ephyr/ephyr_glamor_glx.h |  1 +
 hw/kdrive/ephyr/hostx.c            |  8 ++++
 4 files changed, 103 insertions(+), 2 deletions(-)

diff --git a/hw/kdrive/ephyr/ephyr.c b/hw/kdrive/ephyr/ephyr.c
index aaa9bb9..460d804 100644
--- a/hw/kdrive/ephyr/ephyr.c
+++ b/hw/kdrive/ephyr/ephyr.c
@@ -35,6 +35,7 @@
 #include "inputstr.h"
 #include "scrnintstr.h"
 #include "ephyrlog.h"
+#include "ephyr_glamor_glx.h"
 
 #ifdef XF86DRI
 #include <xcb/xf86dri.h>
diff --git a/hw/kdrive/ephyr/ephyr_glamor_glx.c b/hw/kdrive/ephyr/ephyr_glamor_glx.c
index d56907f..7086c23 100644
--- a/hw/kdrive/ephyr/ephyr_glamor_glx.c
+++ b/hw/kdrive/ephyr/ephyr_glamor_glx.c
@@ -52,6 +52,9 @@
 static Display *dpy;
 static XVisualInfo *visual_info;
 static GLXFBConfig fb_config;
+static int glx_swap_event = -1;
+struct ephyr_glamor *glamor_screens[MAXSCREENS];
+static int num_glamor_screens;
 /** @} */
 
 /**
@@ -67,6 +70,12 @@ struct ephyr_glamor {
     GLuint texture_shader;
     GLuint texture_shader_position_loc;
     GLuint texture_shader_texcoord_loc;
+
+    Bool use_swap_events;
+    Bool swap_outstanding;
+    Bool needs_repaint;
+
+    pixman_region16_t pending_damage;
 };
 
 static GLint
@@ -201,6 +210,17 @@ ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
         0, 0,
     };
 
+    /* If our last swap hasn't hit the screen yet, then wait for it
+     * and repaint then.
+     */
+    if (glamor->use_swap_events && glamor->swap_outstanding) {
+        glamor->needs_repaint = true;
+        pixman_region_union(&glamor->pending_damage,
+                            &glamor->pending_damage,
+                            damage);
+        return;
+    }
+
     glXMakeCurrent(dpy, glamor->glx_win, glamor->ctx);
 
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -221,6 +241,26 @@ ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
     glDisableVertexAttribArray(glamor->texture_shader_texcoord_loc);
 
     glXSwapBuffers(dpy, glamor->glx_win);
+    glamor->swap_outstanding = True;
+    pixman_region_clear(&glamor->pending_damage);
+}
+
+static void
+ephyr_glamor_handle_swap_event(Window win, int type)
+{
+    for (int i = 0; i < num_glamor_screens; i++) {
+        struct ephyr_glamor *glamor = glamor_screens[i];
+
+        if (win != glamor->glx_win && win != glamor->win)
+            continue;
+
+        glamor->swap_outstanding = False;
+
+        if (glamor->needs_repaint) {
+            ephyr_glamor_damage_redisplay(glamor, &glamor->pending_damage);
+            glamor->needs_repaint = False;
+        }
+    }
 }
 
 /**
@@ -229,11 +269,13 @@ ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
  * We need to let the Xlib event filtering run on the event so that
  * Mesa's dri2_glx.c userspace event mangling gets run, and we
  * correctly get our invalidate events propagated into the driver.
+ * Since we need to consume mangled events for GLXBufferSwapComplete
+ * on DRI2, we need to do that here instead of in the main XCB event
+ * loop.
  */
 void
 ephyr_glamor_process_event(xcb_generic_event_t *xev)
 {
-
     uint32_t response_type = xev->response_type & 0x7f;
     /* Note the types on wire_to_event: there's an Xlib XEvent (with
      * the broken types) that it returns, and a protocol xEvent that
@@ -246,15 +288,38 @@ ephyr_glamor_process_event(xcb_generic_event_t *xev)
     wire_to_event = XESetWireToEvent(dpy, response_type, NULL);
     if (wire_to_event) {
         XEvent processed_event;
+        int x_response_type;
+        Bool result;
 
         /* OK they had an event handler.  Plug it back in, and call
          * through to it.
          */
         XESetWireToEvent(dpy, response_type, wire_to_event);
         xev->sequence = LastKnownRequestProcessed(dpy);
+        result = wire_to_event(dpy, &processed_event, (xEvent *)xev);
         wire_to_event(dpy, &processed_event, (xEvent *)xev);
+        XUnlockDisplay(dpy);
+
+        x_response_type = processed_event.type & 0x7f;
+
+        if (result) {
+            if (x_response_type == glx_swap_event) {
+                GLXBufferSwapComplete *swap =
+                    (GLXBufferSwapComplete *)&processed_event;
+                ephyr_glamor_handle_swap_event(swap->drawable,
+                                               swap->event_type);
+                return;
+            }
+        }
+    } else {
+        XUnlockDisplay(dpy);
+    }
+
+    if (response_type == glx_swap_event) {
+        xcb_glx_buffer_swap_complete_event_t *swap =
+            (xcb_glx_buffer_swap_complete_event_t *)xev;
+        ephyr_glamor_handle_swap_event(swap->drawable, swap->event_type);
     }
-    XUnlockDisplay(dpy);
 }
 
 struct ephyr_glamor *
@@ -282,18 +347,42 @@ ephyr_glamor_glx_screen_init(xcb_window_t win)
     glamor->ctx = ctx;
     glamor->win = win;
     glamor->glx_win = glx_win;
+    pixman_region_init(&glamor->pending_damage);
     ephyr_glamor_setup_texturing_shader(glamor);
 
+    if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy),
+                                "GLX_INTEL_swap_event")) {
+        glamor->use_swap_events = TRUE;
+
+        glXSelectEvent(dpy, glamor->glx_win,
+                       GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
+    }
+
+    glamor_screens[num_glamor_screens++] = glamor;
+
     return glamor;
 }
 
 void
 ephyr_glamor_glx_screen_fini(struct ephyr_glamor *glamor)
 {
+    bool found = false;
+    int i;
+
     glXMakeCurrent(dpy, None, NULL);
     glXDestroyContext(dpy, glamor->ctx);
     glXDestroyWindow(dpy, glamor->glx_win);
 
+    for (i = 0; i < num_glamor_screens; i++) {
+        if (glamor_screens[i] == glamor) {
+            found = true;
+        } else if (found) {
+            glamor_screens[i - 1] = glamor_screens[i];
+        }
+    }
+    assert(found);
+    num_glamor_screens--;
+
     free(glamor);
 }
 
@@ -317,6 +406,8 @@ ephyr_glamor_get_visual(void)
     if (!glXQueryExtension (dpy, &error_base, &event_base))
         FatalError("Couldn't find GLX extension\n");
 
+    glx_swap_event = event_base + XCB_GLX_BUFFER_SWAP_COMPLETE;
+
     fbconfigs = glXChooseFBConfig(dpy, DefaultScreen(dpy), attribs, &nelements);
     if (!nelements)
         FatalError("Couldn't choose an FBConfig\n");
diff --git a/hw/kdrive/ephyr/ephyr_glamor_glx.h b/hw/kdrive/ephyr/ephyr_glamor_glx.h
index 8995e1e..a65a67b 100644
--- a/hw/kdrive/ephyr/ephyr_glamor_glx.h
+++ b/hw/kdrive/ephyr/ephyr_glamor_glx.h
@@ -30,6 +30,7 @@
 
 #include <xcb/xcb.h>
 #include "dix-config.h"
+#include <xcb/glx.h>
 
 struct ephyr_glamor;
 struct pixman_region16;
diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c
index f37e1b3..c43f42f 100644
--- a/hw/kdrive/ephyr/hostx.c
+++ b/hw/kdrive/ephyr/hostx.c
@@ -1207,6 +1207,14 @@ ephyr_glamor_init(ScreenPtr screen)
     KdScreenPriv(screen);
     KdScreenInfo *kd_screen = pScreenPriv->screen;
     EphyrScrPriv *scrpriv = kd_screen->driver;
+    const xcb_query_extension_reply_t *glx_rep;
+
+    glx_rep = xcb_get_extension_data(HostX.conn, &xcb_glx_id);
+    if (glx_rep && !glx_rep->present) {
+        ErrorF("X host is missing the GLX extension\n");
+        ephyr_glamor = false;
+        return FALSE;
+    }
 
     scrpriv->glamor = ephyr_glamor_glx_screen_init(scrpriv->win);
 
-- 
1.9.rc1



More information about the xorg-devel mailing list