Merge branch '7.8'
[mesa.git] / src / gallium / state_trackers / egl / x11 / native_dri2.c
index 07f82d878c549cf9a1ecd987e9db202411e872d1..d37f66da07e479c9cfff82a725a8b0000f117951 100644 (file)
  * The above copyright notice and this permission notice shall be included
  * in all copies or substantial portions of the Software.
  *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * 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.
  */
 
 #include "util/u_memory.h"
 #include "util/u_math.h"
 #include "util/u_format.h"
+#include "util/u_inlines.h"
+#include "util/u_hash_table.h"
 #include "pipe/p_compiler.h"
 #include "pipe/p_screen.h"
 #include "pipe/p_context.h"
@@ -38,7 +41,6 @@
 enum dri2_surface_type {
    DRI2_SURFACE_TYPE_WINDOW,
    DRI2_SURFACE_TYPE_PIXMAP,
-   DRI2_SURFACE_TYPE_PBUFFER
 };
 
 struct dri2_display {
@@ -46,12 +48,18 @@ struct dri2_display {
    Display *dpy;
    boolean own_dpy;
 
+   struct native_event_handler *event_handler;
+
    struct drm_api *api;
    struct x11_screen *xscr;
    int xscr_number;
+   const char *dri_driver;
+   int dri_major, dri_minor;
 
    struct dri2_config *configs;
    int num_configs;
+
+   struct util_hash_table *surfaces;
 };
 
 struct dri2_surface {
@@ -61,10 +69,16 @@ struct dri2_surface {
    enum pipe_format color_format;
    struct dri2_display *dri2dpy;
 
-   struct pipe_texture *pbuffer_textures[NUM_NATIVE_ATTACHMENTS];
-   boolean have_back, have_fake;
+   unsigned int server_stamp;
+   unsigned int client_stamp;
    int width, height;
-   unsigned int sequence_number;
+   struct pipe_resource *textures[NUM_NATIVE_ATTACHMENTS];
+   uint valid_mask;
+
+   boolean have_back, have_fake;
+
+   struct x11_drawable_buffer *last_xbufs;
+   int last_num_xbufs;
 };
 
 struct dri2_config {
@@ -89,110 +103,113 @@ dri2_config(const struct native_config *nconf)
    return (struct dri2_config *) nconf;
 }
 
-static boolean
-dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
+/**
+ * Process the buffers returned by the server.
+ */
+static void
+dri2_surface_process_drawable_buffers(struct native_surface *nsurf,
+                                      struct x11_drawable_buffer *xbufs,
+                                      int num_xbufs)
 {
    struct dri2_surface *dri2surf = dri2_surface(nsurf);
    struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+   struct pipe_resource templ;
+   struct winsys_handle whandle;
+   uint valid_mask;
+   int i;
 
-   /* pbuffer is private */
-   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER)
-      return TRUE;
+   /* free the old textures */
+   for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++)
+      pipe_resource_reference(&dri2surf->textures[i], NULL);
+   dri2surf->valid_mask = 0x0;
 
-   /* copy to real front buffer */
-   if (dri2surf->have_fake)
-      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
-            0, 0, dri2surf->width, dri2surf->height,
-            DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
+   dri2surf->have_back = FALSE;
+   dri2surf->have_fake = FALSE;
 
-   return TRUE;
-}
+   if (!xbufs)
+      return;
 
-static boolean
-dri2_surface_swap_buffers(struct native_surface *nsurf)
-{
-   struct dri2_surface *dri2surf = dri2_surface(nsurf);
-   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+   memset(&templ, 0, sizeof(templ));
+   templ.target = PIPE_TEXTURE_2D;
+   templ.last_level = 0;
+   templ.width0 = dri2surf->width;
+   templ.height0 = dri2surf->height;
+   templ.depth0 = 1;
+   templ.format = dri2surf->color_format;
+   templ.bind = PIPE_BIND_RENDER_TARGET;
 
-   /* pbuffer is private */
-   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER)
-      return TRUE;
+   valid_mask = 0x0;
+   for (i = 0; i < num_xbufs; i++) {
+      struct x11_drawable_buffer *xbuf = &xbufs[i];
+      const char *desc;
+      enum native_attachment natt;
 
-   /* copy to front buffer */
-   if (dri2surf->have_back)
-      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
-            0, 0, dri2surf->width, dri2surf->height,
-            DRI2BufferBackLeft, DRI2BufferFrontLeft);
+      switch (xbuf->attachment) {
+      case DRI2BufferFrontLeft:
+         natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+         desc = "DRI2 Front Buffer";
+         break;
+      case DRI2BufferFakeFrontLeft:
+         natt = NATIVE_ATTACHMENT_FRONT_LEFT;
+         desc = "DRI2 Fake Front Buffer";
+         dri2surf->have_fake = TRUE;
+         break;
+      case DRI2BufferBackLeft:
+         natt = NATIVE_ATTACHMENT_BACK_LEFT;
+         desc = "DRI2 Back Buffer";
+         dri2surf->have_back = TRUE;
+         break;
+      default:
+         desc = NULL;
+         break;
+      }
 
