glx: move the glFlush call one layer down
[mesa.git] / src / glx / glxcmds.c
index 191b321ce327c2914d02fe4b05bbbb4f6ed6cb2c..8874e3bebf6695bc35c9bbaf2132d0fc356b24b2 100644 (file)
 #include "glapi.h"
 #include "glxextensions.h"
 #include "indirect.h"
+#include "glx_error.h"
 
 #ifdef GLX_DIRECT_RENDERING
 #ifdef GLX_USE_APPLEGL
 #include "apple_glx_context.h"
 #include "apple_glx.h"
-#include "glx_error.h"
 #else
 #include <sys/time.h>
 #ifdef XF86VIDMODE
 #else
 #endif
 
-#if defined(USE_XCB)
 #include <X11/Xlib-xcb.h>
 #include <xcb/xcb.h>
 #include <xcb/glx.h>
-#endif
 
 static const char __glXGLXClientVendorName[] = "Mesa Project and SGI";
 static const char __glXGLXClientVersion[] = "1.4";
@@ -90,6 +88,51 @@ GetGLXDRIDrawable(Display * dpy, GLXDrawable drawable)
 
 #endif
 
+_X_HIDDEN struct glx_drawable *
+GetGLXDrawable(Display *dpy, GLXDrawable drawable)
+{
+   struct glx_display *priv = __glXInitialize(dpy);
+   struct glx_drawable *glxDraw;
+
+   if (priv == NULL)
+      return NULL;
+
+   if (__glxHashLookup(priv->glXDrawHash, drawable, (void *) &glxDraw) == 0)
+      return glxDraw;
+
+   return NULL;
+}
+
+_X_HIDDEN int
+InitGLXDrawable(Display *dpy, struct glx_drawable *glxDraw, XID xDrawable,
+               GLXDrawable drawable)
+{
+   struct glx_display *priv = __glXInitialize(dpy);
+
+   if (!priv)
+      return -1;
+
+   glxDraw->xDrawable = xDrawable;
+   glxDraw->drawable = drawable;
+   glxDraw->lastEventSbc = 0;
+   glxDraw->eventSbcWrap = 0;
+
+   return __glxHashInsert(priv->glXDrawHash, drawable, glxDraw);
+}
+
+_X_HIDDEN void
+DestroyGLXDrawable(Display *dpy, GLXDrawable drawable)
+{
+   struct glx_display *priv = __glXInitialize(dpy);
+   struct glx_drawable *glxDraw;
+
+   if (!priv)
+      return;
+
+   glxDraw = GetGLXDrawable(dpy, drawable);
+   __glxHashDelete(priv->glXDrawHash, drawable);
+   free(glxDraw);
+}
 
 /**
  * Get the GLX per-screen data structure associated with a GLX context.
@@ -105,7 +148,7 @@ GetGLXDRIDrawable(Display * dpy, GLXDrawable drawable)
  *       number range for \c dpy?
  */
 
