glx: Refactor and simplify context creation
[mesa.git] / src / glx / glxext.c
index 6d6f89e79a274c66eaad034c4a1479d74f374cec..f9a5f7ce5d730f6f14f477ec2f5ada8a3ed08d68 100644 (file)
 #include <X11/extensions/Xext.h>
 #include <X11/extensions/extutil.h>
 #include <X11/extensions/dri2proto.h>
+#ifdef GLX_USE_APPLEGL
+#include "apple_glx.h"
+#include "apple_visual.h"
+#endif
 #include "glxextensions.h"
 #include "glcontextmodes.h"
 
@@ -64,8 +68,8 @@ _X_HIDDEN int __glXDebug = 0;
 
 /* Extension required boiler plate */
 
-static char *__glXExtensionName = GLX_EXTENSION_NAME;
-XExtensionInfo *__glXExtensionInfo = NULL;
+static const char __glXExtensionName[] = GLX_EXTENSION_NAME;
+static __GLXdisplayPrivate *glx_displays;
 
 static /* const */ char *error_list[] = {
    "GLXBadContext",
@@ -83,47 +87,22 @@ static /* const */ char *error_list[] = {
    "GLXBadWindow",
 };
 
-static int
-__glXCloseDisplay(Display * dpy, XExtCodes * codes)
-{
-   GLXContext gc;
-
-   gc = __glXGetCurrentContext();
-   if (dpy == gc->currentDpy) {
-      __glXSetCurrentContextNull();
-      __glXFreeContext(gc);
-   }
-
-   return XextRemoveDisplay(__glXExtensionInfo, dpy);
-}
-
+#ifdef GLX_USE_APPLEGL
+static char *__glXErrorString(Display *dpy, int code, XExtCodes *codes, 
+                              char *buf, int n);
+#endif
 
 static
 XEXT_GENERATE_ERROR_STRING(__glXErrorString, __glXExtensionName,
                            __GLX_NUMBER_ERRORS, error_list)
+
+static int
+__glXCloseDisplay(Display * dpy, XExtCodes * codes);
 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 */
-  NULL,                   /* copy_gc */
-  NULL,                   /* flush_gc */
-  NULL,                   /* free_gc */
-  NULL,                   /* create_font */
-  NULL,                   /* free_font */
-  __glXCloseDisplay,      /* close_display */
-  __glXWireToEvent,       /* wire_to_event */
-  __glXEventToWire,       /* event_to_wire */
-  NULL,                   /* error */
-  __glXErrorString,       /* error_string */
-};
-
-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
@@ -136,11 +115,12 @@ XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
 static Bool
 __glXWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
 {
-   XExtDisplayInfo *info = __glXFindDisplay(dpy);
+   __GLXdisplayPrivate *glx_dpy = __glXInitialize(dpy);
 
-   XextCheckExtension(dpy, info, __glXExtensionName, False);
+   if (glx_dpy == NULL)
+      return False;
 
-   switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
+   switch ((wire->u.u.type & 0x7f) - glx_dpy->codes->first_event) {
    case GLX_PbufferClobber:
    {
       GLXPbufferClobberEvent *aevent = (GLXPbufferClobberEvent *)event;
@@ -195,9 +175,10 @@ __glXWireToEvent(Display *dpy, XEvent *event, xEvent *wire)
 static Status
 __glXEventToWire(Display *dpy, XEvent *event, xEvent *wire)
 {
-   XExtDisplayInfo *info = __glXFindDisplay(dpy);
+   __GLXdisplayPrivate *glx_dpy = __glXInitialize(dpy);
 
-   XextCheckExtension(dpy, info, __glXExtensionName, False);
+   if (glx_dpy == NULL)
+      return False;
 
    switch (event->type) {
    case GLX_DAMAGED:
@@ -230,9 +211,9 @@ FreeScreenConfigs(__GLXdisplayPrivate * priv)
    GLint i, screens;
 
    /* Free screen configuration information */
-   psc = priv->screenConfigs;
    screens = ScreenCount(priv->dpy);
-   for (i = 0; i < screens; i++, psc++) {
+   for (i = 0; i < screens; i++) {
+      psc = priv->screenConfigs[i];
       if (psc->configs) {
          _gl_context_modes_destroy(psc->configs);
          if (psc->effectiveGLXexts)
@@ -245,20 +226,15 @@ FreeScreenConfigs(__GLXdisplayPrivate * priv)
       }
       Xfree((char *) psc->serverGLXexts);
 
-#ifdef GLX_DIRECT_RENDERING
-      if (psc->driver_configs) {
-         unsigned int j;
-         for (j = 0; psc->driver_configs[j]; j++)
-            free((__DRIconfig *) psc->driver_configs[j]);
-         free(psc->driver_configs);
-         psc->driver_configs = NULL;
-      }
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
       if (psc->driScreen) {
          psc->driScreen->destroyScreen(psc);
-         __glxHashDestroy(psc->drawHash);
-         XFree(psc->driScreen);
          psc->driScreen = NULL;
+      } else {
+        Xfree(psc);
       }
+#else
+      Xfree(psc);
 #endif
    }
    XFree((char *) priv->screenConfigs);
@@ -270,22 +246,36 @@ FreeScreenConfigs(__GLXdisplayPrivate * priv)
 ** structure.  The caller will free the extension structure.
 */
 static int
-__glXFreeDisplayPrivate(XExtData * extension)
+__glXCloseDisplay(Display * dpy, XExtCodes * codes)
 {
-   __GLXdisplayPrivate *priv;
+   __GLXdisplayPrivate *priv, **prev;
+   GLXContext gc;
+
+   _XLockMutex(_Xglobal_lock);
+   prev = &glx_displays;
+   for (priv = glx_displays; priv; prev = &priv->next, priv = priv->next) {
+      if (priv->dpy == dpy) {
+        (*prev)->next = priv->next;
+        break;
+      }
+   }
+   _XUnlockMutex(_Xglobal_lock);
+
+   gc = __glXGetCurrentContext();
+   if (dpy == gc->currentDpy) {
+      gc->vtable->destroy(gc);
+      __glXSetCurrentContextNull();
+   }
 
-   priv = (__GLXdisplayPrivate *) extension->private_data;
    FreeScreenConfigs(priv);
-   if (priv->serverGLXvendor) {
+   if (priv->serverGLXvendor)
       Xfree((char *) priv->serverGLXvendor);
-      priv->serverGLXvendor = 0x0;      /* to protect against double free's */
-   }
-   if (priv->serverGLXversion) {
+   if (priv->serverGLXversion)
       Xfree((char *) priv->serverGLXversion);
-      priv->serverGLXversion = 0x0;     /* to protect against double free's */
-   }
 
-#ifdef GLX_DIRECT_RENDERING
+   __glxHashDestroy(priv->drawHash);
+
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
    /* Free the direct rendering per display data */
    if (priv->driswDisplay)
       (*priv->driswDisplay->destroyDisplay) (priv->driswDisplay);
@@ -301,10 +291,9 @@ __glXFreeDisplayPrivate(XExtData * extension)
 #endif
 
    Xfree((char *) priv);
-   return 0;
-}
 
-/************************************************************************/
+   return 1;
+}
 
 /*
 ** Query the version of the GLX extension.  This procedure works even if
@@ -358,7 +347,20 @@ QueryVersion(Display * dpy, int opcode, int *major, int *minor)
 #endif /* USE_XCB */
 }
 
+/* 
+ * We don't want to enable this GLX_OML_swap_method in glxext.h, 
+ * because we can't support it.  The X server writes it out though,
+ * so we should handle it somehow, to avoid false warnings.
+ */
+enum {
+    IGNORE_GLX_SWAP_METHOD_OML = 0x8060
+};
+
 
+/*
+ * getVisualConfigs uses the !tagged_only path.
+ * getFBConfigs uses the tagged_only path.
+ */
 _X_HIDDEN void
 __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
                                     const INT32 * bp, Bool tagged_only,
@@ -392,7 +394,14 @@ __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
       config->numAuxBuffers = *bp++;
       config->level = *bp++;
 
+#ifdef GLX_USE_APPLEGL
+       /* AppleSGLX supports pixmap and pbuffers with all config. */
+       config->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
+       /* Unfortunately this can create an ABI compatibility problem. */
+       count -= 18;
+#else
       count -= __GLX_MIN_CONFIG_PROPS;
+#endif
    }
 
    /*
@@ -405,7 +414,9 @@ __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
     config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1
 
    for (i = 0; i < count; i += 2) {
-      switch (*bp++) {
+      long int tag = *bp++;
+      
+      switch (tag) {
       case GLX_RGBA:
          FETCH_OR_SET(rgbMode);
          break;
@@ -483,6 +494,10 @@ __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
          break;
       case GLX_DRAWABLE_TYPE:
          config->drawableType = *bp++;
+#ifdef GLX_USE_APPLEGL
+         /* AppleSGLX supports pixmap and pbuffers with all config. */
+         config->drawableType |= GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;              
+#endif
          break;
       case GLX_RENDER_TYPE:
          config->renderType = *bp++;
@@ -502,6 +517,7 @@ __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
       case GLX_MAX_PBUFFER_PIXELS:
          config->maxPbufferPixels = *bp++;
          break;
+#ifndef GLX_USE_APPLEGL
       case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
          config->optimalPbufferWidth = *bp++;
          break;
@@ -514,12 +530,19 @@ __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
       case GLX_SWAP_METHOD_OML:
          config->swapMethod = *bp++;
          break;
+#endif
       case GLX_SAMPLE_BUFFERS_SGIS:
          config->sampleBuffers = *bp++;
          break;
       case GLX_SAMPLES_SGIS:
          config->samples = *bp++;
          break;
+#ifdef GLX_USE_APPLEGL
+      case IGNORE_GLX_SWAP_METHOD_OML:
+         /* We ignore this tag.  See the comment above this function. */
+         ++bp;
+         break;
+#else
       case GLX_BIND_TO_TEXTURE_RGB_EXT:
          config->bindToTextureRgb = *bp++;
          break;
@@ -535,12 +558,23 @@ __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
       case GLX_Y_INVERTED_EXT:
          config->yInverted = *bp++;
          break;
+#endif
+      case GLX_USE_GL:
+         if (fbconfig_style_tags)
+            bp++;
+         break;
       case None:
          i = count;
          break;
       default:
-         /* Ignore the unrecognized tag's value */
-         bp++;
+         if(getenv("LIBGL_DIAGNOSTIC")) {
+             long int tagvalue = *bp++;
+             fprintf(stderr, "WARNING: unknown GLX tag from server: "
+                     "tag 0x%lx value 0x%lx\n", tag, tagvalue);
+         } else {
+             /* Ignore the unrecognized tag's value */
+             bp++;
+         }
          break;
       }
    }
@@ -589,9 +623,18 @@ createConfigsFromProperties(Display * dpy, int nvisuals, int nprops,
    m = modes;
    for (i = 0; i < nvisuals; i++) {
       _XRead(dpy, (char *) props, prop_size);
-      /* Older X servers don't send this so we default it here. */
+#ifdef GLX_USE_APPLEGL
+       /* Older X servers don't send this so we default it here. */
       m->drawableType = GLX_WINDOW_BIT;
-      __glXInitializeVisualConfigFromTags(m, nprops, props,
+#else
+      /* 
+       * The XQuartz 2.3.2.1 X server doesn't set this properly, so
+       * set the proper bits here.
+       * AppleSGLX supports windows, pixmaps, and pbuffers with all config.
+       */
+      m->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT;
+#endif
+       __glXInitializeVisualConfigFromTags(m, nprops, props,
                                           tagged_only, GL_TRUE);
       m->screen = screen;
       m = m->next;
@@ -604,15 +647,15 @@ createConfigsFromProperties(Display * dpy, int nvisuals, int nprops,
 }
 
 static GLboolean
-getVisualConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen)
+getVisualConfigs(__GLXscreenConfigs *psc,
+                __GLXdisplayPrivate *priv, int screen)
 {
    xGLXGetVisualConfigsReq *req;
-   __GLXscreenConfigs *psc;
    xGLXGetVisualConfigsReply reply;
+   Display *dpy = priv->dpy;
 
    LockDisplay(dpy);
 
-   psc = priv->screenConfigs + screen;
    psc->visuals = NULL;
    GetReq(GLXGetVisualConfigs, req);
    req->reqType = priv->majorOpcode;
@@ -633,15 +676,14 @@ getVisualConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen)
 }
 
 static GLboolean
-getFBConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen)
+getFBConfigs(__GLXscreenConfigs *psc, __GLXdisplayPrivate *priv, int screen)
 {
    xGLXGetFBConfigsReq *fb_req;
    xGLXGetFBConfigsSGIXReq *sgi_req;
    xGLXVendorPrivateWithReplyReq *vpreq;
    xGLXGetFBConfigsReply reply;
-   __GLXscreenConfigs *psc;
+   Display *dpy = priv->dpy;
 
-   psc = priv->screenConfigs + screen;
    psc->serverGLXexts =
       __glXQueryServerString(dpy, priv->majorOpcode, screen, GLX_EXTENSIONS);
 
@@ -680,6 +722,22 @@ getFBConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen)
    return psc->configs != NULL;
 }
 
