st/dri: replace format conversion functions with single mapping table
[mesa.git] / src / gallium / state_trackers / dri / dri2.c
index 675a9bb21cfdc712d87d742d2e463ce0dd9ccacb..6fc07e42f746862eb7b6011eff2676a2a037839b 100644 (file)
@@ -29,7 +29,6 @@
  */
 
 #include <xf86drm.h>
-#include <dlfcn.h>
 #include "GL/mesa_glinterop.h"
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
 #include "main/bufferobj.h"
 #include "main/texobj.h"
 
-#include "dri_screen.h"
-#include "dri_context.h"
+#include "dri_util.h"
+
+#include "dri_helpers.h"
 #include "dri_drawable.h"
 #include "dri_query_renderer.h"
-#include "dri2_buffer.h"
 
-static int convert_fourcc(int format, int *dri_components_p)
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
+#endif
+
+struct dri2_buffer
 {
-   int dri_components;
-   switch(format) {
-   case __DRI_IMAGE_FOURCC_RGB565:
-      format = __DRI_IMAGE_FORMAT_RGB565;
-      dri_components = __DRI_IMAGE_COMPONENTS_RGB;
-      break;
-   case __DRI_IMAGE_FOURCC_ARGB8888:
-      format = __DRI_IMAGE_FORMAT_ARGB8888;
-      dri_components = __DRI_IMAGE_COMPONENTS_RGBA;
-      break;
-   case __DRI_IMAGE_FOURCC_XRGB8888:
-      format = __DRI_IMAGE_FORMAT_XRGB8888;
-      dri_components = __DRI_IMAGE_COMPONENTS_RGB;
-      break;
-   case __DRI_IMAGE_FOURCC_ABGR8888:
-      format = __DRI_IMAGE_FORMAT_ABGR8888;
-      dri_components = __DRI_IMAGE_COMPONENTS_RGBA;
-      break;
-   case __DRI_IMAGE_FOURCC_XBGR8888:
-      format = __DRI_IMAGE_FORMAT_XBGR8888;
-      dri_components = __DRI_IMAGE_COMPONENTS_RGB;
-      break;
-   default:
-      return -1;
-   }
-   *dri_components_p = dri_components;
-   return format;
-}
+   __DRIbuffer base;
+   struct pipe_resource *resource;
+};
 
-static int convert_to_fourcc(int format)
+static inline struct dri2_buffer *
+dri2_buffer(__DRIbuffer * driBufferPriv)
 {
-   switch(format) {
-   case __DRI_IMAGE_FORMAT_RGB565:
-      format = __DRI_IMAGE_FOURCC_RGB565;
-      break;
-   case __DRI_IMAGE_FORMAT_ARGB8888:
-      format = __DRI_IMAGE_FOURCC_ARGB8888;
-      break;
-   case __DRI_IMAGE_FORMAT_XRGB8888:
-      format = __DRI_IMAGE_FOURCC_XRGB8888;
-      break;
-   case __DRI_IMAGE_FORMAT_ABGR8888:
-      format = __DRI_IMAGE_FOURCC_ABGR8888;
-      break;
-   case __DRI_IMAGE_FORMAT_XBGR8888:
-      format = __DRI_IMAGE_FOURCC_XBGR8888;
-      break;
-   default:
-      return -1;
-   }
-   return format;
+   return (struct dri2_buffer *) driBufferPriv;
 }
 