-static struct glx_screen *
+_X_HIDDEN struct glx_screen *
 GetGLXScreenConfigs(Display * dpy, int scrn)
 {
    struct glx_display *const priv = __glXInitialize(dpy);
@@ -299,6 +342,7 @@ CreateContext(Display *dpy, int generic_id, struct glx_config *config,
    UnlockDisplay(dpy);
    SyncHandle();
 
+   gc->share_xid = shareList ? shareList->xid : None;
    gc->imported = GL_FALSE;
    gc->renderType = renderType;
 
@@ -336,7 +380,7 @@ glXCreateContext(Display * dpy, XVisualInfo * vis,
                         X_GLXCreateContext, renderType, vis->screen);
 }
 
-_X_HIDDEN void
+static void
 glx_send_destroy_context(Display *dpy, XID xid)
 {
    CARD8 opcode = __glXSetupForCommand(dpy);
@@ -360,25 +404,24 @@ glXDestroyContext(Display * dpy, GLXContext ctx)
 {
    struct glx_context *gc = (struct glx_context *) ctx;
 
-   if (!gc)
+   if (gc == NULL || gc->xid == None)
       return;
 
    __glXLock();
+   if (!gc->imported)
+      glx_send_destroy_context(dpy, gc->xid);
+
    if (gc->currentDpy) {
       /* This context is bound to some thread.  According to the man page,
        * we should not actually delete the context until it's unbound.
        * Note that we set gc->xid = None above.  In MakeContextCurrent()
        * we check for that and delete the context there.
        */
-      if (!gc->imported)
-        glx_send_destroy_context(dpy, gc->xid);
       gc->xid = None;
-      __glXUnlock();
-      return;
+   } else {
+      gc->vtable->destroy(gc);
    }
    __glXUnlock();
-
-   gc->vtable->destroy(gc);
 }
 
 /*
@@ -531,10 +574,6 @@ glXCopyContext(Display * dpy, GLXContext source_user,
 static Bool
 __glXIsDirect(Display * dpy, GLXContextID contextID)
 {
-#if !defined(USE_XCB)
-   xGLXIsDirectReq *req;
-   xGLXIsDirectReply reply;
-#endif
    CARD8 opcode;
 
    opcode = __glXSetupForCommand(dpy);
@@ -542,30 +581,23 @@ __glXIsDirect(Display * dpy, GLXContextID contextID)
       return GL_FALSE;
    }
 
-#ifdef USE_XCB
    xcb_connection_t *c = XGetXCBConnection(dpy);
+   xcb_generic_error_t *err;
    xcb_glx_is_direct_reply_t *reply = xcb_glx_is_direct_reply(c,
                                                               xcb_glx_is_direct
                                                               (c, contextID),
-                                                              NULL);
+                                                              &err);
+
+   const Bool is_direct = (reply != NULL && reply->is_direct) ? True : False;
+
+   if (err != NULL) {
+      __glXSendErrorForXcb(dpy, err);
+      free(err);
+   }
 
-   const Bool is_direct = reply->is_direct ? True : False;
    free(reply);
 
    return is_direct;
-#else
-   /* Send the glXIsDirect request */
-   LockDisplay(dpy);
-   GetReq(GLXIsDirect, req);
-   req->reqType = opcode;
-   req->glxCode = X_GLXIsDirect;
-   req->context = contextID;
-   _XReply(dpy, (xReply *) & reply, 0, False);
-   UnlockDisplay(dpy);
-   SyncHandle();
-
-   return reply.isDirect;
-#endif /* USE_XCB */
 }
 
 /**
@@ -608,6 +640,7 @@ glXCreateGLXPixmap(Display * dpy, XVisualInfo * vis, Pixmap pixmap)
    return pixmap;
 #else
    xGLXCreateGLXPixmapReq *req;
+   struct glx_drawable *glxDraw;
    GLXPixmap xid;
    CARD8 opcode;
 
@@ -616,6 +649,10 @@ glXCreateGLXPixmap(Display * dpy, XVisualInfo * vis, Pixmap pixmap)
       return None;
    }
 
+   glxDraw = malloc(sizeof(*glxDraw));
+   if (!glxDraw)
+      return None;
+
    /* Send the glXCreateGLXPixmap request */
    LockDisplay(dpy);
    GetReq(GLXCreateGLXPixmap, req);
@@ -628,6 +665,11 @@ glXCreateGLXPixmap(Display * dpy, XVisualInfo * vis, Pixmap pixmap)
    UnlockDisplay(dpy);
    SyncHandle();
 
+   if (InitGLXDrawable(dpy, glxDraw, pixmap, req->glxpixmap)) {
+      free(glxDraw);
+      return None;
+   }
+
 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
    do {
       /* FIXME: Maybe delay __DRIdrawable creation until the drawable
@@ -700,6 +742,8 @@ glXDestroyGLXPixmap(Display * dpy, GLXPixmap glxpixmap)
    UnlockDisplay(dpy);
    SyncHandle();
 
+   DestroyGLXDrawable(dpy, glxpixmap);
+
 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
    {
       struct glx_display *const priv = __glXInitialize(dpy);
@@ -728,24 +772,20 @@ glXSwapBuffers(Display * dpy, GLXDrawable drawable)
    struct glx_context *gc;
    GLXContextTag tag;
    CARD8 opcode;
-#ifdef USE_XCB
    xcb_connection_t *c;
-#else
-   xGLXSwapBuffersReq *req;
-#endif
 
    gc = __glXGetCurrentContext();
 
 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
-   __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable);
+   {
+      __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable);
 
-   if (pdraw != NULL) {
-      if (gc && drawable == gc->currentDrawable) {
-        glFlush();
-      }
+      if (pdraw != NULL) {
+         Bool flush = gc && drawable == gc->currentDrawable;
 
-      (*pdraw->psc->driScreen->swapBuffers)(pdraw, 0, 0, 0);
-      return;
+         (*pdraw->psc->driScreen->swapBuffers)(pdraw, 0, 0, 0, flush);
+         return;
+      }
    }
 #endif
 
@@ -767,22 +807,9 @@ glXSwapBuffers(Display * dpy, GLXDrawable drawable)
       tag = 0;
    }
 
-#ifdef USE_XCB
    c = XGetXCBConnection(dpy);
    xcb_glx_swap_buffers(c, tag, drawable);
    xcb_flush(c);
-#else
-   /* Send the glXSwapBuffers request */
-   LockDisplay(dpy);
-   GetReq(GLXSwapBuffers, req);
-   req->reqType = opcode;
-   req->glxCode = X_GLXSwapBuffers;
-   req->drawable = drawable;
-   req->contextTag = tag;
-   UnlockDisplay(dpy);
-   SyncHandle();
-   XFlush(dpy);
-#endif /* USE_XCB */
 #endif /* GLX_USE_APPLEGL */
 }
 
@@ -1201,7 +1228,7 @@ glXChooseVisual(Display * dpy, int screen, int *attribList)
                                   &visualTemplate, &i);
 
          if (newList) {
-            Xfree(visualList);
+            free(visualList);
             visualList = newList;
             best_config = config;
          }
