DRI2/GLX: add INTEL_swap_event support
authorJesse Barnes <jbarnes@jbarnes-desktop.localdomain>
Thu, 12 Nov 2009 16:48:07 +0000 (16:48 +0000)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 8 Jan 2010 17:37:43 +0000 (12:37 -0500)
Add event support for the GLX swap buffers event, along with DRI2 protocol
support for generating GLX swap buffers events in the direct rendered case.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
include/GL/glx.h
include/GL/glxext.h
src/glx/x11/dri2.c
src/glx/x11/dri_common.c
src/glx/x11/glxext.c
src/glx/x11/glxextensions.c
src/glx/x11/glxextensions.h
src/mesa/drivers/x11/glxapi.c

index 28844014069ba8f1b92810278f285070ffaf5530..82b0f2211465190f64fc657da8fb107772348fbc 100644 (file)
@@ -186,6 +186,16 @@ typedef XID GLXWindow;
 typedef XID GLXPbuffer;
 
 
+/*
+** Events.
+** __GLX_NUMBER_EVENTS is set to 17 to account for the BufferClobberSGIX
+**  event - this helps initialization if the server supports the pbuffer
+**  extension and the client doesn't.
+*/
+#define GLX_PbufferClobber     0
+#define GLX_BufferSwapComplete 1
+
+#define __GLX_NUMBER_EVENTS 17
 
 extern XVisualInfo* glXChooseVisual( Display *dpy, int screen,
                                     int *attribList );
@@ -507,8 +517,17 @@ typedef struct {
     int count;                 /* if nonzero, at least this many more */
 } GLXPbufferClobberEvent;
 
+typedef struct {
+    int event_type;
+    GLXDrawable drawable;
+    int64_t ust;
+    int64_t msc;
+    int64_t sbc;
+} GLXBufferSwapComplete;
+
 typedef union __GLXEvent {
     GLXPbufferClobberEvent glxpbufferclobber;
+    GLXBufferSwapComplete glxbufferswapcomplete;
     long pad[24];
 } GLXEvent;
 
index 9ac0592e0533edf097682a6fc204f8f31a62bbe5..36ee3665dfde8ec17e468733cae3bbdf6f88e25f 100644 (file)
@@ -696,6 +696,14 @@ extern void glXJoinSwapGroupSGIX (Display *, GLXDrawable, GLXDrawable);
 typedef void ( * PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member);
 #endif
 
+#ifndef GLX_INTEL_swap_event
+#define GLX_INTEL_swap_event
+#define GLX_BUFFER_SWAP_COMPLETE_MASK      0x10000000
+#define GLX_EXCHANGE_COMPLETE              0x8024
+#define GLX_BLIT_COMPLETE                  0x8025
+#define GLX_FLIP_COMPLETE                  0x8026
+#endif
+
 #ifndef GLX_SGIX_swap_barrier
 #define GLX_SGIX_swap_barrier 1
 #ifdef GLX_GLXEXT_PROTOTYPES
index 9ce633c40d486b60298e023e3a9d161ea26cfab0..2cb5d3463afd92d220d8dfa10e79bb76a05b64bc 100644 (file)
@@ -41,6 +41,8 @@
 #include <X11/extensions/dri2proto.h>
 #include "xf86drm.h"
 #include "dri2.h"
+#include "glxclient.h"
+#include "GL/glxext.h"
 
 /* Allow the build to work with an older versions of dri2proto.h and
  * dri2tokens.h.
@@ -56,6 +58,11 @@ static char dri2ExtensionName[] = DRI2_NAME;
 static XExtensionInfo *dri2Info;
 static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
 
+static Bool
+DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
+static Status
+DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
+
 static /* const */ XExtensionHooks dri2ExtensionHooks = {
   NULL,                   /* create_gc */
   NULL,                   /* copy_gc */
@@ -64,8 +71,8 @@ static /* const */ XExtensionHooks dri2ExtensionHooks = {
   NULL,                   /* create_font */
   NULL,                   /* free_font */
   DRI2CloseDisplay,       /* close_display */
-  NULL,                   /* wire_to_event */
-  NULL,                   /* event_to_wire */
+  DRI2WireToEvent,        /* wire_to_event */
+  DRI2EventToWire,        /* event_to_wire */
   NULL,                   /* error */
   NULL,                   /* error_string */
 };
@@ -76,6 +83,65 @@ static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
                                    &dri2ExtensionHooks,
                                    0, NULL)
 