+_X_HIDDEN Bool
+glx_screen_init(__GLXscreenConfigs *psc,
+               int screen, __GLXdisplayPrivate * priv)
+{
+   /* Initialize per screen dynamic client GLX extensions */
+   psc->ext_list_first_time = GL_TRUE;
+   psc->scr = screen;
+   psc->dpy = priv->dpy;
+   psc->display = priv;
+
+   getVisualConfigs(psc, priv, screen);
+   getFBConfigs(psc, priv, screen);
+
+   return GL_TRUE;
+}
+
 /*
 ** Allocate the memory for the per screen configs for each screen.
 ** If that works then fetch the per screen configs data.
@@ -694,12 +752,9 @@ AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv)
     ** First allocate memory for the array of per screen configs.
     */
    screens = ScreenCount(dpy);
-   psc = (__GLXscreenConfigs *) Xmalloc(screens * sizeof(__GLXscreenConfigs));
-   if (!psc) {
+   priv->screenConfigs = Xmalloc(screens * sizeof *priv->screenConfigs);
+   if (!priv->screenConfigs)
       return GL_FALSE;
-   }
-   memset(psc, 0, screens * sizeof(__GLXscreenConfigs));
-   priv->screenConfigs = psc;
 
    priv->serverGLXversion =
       __glXQueryServerString(dpy, priv->majorOpcode, 0, GLX_VERSION);