@@ -1303,30 +1330,11 @@ __glXClientInfo(Display * dpy, int opcode)
    char *ext_str = __glXGetClientGLExtensionString();
    int size = strlen(ext_str) + 1;
 
-#ifdef USE_XCB
    xcb_connection_t *c = XGetXCBConnection(dpy);
    xcb_glx_client_info(c,
                        GLX_MAJOR_VERSION, GLX_MINOR_VERSION, size, ext_str);
-#else
-   xGLXClientInfoReq *req;
 
-   /* Send the glXClientInfo request */
-   LockDisplay(dpy);
-   GetReq(GLXClientInfo, req);
-   req->reqType = opcode;
-   req->glxCode = X_GLXClientInfo;
-   req->major = GLX_MAJOR_VERSION;
-   req->minor = GLX_MINOR_VERSION;
-
-   req->length += (size + 3) >> 2;
-   req->numbytes = size;
-   Data(dpy, ext_str, size);
-
-   UnlockDisplay(dpy);
-   SyncHandle();
-#endif /* USE_XCB */
-
-   Xfree(ext_str);
+   free(ext_str);
 }
 
 
@@ -1352,16 +1360,41 @@ _X_EXPORT GLXContext
 glXImportContextEXT(Display *dpy, GLXContextID contextID)
 {
    struct glx_display *priv = __glXInitialize(dpy);
-   struct glx_screen *psc;
+   struct glx_screen *psc = NULL;
    xGLXQueryContextReply reply;
    CARD8 opcode;
    struct glx_context *ctx;
-   int propList[__GLX_MAX_CONTEXT_PROPS * 2], *pProp, nPropListBytes;
+
+   /* This GLX implementation knows about 5 different properties, so
+    * allow the server to send us one of each.
+    */
+   int propList[5 * 2], *pProp, nPropListBytes;
+   int numProps;
    int i, renderType;
    XID share;
    struct glx_config *mode;
+   uint32_t fbconfigID = 0;
+   uint32_t visualID = 0;
+   uint32_t screen;
+   Bool got_screen = False;
+
+   /* The GLX_EXT_import_context spec says:
+    *
+    *     "If <contextID> does not refer to a valid context, then a BadContext
+    *     error is generated; if <contextID> refers to direct rendering
+    *     context then no error is generated but glXImportContextEXT returns
+    *     NULL."
+    *
+    * If contextID is None, generate BadContext on the client-side.  Other
+    * sorts of invalid contexts will be detected by the server in the
+    * __glXIsDirect call.
+    */
+   if (contextID == None) {
+      __glXSendError(dpy, GLXBadContext, contextID, X_GLXIsDirect, false);
+      return NULL;
+   }
 
-   if (contextID == None || __glXIsDirect(dpy, contextID))
+   if (__glXIsDirect(dpy, contextID))
       return NULL;
 
    opcode = __glXSetupForCommand(dpy);
@@ -1404,35 +1437,45 @@ glXImportContextEXT(Display *dpy, GLXContextID contextID)
    UnlockDisplay(dpy);
    SyncHandle();
 
-   /* Look up screen first so we can look up visuals/fbconfigs later */
-   psc = NULL;
-   for (i = 0, pProp = propList; i < reply.n; i++, pProp += 2)
-      if (pProp[0] == GLX_SCREEN)
-        psc = GetGLXScreenConfigs(dpy, pProp[1]);
-   if (psc == NULL)
-      return NULL;
-
+   numProps = nPropListBytes / (2 * sizeof(propList[0]));
    share = None;
    mode = NULL;
    renderType = 0;
    pProp = propList;
 
-   for (i = 0, pProp = propList; i < reply.n; i++, pProp += 2)
+   for (i = 0, pProp = propList; i < numProps; i++, pProp += 2)
       switch (pProp[0]) {
+      case GLX_SCREEN:
+        screen = pProp[1];
+        got_screen = True;
+        break;
       case GLX_SHARE_CONTEXT_EXT:
         share = pProp[1];
         break;
       case GLX_VISUAL_ID_EXT:
-        mode = glx_config_find_visual(psc->visuals, pProp[1]);
+        visualID = pProp[1];
         break;
       case GLX_FBCONFIG_ID:
-        mode = glx_config_find_fbconfig(psc->configs, pProp[1]);
+        fbconfigID = pProp[1];
         break;
       case GLX_RENDER_TYPE:
         renderType = pProp[1];
         break;
       }
 
+   if (!got_screen)
+      return NULL;
+
+   psc = GetGLXScreenConfigs(dpy, screen);
+   if (psc == NULL)
+      return NULL;
+
+   if (fbconfigID != 0) {
+      mode = glx_config_find_fbconfig(psc->configs, fbconfigID);
+   } else if (visualID != 0) {
+      mode = glx_config_find_visual(psc->visuals, visualID);
+   }
+
    if (mode == NULL)
       return NULL;
 
@@ -1485,12 +1528,33 @@ _X_EXPORT GLXContextID glXGetContextIDEXT(const GLXContext ctx_user)
 {
    struct glx_context *ctx = (struct glx_context *) ctx_user;
 
-   return ctx->xid;
+   return (ctx == NULL) ? None : ctx->xid;
 }
 
-_X_EXPORT
-GLX_ALIAS_VOID(glXFreeContextEXT, (Display *dpy, GLXContext ctx), (dpy, ctx),
-              glXDestroyContext);
+_X_EXPORT void
+glXFreeContextEXT(Display *dpy, GLXContext ctx)
+{
+   struct glx_context *gc = (struct glx_context *) ctx;
+
+   if (gc == NULL || gc->xid == None)
+      return;
+
+   /* The GLX_EXT_import_context spec says:
+    *
+    *     "glXFreeContext does not free the server-side context information or
+    *     the XID associated with the server-side context."
+    *
+    * Don't send any protocol.  Just destroy the client-side tracking of the
+    * context.  Also, only release the context structure if it's not current.
+    */
+   __glXLock();
+   if (gc->currentDpy) {
+      gc->xid = None;
+   } else {
+      gc->vtable->destroy(gc);
+   }
+   __glXUnlock();
+}
 
 _X_EXPORT GLXFBConfig *
 glXChooseFBConfig(Display * dpy, int screen,
@@ -1506,7 +1570,7 @@ glXChooseFBConfig(Display * dpy, int screen,
    if ((config_list != NULL) && (list_size > 0) && (attribList != NULL)) {
       list_size = choose_visual(config_list, list_size, attribList, GL_TRUE);
       if (list_size == 0) {
-         XFree(config_list);
+         free(config_list);
          config_list = NULL;
       }
    }
@@ -1560,7 +1624,7 @@ glXGetFBConfigs(Display * dpy, int screen, int *nelements)
          }
       }
 
-      config_list = Xmalloc(num_configs * sizeof *config_list);
+      config_list = malloc(num_configs * sizeof *config_list);
       if (config_list != NULL) {
          *nelements = num_configs;
          i = 0;
@@ -2105,7 +2169,7 @@ __glXSwapBuffersMscOML(Display * dpy, GLXDrawable drawable,
 #ifdef GLX_DIRECT_RENDERING
    if (psc->driScreen && psc->driScreen->swapBuffers)
       return (*psc->driScreen->swapBuffers)(pdraw, target_msc, divisor,
-                                           remainder);
+                                           remainder, False);
 #endif
 
    return -1;
@@ -2245,8 +2309,7 @@ __glXCopySubBufferMESA(Display * dpy, GLXDrawable drawable,
    if (pdraw != NULL) {
       struct glx_screen *psc = pdraw->psc;
       if (psc->driScreen->copySubBuffer != NULL) {
-         glFlush();
-         (*psc->driScreen->copySubBuffer) (pdraw, x, y, width, height);
+         (*psc->driScreen->copySubBuffer) (pdraw, x, y, width, height, True);
       }
 
       return;
@@ -2332,7 +2395,7 @@ _X_HIDDEN char *
 __glXstrdup(const char *str)
 {
    char *copy;
-   copy = (char *) Xmalloc(strlen(str) + 1);
+   copy = malloc(strlen(str) + 1);
    if (!copy)
       return NULL;
    strcpy(copy, str);
@@ -2481,6 +2544,9 @@ static const struct name_address_pair GLX_functions[] = {
    GLX_FUNCTION(glXGetDriverConfig),
 #endif
 
+   /*** GLX_ARB_create_context and GLX_ARB_create_context_profile ***/
+   GLX_FUNCTION(glXCreateContextAttribsARB),
+
    {NULL, NULL}                 /* end of list */
 };