+static Bool
+DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
+{
+   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+
+   XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+   switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
+   case DRI2_BufferSwapComplete:
+   {
+      GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event;
+      xDRI2BufferSwapComplete *awire = (xDRI2BufferSwapComplete *)wire;
+      switch (awire->type) {
+      case DRI2_EXCHANGE_COMPLETE:
+        aevent->event_type = GLX_EXCHANGE_COMPLETE;
+        break;
+      case DRI2_BLIT_COMPLETE:
+        aevent->event_type = GLX_BLIT_COMPLETE;
+        break;
+      case DRI2_FLIP_COMPLETE:
+        aevent->event_type = GLX_FLIP_COMPLETE;
+        break;
+      default:
+        /* unknown swap completion type */
+        return False;
+      }
+      aevent->drawable = awire->drawable;
+      aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
+      aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
+      aevent->sbc = ((CARD64)awire->sbc_hi << 32) | awire->sbc_lo;
+      return True;
+   }
+   default:
+      /* client doesn't support server event */
+      break;
+   }
+
+   return False;
+}
+
+/* We don't actually support this.  It doesn't make sense for clients to
+ * send each other DRI2 events.
+ */
+static Status
+DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
+{
+   XExtDisplayInfo *info = DRI2FindDisplay(dpy);
+
+   XextCheckExtension(dpy, info, dri2ExtensionName, False);
+
+   switch (event->type) {
+   default:
+      /* client doesn't support server event */
+      break;
+   }
+
+   return Success;
+}
+
 Bool
 DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
 {
index d1b77f308ddd42e1d99630fe2ba75366ba137392..e4034161bb32c2ec07a6e8ba0b85a654ee7b7456 100644 (file)
@@ -394,6 +394,9 @@ dri2BindExtensions(__GLXscreenConfigs *psc)
       __glXEnableDirectExtension(psc, "GLX_SGI_swap_control");
       __glXEnableDirectExtension(psc, "GLX_MESA_swap_control");
 
+      /* FIXME: if DRI2 version supports it... */
+      __glXEnableDirectExtension(psc, "INTEL_swap_event");
+
 #ifdef __DRI2_FLUSH
       if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) {
         psc->f = (__DRI2flushExtension *) extensions[i];
index 5633a3e4a29a22af80562f49589b96f1ac5e7107..fe65216c41154df3e3032228ab29d7199c8df199 100644 (file)
@@ -101,6 +101,10 @@ __glXCloseDisplay(Display * dpy, XExtCodes * codes)
 static
 XEXT_GENERATE_ERROR_STRING(__glXErrorString, __glXExtensionName,
                            __GLX_NUMBER_ERRORS, error_list)
+static Bool
+__glXWireToEvent(Display *dpy, XEvent *event, xEvent *wire);
+static Status
+__glXEventToWire(Display *dpy, XEvent *event, xEvent *wire);
 
 static /* const */ XExtensionHooks __glXExtensionHooks = {
   NULL,                   /* create_gc */
@@ -110,8 +114,8 @@ static /* const */ XExtensionHooks __glXExtensionHooks = {
   NULL,                   /* create_font */
   NULL,                   /* free_font */
   __glXCloseDisplay,      /* close_display */
-  NULL,                   /* wire_to_event */
-  NULL,                   /* event_to_wire */
+  __glXWireToEvent,       /* wire_to_event */
+  __glXEventToWire,       /* event_to_wire */
   NULL,                   /* error */
   __glXErrorString,       /* error_string */
 };
@@ -121,6 +125,89 @@ XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
                            __glXExtensionName, &__glXExtensionHooks,
                            __GLX_NUMBER_EVENTS, NULL)
 
+/*
+ * GLX events are a bit funky.  We don't stuff the X event code into
+ * our user exposed (via XNextEvent) structure.  Instead we use the GLX
+ * private event code namespace (and hope it doesn't conflict).  Clients
+ * have to know that bit 15 in the event type field means they're getting
+ * a GLX event, and then handle the various sub-event types there, rather
+ * than simply checking the event code and handling it directly.
+ */
+
+static Bool
+__glXWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
+{
+   XExtDisplayInfo *info = __glXFindDisplay(dpy);
+
+   XextCheckExtension(dpy, info, __glXExtensionName, False);
+
+   switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
+   case GLX_PbufferClobber:
+   {
+      GLXPbufferClobberEvent *aevent = (GLXPbufferClobberEvent *)event;
+      xGLXPbufferClobberEvent *awire = (xGLXPbufferClobberEvent *)wire;
+      aevent->event_type = awire->type;
+      aevent->serial = awire->sequenceNumber;
+      aevent->event_type = awire->event_type;
+      aevent->draw_type = awire->draw_type;
+      aevent->drawable = awire->drawable;
+      aevent->buffer_mask = awire->buffer_mask;
+      aevent->aux_buffer = awire->aux_buffer;
+      aevent->x = awire->x;
+      aevent->y = awire->y;
+      aevent->width = awire->width;
+      aevent->height = awire->height;
+      aevent->count = awire->count;
+      return True;
+   }
+   case GLX_BufferSwapComplete:
+   {
+      GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event;
+      xGLXBufferSwapComplete *awire = (xGLXBufferSwapComplete *)wire;
+      aevent->event_type = awire->event_type;
+      aevent->drawable = awire->drawable;
+      aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo;
+      aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo;
+      aevent->sbc = ((CARD64)awire->sbc_hi << 32) | awire->sbc_lo;
+      return True;
+   }
+   default:
+      /* client doesn't support server event */
+      break;
+   }
+
+   return False;
+}
+
+/* We don't actually support this.  It doesn't make sense for clients to
+ * send each other GLX events.
+ */
+static Status
+__glXEventToWire(Display *dpy, XEvent *event, xEvent *wire)
+{
+   XExtDisplayInfo *info = __glXFindDisplay(dpy);
+
+   XextCheckExtension(dpy, info, __glXExtensionName, False);
+
+   switch (event->type) {
+   case GLX_DAMAGED:
+      break;
+   case GLX_SAVED:
+      break;
+   case GLX_EXCHANGE_COMPLETE:
+      break;
+   case GLX_BLIT_COMPLETE:
+      break;
+   case GLX_FLIP_COMPLETE:
+      break;
+   default:
+      /* client doesn't support server event */
+      break;
+   }
+
+   return Success;
+}
+
 /************************************************************************/
 /*
 ** Free the per screen configs data as well as the array of
index 6852128e2ae189032ceedf9886c7c2a3ef0acadf..25a5c4929309207409aa44430a77133b3e27a538 100644 (file)
@@ -104,6 +104,7 @@ static const struct extension_info known_glx_extensions[] = {
    { GLX(SGIX_swap_group),             VER(0,0), N, N, N, N },
    { GLX(SGIX_visual_select_group),    VER(0,0), Y, Y, N, N },
    { GLX(EXT_texture_from_pixmap),     VER(0,0), Y, N, N, N },
+   { GLX(INTEL_swap_event),            VER(1,4), Y, Y, N, N },
    { NULL }
 };
 
index 652c5db1c81078769c3aaa5d01efbdab25019c8b..f556b1239c9109d9298c0db7e01cc0da1f00113a 100644 (file)
@@ -65,7 +65,8 @@ enum
    SGIX_swap_barrier_bit,
    SGIX_swap_group_bit,
    SGIX_visual_select_group_bit,
-   EXT_texture_from_pixmap_bit
+   EXT_texture_from_pixmap_bit,
+   INTEL_swap_event_bit,
 };
 
 enum
index 02eea25a7129a90aa616ddeae938b31af46db0fb..a17c2c3ffc6df7ed8778bbb87cb897f7f9262f53 100644 (file)
@@ -1172,6 +1172,9 @@ _glxapi_get_extensions(void)
 #endif
 #ifdef GLX_EXT_texture_from_pixmap
       "GLX_EXT_texture_from_pixmap",
+#endif
+#ifdef GLX_INTEL_swap_event
+      "GLX_INTEL_swap_event",
 #endif
       NULL
    };