-static enum pipe_format dri2_format_to_pipe_format (int format)
-{
-   enum pipe_format pf;
+struct dri2_format_mapping {
+   int dri_fourcc;
+   int dri_format;
+   int dri_components;
+   enum pipe_format pipe_format;
+};
 
-   switch (format) {
-   case __DRI_IMAGE_FORMAT_RGB565:
-      pf = PIPE_FORMAT_B5G6R5_UNORM;
-      break;
-   case __DRI_IMAGE_FORMAT_XRGB8888:
-      pf = PIPE_FORMAT_BGRX8888_UNORM;
-      break;
-   case __DRI_IMAGE_FORMAT_ARGB8888:
-      pf = PIPE_FORMAT_BGRA8888_UNORM;
-      break;
-   case __DRI_IMAGE_FORMAT_ABGR8888:
-      pf = PIPE_FORMAT_RGBA8888_UNORM;
-      break;
-   default:
-      pf = PIPE_FORMAT_NONE;
-      break;
+static const struct dri2_format_mapping dri2_format_table[] = {
+      { __DRI_IMAGE_FOURCC_ARGB2101010,   __DRI_IMAGE_FORMAT_ARGB2101010,
+        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_B10G10R10A2_UNORM },
+      { __DRI_IMAGE_FOURCC_XRGB2101010,   __DRI_IMAGE_FORMAT_XRGB2101010,
+        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_B10G10R10X2_UNORM },
+      { __DRI_IMAGE_FOURCC_ABGR2101010,   __DRI_IMAGE_FORMAT_ABGR2101010,
+        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_R10G10B10A2_UNORM },
+      { __DRI_IMAGE_FOURCC_XBGR2101010,   __DRI_IMAGE_FORMAT_XBGR2101010,
+        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_R10G10B10X2_UNORM },
+      { __DRI_IMAGE_FOURCC_ARGB8888,      __DRI_IMAGE_FORMAT_ARGB8888,
+        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_UNORM },
+      { __DRI_IMAGE_FOURCC_ABGR8888,      __DRI_IMAGE_FORMAT_ABGR8888,
+        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_RGBA8888_UNORM },
+      { __DRI_IMAGE_FOURCC_SARGB8888,     __DRI_IMAGE_FORMAT_SARGB8,
+        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_BGRA8888_SRGB },
+      { __DRI_IMAGE_FOURCC_XRGB8888,      __DRI_IMAGE_FORMAT_XRGB8888,
+        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_BGRX8888_UNORM },
+      { __DRI_IMAGE_FOURCC_XBGR8888,      __DRI_IMAGE_FORMAT_XBGR8888,
+        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_RGBX8888_UNORM },
+      { __DRI_IMAGE_FOURCC_ARGB1555,      __DRI_IMAGE_FORMAT_RGB565,
+        __DRI_IMAGE_COMPONENTS_RGBA,      PIPE_FORMAT_B5G5R5A1_UNORM },
+      { __DRI_IMAGE_FOURCC_RGB565,        __DRI_IMAGE_FORMAT_RGB565,
+        __DRI_IMAGE_COMPONENTS_RGB,       PIPE_FORMAT_B5G6R5_UNORM },
+      { __DRI_IMAGE_FOURCC_R8,            __DRI_IMAGE_FORMAT_R8,
+        __DRI_IMAGE_COMPONENTS_R,         PIPE_FORMAT_R8_UNORM },
+      { __DRI_IMAGE_FOURCC_R16,           __DRI_IMAGE_FORMAT_R16,
+        __DRI_IMAGE_COMPONENTS_R,         PIPE_FORMAT_R16_UNORM },
+      { __DRI_IMAGE_FOURCC_GR88,          __DRI_IMAGE_FORMAT_GR88,
+        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG88_UNORM },
+      { __DRI_IMAGE_FOURCC_GR1616,        __DRI_IMAGE_FORMAT_GR88,
+        __DRI_IMAGE_COMPONENTS_RG,        PIPE_FORMAT_RG1616_UNORM },
+      { __DRI_IMAGE_FOURCC_YUV420,        __DRI_IMAGE_FORMAT_NONE,
+        __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_IYUV },
+      { __DRI_IMAGE_FOURCC_YVU420,        __DRI_IMAGE_FORMAT_NONE,
+        __DRI_IMAGE_COMPONENTS_Y_U_V,     PIPE_FORMAT_YV12 },
+      { __DRI_IMAGE_FOURCC_NV12,          __DRI_IMAGE_FORMAT_NONE,
+        __DRI_IMAGE_COMPONENTS_Y_UV,      PIPE_FORMAT_NV12 },
+      { __DRI_IMAGE_FOURCC_YUYV,          __DRI_IMAGE_FORMAT_YUYV,
+        __DRI_IMAGE_COMPONENTS_Y_XUXV,    PIPE_FORMAT_YUYV },
+};
+
+static const struct dri2_format_mapping *
+dri2_get_mapping_by_fourcc(int fourcc) {
+   for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
+      if (dri2_format_table[i].dri_fourcc == fourcc)
+               return &dri2_format_table[i];
    }
 
-   return pf;
+   return NULL;
+}
+
+static const struct dri2_format_mapping *
+dri2_get_mapping_by_format(int format) {
+   for (unsigned i = 0; i < ARRAY_SIZE(dri2_format_table); i++) {
+      if (dri2_format_table[i].dri_format == format)
+               return &dri2_format_table[i];
+   }
+
+   return NULL;
 }
 
 /**
@@ -147,6 +150,7 @@ dri2_invalidate_drawable(__DRIdrawable *dPriv)
 
    dri2InvalidateDrawable(dPriv);
    drawable->dPriv->lastStamp = drawable->dPriv->dri2.stamp;
+   drawable->texture_mask = 0;
 
    p_atomic_inc(&drawable->base.stamp);
 }
@@ -218,10 +222,18 @@ dri2_drawable_get_buffers(struct dri_drawable *drawable,
        * may occur as the stvis->color_format.
        */
       switch(format) {
+      case PIPE_FORMAT_B10G10R10A2_UNORM:
+      case PIPE_FORMAT_R10G10B10A2_UNORM:
       case PIPE_FORMAT_BGRA8888_UNORM:
+      case PIPE_FORMAT_RGBA8888_UNORM:
         depth = 32;
         break;
+      case PIPE_FORMAT_R10G10B10X2_UNORM:
+      case PIPE_FORMAT_B10G10R10X2_UNORM:
+         depth = 30;
+         break;
       case PIPE_FORMAT_BGRX8888_UNORM:
+      case PIPE_FORMAT_RGBX8888_UNORM:
         depth = 24;
         break;
       case PIPE_FORMAT_B5G6R5_UNORM:
@@ -288,6 +300,9 @@ dri_image_drawable_get_buffers(struct dri_drawable *drawable,
       }
 
       switch (pf) {
+      case PIPE_FORMAT_B5G5R5A1_UNORM:
+         image_format = __DRI_IMAGE_FORMAT_ARGB1555;
+         break;
       case PIPE_FORMAT_B5G6R5_UNORM:
          image_format = __DRI_IMAGE_FORMAT_RGB565;
          break;
@@ -297,9 +312,24 @@ dri_image_drawable_get_buffers(struct dri_drawable *drawable,
       case PIPE_FORMAT_BGRA8888_UNORM:
          image_format = __DRI_IMAGE_FORMAT_ARGB8888;
          break;
+      case PIPE_FORMAT_RGBX8888_UNORM:
+         image_format = __DRI_IMAGE_FORMAT_XBGR8888;
+         break;
       case PIPE_FORMAT_RGBA8888_UNORM:
          image_format = __DRI_IMAGE_FORMAT_ABGR8888;
          break;
+      case PIPE_FORMAT_B10G10R10X2_UNORM:
+         image_format = __DRI_IMAGE_FORMAT_XRGB2101010;
+         break;
+      case PIPE_FORMAT_B10G10R10A2_UNORM:
+         image_format = __DRI_IMAGE_FORMAT_ARGB2101010;
+         break;
+      case PIPE_FORMAT_R10G10B10X2_UNORM:
+         image_format = __DRI_IMAGE_FORMAT_XBGR2101010;
+         break;
+      case PIPE_FORMAT_R10G10B10A2_UNORM:
+         image_format = __DRI_IMAGE_FORMAT_ABGR2101010;
+         break;
       default:
          image_format = __DRI_IMAGE_FORMAT_NONE;
          break;
@@ -346,6 +376,9 @@ dri2_allocate_buffer(__DRIscreen *sPriv,
       case 32:
          pf = PIPE_FORMAT_BGRA8888_UNORM;
          break;
+      case 30:
+         pf = PIPE_FORMAT_B10G10R10X2_UNORM;
+         break;
       case 24:
          pf = PIPE_FORMAT_BGRX8888_UNORM;
          break;
@@ -379,13 +412,13 @@ dri2_allocate_buffer(__DRIscreen *sPriv,
 
    memset(&whandle, 0, sizeof(whandle));
    if (screen->can_share_buffer)
-      whandle.type = DRM_API_HANDLE_TYPE_SHARED;
+      whandle.type = WINSYS_HANDLE_TYPE_SHARED;
    else
-      whandle.type = DRM_API_HANDLE_TYPE_KMS;
+      whandle.type = WINSYS_HANDLE_TYPE_KMS;
 
-   screen->base.screen->resource_get_handle(screen->base.screen,
+   screen->base.screen->resource_get_handle(screen->base.screen, NULL,
          buffer->resource, &whandle,
-         PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ);
+         PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
 
    buffer->base.attachment = attachment;
    buffer->base.name = whandle.handle;
@@ -565,14 +598,15 @@ dri2_allocate_textures(struct dri_context *ctx,
          whandle.handle = buf->name;
          whandle.stride = buf->pitch;
          whandle.offset = 0;
+         whandle.modifier = DRM_FORMAT_MOD_INVALID;
          if (screen->can_share_buffer)
-            whandle.type = DRM_API_HANDLE_TYPE_SHARED;
+            whandle.type = WINSYS_HANDLE_TYPE_SHARED;
          else
-            whandle.type = DRM_API_HANDLE_TYPE_KMS;
+            whandle.type = WINSYS_HANDLE_TYPE_KMS;
          drawable->textures[statt] =
             screen->base.screen->resource_from_handle(screen->base.screen,
                   &templ, &whandle,
-                  PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ);
+                  PIPE_HANDLE_USAGE_EXPLICIT_FLUSH);
          assert(drawable->textures[statt]);
       }
    }
@@ -587,8 +621,10 @@ dri2_allocate_textures(struct dri_context *ctx,
 
          if (drawable->textures[statt]) {
             templ.format = drawable->textures[statt]->format;
-            templ.bind = drawable->textures[statt]->bind & ~PIPE_BIND_SCANOUT;
+            templ.bind = drawable->textures[statt]->bind &
+                         ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED);
             templ.nr_samples = drawable->stvis.samples;
+            templ.nr_storage_samples = drawable->stvis.samples;
 
             /* Try to reuse the resource.
              * (the other resource parameters should be constant)
@@ -636,14 +672,16 @@ dri2_allocate_textures(struct dri_context *ctx,
 
       if (format) {
          templ.format = format;
-         templ.bind = bind;
+         templ.bind = bind & ~PIPE_BIND_SHARED;
 
          if (drawable->stvis.samples > 1) {
             templ.nr_samples = drawable->stvis.samples;
+            templ.nr_storage_samples = drawable->stvis.samples;
             zsbuf = &drawable->msaa_textures[statt];
          }
          else {
             templ.nr_samples = 0;
+            templ.nr_storage_samples = 0;
             zsbuf = &drawable->textures[statt];
          }
 
@@ -715,6 +753,21 @@ dri2_flush_frontbuffer(struct dri_context *ctx,
    }
 }
 
+/**
+ * The struct dri_drawable flush_swapbuffers callback
+ */
+static void
+dri2_flush_swapbuffers(struct dri_context *ctx,
+                       struct dri_drawable *drawable)
+{
+   __DRIdrawable *dri_drawable = drawable->dPriv;
+   const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader;
+
+   if (image && image->base.version >= 3 && image->flushSwapBuffers) {
+      image->flushSwapBuffers(dri_drawable, dri_drawable->loaderPrivate);
+   }
+}
+
 static void
 dri2_update_tex_buffer(struct dri_drawable *drawable,
                        struct dri_context *ctx,
@@ -723,37 +776,38 @@ dri2_update_tex_buffer(struct dri_drawable *drawable,
    /* no-op */
 }
 
-static __DRIimage *
-dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
-{
-   const __DRIimageLookupExtension *loader = screen->sPriv->dri2.image;
-   __DRIimage *img;
-
-   if (!loader->lookupEGLImage)
-      return NULL;
-
-   img = loader->lookupEGLImage(screen->sPriv,
-                               handle, screen->sPriv->loaderPrivate);
-
-   return img;
-}
-
 static __DRIimage *
 dri2_create_image_from_winsys(__DRIscreen *_screen,
-                              int width, int height, int format,
-                              struct winsys_handle *whandle,
+                              int width, int height, enum pipe_format pf,
+                              int num_handles, struct winsys_handle *whandle,
                               void *loaderPrivate)
 {
    struct dri_screen *screen = dri_screen(_screen);
+   struct pipe_screen *pscreen = screen->base.screen;
    __DRIimage *img;
    struct pipe_resource templ;
-   unsigned tex_usage;
-   enum pipe_format pf;
+   unsigned tex_usage = 0;
+   int i;
+
+   if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0,
+                                    PIPE_BIND_RENDER_TARGET))
+      tex_usage |= PIPE_BIND_RENDER_TARGET;
+   if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0,
+                                    PIPE_BIND_SAMPLER_VIEW))
+      tex_usage |= PIPE_BIND_SAMPLER_VIEW;
+
+   if (!tex_usage && util_format_is_yuv(pf)) {
+      /* YUV format sampling can be emulated by the Mesa state tracker by
+       * using multiple R8/RG88 samplers. So try to rewrite the pipe format.
+       */
+      pf = PIPE_FORMAT_R8_UNORM;
 
-   tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+      if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0,
+                                       PIPE_BIND_SAMPLER_VIEW))
+         tex_usage |= PIPE_BIND_SAMPLER_VIEW;
+   }
 
-   pf = dri2_format_to_pipe_format (format);
-   if (pf == PIPE_FORMAT_NONE)
+   if (!tex_usage)
       return NULL;
 
    img = CALLOC_STRUCT(__DRIimageRec);
@@ -762,26 +816,51 @@ dri2_create_image_from_winsys(__DRIscreen *_screen,
 
    memset(&templ, 0, sizeof(templ));
    templ.bind = tex_usage;
-   templ.format = pf;
    templ.target = screen->target;
    templ.last_level = 0;
-   templ.width0 = width;
-   templ.height0 = height;
    templ.depth0 = 1;
    templ.array_size = 1;
 
-   whandle->offset = 0;
+   for (i = num_handles - 1; i >= 0; i--) {
+      struct pipe_resource *tex;
 
-   img->texture = screen->base.screen->resource_from_handle(screen->base.screen,
-         &templ, whandle, PIPE_HANDLE_USAGE_READ_WRITE);
-   if (!img->texture) {
-      FREE(img);
-      return NULL;
+      /* TODO: something a lot less ugly */
+      switch (i) {
+      case 0:
+         templ.width0 = width;
+         templ.height0 = height;
+         templ.format = pf;
+         break;
+      case 1:
+         templ.width0 = width / 2;
+         templ.height0 = height / 2;
+         templ.format = (num_handles == 2) ?
+               PIPE_FORMAT_RG88_UNORM :   /* NV12, etc */
+               PIPE_FORMAT_R8_UNORM;      /* I420, etc */
+         break;
+      case 2:
+         templ.width0 = width / 2;
+         templ.height0 = height / 2;
+         templ.format = PIPE_FORMAT_R8_UNORM;
+         break;
+      default:
+         unreachable("too many planes!");
+      }
+
+      tex = pscreen->resource_from_handle(pscreen,
+            &templ, &whandle[i], PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
+      if (!tex) {
+         pipe_resource_reference(&img->texture, NULL);
+         FREE(img);
+         return NULL;
+      }
+
+      tex->next = img->texture;
+      img->texture = tex;
    }
 
    img->level = 0;
    img->layer = 0;
-   img->dri_format = format;
    img->use = 0;
    img->loader_private = loaderPrivate;
 
@@ -793,67 +872,135 @@ dri2_create_image_from_name(__DRIscreen *_screen,
                             int width, int height, int format,
                             int name, int pitch, void *loaderPrivate)
 {
+   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
    struct winsys_handle whandle;
-   enum pipe_format pf;
+   __DRIimage *img;
+
+   if (!map)
+      return NULL;
 
    memset(&whandle, 0, sizeof(whandle));
-   whandle.type = DRM_API_HANDLE_TYPE_SHARED;
+   whandle.type = WINSYS_HANDLE_TYPE_SHARED;
    whandle.handle = name;
+   whandle.modifier = DRM_FORMAT_MOD_INVALID;
+
+   whandle.stride = pitch * util_format_get_blocksize(map->pipe_format);
+
+   img = dri2_create_image_from_winsys(_screen, width, height, map->pipe_format,
+                                       1, &whandle, loaderPrivate);
 
-   pf = dri2_format_to_pipe_format (format);
-   if (pf == PIPE_FORMAT_NONE)
+   if (!img)
       return NULL;
 
-   whandle.stride = pitch * util_format_get_blocksize(pf);
+   img->dri_components = map->dri_components;
+   img->dri_fourcc = map->dri_fourcc;
+   img->dri_format = map->dri_format;
 
-   return dri2_create_image_from_winsys(_screen, width, height, format,
-                                        &whandle, loaderPrivate);
+   return img;
 }
 
 static __DRIimage *
 dri2_create_image_from_fd(__DRIscreen *_screen,
-                          int width, int height, int format,
-                          int fd, int stride, void *loaderPrivate)
+                          int width, int height, int fourcc,
+                          uint64_t modifier, int *fds, int num_fds,
+                          int *strides, int *offsets, unsigned *error,
+                          void *loaderPrivate)
 {
-   struct winsys_handle whandle;
+   struct winsys_handle whandles[3];
+   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
+   __DRIimage *img = NULL;
+   unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
+   int expected_num_fds, i;
+
+   if (!map) {
+      err = __DRI_IMAGE_ERROR_BAD_MATCH;
+      goto exit;
+   }
 
-   if (fd < 0)
-      return NULL;
+   switch (fourcc) {
+   case __DRI_IMAGE_FOURCC_YUV420:
+   case __DRI_IMAGE_FOURCC_YVU420:
+      expected_num_fds = 3;
+      break;
+   case __DRI_IMAGE_FOURCC_NV12:
+      expected_num_fds = 2;
+      break;
+   default:
+      expected_num_fds = 1;
+      break;
+   }
 
-   memset(&whandle, 0, sizeof(whandle));
-   whandle.type = DRM_API_HANDLE_TYPE_FD;
-   whandle.handle = (unsigned)fd;
-   whandle.stride = stride;
+   if (num_fds != expected_num_fds) {
+      err = __DRI_IMAGE_ERROR_BAD_MATCH;
+      goto exit;
+   }
 
-   return dri2_create_image_from_winsys(_screen, width, height, format,
-                                        &whandle, loaderPrivate);
-}
+   memset(whandles, 0, sizeof(whandles));
 
-static __DRIimage *
-dri2_create_image_from_renderbuffer(__DRIcontext *context,
-                                   int renderbuffer, void *loaderPrivate)
-{
-   struct dri_context *ctx = dri_context(context);
+   for (i = 0; i < num_fds; i++) {
+      if (fds[i] < 0) {
+         err = __DRI_IMAGE_ERROR_BAD_ALLOC;
+         goto exit;
+      }
 
-   if (!ctx->st->get_resource_for_egl_image)
-      return NULL;
+      whandles[i].type = WINSYS_HANDLE_TYPE_FD;
+      whandles[i].handle = (unsigned)fds[i];
+      whandles[i].stride = (unsigned)strides[i];
+      whandles[i].offset = (unsigned)offsets[i];
+      whandles[i].modifier = modifier;
+   }
 
-   /* TODO */
-   return NULL;
+   if (fourcc == __DRI_IMAGE_FOURCC_YVU420) {
+      /* convert to YUV420 by swapping 2nd and 3rd planes: */
+      struct winsys_handle tmp = whandles[1];
+      whandles[1] = whandles[2];
+      whandles[2] = tmp;
+      fourcc = __DRI_IMAGE_FOURCC_YUV420;
+      map = dri2_get_mapping_by_fourcc(fourcc);
+   }
+
+   img = dri2_create_image_from_winsys(_screen, width, height, map->pipe_format,
+                                       num_fds, whandles, loaderPrivate);
+   if(img == NULL) {
+      err = __DRI_IMAGE_ERROR_BAD_ALLOC;
+      goto exit;
+   }
+
+   img->dri_components = map->dri_components;
+   img->dri_fourcc = fourcc;
+   img->dri_format = map->dri_format;
+
+exit:
+   if (error)
+      *error = err;
+
+   return img;
 }
 
 static __DRIimage *
-dri2_create_image(__DRIscreen *_screen,
-                   int width, int height, int format,
-                   unsigned int use, void *loaderPrivate)
+dri2_create_image_common(__DRIscreen *_screen,
+                         int width, int height,
+                         int format, unsigned int use,
+                         const uint64_t *modifiers,
+                         const unsigned count,
+                         void *loaderPrivate)
 {
+   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
    struct dri_screen *screen = dri_screen(_screen);
    __DRIimage *img;
    struct pipe_resource templ;
    unsigned tex_usage;
-   enum pipe_format pf;
+
+   if (!map)
+      return NULL;
+
+   /* createImageWithModifiers doesn't supply usage, and we should not get
+    * here with both modifiers and a usage flag.
+    */
+   assert(!(use && (modifiers != NULL)));
 
    tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+
    if (use & __DRI_IMAGE_USE_SCANOUT)
       tex_usage |= PIPE_BIND_SCANOUT;
    if (use & __DRI_IMAGE_USE_SHARE)
@@ -866,17 +1013,13 @@ dri2_create_image(__DRIscreen *_screen,
       tex_usage |= PIPE_BIND_CURSOR;
    }
 
-   pf = dri2_format_to_pipe_format (format);
-   if (pf == PIPE_FORMAT_NONE)
-      return NULL;
-
    img = CALLOC_STRUCT(__DRIimageRec);
    if (!img)
       return NULL;
 
    memset(&templ, 0, sizeof(templ));
    templ.bind = tex_usage;
-   templ.format = pf;
+   templ.format = map->pipe_format;
    templ.target = PIPE_TEXTURE_2D;
    templ.last_level = 0;
    templ.width0 = width;
@@ -884,7 +1027,16 @@ dri2_create_image(__DRIscreen *_screen,
    templ.depth0 = 1;
    templ.array_size = 1;
 
-   img->texture = screen->base.screen->resource_create(screen->base.screen, &templ);
+   if (modifiers)
+      img->texture =
+         screen->base.screen
+            ->resource_create_with_modifiers(screen->base.screen,
+                                             &templ,
+                                             modifiers,
+                                             count);
+   else
+      img->texture =
+         screen->base.screen->resource_create(screen->base.screen, &templ);
    if (!img->texture) {
       FREE(img);
       return NULL;
@@ -893,6 +1045,7 @@ dri2_create_image(__DRIscreen *_screen,
    img->level = 0;
    img->layer = 0;
    img->dri_format = format;
+   img->dri_fourcc = map->dri_fourcc;
    img->dri_components = 0;
    img->use = use;
 
@@ -900,6 +1053,28 @@ dri2_create_image(__DRIscreen *_screen,
    return img;
 }
 
+static __DRIimage *
+dri2_create_image(__DRIscreen *_screen,
+                   int width, int height, int format,
+                   unsigned int use, void *loaderPrivate)
+{
+   return dri2_create_image_common(_screen, width, height, format, use,
+                                   NULL /* modifiers */, 0 /* count */,
+                                   loaderPrivate);
+}
+
+static __DRIimage *
+dri2_create_image_with_modifiers(__DRIscreen *dri_screen,
+                                 int width, int height, int format,
+                                 const uint64_t *modifiers,
+                                 const unsigned count,
+                                 void *loaderPrivate)
+{
+   return dri2_create_image_common(dri_screen, width, height, format,
+                                   0 /* use */, modifiers, count,
+                                   loaderPrivate);
+}
+
 static GLboolean
 dri2_query_image(__DRIimage *image, int attrib, int *value)
 {
@@ -907,35 +1082,47 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
    unsigned usage;
 
    if (image->use & __DRI_IMAGE_USE_BACKBUFFER)
-      usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH | PIPE_HANDLE_USAGE_READ;
+      usage = PIPE_HANDLE_USAGE_EXPLICIT_FLUSH;
    else
-      usage = PIPE_HANDLE_USAGE_READ_WRITE;
+      usage = PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
 
    memset(&whandle, 0, sizeof(whandle));
 
    switch (attrib) {
    case __DRI_IMAGE_ATTRIB_STRIDE:
-      whandle.type = DRM_API_HANDLE_TYPE_KMS;
-      image->texture->screen->resource_get_handle(image->texture->screen,
-            image->texture, &whandle, usage);
+      whandle.type = WINSYS_HANDLE_TYPE_KMS;
+      if (!image->texture->screen->resource_get_handle(image->texture->screen,
+            NULL, image->texture, &whandle, usage))
+         return GL_FALSE;
       *value = whandle.stride;
       return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_OFFSET:
+      whandle.type = WINSYS_HANDLE_TYPE_KMS;
+      if (!image->texture->screen->resource_get_handle(image->texture->screen,
+            NULL, image->texture, &whandle, usage))
+         return GL_FALSE;
+      *value = whandle.offset;
+      return GL_TRUE;
    case __DRI_IMAGE_ATTRIB_HANDLE:
-      whandle.type = DRM_API_HANDLE_TYPE_KMS;
-      image->texture->screen->resource_get_handle(image->texture->screen,
-         image->texture, &whandle, usage);
+      whandle.type = WINSYS_HANDLE_TYPE_KMS;
+      if (!image->texture->screen->resource_get_handle(image->texture->screen,
+         NULL, image->texture, &whandle, usage))
+         return GL_FALSE;
       *value = whandle.handle;
       return GL_TRUE;
    case __DRI_IMAGE_ATTRIB_NAME:
-      whandle.type = DRM_API_HANDLE_TYPE_SHARED;
-      image->texture->screen->resource_get_handle(image->texture->screen,
-         image->texture, &whandle, usage);
+      whandle.type = WINSYS_HANDLE_TYPE_SHARED;
+      if (!image->texture->screen->resource_get_handle(image->texture->screen,
+         NULL, image->texture, &whandle, usage))
+         return GL_FALSE;
       *value = whandle.handle;
       return GL_TRUE;
    case __DRI_IMAGE_ATTRIB_FD:
-      whandle.type= DRM_API_HANDLE_TYPE_FD;
-      image->texture->screen->resource_get_handle(image->texture->screen,
-         image->texture, &whandle, usage);
+      whandle.type= WINSYS_HANDLE_TYPE_FD;
+      if (!image->texture->screen->resource_get_handle(image->texture->screen,
+            NULL, image->texture, &whandle, usage))
+         return GL_FALSE;
+
       *value = whandle.handle;
       return GL_TRUE;
    case __DRI_IMAGE_ATTRIB_FORMAT:
@@ -953,11 +1140,41 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
       *value = image->dri_components;
       return GL_TRUE;
    case __DRI_IMAGE_ATTRIB_FOURCC:
-      *value = convert_to_fourcc(image->dri_format);
+      if (image->dri_fourcc) {
+         *value = image->dri_fourcc;
+      } else {
+         const struct dri2_format_mapping *map;
+
+         map = dri2_get_mapping_by_format(image->dri_format);
+         if (!map)
+            return GL_FALSE;
+
+         *value = map->dri_fourcc;
+      }
       return GL_TRUE;
    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
       *value = 1;
       return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
+      whandle.type = WINSYS_HANDLE_TYPE_KMS;
+      whandle.modifier = DRM_FORMAT_MOD_INVALID;
+      if (!image->texture->screen->resource_get_handle(image->texture->screen,
+            NULL, image->texture, &whandle, usage))
+         return GL_FALSE;
+      if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
+         return GL_FALSE;
+      *value = (whandle.modifier >> 32) & 0xffffffff;
+      return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
+      whandle.type = WINSYS_HANDLE_TYPE_KMS;
+      whandle.modifier = DRM_FORMAT_MOD_INVALID;
+      if (!image->texture->screen->resource_get_handle(image->texture->screen,
+            NULL, image->texture, &whandle, usage))
+         return GL_FALSE;
+      if (whandle.modifier == DRM_FORMAT_MOD_INVALID)
+         return GL_FALSE;
+      *value = whandle.modifier & 0xffffffff;
+      return GL_TRUE;
    default:
       return GL_FALSE;
    }
@@ -987,15 +1204,29 @@ dri2_dup_image(__DRIimage *image, void *loaderPrivate)
 static GLboolean
 dri2_validate_usage(__DRIimage *image, unsigned int use)
 {
-   /*
-    * Gallium drivers are bad at adding usages to the resources
-    * once opened again in another process, which is the main use
-    * case for this, so we have to lie.
+   if (!image || !image->texture)
+      return false;
+
+   struct pipe_screen *screen = image->texture->screen;
+   if (!screen->check_resource_capability)
+      return true;
+
+   /* We don't want to check these:
+    *   __DRI_IMAGE_USE_SHARE (all images are shareable)
+    *   __DRI_IMAGE_USE_BACKBUFFER (all images support this)
     */
-   if (image != NULL)
-      return GL_TRUE;
-   else
-      return GL_FALSE;
+   unsigned bind = 0;
+   if (use & __DRI_IMAGE_USE_SCANOUT)
+      bind |= PIPE_BIND_SCANOUT;
+   if (use & __DRI_IMAGE_USE_LINEAR)
+      bind |= PIPE_BIND_LINEAR;
+   if (use & __DRI_IMAGE_USE_CURSOR)
+      bind |= PIPE_BIND_CURSOR;
+
+   if (!bind)
+      return true;
+
+   return screen->check_resource_capability(screen, image->texture, bind);
 }
 
 static __DRIimage *
@@ -1003,30 +1234,32 @@ dri2_from_names(__DRIscreen *screen, int width, int height, int format,
                 int *names, int num_names, int *strides, int *offsets,
                 void *loaderPrivate)
 {
+   const struct dri2_format_mapping *map = dri2_get_mapping_by_format(format);
    __DRIimage *img;
-   int dri_components;
    struct winsys_handle whandle;
 
-   if (num_names != 1)
-      return NULL;
-   if (offsets[0] != 0)
+   if (!map)
       return NULL;
 
-   format = convert_fourcc(format, &dri_components);
-   if (format == -1)
+   if (num_names != 1)
       return NULL;
 
    memset(&whandle, 0, sizeof(whandle));
-   whandle.type = DRM_API_HANDLE_TYPE_SHARED;
+   whandle.type = WINSYS_HANDLE_TYPE_SHARED;
    whandle.handle = names[0];
    whandle.stride = strides[0];
+   whandle.offset = offsets[0];
+   whandle.modifier = DRM_FORMAT_MOD_INVALID;
 
-   img = dri2_create_image_from_winsys(screen, width, height, format,
-                                       &whandle, loaderPrivate);
+   img = dri2_create_image_from_winsys(screen, width, height, map->pipe_format,
+                                       1, &whandle, loaderPrivate);
    if (img == NULL)
       return NULL;
 
-   img->dri_components = dri_components;
+   img->dri_components = map->dri_components;
+   img->dri_fourcc = map->dri_fourcc;
+   img->dri_format = map->pipe_format;
+
    return img;
 }
 
@@ -1045,101 +1278,83 @@ dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
    if (img == NULL)
       return NULL;
 
+   if (img->texture->screen->resource_changed)
+      img->texture->screen->resource_changed(img->texture->screen,
+                                             img->texture);
+
    /* set this to 0 for sub images. */
    img->dri_components = 0;
    return img;
 }
 
 static __DRIimage *
-dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture,
-                         int depth, int level, unsigned *error,
-                         void *loaderPrivate)
+dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
+              int *fds, int num_fds, int *strides, int *offsets,
+              void *loaderPrivate)
 {
-   __DRIimage *img;
-   struct gl_context *ctx = ((struct st_context *)dri_context(context)->st)->ctx;
-   struct gl_texture_object *obj;
-   struct pipe_resource *tex;
-   GLuint face = 0;
-
-   obj = _mesa_lookup_texture(ctx, texture);
-   if (!obj || obj->Target != target) {
-      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
-      return NULL;
-   }
-
-   tex = st_get_texobj_resource(obj);
-   if (!tex) {
-      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
-      return NULL;
-   }
-
-   if (target == GL_TEXTURE_CUBE_MAP)
-      face = depth;
-
-   _mesa_test_texobj_completeness(ctx, obj);
-   if (!obj->_BaseComplete || (level > 0 && !obj->_MipmapComplete)) {
-      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
-      return NULL;
-   }
-
-   if (level < obj->BaseLevel || level > obj->_MaxLevel) {
-      *error = __DRI_IMAGE_ERROR_BAD_MATCH;
-      return NULL;
-   }
-
-   if (target == GL_TEXTURE_3D && obj->Image[face][level]->Depth < depth) {
-      *error = __DRI_IMAGE_ERROR_BAD_MATCH;
-      return NULL;
-   }
+   return dri2_create_image_from_fd(screen, width, height, fourcc,
+                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
+                                   strides, offsets, NULL, loaderPrivate);
+}
 
-   img = CALLOC_STRUCT(__DRIimageRec);
-   if (!img) {
-      *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
-      return NULL;
-   }
+static boolean
+dri2_query_dma_buf_formats(__DRIscreen *_screen, int max, int *formats,
+                           int *count)
+{
+   struct dri_screen *screen = dri_screen(_screen);
+   struct pipe_screen *pscreen = screen->base.screen;
+   int i, j;
 
-   img->level = level;
-   img->layer = depth;
-   img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat);
+   for (i = 0, j = 0; (i < ARRAY_SIZE(dri2_format_table)) &&
+         (j < max || max == 0); i++) {
+      const struct dri2_format_mapping *map = &dri2_format_table[i];
 
-   img->loader_private = loaderPrivate;
+      /* The sRGB format is not a real FourCC as defined by drm_fourcc.h, so we
+       * must not leak it out to clients.
+       */
+      if (dri2_format_table[i].dri_fourcc == __DRI_IMAGE_FOURCC_SARGB8888)
+         continue;
 
-   if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) {
-      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
-      free(img);
-      return NULL;
+      if (pscreen->is_format_supported(pscreen, map->pipe_format,
+                                       screen->target, 0, 0,
+                                       PIPE_BIND_RENDER_TARGET) ||
+          pscreen->is_format_supported(pscreen, map->pipe_format,
+                                       screen->target, 0, 0,
+                                       PIPE_BIND_SAMPLER_VIEW)) {
+         if (j < max)
+            formats[j] = map->dri_fourcc;
+         j++;
+      }
    }
-
-   pipe_resource_reference(&img->texture, tex);
-
-   *error = __DRI_IMAGE_ERROR_SUCCESS;
-   return img;
+   *count = j;
+   return true;
 }
 
-static __DRIimage *
-dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
-              int *fds, int num_fds, int *strides, int *offsets,
-              void *loaderPrivate)
+static boolean
+dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max,
+                             uint64_t *modifiers, unsigned int *external_only,
+                             int *count)
 {
-   __DRIimage *img;
-   int format, dri_components;
-
-   if (num_fds != 1)
-      return NULL;
-   if (offsets[0] != 0)
-      return NULL;
+   struct dri_screen *screen = dri_screen(_screen);
+   struct pipe_screen *pscreen = screen->base.screen;
+   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
+   enum pipe_format format;
 
-   format = convert_fourcc(fourcc, &dri_components);
-   if (format == -1)
-      return NULL;
+   if (!map)
+      return false;
 
-   img = dri2_create_image_from_fd(screen, width, height, format,
-                                   fds[0], strides[0], loaderPrivate);
-   if (img == NULL)
-      return NULL;
+   format = map->pipe_format;
 
-   img->dri_components = dri_components;
-   return img;
+   if (pscreen->query_dmabuf_modifiers != NULL &&
+       (pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
+                                     PIPE_BIND_RENDER_TARGET) ||
+        pscreen->is_format_supported(pscreen, format, screen->target, 0, 0,
+                                     PIPE_BIND_SAMPLER_VIEW))) {
+      pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers,
+                                      external_only, count);
+      return true;
+   }
+   return false;
 }
 
 static __DRIimage *
@@ -1155,31 +1370,46 @@ dri2_from_dma_bufs(__DRIscreen *screen,
                    void *loaderPrivate)
 {
    __DRIimage *img;
-   int format, dri_components;
 
-   if (num_fds != 1 || offsets[0] != 0) {
-      *error = __DRI_IMAGE_ERROR_BAD_MATCH;
+   img = dri2_create_image_from_fd(screen, width, height, fourcc,
+                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
+                                   strides, offsets, error, loaderPrivate);
+   if (img == NULL)
       return NULL;
-   }
 
-   format = convert_fourcc(fourcc, &dri_components);
-   if (format == -1) {
-      *error = __DRI_IMAGE_ERROR_BAD_MATCH;
-      return NULL;
-   }
+   img->yuv_color_space = yuv_color_space;
+   img->sample_range = sample_range;
+   img->horizontal_siting = horizontal_siting;
+   img->vertical_siting = vertical_siting;
+
+   *error = __DRI_IMAGE_ERROR_SUCCESS;
+   return img;
+}
+
+static __DRIimage *
+dri2_from_dma_bufs2(__DRIscreen *screen,
+                    int width, int height, int fourcc,
+                    uint64_t modifier, int *fds, int num_fds,
+                    int *strides, int *offsets,
+                    enum __DRIYUVColorSpace yuv_color_space,
+                    enum __DRISampleRange sample_range,
+                    enum __DRIChromaSiting horizontal_siting,
+                    enum __DRIChromaSiting vertical_siting,
+                    unsigned *error,
+                    void *loaderPrivate)
+{
+   __DRIimage *img;
 
-   img = dri2_create_image_from_fd(screen, width, height, format,
-                                   fds[0], strides[0], loaderPrivate);
-   if (img == NULL) {
-      *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
+   img = dri2_create_image_from_fd(screen, width, height, fourcc,
+                                   modifier, fds, num_fds, strides, offsets,
+                                   error, loaderPrivate);
+   if (img == NULL)
       return NULL;
-   }
 
    img->yuv_color_space = yuv_color_space;
    img->sample_range = sample_range;
    img->horizontal_siting = horizontal_siting;
    img->vertical_siting = vertical_siting;
-   img->dri_components = dri_components;
 
    *error = __DRI_IMAGE_ERROR_SUCCESS;
    return img;
@@ -1227,16 +1457,48 @@ dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src,
       screen = dri_screen(ctx->sPriv)->base.screen;
       pipe->flush_resource(pipe, dst->texture);
       ctx->st->flush(ctx->st, 0, &fence);
-      (void) screen->fence_finish(screen, fence, PIPE_TIMEOUT_INFINITE);
+      (void) screen->fence_finish(screen, NULL, fence, PIPE_TIMEOUT_INFINITE);
       screen->fence_reference(screen, &fence, NULL);
    }
 }
 