@@ -709,33 +764,18 @@ AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv)
    }
 
    for (i = 0; i < screens; i++, psc++) {
-      getVisualConfigs(dpy, priv, i);
-      getFBConfigs(dpy, priv, i);
-
-#ifdef GLX_DIRECT_RENDERING
-      psc->scr = i;
-      psc->dpy = dpy;
-      psc->drawHash = __glxHashCreate();
-      if (psc->drawHash == NULL)
-         continue;
-
-      /* Initialize per screen dynamic client GLX extensions */
-      psc->ext_list_first_time = GL_TRUE;
-
+      psc = NULL;
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
       if (priv->dri2Display)
-         psc->driScreen = (*priv->dri2Display->createScreen) (psc, i, priv);
-
-      if (psc->driScreen == NULL && priv->driDisplay)
-         psc->driScreen = (*priv->driDisplay->createScreen) (psc, i, priv);
-
-      if (psc->driScreen == NULL && priv->driswDisplay)
-         psc->driScreen = (*priv->driswDisplay->createScreen) (psc, i, priv);
-
-      if (psc->driScreen == NULL) {
-         __glxHashDestroy(psc->drawHash);
-         psc->drawHash = NULL;
-      }
+        psc = (*priv->dri2Display->createScreen) (i, priv);
+      if (psc == NULL && priv->driDisplay)
+        psc = (*priv->driDisplay->createScreen) (i, priv);
+      if (psc == NULL && priv->driswDisplay)
+        psc = (*priv->driswDisplay->createScreen) (i, priv);
 #endif
+      if (psc == NULL)
+        psc = indirect_create_screen(i, priv);
+      priv->screenConfigs[i] = psc;
    }
    SyncHandle();
    return GL_TRUE;