-   /* and update fake front buffer */
-   if (dri2surf->have_fake)
-      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
-            0, 0, dri2surf->width, dri2surf->height,
-            DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
+      if (!desc || dri2surf->textures[natt]) {
+         if (!desc)
+            _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
+         else
+            _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
+         continue;
+      }
 
-   return TRUE;
+      memset(&whandle, 0, sizeof(whandle));
+      whandle.stride = xbuf->pitch;
+      whandle.handle = xbuf->name;
+      dri2surf->textures[natt] = dri2dpy->base.screen->resource_from_handle(
+         dri2dpy->base.screen, &templ, &whandle);
+      if (dri2surf->textures[natt])
+         valid_mask |= 1 << natt;
+   }
+
+   dri2surf->valid_mask = valid_mask;
 }
 
-static boolean
-dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
-                      unsigned int *seq_num, struct pipe_texture **textures,
-                      int *width, int *height)
+/**
+ * Get the buffers from the server.
+ */
+static void
+dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask)
 {
    struct dri2_surface *dri2surf = dri2_surface(nsurf);
    struct dri2_display *dri2dpy = dri2surf->dri2dpy;
-   unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS];
-   struct pipe_texture templ;
+   unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS * 2];
+   int num_ins, num_outs, att;
    struct x11_drawable_buffer *xbufs;
-   int num_ins, num_outs, att, i;
-
-   if (attachment_mask) {
-      memset(&templ, 0, sizeof(templ));
-      templ.target = PIPE_TEXTURE_2D;
-      templ.last_level = 0;
-      templ.width0 = dri2surf->width;
-      templ.height0 = dri2surf->height;
-      templ.depth0 = 1;
-      templ.format = dri2surf->color_format;
-      templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
-
-      if (textures)
-         memset(textures, 0, sizeof(*textures) * NUM_NATIVE_ATTACHMENTS);
-   }
-
-   /* create textures for pbuffer */
-   if (dri2surf->type == DRI2_SURFACE_TYPE_PBUFFER) {
-      struct pipe_screen *screen = dri2dpy->base.screen;
-
-      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
-         struct pipe_texture *ptex = dri2surf->pbuffer_textures[att];
-
-         /* delay the allocation */
-         if (!native_attachment_mask_test(attachment_mask, att))
-            continue;
-
-         if (!ptex) {
-            ptex = screen->texture_create(screen, &templ);
-            dri2surf->pbuffer_textures[att] = ptex;
-         }
-
-         if (textures)
-            pipe_texture_reference(&textures[att], ptex);
-      }
-
-      if (seq_num)
-         *seq_num = dri2surf->sequence_number;
-      if (width)
-         *width = dri2surf->width;
-      if (height)
-         *height = dri2surf->height;
-
-      return TRUE;
+   uint bpp = util_format_get_blocksizebits(dri2surf->color_format);
+   boolean with_format = FALSE; /* never ask for depth/stencil */
+
+   /* We must get the front on servers which doesn't support with format
+    * due to a silly bug in core dri2. You can't copy to/from a buffer
+    * that you haven't requested and you recive BadValue errors */
+   if (dri2surf->dri2dpy->dri_minor < 1) {
+      with_format = FALSE;
+      buffer_mask |= (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
    }
 
    /* prepare the attachments */
    num_ins = 0;
    for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
-      if (native_attachment_mask_test(attachment_mask, att)) {
+      if (native_attachment_mask_test(buffer_mask, att)) {
          unsigned int dri2att;
 
          switch (att) {
@@ -214,84 +231,139 @@ dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
             break;
          }
 
-         dri2atts[num_ins] = dri2att;
-         num_ins++;
+         dri2atts[num_ins++] = dri2att;
+         if (with_format)
+            dri2atts[num_ins++] = bpp;
       }
    }
-
-   dri2surf->have_back = FALSE;
-   dri2surf->have_fake = FALSE;
-
-   /* remember old geometry */
-   templ.width0 = dri2surf->width;
-   templ.height0 = dri2surf->height;
+   if (with_format)
+      num_ins /= 2;
 
    xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable,
                                     &dri2surf->width, &dri2surf->height,
-                                    dri2atts, FALSE, num_ins, &num_outs);
-   if (!xbufs)
-      return FALSE;
+                                    dri2atts, with_format, num_ins, &num_outs);
+
+   /* we should be able to do better... */
+   if (xbufs && dri2surf->last_num_xbufs == num_outs &&
+       memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) {
+      FREE(xbufs);
+      dri2surf->client_stamp = dri2surf->server_stamp;
+      return;
+   }
+
+   dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs);
+
+   dri2surf->server_stamp++;
+   dri2surf->client_stamp = dri2surf->server_stamp;
+
+   if (dri2surf->last_xbufs)
+      FREE(dri2surf->last_xbufs);
+   dri2surf->last_xbufs = xbufs;
+   dri2surf->last_num_xbufs = num_outs;
+}
 