+static void *
+dri2_map_image(__DRIcontext *context, __DRIimage *image,
+                int x0, int y0, int width, int height,
+                unsigned int flags, int *stride, void **data)
+{
+   struct dri_context *ctx = dri_context(context);
+   struct pipe_context *pipe = ctx->st->pipe;
+   enum pipe_transfer_usage pipe_access = 0;
+   struct pipe_transfer *trans;
+   void *map;
+
+   if (!image || !data || *data)
+      return NULL;
+
+   if (flags & __DRI_IMAGE_TRANSFER_READ)
+         pipe_access |= PIPE_TRANSFER_READ;
+   if (flags & __DRI_IMAGE_TRANSFER_WRITE)
+         pipe_access |= PIPE_TRANSFER_WRITE;
+
+   map = pipe_transfer_map(pipe, image->texture,
+                           0, 0, pipe_access, x0, y0, width, height,
+                           &trans);
+   if (map) {
+      *data = trans;
+      *stride = trans->stride;
+   }
+
+   return map;
+}
+
 static void
-dri2_destroy_image(__DRIimage *img)
+dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data)
 {
-   pipe_resource_reference(&img->texture, NULL);
-   FREE(img);
+   struct dri_context *ctx = dri_context(context);
+   struct pipe_context *pipe = ctx->st->pipe;
+
+   pipe_transfer_unmap(pipe, (struct pipe_transfer *)data);
 }
 
 static int
