tu: Implement fallback linear staging blit for CopyImage
[mesa.git] / src / gallium / state_trackers / glx / xlib / xm_api.c
index f950c8858bc164dfccbde3e770de39e29d679245..94a787b422aa198c834fc170b11e965eba5ed9d0 100644 (file)
@@ -1,6 +1,5 @@
 /*
  * Mesa 3-D graphics library
- * Version:  7.1
  *
  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /**
 #undef __WIN32__
 #endif
 
+#include <stdio.h>
 #include "xm_api.h"
 #include "xm_st.h"
 
+#include "pipe/p_context.h"
 #include "pipe/p_defines.h"
 #include "pipe/p_screen.h"
-#include "pipe/p_context.h"
+#include "pipe/p_state.h"
+#include "state_tracker/st_api.h"
+
+#include "util/u_atomic.h"
+#include "util/u_inlines.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+#include "hud/hud_context.h"
+
+#include "main/errors.h"
 
 #include "xm_public.h"
 #include <GL/glx.h>
@@ -103,14 +115,6 @@ void xmesa_set_driver( const struct xm_driver *templ )
 }
 
 
-/*
- * XXX replace this with a linked list, or better yet, try to attach the
- * gallium/mesa extra bits to the X Display object with XAddExtension().
- */
-#define MAX_DISPLAYS 10
-static struct xmesa_display Displays[MAX_DISPLAYS];
-static int NumDisplays = 0;
-
 static int
 xmesa_get_param(struct st_manager *smapi,
                 enum st_manager_param param)
@@ -123,63 +127,148 @@ xmesa_get_param(struct st_manager *smapi,
    }
 }
 