-   if (templ.width0 != dri2surf->width || templ.height0 != dri2surf->height) {
-      /* are there cases where the buffers change and the geometry doesn't? */
-      dri2surf->sequence_number++;
+/**
+ * Update the buffers of the surface.  This is a slow function due to the
+ * round-trip to the server.
+ */
+static boolean
+dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+
+   dri2_surface_get_buffers(&dri2surf->base, buffer_mask);
+
+   return ((dri2surf->valid_mask & buffer_mask) == buffer_mask);
+}
 
-      templ.width0 = dri2surf->width;
-      templ.height0 = dri2surf->height;
+/**
+ * Return TRUE if the surface receives DRI2_InvalidateBuffers events.
+ */
+static INLINE boolean
+dri2_surface_receive_events(struct native_surface *nsurf)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+   return (dri2surf->dri2dpy->dri_minor >= 3);
+}
+
+static boolean
+dri2_surface_flush_frontbuffer(struct native_surface *nsurf)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
+
+   /* copy to real front buffer */
+   if (dri2surf->have_fake)
+      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+            0, 0, dri2surf->width, dri2surf->height,
+            DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
+
+   /* force buffers to be updated in next validation call */
+   if (!dri2_surface_receive_events(&dri2surf->base)) {
+      dri2surf->server_stamp++;
+      dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
+            &dri2surf->base, dri2surf->server_stamp);
    }
 
-   for (i = 0; i < num_outs; i++) {
-      struct x11_drawable_buffer *xbuf = &xbufs[i];
-      const char *desc;
-      enum native_attachment natt;
+   return TRUE;
+}
 
-      switch (xbuf->attachment) {
-      case DRI2BufferFrontLeft:
-         natt = NATIVE_ATTACHMENT_FRONT_LEFT;
-         desc = "DRI2 Front Buffer";
-         break;
-      case DRI2BufferFakeFrontLeft:
-         natt = NATIVE_ATTACHMENT_FRONT_LEFT;
-         desc = "DRI2 Fake Front Buffer";
-         dri2surf->have_fake = TRUE;
-         break;
-      case DRI2BufferBackLeft:
-         natt = NATIVE_ATTACHMENT_BACK_LEFT;
-         desc = "DRI2 Back Buffer";
-         dri2surf->have_back = TRUE;
-         break;
-      default:
-         desc = NULL;
-         break;
-      }
+static boolean
+dri2_surface_swap_buffers(struct native_surface *nsurf)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+   struct dri2_display *dri2dpy = dri2surf->dri2dpy;
 
-      if (!desc || !native_attachment_mask_test(attachment_mask, natt) ||
-          (textures && textures[natt])) {
-         if (!desc)
-            _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment);
-         else if (!native_attachment_mask_test(attachment_mask, natt))
-            _eglLog(_EGL_WARNING, "unexpected buffer %d", xbuf->attachment);
-         else
-            _eglLog(_EGL_WARNING, "both real and fake front buffers are listed");
-         continue;
-      }
+   /* copy to front buffer */
+   if (dri2surf->have_back)
+      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+            0, 0, dri2surf->width, dri2surf->height,
+            DRI2BufferBackLeft, DRI2BufferFrontLeft);
 