@@ -1249,7 +1511,7 @@ dri2_get_capabilities(__DRIscreen *_screen)
 
 /* The extension is modified during runtime if DRI_PRIME is detected */
 static __DRIimageExtension dri2ImageExtension = {
-    .base = { __DRI_IMAGE, 11 },
+    .base = { __DRI_IMAGE, 17 },
 
     .createImageFromName          = dri2_create_image_from_name,
     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
@@ -1265,156 +1527,14 @@ static __DRIimageExtension dri2ImageExtension = {
     .createImageFromDmaBufs       = NULL,
     .blitImage                    = dri2_blit_image,
     .getCapabilities              = dri2_get_capabilities,
-};
-
-
-static bool
-dri2_is_opencl_interop_loaded_locked(struct dri_screen *screen)
-{
-   return screen->opencl_dri_event_add_ref &&
-          screen->opencl_dri_event_release &&
-          screen->opencl_dri_event_wait &&
-          screen->opencl_dri_event_get_fence;
-}
-
-static bool
-dri2_load_opencl_interop(struct dri_screen *screen)
-{
-#if defined(RTLD_DEFAULT)
-   bool success;
-
-   pipe_mutex_lock(screen->opencl_func_mutex);
-
-   if (dri2_is_opencl_interop_loaded_locked(screen)) {
-      pipe_mutex_unlock(screen->opencl_func_mutex);
-      return true;
-   }
-
-   screen->opencl_dri_event_add_ref =
-      dlsym(RTLD_DEFAULT, "opencl_dri_event_add_ref");
-   screen->opencl_dri_event_release =
-      dlsym(RTLD_DEFAULT, "opencl_dri_event_release");
-   screen->opencl_dri_event_wait =
-      dlsym(RTLD_DEFAULT, "opencl_dri_event_wait");
-   screen->opencl_dri_event_get_fence =
-      dlsym(RTLD_DEFAULT, "opencl_dri_event_get_fence");
-
-   success = dri2_is_opencl_interop_loaded_locked(screen);
-   pipe_mutex_unlock(screen->opencl_func_mutex);
-   return success;
-#else
-   return false;
-#endif
-}
-
-struct dri2_fence {
-   struct dri_screen *driscreen;
-   struct pipe_fence_handle *pipe_fence;
-   void *cl_event;
-};
-
-static void *
-dri2_create_fence(__DRIcontext *_ctx)
-{
-   struct pipe_context *ctx = dri_context(_ctx)->st->pipe;
-   struct dri2_fence *fence = CALLOC_STRUCT(dri2_fence);
-
-   if (!fence)
-      return NULL;
-
-   ctx->flush(ctx, &fence->pipe_fence, 0);
-
-   if (!fence->pipe_fence) {
-      FREE(fence);
-      return NULL;
-   }
-
-   fence->driscreen = dri_screen(_ctx->driScreenPriv);
-   return fence;
-}
-
-static void *
-dri2_get_fence_from_cl_event(__DRIscreen *_screen, intptr_t cl_event)
-{
-   struct dri_screen *driscreen = dri_screen(_screen);
-   struct dri2_fence *fence;
-
-   if (!dri2_load_opencl_interop(driscreen))
-      return NULL;
-
-   fence = CALLOC_STRUCT(dri2_fence);
-   if (!fence)
-      return NULL;
-
-   fence->cl_event = (void*)cl_event;
-
-   if (!driscreen->opencl_dri_event_add_ref(fence->cl_event)) {
-      free(fence);
-      return NULL;
-   }
-
-   fence->driscreen = driscreen;
-   return fence;
-}
-
-static void
-dri2_destroy_fence(__DRIscreen *_screen, void *_fence)
-{
-   struct dri_screen *driscreen = dri_screen(_screen);
-   struct pipe_screen *screen = driscreen->base.screen;
-   struct dri2_fence *fence = (struct dri2_fence*)_fence;
-
-   if (fence->pipe_fence)
-      screen->fence_reference(screen, &fence->pipe_fence, NULL);
-   else if (fence->cl_event)
-      driscreen->opencl_dri_event_release(fence->cl_event);
-   else
-      assert(0);
-
-   FREE(fence);
-}
-
-static GLboolean
-dri2_client_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags,
-                      uint64_t timeout)
-{
-   struct dri2_fence *fence = (struct dri2_fence*)_fence;
-   struct dri_screen *driscreen = fence->driscreen;
-   struct pipe_screen *screen = driscreen->base.screen;
-
-   /* No need to flush. The context was flushed when the fence was created. */
-
-   if (fence->pipe_fence)
-      return screen->fence_finish(screen, fence->pipe_fence, timeout);
-   else if (fence->cl_event) {
-      struct pipe_fence_handle *pipe_fence =
-         driscreen->opencl_dri_event_get_fence(fence->cl_event);
-
-      if (pipe_fence)
-         return screen->fence_finish(screen, pipe_fence, timeout);
-      else
-         return driscreen->opencl_dri_event_wait(fence->cl_event, timeout);
-   }
-   else {
-      assert(0);
-      return false;
-   }
-}
-
-static void
-dri2_server_wait_sync(__DRIcontext *_ctx, void *_fence, unsigned flags)
-{
-   /* AFAIK, no driver currently supports parallel context execution. */
-}
-
-static __DRI2fenceExtension dri2FenceExtension = {
-   .base = { __DRI2_FENCE, 1 },
-
-   .create_fence = dri2_create_fence,
-   .get_fence_from_cl_event = dri2_get_fence_from_cl_event,
-   .destroy_fence = dri2_destroy_fence,
-   .client_wait_sync = dri2_client_wait_sync,
-   .server_wait_sync = dri2_server_wait_sync
+    .mapImage                     = dri2_map_image,
+    .unmapImage                   = dri2_unmap_image,
+    .createImageWithModifiers     = NULL,
+    .createImageFromDmaBufs2      = NULL,
+    .queryDmaBufFormats           = NULL,
+    .queryDmaBufModifiers         = NULL,
+    .queryDmaBufFormatModifierAttribs = NULL,
+    .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2,
 };
 
 static const __DRIrobustnessExtension dri2Robustness = {
@@ -1423,12 +1543,13 @@ static const __DRIrobustnessExtension dri2Robustness = {
 
 static int
 dri2_interop_query_device_info(__DRIcontext *_ctx,
-                               mesa_glinterop_device_info *out)
+                               struct mesa_glinterop_device_info *out)
 {
    struct pipe_screen *screen = dri_context(_ctx)->st->pipe->screen;
 
-   if (!out->struct_version)
-      return MESA_GLINTEROP_INVALID_VALUE;
+   /* There is no version 0, thus we do not support it */
+   if (out->version == 0)
+      return MESA_GLINTEROP_INVALID_VERSION;
 
    out->pci_segment_group = screen->get_param(screen, PIPE_CAP_PCI_GROUP);
    out->pci_bus = screen->get_param(screen, PIPE_CAP_PCI_BUS);
@@ -1438,15 +1559,16 @@ dri2_interop_query_device_info(__DRIcontext *_ctx,
    out->vendor_id = screen->get_param(screen, PIPE_CAP_VENDOR_ID);
    out->device_id = screen->get_param(screen, PIPE_CAP_DEVICE_ID);
 
-   out->interop_version = 1;
+   /* Instruct the caller that we support up-to version one of the interface */
+   out->version = 1;
 
    return MESA_GLINTEROP_SUCCESS;
 }
 
 static int
 dri2_interop_export_object(__DRIcontext *_ctx,
-                           const mesa_glinterop_export_in *in,
-                           mesa_glinterop_export_out *out)
+                           struct mesa_glinterop_export_in *in,
+                           struct mesa_glinterop_export_out *out)
 {
    struct st_context_iface *st = dri_context(_ctx)->st;
    struct pipe_screen *screen = st->pipe->screen;
@@ -1456,8 +1578,9 @@ dri2_interop_export_object(__DRIcontext *_ctx,
    unsigned target, usage;
    boolean success;
 
-   if (!in->struct_version || !out->struct_version)
-      return MESA_GLINTEROP_INVALID_VALUE;
+   /* There is no version 0, thus we do not support it */
+   if (in->version == 0 || out->version == 0)
+      return MESA_GLINTEROP_INVALID_VERSION;
 
    /* Validate the target. */
    switch (in->target) {
@@ -1495,7 +1618,7 @@ dri2_interop_export_object(__DRIcontext *_ctx,
       return MESA_GLINTEROP_INVALID_MIP_LEVEL;
 
    /* Validate the OpenGL object and get pipe_resource. */
-   mtx_lock(&ctx->Shared->Mutex);
+   simple_mtx_lock(&ctx->Shared->Mutex);
 
    if (target == GL_ARRAY_BUFFER) {
       /* Buffer objects.
@@ -1511,14 +1634,14 @@ dri2_interop_export_object(__DRIcontext *_ctx,
        *   the size of the buffer is 0."
        */
       if (!buf || buf->Size == 0) {
-         mtx_unlock(&ctx->Shared->Mutex);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_INVALID_OBJECT;
       }
 
       res = st_buffer_object(buf)->buffer;
       if (!res) {
          /* this shouldn't happen */
-         mtx_unlock(&ctx->Shared->Mutex);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_INVALID_OBJECT;
       }
 
@@ -1539,7 +1662,7 @@ dri2_interop_export_object(__DRIcontext *_ctx,
        *    object or if the width or height of renderbuffer is zero."
        */
       if (!rb || rb->Width == 0 || rb->Height == 0) {
-         mtx_unlock(&ctx->Shared->Mutex);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_INVALID_OBJECT;
       }
 
@@ -1548,7 +1671,7 @@ dri2_interop_export_object(__DRIcontext *_ctx,
        *    renderbuffer object."
        */
       if (rb->NumSamples > 1) {
-         mtx_unlock(&ctx->Shared->Mutex);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_INVALID_OPERATION;
       }
 
@@ -1558,11 +1681,11 @@ dri2_interop_export_object(__DRIcontext *_ctx,
        */
       res = st_renderbuffer(rb)->texture;
       if (!res) {
-         mtx_unlock(&ctx->Shared->Mutex);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_OUT_OF_RESOURCES;
       }
 
-      out->internalformat = rb->InternalFormat;
+      out->internal_format = rb->InternalFormat;
       out->view_minlevel = 0;
       out->view_numlevels = 1;
       out->view_minlayer = 0;
@@ -1588,44 +1711,54 @@ dri2_interop_export_object(__DRIcontext *_ctx,
           obj->Target != target ||
           !obj->_BaseComplete ||
           (in->miplevel > 0 && !obj->_MipmapComplete)) {
-         mtx_unlock(&ctx->Shared->Mutex);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_INVALID_OBJECT;
       }
 
-      /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
-       *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
-       *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
-       *    implementations); or greater than the value of q (for both OpenGL
-       *    and OpenGL ES). levelbase and q are defined for the texture in
-       *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
-       *    specification and section 3.7.10 of the OpenGL ES 2.0."
-       */
-      if (in->miplevel < obj->BaseLevel || in->miplevel > obj->_MaxLevel) {
-         mtx_unlock(&ctx->Shared->Mutex);
-         return MESA_GLINTEROP_INVALID_MIP_LEVEL;
-      }
-
-      if (!st_finalize_texture(ctx, st->pipe, obj)) {
-         mtx_unlock(&ctx->Shared->Mutex);
-         return MESA_GLINTEROP_OUT_OF_RESOURCES;
-      }
+      if (target == GL_TEXTURE_BUFFER) {
+         struct st_buffer_object *stBuf =
+            st_buffer_object(obj->BufferObject);
 
-      res = st_get_texobj_resource(obj);
-      if (!res) {
-         /* Incomplete texture buffer object? This shouldn't really occur. */
-         mtx_unlock(&ctx->Shared->Mutex);
-         return MESA_GLINTEROP_INVALID_OBJECT;
-      }
+         if (!stBuf || !stBuf->buffer) {
+            /* this shouldn't happen */
+            simple_mtx_unlock(&ctx->Shared->Mutex);
+            return MESA_GLINTEROP_INVALID_OBJECT;
+         }
+         res = stBuf->buffer;
 
-      if (target == GL_TEXTURE_BUFFER) {
-         out->internalformat = obj->BufferObjectFormat;
+         out->internal_format = obj->BufferObjectFormat;
          out->buf_offset = obj->BufferOffset;
          out->buf_size = obj->BufferSize == -1 ? obj->BufferObject->Size :
                                                  obj->BufferSize;
 
          obj->BufferObject->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
       } else {
-         out->internalformat = obj->Image[0][0]->InternalFormat;
+         /* From OpenCL 2.0 SDK, clCreateFromGLTexture:
+          *   "CL_INVALID_MIP_LEVEL if miplevel is less than the value of
+          *    levelbase (for OpenGL implementations) or zero (for OpenGL ES
+          *    implementations); or greater than the value of q (for both OpenGL
+          *    and OpenGL ES). levelbase and q are defined for the texture in
+          *    section 3.8.10 (Texture Completeness) of the OpenGL 2.1
+          *    specification and section 3.7.10 of the OpenGL ES 2.0."
+          */
+         if (in->miplevel < obj->BaseLevel || in->miplevel > obj->_MaxLevel) {
+            simple_mtx_unlock(&ctx->Shared->Mutex);
+            return MESA_GLINTEROP_INVALID_MIP_LEVEL;
+         }
+
+         if (!st_finalize_texture(ctx, st->pipe, obj, 0)) {
+            simple_mtx_unlock(&ctx->Shared->Mutex);
+            return MESA_GLINTEROP_OUT_OF_RESOURCES;
+         }
+
+         res = st_get_texobj_resource(obj);
+         if (!res) {
+            /* Incomplete texture buffer object? This shouldn't really occur. */
+            simple_mtx_unlock(&ctx->Shared->Mutex);
+            return MESA_GLINTEROP_INVALID_OBJECT;
+         }
+
+         out->internal_format = obj->Image[0][0]->InternalFormat;
          out->view_minlevel = obj->MinLevel;
          out->view_numlevels = obj->NumLevels;
          out->view_minlayer = obj->MinLayer;
@@ -1635,24 +1768,23 @@ dri2_interop_export_object(__DRIcontext *_ctx,
 
    /* Get the handle. */
    switch (in->access) {
-   case MESA_GLINTEROP_ACCESS_READ_WRITE:
-      usage = PIPE_HANDLE_USAGE_READ_WRITE;
-      break;
    case MESA_GLINTEROP_ACCESS_READ_ONLY:
-      usage = PIPE_HANDLE_USAGE_READ;
+      usage = 0;
       break;
+   case MESA_GLINTEROP_ACCESS_READ_WRITE:
    case MESA_GLINTEROP_ACCESS_WRITE_ONLY:
-      usage = PIPE_HANDLE_USAGE_WRITE;
+      usage = PIPE_HANDLE_USAGE_SHADER_WRITE;
       break;
    default:
       usage = 0;
    }
 
    memset(&whandle, 0, sizeof(whandle));
-   whandle.type = DRM_API_HANDLE_TYPE_FD;
+   whandle.type = WINSYS_HANDLE_TYPE_FD;
 
-   success = screen->resource_get_handle(screen, res, &whandle, usage);
-   mtx_unlock(&ctx->Shared->Mutex);
+   success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
+                                         usage);
+   simple_mtx_unlock(&ctx->Shared->Mutex);
 
    if (!success)
       return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
@@ -1663,6 +1795,10 @@ dri2_interop_export_object(__DRIcontext *_ctx,
    if (res->target == PIPE_BUFFER)
       out->buf_offset += whandle.offset;
 
+   /* Instruct the caller that we support up-to version one of the interface */
+   in->version = 1;
+   out->version = 1;
+
    return MESA_GLINTEROP_SUCCESS;
 }
 
@@ -1672,6 +1808,69 @@ static const __DRI2interopExtension dri2InteropExtension = {
    .export_object = dri2_interop_export_object
 };
 
+/**
+ * \brief the DRI2ConfigQueryExtension configQueryb method
+ */
+static int
+dri2GalliumConfigQueryb(__DRIscreen *sPriv, const char *var,
+                        unsigned char *val)
+{
+   struct dri_screen *screen = dri_screen(sPriv);
+
+   if (!driCheckOption(&screen->dev->option_cache, var, DRI_BOOL))
+      return dri2ConfigQueryExtension.configQueryb(sPriv, var, val);
+
+   *val = driQueryOptionb(&screen->dev->option_cache, var);
+
+   return 0;
+}
+
+/**
+ * \brief the DRI2ConfigQueryExtension configQueryi method
+ */
+static int
+dri2GalliumConfigQueryi(__DRIscreen *sPriv, const char *var, int *val)
+{
+   struct dri_screen *screen = dri_screen(sPriv);
+
+   if (!driCheckOption(&screen->dev->option_cache, var, DRI_INT) &&
+       !driCheckOption(&screen->dev->option_cache, var, DRI_ENUM))
+      return dri2ConfigQueryExtension.configQueryi(sPriv, var, val);
+
+    *val = driQueryOptioni(&screen->dev->option_cache, var);
+
+    return 0;
+}
+
+/**
+ * \brief the DRI2ConfigQueryExtension configQueryf method
+ */
+static int
+dri2GalliumConfigQueryf(__DRIscreen *sPriv, const char *var, float *val)
+{
+   struct dri_screen *screen = dri_screen(sPriv);
+
+   if (!driCheckOption(&screen->dev->option_cache, var, DRI_FLOAT))
+      return dri2ConfigQueryExtension.configQueryf(sPriv, var, val);
+
+    *val = driQueryOptionf(&screen->dev->option_cache, var);
+
+    return 0;
+}
+
+/**
+ * \brief the DRI2ConfigQueryExtension struct.
+ *
+ * We first query the driver option cache. Then the dri2 option cache.
+ */
+static const __DRI2configQueryExtension dri2GalliumConfigQueryExtension = {
+   .base = { __DRI2_CONFIG_QUERY, 1 },
+
+   .configQueryb        = dri2GalliumConfigQueryb,
+   .configQueryi        = dri2GalliumConfigQueryi,
+   .configQueryf        = dri2GalliumConfigQueryf,
+};
+
 /*
  * Backend function init_screen.
  */
@@ -1681,10 +1880,11 @@ static const __DRIextension *dri_screen_extensions[] = {
    &dri2FlushExtension.base,
    &dri2ImageExtension.base,
    &dri2RendererQueryExtension.base,
-   &dri2ConfigQueryExtension.base,
+   &dri2GalliumConfigQueryExtension.base,
    &dri2ThrottleExtension.base,
    &dri2FenceExtension.base,
    &dri2InteropExtension.base,
+   &dri2NoErrorExtension.base,
    NULL
 };
 
@@ -1693,11 +1893,12 @@ static const __DRIextension *dri_robust_screen_extensions[] = {
    &dri2FlushExtension.base,
    &dri2ImageExtension.base,
    &dri2RendererQueryExtension.base,
-   &dri2ConfigQueryExtension.base,
+   &dri2GalliumConfigQueryExtension.base,
    &dri2ThrottleExtension.base,
    &dri2FenceExtension.base,
    &dri2InteropExtension.base,
    &dri2Robustness.base,
+   &dri2NoErrorExtension.base,
    NULL
 };
 
@@ -1714,7 +1915,6 @@ dri2_init_screen(__DRIscreen * sPriv)
    struct pipe_screen *pscreen = NULL;
    const struct drm_conf_ret *throttle_ret;
    const struct drm_conf_ret *dmabuf_ret;
-   int fd = -1;
 
    screen = CALLOC_STRUCT(dri_screen);
    if (!screen)
@@ -1722,18 +1922,18 @@ dri2_init_screen(__DRIscreen * sPriv)
 
    screen->sPriv = sPriv;
    screen->fd = sPriv->fd;
-   pipe_mutex_init(screen->opencl_func_mutex);
+   (void) mtx_init(&screen->opencl_func_mutex, mtx_plain);
 
    sPriv->driverPrivate = (void *)screen;
 
-   if (screen->fd < 0 || (fd = dup(screen->fd)) < 0)
-      goto fail;
+   if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd)) {
+      dri_init_options(screen);
 
-   if (pipe_loader_drm_probe_fd(&screen->dev, fd))
       pscreen = pipe_loader_create_screen(screen->dev);
+   }
 
    if (!pscreen)
-       goto fail;
+       goto release_pipe;
 
    throttle_ret = pipe_loader_configuration(screen->dev, DRM_CONF_THROTTLE);
    dmabuf_ret = pipe_loader_configuration(screen->dev, DRM_CONF_SHARE_FD);
@@ -1743,6 +1943,10 @@ dri2_init_screen(__DRIscreen * sPriv)
       screen->default_throttle_frames = throttle_ret->val.val_int;
    }
 
+   if (pscreen->resource_create_with_modifiers)
+      dri2ImageExtension.createImageWithModifiers =
+         dri2_create_image_with_modifiers;
+
    if (dmabuf_ret && dmabuf_ret->val.val_bool) {
       uint64_t cap;
 
@@ -1750,6 +1954,12 @@ dri2_init_screen(__DRIscreen * sPriv)
           (cap & DRM_PRIME_CAP_IMPORT)) {
          dri2ImageExtension.createImageFromFds = dri2_from_fds;
          dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs;
+         dri2ImageExtension.createImageFromDmaBufs2 = dri2_from_dma_bufs2;
+         if (pscreen->query_dmabuf_modifiers) {
+            dri2ImageExtension.queryDmaBufFormats = dri2_query_dma_buf_formats;
+            dri2ImageExtension.queryDmaBufModifiers =
+                                       dri2_query_dma_buf_modifiers;
+         }
       }
    }
 
@@ -1760,9 +1970,9 @@ dri2_init_screen(__DRIscreen * sPriv)
    else
       sPriv->extensions = dri_screen_extensions;
 
-   configs = dri_init_screen_helper(screen, pscreen, screen->dev->driver_name);
+   configs = dri_init_screen_helper(screen, pscreen);
    if (!configs)
-      goto fail;
+      goto destroy_screen;
 
    screen->can_share_buffer = true;
    screen->auto_fake_front = dri_with_format(sPriv);
@@ -1770,12 +1980,14 @@ dri2_init_screen(__DRIscreen * sPriv)
    screen->lookup_egl_image = dri2_lookup_egl_image;
 
    return configs;
-fail:
+
+destroy_screen:
    dri_destroy_screen_helper(screen);
+
+release_pipe:
    if (screen->dev)
       pipe_loader_release(&screen->dev, 1);
-   else
-      close(fd);
+
    FREE(screen);
    return NULL;
 }
@@ -1793,7 +2005,6 @@ dri_kms_init_screen(__DRIscreen * sPriv)
    struct dri_screen *screen;
    struct pipe_screen *pscreen = NULL;
    uint64_t cap;
-   int fd = -1;
 
    screen = CALLOC_STRUCT(dri_screen);
    if (!screen)
@@ -1804,26 +2015,34 @@ dri_kms_init_screen(__DRIscreen * sPriv)
 
    sPriv->driverPrivate = (void *)screen;
 
-   if (screen->fd < 0 || (fd = dup(screen->fd)) < 0)
-      goto fail;
-
-   if (pipe_loader_sw_probe_kms(&screen->dev, fd))
+   if (pipe_loader_sw_probe_kms(&screen->dev, screen->fd)) {
+      dri_init_options(screen);
       pscreen = pipe_loader_create_screen(screen->dev);
+   }
 
    if (!pscreen)
-       goto fail;
+       goto release_pipe;
+
+   if (pscreen->resource_create_with_modifiers)
+      dri2ImageExtension.createImageWithModifiers =
+         dri2_create_image_with_modifiers;
 
    if (drmGetCap(sPriv->fd, DRM_CAP_PRIME, &cap) == 0 &&
           (cap & DRM_PRIME_CAP_IMPORT)) {
       dri2ImageExtension.createImageFromFds = dri2_from_fds;
       dri2ImageExtension.createImageFromDmaBufs = dri2_from_dma_bufs;
+      dri2ImageExtension.createImageFromDmaBufs2 = dri2_from_dma_bufs2;
+      if (pscreen->query_dmabuf_modifiers) {
+         dri2ImageExtension.queryDmaBufFormats = dri2_query_dma_buf_formats;
+         dri2ImageExtension.queryDmaBufModifiers = dri2_query_dma_buf_modifiers;
+      }
    }
 
    sPriv->extensions = dri_screen_extensions;
 
-   configs = dri_init_screen_helper(screen, pscreen, "swrast");
+   configs = dri_init_screen_helper(screen, pscreen);
    if (!configs)
-      goto fail;
+      goto destroy_screen;
 
    screen->can_share_buffer = false;
    screen->auto_fake_front = dri_with_format(sPriv);
@@ -1831,12 +2050,14 @@ dri_kms_init_screen(__DRIscreen * sPriv)
    screen->lookup_egl_image = dri2_lookup_egl_image;
 
    return configs;
-fail:
+
+destroy_screen:
    dri_destroy_screen_helper(screen);
+
+release_pipe:
    if (screen->dev)
       pipe_loader_release(&screen->dev, 1);
-   else
-      close(fd);
+
    FREE(screen);
 #endif // GALLIUM_SOFTPIPE
    return NULL;
@@ -1857,6 +2078,7 @@ dri2_create_buffer(__DRIscreen * sPriv,
    drawable->allocate_textures = dri2_allocate_textures;
    drawable->flush_frontbuffer = dri2_flush_frontbuffer;
    drawable->update_tex_buffer = dri2_update_tex_buffer;
+   drawable->flush_swapbuffers = dri2_flush_swapbuffers;
 
    return TRUE;
 }