@@ -747,72 +787,59 @@ AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv)
 _X_HIDDEN __GLXdisplayPrivate *
 __glXInitialize(Display * dpy)
 {
-   XExtDisplayInfo *info = __glXFindDisplay(dpy);
-   XExtData **privList, *private, *found;
    __GLXdisplayPrivate *dpyPriv;
-   XEDataObject dataObj;
-   int major, minor;
-#ifdef GLX_DIRECT_RENDERING
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
    Bool glx_direct, glx_accel;
 #endif
+   int i;
 
-   /* The one and only long long lock */
-   __glXLock();
+   _XLockMutex(_Xglobal_lock);
 
-   if (!XextHasExtension(info)) {
-      /* No GLX extension supported by this server. Oh well. */
-      __glXUnlock();
-      XMissingExtension(dpy, __glXExtensionName);
-      return 0;
+   for (dpyPriv = glx_displays; dpyPriv; dpyPriv = dpyPriv->next) {
+      if (dpyPriv->dpy == dpy) {
+        _XUnlockMutex(_Xglobal_lock);
+        return dpyPriv;
+      }
    }
 
-   /* See if a display private already exists.  If so, return it */
-   dataObj.display = dpy;
-   privList = XEHeadOfExtensionList(dataObj);
-   found = XFindOnExtensionList(privList, info->codes->extension);
-   if (found) {
-      __glXUnlock();
-      return (__GLXdisplayPrivate *) found->private_data;
+   dpyPriv = Xcalloc(1, sizeof *dpyPriv);
+   if (!dpyPriv)
+      return NULL;
+
+   dpyPriv->codes = XInitExtension(dpy, __glXExtensionName);
+   if (!dpyPriv->codes) {
+      Xfree(dpyPriv);
+      _XUnlockMutex(_Xglobal_lock);
+      return NULL;
    }
 
+   dpyPriv->dpy = dpy;
+   dpyPriv->majorOpcode = dpyPriv->codes->major_opcode;
+   dpyPriv->serverGLXvendor = 0x0;
+   dpyPriv->serverGLXversion = 0x0;
+
    /* See if the versions are compatible */
-   if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor)) {
-      /* The client and server do not agree on versions.  Punt. */
-      __glXUnlock();
-      return 0;
+   if (!QueryVersion(dpy, dpyPriv->majorOpcode,
+                    &dpyPriv->majorVersion, &dpyPriv->minorVersion)) {
+      Xfree(dpyPriv);
+      _XUnlockMutex(_Xglobal_lock);
+      return NULL;
    }
 
-   /*
-    ** Allocate memory for all the pieces needed for this buffer.
-    */
-   private = (XExtData *) Xmalloc(sizeof(XExtData));
-   if (!private) {
-      __glXUnlock();
-      return 0;
+   for (i = 0; i < __GLX_NUMBER_EVENTS; i++) {
+      XESetWireToEvent(dpy, dpyPriv->codes->first_event + i, __glXWireToEvent);
+      XESetEventToWire(dpy, dpyPriv->codes->first_event + i, __glXEventToWire);
    }
-   dpyPriv = (__GLXdisplayPrivate *) Xcalloc(1, sizeof(__GLXdisplayPrivate));
-   if (!dpyPriv) {
-      __glXUnlock();
-      Xfree((char *) private);
-      return 0;
-   }
-
-   /*
-    ** Init the display private and then read in the screen config
-    ** structures from the server.
-    */
-   dpyPriv->majorOpcode = info->codes->major_opcode;
-   dpyPriv->majorVersion = major;
-   dpyPriv->minorVersion = minor;
-   dpyPriv->dpy = dpy;
 
-   dpyPriv->serverGLXvendor = 0x0;
-   dpyPriv->serverGLXversion = 0x0;
+   XESetCloseDisplay(dpy, dpyPriv->codes->extension, __glXCloseDisplay);
+   XESetErrorString (dpy, dpyPriv->codes->extension,__glXErrorString);
 
-#ifdef GLX_DIRECT_RENDERING
+#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
    glx_direct = (getenv("LIBGL_ALWAYS_INDIRECT") == NULL);
    glx_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
 
+   dpyPriv->drawHash = __glxHashCreate();
+
    /*
     ** Initialize the direct rendering per display data and functions.
     ** Note: This _must_ be done before calling any other DRI routines
@@ -826,28 +853,24 @@ __glXInitialize(Display * dpy)
       dpyPriv->driswDisplay = driswCreateDisplay(dpy);
 #endif
 
+#ifdef GLX_USE_APPLEGL
+   if (apple_init_glx(dpy)) {
+      Xfree(dpyPriv);
+      return NULL;
+   }
+#endif
    if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) {
-      __glXUnlock();
-      Xfree((char *) dpyPriv);
-      Xfree((char *) private);
-      return 0;
+      Xfree(dpyPriv);
+      return NULL;
    }
 
-   /*
-    ** Fill in the private structure.  This is the actual structure that
-    ** hangs off of the Display structure.  Our private structure is
-    ** referred to by this structure.  Got that?
-    */
-   private->number = info->codes->extension;
-   private->next = 0;
-   private->free_private = __glXFreeDisplayPrivate;
-   private->private_data = (char *) dpyPriv;
-   XAddToExtensionList(privList, private);
-
-   if (dpyPriv->majorVersion == 1 && dpyPriv->minorVersion >= 1) {
+   if (dpyPriv->majorVersion == 1 && dpyPriv->minorVersion >= 1)
       __glXClientInfo(dpy, dpyPriv->majorOpcode);
-   }
-   __glXUnlock();
+
+   dpyPriv->next = glx_displays;
+   glx_displays = dpyPriv;
+
+    _XUnlockMutex(_Xglobal_lock);
 
    return dpyPriv;
 }