-      if (textures) {
-         struct pipe_texture *ptex =
-            dri2dpy->api->texture_from_shared_handle(dri2dpy->api,
-                  dri2dpy->base.screen, &templ,
-                  desc, xbuf->pitch, xbuf->name);
-         if (ptex) {
-            /* the caller owns the textures */
-            textures[natt] = ptex;
-         }
-      }
+   /* and update fake front buffer */
+   if (dri2surf->have_fake)
+      x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable,
+            0, 0, dri2surf->width, dri2surf->height,
+            DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
+
+   /* force buffers to be updated in next validation call */
+   if (!dri2_surface_receive_events(&dri2surf->base)) {
+      dri2surf->server_stamp++;
+      dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
+            &dri2surf->base, dri2surf->server_stamp);
    }
 
-   free(xbufs);
+   return TRUE;
+}
+
+static boolean
+dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask,
+                      unsigned int *seq_num, struct pipe_resource **textures,
+                      int *width, int *height)
+{
+   struct dri2_surface *dri2surf = dri2_surface(nsurf);
+
+   if (dri2surf->server_stamp != dri2surf->client_stamp ||
+       (dri2surf->valid_mask & attachment_mask) != attachment_mask) {
+      if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask))
+         return FALSE;
+   }
 
    if (seq_num)
-      *seq_num = dri2surf->sequence_number;
+      *seq_num = dri2surf->client_stamp;
+
+   if (textures) {
+      int att;
+      for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) {
+         if (native_attachment_mask_test(attachment_mask, att)) {
+            struct pipe_resource *ptex = dri2surf->textures[att];
+
+            textures[att] = NULL;
+            pipe_resource_reference(&textures[att], ptex);
+         }
+      }
+   }
+
    if (width)
       *width = dri2surf->width;
    if (height)
@@ -319,15 +391,22 @@ dri2_surface_destroy(struct native_surface *nsurf)
    struct dri2_surface *dri2surf = dri2_surface(nsurf);
    int i;
 
+   if (dri2surf->last_xbufs)
+      FREE(dri2surf->last_xbufs);
+
    for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) {
-      struct pipe_texture *ptex = dri2surf->pbuffer_textures[i];
-      pipe_texture_reference(&ptex, NULL);
+      struct pipe_resource *ptex = dri2surf->textures[i];
+      pipe_resource_reference(&ptex, NULL);
    }
 
-   if (dri2surf->drawable)
+   if (dri2surf->drawable) {
       x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr,
             dri2surf->drawable, FALSE);
-   free(dri2surf);
+
+      util_hash_table_remove(dri2surf->dri2dpy->surfaces,
+            (void *) dri2surf->drawable);
+   }
+   FREE(dri2surf);
 }
 
 static struct dri2_surface *
@@ -344,9 +423,6 @@ dri2_display_create_surface(struct native_display *ndpy,
    if (!dri2surf)
       return NULL;
 
-   if (drawable)
-      x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
-
    dri2surf->dri2dpy = dri2dpy;
    dri2surf->type = type;
    dri2surf->drawable = drawable;
@@ -358,6 +434,15 @@ dri2_display_create_surface(struct native_display *ndpy,
    dri2surf->base.validate = dri2_surface_validate;
    dri2surf->base.wait = dri2_surface_wait;
 
+   if (drawable) {
+      x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE);
+      /* initialize the geometry */
+      dri2_surface_update_buffers(&dri2surf->base, 0x0);
+
+      util_hash_table_set(dri2surf->dri2dpy->surfaces,
+            (void *) dri2surf->drawable, (void *) &dri2surf->base);
+   }
+
    return dri2surf;
 }
 
@@ -385,34 +470,6 @@ dri2_display_create_pixmap_surface(struct native_display *ndpy,
    return (dri2surf) ? &dri2surf->base : NULL;
 }
 