+/* linked list of XMesaDisplay hooks per display */
+typedef struct _XMesaExtDisplayInfo {
+   struct _XMesaExtDisplayInfo *next;
+   Display *display;
+   struct xmesa_display mesaDisplay;
+} XMesaExtDisplayInfo;
+
+typedef struct _XMesaExtInfo {
+   XMesaExtDisplayInfo *head;
+   int ndisplays;
+} XMesaExtInfo;
+
+static XMesaExtInfo MesaExtInfo;
+
+/* hook to delete XMesaDisplay on XDestroyDisplay */
+extern void
+xmesa_close_display(Display *display)
+{
+   XMesaExtDisplayInfo *info, *prev;
+
+   /* These assertions are not valid since screen creation can fail and result
+    * in an empty list
+   assert(MesaExtInfo.ndisplays > 0);
+   assert(MesaExtInfo.head);
+   */
+
+   _XLockMutex(_Xglobal_lock);
+   /* first find display */
+   prev = NULL;
+   for (info = MesaExtInfo.head; info; info = info->next) {
+      if (info->display == display) {
+         prev = info;
+         break;
+      }
+   }
+
+   if (info == NULL) {
+      /* no display found */
+      _XUnlockMutex(_Xglobal_lock);
+      return;
+   }
+
+   /* remove display entry from list */
+   if (prev != MesaExtInfo.head) {
+      prev->next = info->next;
+   } else {
+      MesaExtInfo.head = info->next;
+   }
+   MesaExtInfo.ndisplays--;
+
+   _XUnlockMutex(_Xglobal_lock);
+
+   /* don't forget to clean up mesaDisplay */
+   XMesaDisplay xmdpy = &info->mesaDisplay;
+
+   /**
+    * XXX: Don't destroy the screens here, since there may still
+    * be some dangling screen pointers that are used after this point
+    * if (xmdpy->screen) {
+    *    xmdpy->screen->destroy(xmdpy->screen);
+    * }
+    */
+
+   if (xmdpy->smapi->destroy)
+      xmdpy->smapi->destroy(xmdpy->smapi);
+   free(xmdpy->smapi);
+
+   XFree((char *) info);
+}
+
 static XMesaDisplay
 xmesa_init_display( Display *display )
 {
-   pipe_static_mutex(init_mutex);
+   static mtx_t init_mutex = _MTX_INITIALIZER_NP;
    XMesaDisplay xmdpy;
-   int i;
+   XMesaExtDisplayInfo *info;
+
+   if (display == NULL) {
+      return NULL;
+   }
 
-   pipe_mutex_lock(init_mutex);
+   mtx_lock(&init_mutex);
 
-   /* Look for XMesaDisplay which corresponds to 'display' */
-   for (i = 0; i < NumDisplays; i++) {
-      if (Displays[i].display == display) {
+   /* Look for XMesaDisplay which corresponds to this display */
+   info = MesaExtInfo.head;
+   while(info) {
+      if (info->display == display) {
          /* Found it */
-         pipe_mutex_unlock(init_mutex);
-         return &Displays[i];
+         mtx_unlock(&init_mutex);
+         return  &info->mesaDisplay;
       }
+      info = info->next;
    }
 
-   /* Create new XMesaDisplay */
+   /* Not found.  Create new XMesaDisplay */
+   /* first allocate X-related resources and hook destroy callback */
 
-   assert(NumDisplays < MAX_DISPLAYS);
-   xmdpy = &Displays[NumDisplays];
-   NumDisplays++;
+   /* allocate mesa display info */
+   info = (XMesaExtDisplayInfo *) Xmalloc(sizeof(XMesaExtDisplayInfo));
+   if (info == NULL) {
+      mtx_unlock(&init_mutex);
+      return NULL;
+   }
+   info->display = display;
 
-   if (!xmdpy->display && display) {
-      xmdpy->display = display;
-      xmdpy->screen = driver.create_pipe_screen(display);
-      xmdpy->smapi = CALLOC_STRUCT(st_manager);
-      if (xmdpy->smapi) {
-         xmdpy->smapi->screen = xmdpy->screen;
-         xmdpy->smapi->get_param = xmesa_get_param;
-      }
+   xmdpy = &info->mesaDisplay; /* to be filled out below */
+   xmdpy->display = display;
+   xmdpy->pipe = NULL;
 
-      if (xmdpy->screen && xmdpy->smapi) {
-         pipe_mutex_init(xmdpy->mutex);
-      }
-      else {
-         if (xmdpy->screen) {
-            xmdpy->screen->destroy(xmdpy->screen);
-            xmdpy->screen = NULL;
-         }
-         if (xmdpy->smapi) {
-            FREE(xmdpy->smapi);
-            xmdpy->smapi = NULL;
-         }
+   xmdpy->smapi = CALLOC_STRUCT(st_manager);
+   if (!xmdpy->smapi) {
+      Xfree(info);
+      mtx_unlock(&init_mutex);
+      return NULL;
+   }
 
-         xmdpy->display = NULL;
-      }
+   xmdpy->screen = driver.create_pipe_screen(display);
+   if (!xmdpy->screen) {
+      free(xmdpy->smapi);
+      Xfree(info);
+      mtx_unlock(&init_mutex);
+      return NULL;
    }
-   if (!xmdpy->display || xmdpy->display != display)
-      xmdpy = NULL;
 
-   pipe_mutex_unlock(init_mutex);
+   /* At this point, both smapi and screen are known to be valid */
+   xmdpy->smapi->screen = xmdpy->screen;
+   xmdpy->smapi->get_param = xmesa_get_param;
+   (void) mtx_init(&xmdpy->mutex, mtx_plain);
+
+   /* chain to the list of displays */
+   _XLockMutex(_Xglobal_lock);
+   info->next = MesaExtInfo.head;
+   MesaExtInfo.head = info;
+   MesaExtInfo.ndisplays++;
+   _XUnlockMutex(_Xglobal_lock);
+
+   mtx_unlock(&init_mutex);
 
    return xmdpy;
 }
 
+
 /**********************************************************************/
 /*****                     X Utility Functions                    *****/
 /**********************************************************************/
@@ -216,7 +305,7 @@ bits_per_pixel( XMesaVisual xmv )
    /* Create a temporary XImage */
    img = XCreateImage( dpy, visinfo->visual, visinfo->depth,
                       ZPixmap, 0,           /*format, offset*/
-                      (char*) MALLOC(8),    /*data*/
+                      malloc(8),    /*data*/
                       1, 1,                 /*width, height*/
                       32,                   /*bitmap_pad*/
                       0                     /*bytes_per_line*/
@@ -238,7 +327,7 @@ bits_per_pixel( XMesaVisual xmv )
  * Do this by calling XGetWindowAttributes() for the window and
  * checking if we catch an X error.
  * Input:  dpy - the display
- *         win - the window to check for existance
+ *         win - the window to check for existence
  * Return:  GL_TRUE - window exists
  *          GL_FALSE - window doesn't exist
  */
@@ -291,9 +380,9 @@ xmesa_get_window_size(Display *dpy, XMesaBuffer b,
    XMesaDisplay xmdpy = xmesa_init_display(dpy);
    Status stat;
 
-   pipe_mutex_lock(xmdpy->mutex);
+   mtx_lock(&xmdpy->mutex);
    stat = get_drawable_size(dpy, b->ws.drawable, width, height);
-   pipe_mutex_unlock(xmdpy->mutex);
+   mtx_unlock(&xmdpy->mutex);
 
    if (!stat) {
       /* probably querying a window that's recently been destroyed */
@@ -315,7 +404,7 @@ xmesa_get_window_size(Display *dpy, XMesaBuffer b,
 static GLuint
 choose_pixel_format(XMesaVisual v)
 {
-   boolean native_byte_order = (host_byte_order() == 
+   boolean native_byte_order = (host_byte_order() ==
                                 ImageByteOrder(v->display));
 
    if (   GET_REDMASK(v)   == 0x0000ff
@@ -324,10 +413,10 @@ choose_pixel_format(XMesaVisual v)
        && v->BitsPerPixel == 32) {
       if (native_byte_order) {
          /* no byteswapping needed */
-         return PIPE_FORMAT_R8G8B8A8_UNORM;
+         return PIPE_FORMAT_RGBA8888_UNORM;
       }
       else {
-         return PIPE_FORMAT_A8B8G8R8_UNORM;
+         return PIPE_FORMAT_ABGR8888_UNORM;
       }
    }
    else if (   GET_REDMASK(v)   == 0xff0000
@@ -336,10 +425,10 @@ choose_pixel_format(XMesaVisual v)
             && v->BitsPerPixel == 32) {
       if (native_byte_order) {
          /* no byteswapping needed */
-         return PIPE_FORMAT_B8G8R8A8_UNORM;
+         return PIPE_FORMAT_BGRA8888_UNORM;
       }
       else {
-         return PIPE_FORMAT_A8R8G8B8_UNORM;
+         return PIPE_FORMAT_ARGB8888_UNORM;
       }
    }
    else if (   GET_REDMASK(v)   == 0x0000ff00
@@ -348,10 +437,10 @@ choose_pixel_format(XMesaVisual v)
             && v->BitsPerPixel == 32) {
       if (native_byte_order) {
          /* no byteswapping needed */
-         return PIPE_FORMAT_A8R8G8B8_UNORM;
+         return PIPE_FORMAT_ARGB8888_UNORM;
       }
       else {
-         return PIPE_FORMAT_B8G8R8A8_UNORM;
+         return PIPE_FORMAT_BGRA8888_UNORM;
       }
    }
    else if (   GET_REDMASK(v)   == 0xf800
@@ -372,13 +461,11 @@ choose_pixel_format(XMesaVisual v)
  * stencil sizes.
  */
 static enum pipe_format
-choose_depth_stencil_format(XMesaDisplay xmdpy, int depth, int stencil)
+choose_depth_stencil_format(XMesaDisplay xmdpy, int depth, int stencil,
+                            int sample_count)
 {
    const enum pipe_texture_target target = PIPE_TEXTURE_2D;
    const unsigned tex_usage = PIPE_BIND_DEPTH_STENCIL;
-   const unsigned geom_flags = (PIPE_TEXTURE_GEOM_NON_SQUARE |
-                                PIPE_TEXTURE_GEOM_NON_POWER_OF_TWO);
-   const unsigned sample_count = 0;
    enum pipe_format formats[8], fmt;
    int count, i;
 
@@ -392,8 +479,8 @@ choose_depth_stencil_format(XMesaDisplay xmdpy, int depth, int stencil)
       formats[count++] = PIPE_FORMAT_Z24X8_UNORM;
    }
    if (depth <= 24 && stencil <= 8) {
-      formats[count++] = PIPE_FORMAT_S8_USCALED_Z24_UNORM;
-      formats[count++] = PIPE_FORMAT_Z24_UNORM_S8_USCALED;
+      formats[count++] = PIPE_FORMAT_S8_UINT_Z24_UNORM;
+      formats[count++] = PIPE_FORMAT_Z24_UNORM_S8_UINT;
    }
    if (depth <= 32 && stencil == 0) {
       formats[count++] = PIPE_FORMAT_Z32_UNORM;
@@ -403,7 +490,7 @@ choose_depth_stencil_format(XMesaDisplay xmdpy, int depth, int stencil)
    for (i = 0; i < count; i++) {
       if (xmdpy->screen->is_format_supported(xmdpy->screen, formats[i],
                                              target, sample_count,
-                                             tex_usage, geom_flags)) {
+                                             sample_count, tex_usage)) {
          fmt = formats[i];
          break;
       }
@@ -423,7 +510,7 @@ static XMesaBuffer XMesaBufferList = NULL;
 
 /**
  * Allocate a new XMesaBuffer object which corresponds to the given drawable.
- * Note that XMesaBuffer is derived from GLframebuffer.
+ * Note that XMesaBuffer is derived from struct gl_framebuffer.
  * The new XMesaBuffer will not have any size (Width=Height=0).
  *
  * \param d  the corresponding X drawable (window or pixmap)
@@ -438,9 +525,8 @@ create_xmesa_buffer(Drawable d, BufferType type,
 {
    XMesaDisplay xmdpy = xmesa_init_display(vis->display);
    XMesaBuffer b;
-   uint width, height;
 
-   ASSERT(type == WINDOW || type == PIXMAP || type == PBUFFER);
+   assert(type == WINDOW || type == PIXMAP || type == PBUFFER);
 
    if (!xmdpy)
       return NULL;
@@ -457,7 +543,7 @@ create_xmesa_buffer(Drawable d, BufferType type,
    b->type = type;
    b->cmap = cmap;
 
-   get_drawable_size(vis->display, d, &width, &height);
+   get_drawable_size(vis->display, d, &b->width, &b->height);
 
    /*
     * Create framebuffer, but we'll plug in our own renderbuffers below.
@@ -517,6 +603,11 @@ xmesa_free_buffer(XMesaBuffer buffer)
           */
          b->ws.drawable = 0;
 
+         /* Notify the st manager that the associated framebuffer interface
+          * object is no longer valid.
+          */
+         stapi->destroy_drawable(stapi, buffer->stfb);
+
          /* XXX we should move the buffer to a delete-pending list and destroy
           * the buffer until it is no longer current.
           */
@@ -545,45 +636,36 @@ xmesa_free_buffer(XMesaBuffer buffer)
  * initializing the context's visual and buffer information.
  * \param v  the XMesaVisual to initialize
  * \param b  the XMesaBuffer to initialize (may be NULL)
- * \param rgb_flag  TRUE = RGBA mode, FALSE = color index mode
  * \param window  the window/pixmap we're rendering into
  * \param cmap  the colormap associated with the window/pixmap
  * \return GL_TRUE=success, GL_FALSE=failure
  */
 static GLboolean
 initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
-                             GLboolean rgb_flag, Drawable window,
-                             Colormap cmap)
+                             Drawable window, Colormap cmap)
 {
-   ASSERT(!b || b->xm_visual == v);
+   assert(!b || b->xm_visual == v);
 
    /* Save true bits/pixel */
    v->BitsPerPixel = bits_per_pixel(v);
    assert(v->BitsPerPixel > 0);
 
-   if (rgb_flag == GL_FALSE) {
-      /* COLOR-INDEXED WINDOW: not supported*/
+   /* RGB WINDOW:
+    * We support RGB rendering into almost any kind of visual.
+    */
+   const int xclass = v->visualType;
+   if (xclass != GLX_TRUE_COLOR && xclass != GLX_DIRECT_COLOR) {
+      _mesa_warning(NULL,
+         "XMesa: RGB mode rendering not supported in given visual.\n");
       return GL_FALSE;
    }
-   else {
-      /* RGB WINDOW:
-       * We support RGB rendering into almost any kind of visual.
-       */
-      const int xclass = v->mesa_visual.visualType;
-      if (xclass != GLX_TRUE_COLOR && xclass == !GLX_DIRECT_COLOR) {
-        _mesa_warning(NULL,
-            "XMesa: RGB mode rendering not supported in given visual.\n");
-        return GL_FALSE;
-      }
-      v->mesa_visual.indexBits = 0;
 
-      if (v->BitsPerPixel == 32) {
-         /* We use XImages for all front/back buffers.  If an X Window or
-          * X Pixmap is 32bpp, there's no guarantee that the alpha channel
-          * will be preserved.  For XImages we're in luck.
-          */
-         v->mesa_visual.alphaBits = 8;
-      }
+   if (v->BitsPerPixel == 32) {
+      /* We use XImages for all front/back buffers.  If an X Window or
+       * X Pixmap is 32bpp, there's no guarantee that the alpha channel
+       * will be preserved.  For XImages we're in luck.
+       */
+      v->mesa_visual.alphaBits = 8;
    }
 
    /*
@@ -591,7 +673,7 @@ initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
     * which can help Brian figure out what's going on when a user
     * reports bugs.
     */
-   if (_mesa_getenv("MESA_INFO")) {
+   if (getenv("MESA_INFO")) {
       printf("X/Mesa visual = %p\n", (void *) v);
       printf("X/Mesa level = %d\n", v->mesa_visual.level);
       printf("X/Mesa depth = %d\n", v->visinfo->depth);
@@ -607,12 +689,12 @@ initialize_visual_and_buffer(XMesaVisual v, XMesaBuffer b,
 
 /**
  * Convert an X visual type to a GLX visual type.
- * 
+ *
  * \param visualType X visual type (i.e., \c TrueColor, \c StaticGray, etc.)
  *        to be converted.
  * \return If \c visualType is a valid X visual type, a GLX visual type will
  *         be returned.  Otherwise \c GLX_NONE will be returned.
- * 
+ *
  * \note
  * This code was lifted directly from lib/GL/glx/glcontextmodes.c in the
  * DRI CVS tree.
@@ -684,8 +766,11 @@ XMesaVisual XMesaCreateVisual( Display *display,
    if (!xmdpy)
       return NULL;
 
+   if (!rgb_flag)
+      return NULL;
+
    /* For debugging only */
-   if (_mesa_getenv("MESA_XSYNC")) {
+   if (getenv("MESA_XSYNC")) {
       /* This makes debugging X easier.
        * In your debugger, set a breakpoint on _XError to stop when an
        * X protocol error is generated.
@@ -704,7 +789,7 @@ XMesaVisual XMesaCreateVisual( Display *display,
     * the struct but we may need some of the information contained in it
     * at a later time.
     */
-   v->visinfo = (XVisualInfo *) MALLOC(sizeof(*visinfo));
+   v->visinfo = malloc(sizeof(*visinfo));
    if (!v->visinfo) {
       free(v);
       return NULL;
@@ -716,13 +801,13 @@ XMesaVisual XMesaCreateVisual( Display *display,
    v->mesa_visual.redMask = visinfo->red_mask;
    v->mesa_visual.greenMask = visinfo->green_mask;
    v->mesa_visual.blueMask = visinfo->blue_mask;
-   v->mesa_visual.visualID = visinfo->visualid;
-   v->mesa_visual.screen = visinfo->screen;
+   v->visualID = visinfo->visualid;
+   v->screen = visinfo->screen;
 
 #if !(defined(__cplusplus) || defined(c_plusplus))
-   v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->class);
+   v->visualType = xmesa_convert_from_x_visual_type(visinfo->class);
 #else
-   v->mesa_visual.visualType = xmesa_convert_from_x_visual_type(visinfo->c_class);
+   v->visualType = xmesa_convert_from_x_visual_type(visinfo->c_class);
 #endif
 
    v->mesa_visual.visualRating = visualCaveat;
@@ -730,14 +815,14 @@ XMesaVisual XMesaCreateVisual( Display *display,
    if (alpha_flag)
       v->mesa_visual.alphaBits = 8;
 
-   (void) initialize_visual_and_buffer( v, NULL, rgb_flag, 0, 0 );
+   (void) initialize_visual_and_buffer( v, NULL, 0, 0 );
 
    {
-      const int xclass = v->mesa_visual.visualType;
+      const int xclass = v->visualType;
       if (xclass == GLX_TRUE_COLOR || xclass == GLX_DIRECT_COLOR) {
-         red_bits   = _mesa_bitcount(GET_REDMASK(v));
-         green_bits = _mesa_bitcount(GET_GREENMASK(v));
-         blue_bits  = _mesa_bitcount(GET_BLUEMASK(v));
+         red_bits   = util_bitcount(GET_REDMASK(v));
+         green_bits = util_bitcount(GET_GREENMASK(v));
+         blue_bits  = util_bitcount(GET_BLUEMASK(v));
       }
       else {
          /* this is an approximation */
@@ -756,9 +841,8 @@ XMesaVisual XMesaCreateVisual( Display *display,
 
    /* initialize visual */
    {
-      __GLcontextModes *vis = &v->mesa_visual;
+      struct gl_config *vis = &v->mesa_visual;
 
-      vis->rgbMode          = GL_TRUE;
       vis->doubleBufferMode = db_flag;
       vis->stereoMode       = stereo_flag;
 
@@ -768,7 +852,6 @@ XMesaVisual XMesaCreateVisual( Display *display,
       vis->alphaBits        = alpha_bits;
       vis->rgbBits          = red_bits + green_bits + blue_bits;
 
-      vis->indexBits      = 0;
       vis->depthBits      = depth_size;
       vis->stencilBits    = stencil_size;
 
@@ -777,15 +860,10 @@ XMesaVisual XMesaCreateVisual( Display *display,
       vis->accumBlueBits  = accum_blue_size;
       vis->accumAlphaBits = accum_alpha_size;
 
-      vis->haveAccumBuffer   = accum_red_size > 0;
-      vis->haveDepthBuffer   = depth_size > 0;
-      vis->haveStencilBuffer = stencil_size > 0;
-
       vis->numAuxBuffers = 0;
       vis->level = 0;
-      vis->pixmapMode = 0;
-      vis->sampleBuffers = 0;
-      vis->samples = 0;
+      vis->sampleBuffers = num_samples > 1;
+      vis->samples = num_samples;
    }
 
    v->stvis.buffer_mask = ST_ATTACHMENT_FRONT_LEFT_MASK;
@@ -798,14 +876,24 @@ XMesaVisual XMesaCreateVisual( Display *display,
    }
 
    v->stvis.color_format = choose_pixel_format(v);
+
+   /* Check format support at requested num_samples (for multisample) */
+   if (!xmdpy->screen->is_format_supported(xmdpy->screen,
+                                           v->stvis.color_format,
+                                           PIPE_TEXTURE_2D, num_samples,
+                                           num_samples,
+                                           PIPE_BIND_RENDER_TARGET))
+      v->stvis.color_format = PIPE_FORMAT_NONE;
+
    if (v->stvis.color_format == PIPE_FORMAT_NONE) {
-      FREE(v->visinfo);
-      FREE(v);
+      free(v->visinfo);
+      free(v);
       return NULL;
    }
 
    v->stvis.depth_stencil_format =
-      choose_depth_stencil_format(xmdpy, depth_size, stencil_size);
+      choose_depth_stencil_format(xmdpy, depth_size, stencil_size,
+                                  num_samples);
 
    v->stvis.accum_format = (accum_red_size +
          accum_green_size + accum_blue_size + accum_alpha_size) ?
@@ -828,13 +916,23 @@ void XMesaDestroyVisual( XMesaVisual v )
 }
 
 
+/**
+ * Return the informative name.
+ */
+const char *
+xmesa_get_name(void)
+{
+   return stapi->name;
+}
+
+
 /**
  * Do per-display initializations.
  */
-void
+int
 xmesa_init( Display *display )
 {
-   xmesa_init_display(display);
+   return xmesa_init_display(display) ? 0 : 1;
 }
 
 
@@ -846,42 +944,98 @@ xmesa_init( Display *display )
  * \return an XMesaContext or NULL if error.
  */
 PUBLIC
-XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list )
+XMesaContext XMesaCreateContext( XMesaVisual v, XMesaContext share_list,
+                                 GLuint major, GLuint minor,
+                                 GLuint profileMask, GLuint contextFlags)
 {
    XMesaDisplay xmdpy = xmesa_init_display(v->display);
    struct st_context_attribs attribs;
+   enum st_context_error ctx_err = 0;
    XMesaContext c;
 
    if (!xmdpy)
-      return NULL;
+      goto no_xmesa_context;
 
-   /* Note: the XMesaContext contains a Mesa GLcontext struct (inheritance) */
+   /* Note: the XMesaContext contains a Mesa struct gl_context struct (inheritance) */
    c = (XMesaContext) CALLOC_STRUCT(xmesa_context);
    if (!c)
-      return NULL;
+      goto no_xmesa_context;
 
    c->xm_visual = v;
    c->xm_buffer = NULL;   /* set later by XMesaMakeCurrent */
    c->xm_read_buffer = NULL;
 
    memset(&attribs, 0, sizeof(attribs));
-   attribs.profile = ST_PROFILE_DEFAULT;
    attribs.visual = v->stvis;
+   attribs.major = major;
+   attribs.minor = minor;
+   if (contextFlags & GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
+      attribs.flags |= ST_CONTEXT_FLAG_FORWARD_COMPATIBLE;
+   if (contextFlags & GLX_CONTEXT_DEBUG_BIT_ARB)
+      attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
+   if (contextFlags & GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB)
+      attribs.flags |= ST_CONTEXT_FLAG_ROBUST_ACCESS;
+
+   switch (profileMask) {
+   case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
+      /* There are no profiles before OpenGL 3.2.  The
+       * GLX_ARB_create_context_profile spec says:
+       *
+       *     "If the requested OpenGL version is less than 3.2,
+       *     GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
+       *     of the context is determined solely by the requested version."
+       */
+      if (major > 3 || (major == 3 && minor >= 2)) {
+         attribs.profile = ST_PROFILE_OPENGL_CORE;
+         break;
+      }
+      /* fall-through */
+   case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
+      /*
+       * The spec also says:
+       *
+       *     "If version 3.1 is requested, the context returned may implement
+       *     any of the following versions:
+       *
+       *       * Version 3.1. The GL_ARB_compatibility extension may or may not
+       *         be implemented, as determined by the implementation.
+       *       * The core profile of version 3.2 or greater."
+       *
+       * and because Mesa doesn't support GL_ARB_compatibility, the only chance to
+       * honour a 3.1 context is through core profile.
+       */
+      if (major == 3 && minor == 1) {
+         attribs.profile = ST_PROFILE_OPENGL_CORE;
+      } else {
+         attribs.profile = ST_PROFILE_DEFAULT;
+      }
+      break;
+   case GLX_CONTEXT_ES_PROFILE_BIT_EXT:
+      if (major >= 2) {
+         attribs.profile = ST_PROFILE_OPENGL_ES2;
+      } else {
+         attribs.profile = ST_PROFILE_OPENGL_ES1;
+      }
+      break;
+   default:
+      assert(0);
+      goto no_st;
+   }
 
-   c->st = stapi->create_context(stapi, xmdpy->smapi,
-         &attribs, (share_list) ? share_list->st : NULL);
+   c->st = stapi->create_context(stapi, xmdpy->smapi, &attribs,
+         &ctx_err, (share_list) ? share_list->st : NULL);
    if (c->st == NULL)
-      goto fail;
+      goto no_st;
 
    c->st->st_manager_private = (void *) c;
 
-   return c;
+   c->hud = hud_create(c->st->cso_context, NULL);
 
-fail:
-   if (c->st)
-      c->st->destroy(c->st);
+   return c;
 
+no_st:
    free(c);
+no_xmesa_context:
    return NULL;
 }
 
@@ -890,11 +1044,15 @@ fail:
 PUBLIC
 void XMesaDestroyContext( XMesaContext c )
 {
+   if (c->hud) {
+      hud_destroy(c->hud, NULL);
+   }
+
    c->st->destroy(c->st);
 
-   /* FIXME: We should destroy the screen here, but if we do so, surfaces may 
+   /* FIXME: We should destroy the screen here, but if we do so, surfaces may
     * outlive it, causing segfaults
-   struct pipe_screen *screen = c->st->pipe->screen; 
+   struct pipe_screen *screen = c->st->pipe->screen;
    screen->destroy(screen);
    */
 
@@ -945,8 +1103,7 @@ XMesaCreateWindowBuffer(XMesaVisual v, Window w)
    if (!b)
       return NULL;
 
-   if (!initialize_visual_and_buffer( v, b, v->mesa_visual.rgbMode,
-                                      (Drawable) w, cmap )) {
+   if (!initialize_visual_and_buffer( v, b, (Drawable) w, cmap )) {
       xmesa_free_buffer(b);
       return NULL;
    }
@@ -976,8 +1133,7 @@ XMesaCreatePixmapBuffer(XMesaVisual v, Pixmap p, Colormap cmap)
    if (!b)
       return NULL;
 
-   if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
-                                    (Drawable) p, cmap)) {
+   if (!initialize_visual_and_buffer(v, b, (Drawable) p, cmap)) {
       xmesa_free_buffer(b);
       return NULL;
    }
@@ -1011,8 +1167,8 @@ XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p,
       if (ctx->Extensions.ARB_texture_non_power_of_two) {
          target = GLX_TEXTURE_2D_EXT;
       }
-      else if (   _mesa_bitcount(b->width)  == 1
-               && _mesa_bitcount(b->height) == 1) {
+      else if (   util_bitcount(b->width)  == 1
+               && util_bitcount(b->height) == 1) {
          /* power of two size */
          if (b->height == 1) {
             target = GLX_TEXTURE_1D_EXT;
@@ -1035,8 +1191,7 @@ XMesaCreatePixmapTextureBuffer(XMesaVisual v, Pixmap p,
    b->TextureFormat = format;
    b->TextureMipmap = mipmap;
 
-   if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
-                                    (Drawable) p, cmap)) {
+   if (!initialize_visual_and_buffer(v, b, (Drawable) p, cmap)) {
       xmesa_free_buffer(b);
       return NULL;
    }
@@ -1065,8 +1220,7 @@ XMesaCreatePBuffer(XMesaVisual v, Colormap cmap,
    if (!b)
       return NULL;
 
-   if (!initialize_visual_and_buffer(v, b, v->mesa_visual.rgbMode,
-                                    drawable, cmap)) {
+   if (!initialize_visual_and_buffer(v, b, drawable, cmap)) {
       xmesa_free_buffer(b);
       return NULL;
    }
@@ -1092,10 +1246,7 @@ XMesaDestroyBuffer(XMesaBuffer b)
 void
 xmesa_notify_invalid_buffer(XMesaBuffer b)
 {
-   XMesaContext xmctx = XMesaGetCurrentContext();
-
-   if (xmctx && xmctx->xm_buffer == b)
-      xmctx->st->notify_invalid_framebuffer(xmctx->st, b->stfb);
+   p_atomic_inc(&b->stfb->stamp);
 }
 
 
@@ -1105,11 +1256,21 @@ xmesa_notify_invalid_buffer(XMesaBuffer b)
 void
 xmesa_check_buffer_size(XMesaBuffer b)
 {
+   GLuint old_width, old_height;
+
+   if (!b)
+      return;
+
    if (b->type == PBUFFER)
       return;
 
+   old_width = b->width;
+   old_height = b->height;
+
    xmesa_get_window_size(b->xm_visual->display, b, &b->width, &b->height);
-   xmesa_notify_invalid_buffer(b);
+
+   if (b->width != old_width || b->height != old_height)
+      xmesa_notify_invalid_buffer(b);
 }
 
 
@@ -1129,8 +1290,9 @@ GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer,
    }
 
    if (c) {
-      if (!drawBuffer || !readBuffer)
-         return GL_FALSE;  /* must specify buffers! */
+      if (!drawBuffer != !readBuffer) {
+         return GL_FALSE;  /* must specify zero or two buffers! */
+      }
 
       if (c == old_ctx &&
          c->xm_buffer == drawBuffer &&
@@ -1144,10 +1306,13 @@ GLboolean XMesaMakeCurrent2( XMesaContext c, XMesaBuffer drawBuffer,
       c->xm_buffer = drawBuffer;
       c->xm_read_buffer = readBuffer;
 
-      stapi->make_current(stapi, c->st, drawBuffer->stfb, readBuffer->stfb);
+      stapi->make_current(stapi, c->st,
+                          drawBuffer ? drawBuffer->stfb : NULL,
+                          readBuffer ? readBuffer->stfb : NULL);
 
       /* Solution to Stephane Rehel's problem with glXReleaseBuffersMESA(): */
-      drawBuffer->wasCurrent = GL_TRUE;
+      if (drawBuffer)
+         drawBuffer->wasCurrent = GL_TRUE;
    }
    else {
       /* Detach */
@@ -1185,12 +1350,15 @@ void XMesaSwapBuffers( XMesaBuffer b )
 {
    XMesaContext xmctx = XMesaGetCurrentContext();
 
+   /* Need to draw HUD before flushing */
+   if (xmctx && xmctx->hud) {
+      struct pipe_resource *back =
+         xmesa_get_framebuffer_resource(b->stfb, ST_ATTACHMENT_BACK_LEFT);
+      hud_run(xmctx->hud, NULL, back);
+   }
+
    if (xmctx && xmctx->xm_buffer == b) {
-      xmctx->st->flush( xmctx->st,
-            PIPE_FLUSH_RENDER_CACHE | 
-            PIPE_FLUSH_SWAPBUFFERS |
-            PIPE_FLUSH_FRAME,
-            NULL);
+      xmctx->st->flush( xmctx->st, ST_FLUSH_FRONT, NULL, NULL, NULL);
    }
 
    xmesa_swap_st_framebuffer(b->stfb);
@@ -1203,9 +1371,13 @@ void XMesaSwapBuffers( XMesaBuffer b )
  */
 void XMesaCopySubBuffer( XMesaBuffer b, int x, int y, int width, int height )
 {
+   XMesaContext xmctx = XMesaGetCurrentContext();
+
+   xmctx->st->flush( xmctx->st, ST_FLUSH_FRONT, NULL, NULL, NULL);
+
    xmesa_copy_st_framebuffer(b->stfb,
          ST_ATTACHMENT_BACK_LEFT, ST_ATTACHMENT_FRONT_LEFT,
-         x, y, width, height);
+         x, b->height - y - height, width, height);
 }
 
 
@@ -1216,9 +1388,10 @@ void XMesaFlush( XMesaContext c )
       XMesaDisplay xmdpy = xmesa_init_display(c->xm_visual->display);
       struct pipe_fence_handle *fence = NULL;
 
-      c->st->flush(c->st, PIPE_FLUSH_RENDER_CACHE | PIPE_FLUSH_FRAME, &fence);
+      c->st->flush(c->st, ST_FLUSH_FRONT, &fence, NULL, NULL);
       if (fence) {
-         xmdpy->screen->fence_finish(xmdpy->screen, fence, 0);
+         xmdpy->screen->fence_finish(xmdpy->screen, NULL, fence,
+                                     PIPE_TIMEOUT_INFINITE);
          xmdpy->screen->fence_reference(xmdpy->screen, &fence, NULL);
       }
       XFlush( c->xm_visual->display );
@@ -1283,12 +1456,93 @@ void XMesaGarbageCollect( void )
 }
 
 
+static enum st_attachment_type xmesa_attachment_type(int glx_attachment)
+{
+   switch(glx_attachment) {
+      case GLX_FRONT_LEFT_EXT:
+         return ST_ATTACHMENT_FRONT_LEFT;
+      case GLX_FRONT_RIGHT_EXT:
+         return ST_ATTACHMENT_FRONT_RIGHT;
+      case GLX_BACK_LEFT_EXT:
+         return ST_ATTACHMENT_BACK_LEFT;
+      case GLX_BACK_RIGHT_EXT:
+         return ST_ATTACHMENT_BACK_RIGHT;
+      default:
+         assert(0);
+         return ST_ATTACHMENT_FRONT_LEFT;
+   }
+}
 
 
 PUBLIC void
 XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer,
                   const int *attrib_list)
 {
+   struct st_context_iface *st = stapi->get_current(stapi);
+   struct st_framebuffer_iface* stfbi = drawable->stfb;
+   struct pipe_resource *res;
+   int x, y, w, h;
+   enum st_attachment_type st_attachment = xmesa_attachment_type(buffer);
+
+   x = 0;
+   y = 0;
+   w = drawable->width;
+   h = drawable->height;
+
+   /* We need to validate our attachments before using them,
+    * in case the texture doesn't exist yet. */
+   xmesa_st_framebuffer_validate_textures(stfbi, w, h, 1 << st_attachment);
+   res = xmesa_get_attachment(stfbi, st_attachment);
+
+   if (res) {
+      struct pipe_context* pipe = xmesa_get_context(stfbi);
+      enum pipe_format internal_format = res->format;
+      struct pipe_transfer *tex_xfer;
+      char *map;
+      int line, byte_width;
+      XImage *img;
+
+      internal_format = choose_pixel_format(drawable->xm_visual);
+
+      map = pipe_transfer_map(pipe, res,
+                              0, 0,    /* level, layer */
+                              PIPE_TRANSFER_WRITE,
+                              x, y,
+                              w, h, &tex_xfer);
+      if (!map)
+         return;
+
+      /* Grab the XImage that we want to turn into a texture. */
+      img = XGetImage(dpy,
+                      drawable->ws.drawable,
+                      x, y,
+                      w, h,
+                      AllPlanes,
+                      ZPixmap);
+
+      if (!img) {
+         pipe_transfer_unmap(pipe, tex_xfer);
+         return;
+      }
+
+      /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. */
+      byte_width = w * ((img->bits_per_pixel + 7) / 8);
+
+      for (line = 0; line < h; line++)
+         memcpy(&map[line * tex_xfer->stride],
+                &img->data[line * img->bytes_per_line],
+                byte_width);
+
+      pipe_transfer_unmap(pipe, tex_xfer);
+
+      st->teximage(st,
+                   ST_TEXTURE_2D,
+                   0,    /* level */
+                   internal_format,
+                   res,
+                   FALSE /* no mipmap */);
+
+   }
 }