-static struct native_surface *
-dri2_display_create_pbuffer_surface(struct native_display *ndpy,
-                                    const struct native_config *nconf,
-                                    uint width, uint height)
-{
-   struct dri2_surface *dri2surf;
-
-   dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_PBUFFER,
-         (Drawable) None, nconf);
-   if (dri2surf) {
-      dri2surf->width = width;
-      dri2surf->height = height;
-   }
-   return (dri2surf) ? &dri2surf->base : NULL;
-}
-
-static struct pipe_context *
-dri2_display_create_context(struct native_display *ndpy, void *context_private)
-{
-   struct dri2_display *dri2dpy = dri2_display(ndpy);
-   struct pipe_context *pctx;
-
-   pctx = dri2dpy->api->create_context(dri2dpy->api, dri2dpy->base.screen);
-   if (pctx)
-      pctx->priv = context_private;
-   return pctx;
-}
-
 static int
 choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
 {
@@ -420,47 +477,17 @@ choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32])
 
    switch (mode->rgbBits) {
    case 32:
-      formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
       formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
+      formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
       break;
    case 24:
-      formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
       formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM;
-      formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
+      formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM;
       formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM;
+      formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM;
       break;
    case 16:
-      formats[count++] = PIPE_FORMAT_R5G6B5_UNORM;
-      break;
-   default:
-      break;
-   }
-
-   return count;
-}
-
-static int
-choose_depth_stencil_format(const __GLcontextModes *mode,
-                            enum pipe_format formats[32])
-{
-   int count = 0;
-
-   switch (mode->depthBits) {
-   case 32:
-      formats[count++] = PIPE_FORMAT_Z32_UNORM;
-      break;
-   case 24:
-      if (mode->stencilBits) {
-         formats[count++] = PIPE_FORMAT_S8Z24_UNORM;
-         formats[count++] = PIPE_FORMAT_Z24S8_UNORM;
-      }
-      else {
-         formats[count++] = PIPE_FORMAT_X8Z24_UNORM;
-         formats[count++] = PIPE_FORMAT_Z24X8_UNORM;
-      }
-      break;
-   case 16:
-      formats[count++] = PIPE_FORMAT_Z16_UNORM;
+      formats[count++] = PIPE_FORMAT_B5G6R5_UNORM;
       break;
    default:
       break;
@@ -474,8 +501,8 @@ is_format_supported(struct pipe_screen *screen,
                     enum pipe_format fmt, boolean is_color)
 {
    return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D,
-         (is_color) ? PIPE_TEXTURE_USAGE_RENDER_TARGET :
-         PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0);
+         (is_color) ? PIPE_BIND_RENDER_TARGET :
+         PIPE_BIND_DEPTH_STENCIL, 0);
 }
 
 static boolean
@@ -493,30 +520,18 @@ dri2_display_convert_config(struct native_display *ndpy,
    if (!mode->doubleBufferMode)
       return FALSE;
 
-   nconf->mode = *mode;
-   nconf->mode.renderType = GLX_RGBA_BIT;
-   nconf->mode.rgbMode = TRUE;
-   /* pbuffer is allocated locally and is always supported */
-   nconf->mode.drawableType |= GLX_PBUFFER_BIT;
-   /* the swap method is always copy */
-   nconf->mode.swapMethod = GLX_SWAP_COPY_OML;
-
-   /* fix up */
-   nconf->mode.rgbBits =
-      nconf->mode.redBits + nconf->mode.greenBits +
-      nconf->mode.blueBits + nconf->mode.alphaBits;
-   if (!(nconf->mode.drawableType & GLX_WINDOW_BIT)) {
-      nconf->mode.visualID = 0;
-      nconf->mode.visualType = GLX_NONE;
-   }
-   if (!(nconf->mode.drawableType & GLX_PBUFFER_BIT)) {
-      nconf->mode.bindToTextureRgb = FALSE;
-      nconf->mode.bindToTextureRgba = FALSE;
-   }
+   /* only interested in native renderable configs */
+   if (!mode->xRenderable || !mode->drawableType)
+      return FALSE;
 
-   nconf->color_format = PIPE_FORMAT_NONE;
-   nconf->depth_format = PIPE_FORMAT_NONE;
-   nconf->stencil_format = PIPE_FORMAT_NONE;
+   nconf->buffer_mask = 1 << NATIVE_ATTACHMENT_FRONT_LEFT;
+   if (mode->doubleBufferMode)
+      nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_LEFT;
+   if (mode->stereoMode) {
+      nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_FRONT_RIGHT;
+      if (mode->doubleBufferMode)
+         nconf->buffer_mask |= 1 << NATIVE_ATTACHMENT_BACK_RIGHT;
+   }
 
    /* choose color format */
    num_formats = choose_color_format(mode, formats);
@@ -529,18 +544,24 @@ dri2_display_convert_config(struct native_display *ndpy,
    if (nconf->color_format == PIPE_FORMAT_NONE)
       return FALSE;
 
-   /* choose depth/stencil format */
-   num_formats = choose_depth_stencil_format(mode, formats);
-   for (i = 0; i < num_formats; i++) {
-      if (is_format_supported(ndpy->screen, formats[i], FALSE)) {
-         nconf->depth_format = formats[i];
-         nconf->stencil_format = formats[i];
-         break;
-      }
+   if (mode->drawableType & GLX_WINDOW_BIT)
+      nconf->window_bit = TRUE;
+   if (mode->drawableType & GLX_PIXMAP_BIT)
+      nconf->pixmap_bit = TRUE;
+
+   nconf->native_visual_id = mode->visualID;
+   nconf->native_visual_type = mode->visualType;
+   nconf->level = mode->level;
+   nconf->samples = mode->samples;
+
+   nconf->slow_config = (mode->visualRating == GLX_SLOW_CONFIG);
+
+   if (mode->transparentPixel == GLX_TRANSPARENT_RGB) {
+      nconf->transparent_rgb = TRUE;
+      nconf->transparent_rgb_values[0] = mode->transparentRed;
+      nconf->transparent_rgb_values[1] = mode->transparentGreen;
+      nconf->transparent_rgb_values[2] = mode->transparentBlue;
    }
-   if ((nconf->mode.depthBits && nconf->depth_format == PIPE_FORMAT_NONE) ||
-       (nconf->mode.stencilBits && nconf->stencil_format == PIPE_FORMAT_NONE))
-      return FALSE;
 
    return TRUE;
 }
@@ -562,7 +583,7 @@ dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
          return NULL;
       num_modes = x11_context_modes_count(modes);
 
-      dri2dpy->configs = calloc(num_modes, sizeof(*dri2dpy->configs));
+      dri2dpy->configs = CALLOC(num_modes, sizeof(*dri2dpy->configs));
       if (!dri2dpy->configs)
          return NULL;
 
@@ -577,7 +598,7 @@ dri2_display_get_configs(struct native_display *ndpy, int *num_configs)
       dri2dpy->num_configs = count;
    }
 
-   configs = malloc(dri2dpy->num_configs * sizeof(*configs));
+   configs = MALLOC(dri2dpy->num_configs * sizeof(*configs));
    if (configs) {
       for (i = 0; i < dri2dpy->num_configs; i++)
          configs[i] = (const struct native_config *) &dri2dpy->configs[i];
@@ -603,24 +624,67 @@ dri2_display_is_pixmap_supported(struct native_display *ndpy,
    return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth));
 }
 
+static int
+dri2_display_get_param(struct native_display *ndpy,
+                       enum native_param_type param)
+{
+   int val;
+
+   switch (param) {
+   case NATIVE_PARAM_USE_NATIVE_BUFFER:
+      /* DRI2GetBuffers use the native buffers */
+      val = TRUE;
+      break;
+   default:
+      val = 0;
+      break;
+   }
+
+   return val;
+}
+
 static void
 dri2_display_destroy(struct native_display *ndpy)
 {
    struct dri2_display *dri2dpy = dri2_display(ndpy);
 
    if (dri2dpy->configs)
-      free(dri2dpy->configs);
+      FREE(dri2dpy->configs);
 
    if (dri2dpy->base.screen)
       dri2dpy->base.screen->destroy(dri2dpy->base.screen);
 
+   if (dri2dpy->surfaces)
+      util_hash_table_destroy(dri2dpy->surfaces);
+
    if (dri2dpy->xscr)
       x11_screen_destroy(dri2dpy->xscr);
    if (dri2dpy->own_dpy)
       XCloseDisplay(dri2dpy->dpy);
    if (dri2dpy->api && dri2dpy->api->destroy)
       dri2dpy->api->destroy(dri2dpy->api);
-   free(dri2dpy);
+   FREE(dri2dpy);
+}
+
+static void
+dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable,
+                                void *user_data)
+{
+   struct native_display *ndpy = (struct native_display* ) user_data;
+   struct dri2_display *dri2dpy = dri2_display(ndpy);
+   struct native_surface *nsurf;
+   struct dri2_surface *dri2surf;
+
+   nsurf = (struct native_surface *)
+      util_hash_table_get(dri2dpy->surfaces, (void *) drawable);
+   if (!nsurf)
+      return;
+
+   dri2surf = dri2_surface(nsurf);
+
+   dri2surf->server_stamp++;
+   dri2dpy->event_handler->invalid_surface(&dri2dpy->base,
+         &dri2surf->base, dri2surf->server_stamp);
 }
 
 /**
@@ -631,7 +695,6 @@ dri2_display_init_screen(struct native_display *ndpy)
 {
    struct dri2_display *dri2dpy = dri2_display(ndpy);
    const char *driver = dri2dpy->api->name;
-   struct drm_create_screen_arg arg;
    int fd;
 
    if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) ||
@@ -640,13 +703,21 @@ dri2_display_init_screen(struct native_display *ndpy)
       return FALSE;
    }
 
-   fd = x11_screen_enable_dri2(dri2dpy->xscr, driver);
+   dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr,
+         &dri2dpy->dri_major, &dri2dpy->dri_minor);
+   if (!dri2dpy->dri_driver || !driver ||
+       strcmp(dri2dpy->dri_driver, driver) != 0) {
+      _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s",
+            dri2dpy->dri_driver, dri2dpy->api->name);
+      return FALSE;
+   }
+
+   fd = x11_screen_enable_dri2(dri2dpy->xscr,
+         dri2_display_invalidate_buffers, &dri2dpy->base);
    if (fd < 0)
       return FALSE;
 
-   memset(&arg, 0, sizeof(arg));
-   arg.mode = DRM_CREATE_NORMAL;
-   dri2dpy->base.screen = dri2dpy->api->create_screen(dri2dpy->api, fd, &arg);
+   dri2dpy->base.screen = dri2dpy->api->create_screen(dri2dpy->api, fd, NULL);
    if (!dri2dpy->base.screen) {
       _eglLog(_EGL_WARNING, "failed to create DRM screen");
       return FALSE;
@@ -655,8 +726,23 @@ dri2_display_init_screen(struct native_display *ndpy)
    return TRUE;
 }
 
+static unsigned
+dri2_display_hash_table_hash(void *key)
+{
+   XID drawable = pointer_to_uintptr(key);
+   return (unsigned) drawable;
+}
+
+static int
+dri2_display_hash_table_compare(void *key1, void *key2)
+{
+   return (key1 - key2);
+}
+
 struct native_display *
-x11_create_dri2_display(EGLNativeDisplayType dpy, struct drm_api *api)
+x11_create_dri2_display(EGLNativeDisplayType dpy,
+                        struct native_event_handler *event_handler,
+                        struct drm_api *api)
 {
    struct dri2_display *dri2dpy;
 
@@ -664,12 +750,8 @@ x11_create_dri2_display(EGLNativeDisplayType dpy, struct drm_api *api)
    if (!dri2dpy)
       return NULL;
 
+   dri2dpy->event_handler = event_handler;
    dri2dpy->api = api;
-   if (!dri2dpy->api) {
-      _eglLog(_EGL_WARNING, "failed to create DRM API");
-      free(dri2dpy);
-      return NULL;
-   }
 
    dri2dpy->dpy = dpy;
    if (!dri2dpy->dpy) {
@@ -693,13 +775,19 @@ x11_create_dri2_display(EGLNativeDisplayType dpy, struct drm_api *api)
       return NULL;
    }
 
+   dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash,
+         dri2_display_hash_table_compare);
+   if (!dri2dpy->surfaces) {
+      dri2_display_destroy(&dri2dpy->base);
+      return NULL;
+   }
+
    dri2dpy->base.destroy = dri2_display_destroy;
+   dri2dpy->base.get_param = dri2_display_get_param;
    dri2dpy->base.get_configs = dri2_display_get_configs;
    dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported;
-   dri2dpy->base.create_context = dri2_display_create_context;
    dri2dpy->base.create_window_surface = dri2_display_create_window_surface;
    dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface;
-   dri2dpy->base.create_pbuffer_surface = dri2_display_create_pbuffer_surface;
 
    return &dri2dpy->base;
 }