st/dri2: Add buffer handling for BGR[A/X]1010102 formats.
[mesa.git] / src / gallium / state_trackers / dri / dri2.c
index 625678f25750829891e5793984267b3af7f9c496..d0731419522d5954f0089f3087f3187e0fa73c45 100644 (file)
 #include "main/bufferobj.h"
 #include "main/texobj.h"
 
-#include "dri_screen.h"
-#include "dri_context.h"
+#include "dri_helpers.h"
 #include "dri_drawable.h"
-#include "dri_extensions.h"
 #include "dri_query_renderer.h"
 #include "dri2_buffer.h"
 
+#ifndef DRM_FORMAT_MOD_INVALID
+#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
+#endif
+
+static const int fourcc_formats[] = {
+   __DRI_IMAGE_FOURCC_ARGB2101010,
+   __DRI_IMAGE_FOURCC_XRGB2101010,
+   __DRI_IMAGE_FOURCC_ARGB8888,
+   __DRI_IMAGE_FOURCC_ABGR8888,
+   __DRI_IMAGE_FOURCC_SARGB8888,
+   __DRI_IMAGE_FOURCC_XRGB8888,
+   __DRI_IMAGE_FOURCC_XBGR8888,
+   __DRI_IMAGE_FOURCC_ARGB1555,
+   __DRI_IMAGE_FOURCC_RGB565,
+   __DRI_IMAGE_FOURCC_R8,
+   __DRI_IMAGE_FOURCC_R16,
+   __DRI_IMAGE_FOURCC_GR88,
+   __DRI_IMAGE_FOURCC_GR1616,
+   __DRI_IMAGE_FOURCC_YUV410,
+   __DRI_IMAGE_FOURCC_YUV411,
+   __DRI_IMAGE_FOURCC_YUV420,
+   __DRI_IMAGE_FOURCC_YUV422,
+   __DRI_IMAGE_FOURCC_YUV444,
+   __DRI_IMAGE_FOURCC_YVU410,
+   __DRI_IMAGE_FOURCC_YVU411,
+   __DRI_IMAGE_FOURCC_YVU420,
+   __DRI_IMAGE_FOURCC_YVU422,
+   __DRI_IMAGE_FOURCC_YVU444,
+   __DRI_IMAGE_FOURCC_NV12,
+   __DRI_IMAGE_FOURCC_NV16,
+   __DRI_IMAGE_FOURCC_YUYV
+};
+
 static int convert_fourcc(int format, int *dri_components_p)
 {
    int dri_components;
@@ -76,6 +107,14 @@ static int convert_fourcc(int format, int *dri_components_p)
       format = __DRI_IMAGE_FORMAT_XBGR8888;
       dri_components = __DRI_IMAGE_COMPONENTS_RGB;
       break;
+   case __DRI_IMAGE_FOURCC_ARGB2101010:
+      format = __DRI_IMAGE_FORMAT_ARGB2101010;
+      dri_components = __DRI_IMAGE_COMPONENTS_RGBA;
+      break;
+   case __DRI_IMAGE_FOURCC_XRGB2101010:
+      format = __DRI_IMAGE_FORMAT_XRGB2101010;
+      dri_components = __DRI_IMAGE_COMPONENTS_RGB;
+      break;
    case __DRI_IMAGE_FOURCC_R8:
       format = __DRI_IMAGE_FORMAT_R8;
       dri_components = __DRI_IMAGE_COMPONENTS_R;
@@ -84,6 +123,18 @@ static int convert_fourcc(int format, int *dri_components_p)
       format = __DRI_IMAGE_FORMAT_GR88;
       dri_components = __DRI_IMAGE_COMPONENTS_RG;
       break;
+   case __DRI_IMAGE_FOURCC_R16:
+      format = __DRI_IMAGE_FORMAT_R16;
+      dri_components = __DRI_IMAGE_COMPONENTS_R;
+      break;
+   case __DRI_IMAGE_FOURCC_GR1616:
+      format = __DRI_IMAGE_FORMAT_GR1616;
+      dri_components = __DRI_IMAGE_COMPONENTS_RG;
+      break;
+   case __DRI_IMAGE_FOURCC_YUYV:
+      format = __DRI_IMAGE_FORMAT_YUYV;
+      dri_components = __DRI_IMAGE_COMPONENTS_Y_XUXV;
+      break;
    /*
     * For multi-planar YUV formats, we return the format of the first
     * plane only.  Since there is only one caller which supports multi-
@@ -129,6 +180,12 @@ static int convert_to_fourcc(int format)
    case __DRI_IMAGE_FORMAT_XBGR8888:
       format = __DRI_IMAGE_FOURCC_XBGR8888;
       break;
+   case __DRI_IMAGE_FORMAT_ARGB2101010:
+      format = __DRI_IMAGE_FOURCC_ARGB2101010;
+      break;
+   case __DRI_IMAGE_FORMAT_XRGB2101010:
+      format = __DRI_IMAGE_FOURCC_XRGB2101010;
+      break;
    case __DRI_IMAGE_FORMAT_R8:
       format = __DRI_IMAGE_FOURCC_R8;
       break;
@@ -155,15 +212,33 @@ static enum pipe_format dri2_format_to_pipe_format (int format)
    case __DRI_IMAGE_FORMAT_ARGB8888:
       pf = PIPE_FORMAT_BGRA8888_UNORM;
       break;
+   case __DRI_IMAGE_FORMAT_XBGR8888:
+      pf = PIPE_FORMAT_RGBX8888_UNORM;
+      break;
    case __DRI_IMAGE_FORMAT_ABGR8888:
       pf = PIPE_FORMAT_RGBA8888_UNORM;
       break;
+   case __DRI_IMAGE_FORMAT_XRGB2101010:
+      pf = PIPE_FORMAT_B10G10R10X2_UNORM;
+      break;
+   case __DRI_IMAGE_FORMAT_ARGB2101010:
+      pf = PIPE_FORMAT_B10G10R10A2_UNORM;
+      break;
    case __DRI_IMAGE_FORMAT_R8:
       pf = PIPE_FORMAT_R8_UNORM;
       break;
    case __DRI_IMAGE_FORMAT_GR88:
       pf = PIPE_FORMAT_RG88_UNORM;
       break;
+   case __DRI_IMAGE_FORMAT_R16:
+      pf = PIPE_FORMAT_R16_UNORM;
+      break;
+   case __DRI_IMAGE_FORMAT_GR1616:
+      pf = PIPE_FORMAT_R16G16_UNORM;
+      break;
+   case __DRI_IMAGE_FORMAT_YUYV:
+      pf = PIPE_FORMAT_YUYV;
+      break;
    default:
       pf = PIPE_FORMAT_NONE;
       break;
@@ -172,6 +247,76 @@ static enum pipe_format dri2_format_to_pipe_format (int format)
    return pf;
 }
 
+static enum pipe_format fourcc_to_pipe_format(int fourcc)
+{
+   enum pipe_format pf;
+
+   switch (fourcc) {
+   case __DRI_IMAGE_FOURCC_R8:
+      pf = PIPE_FORMAT_R8_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_GR88:
+      pf = PIPE_FORMAT_RG88_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_ARGB1555:
+      pf = PIPE_FORMAT_B5G5R5A1_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_R16:
+      pf = PIPE_FORMAT_R16_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_GR1616:
+      pf = PIPE_FORMAT_RG1616_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_RGB565:
+      pf = PIPE_FORMAT_B5G6R5_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_ARGB8888:
+      pf = PIPE_FORMAT_BGRA8888_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_XRGB8888:
+      pf = PIPE_FORMAT_BGRX8888_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_ABGR8888:
+      pf = PIPE_FORMAT_RGBA8888_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_XBGR8888:
+      pf = PIPE_FORMAT_RGBX8888_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_ARGB2101010:
+      pf = PIPE_FORMAT_B10G10R10A2_UNORM;
+      break;
+   case __DRI_IMAGE_FOURCC_XRGB2101010:
+      pf = PIPE_FORMAT_B10G10R10X2_UNORM;
+      break;
+
+   case __DRI_IMAGE_FOURCC_NV12:
+      pf = PIPE_FORMAT_NV12;
+      break;
+   case __DRI_IMAGE_FOURCC_YUYV:
+      pf = PIPE_FORMAT_YUYV;
+      break;
+   case __DRI_IMAGE_FOURCC_YUV420:
+   case __DRI_IMAGE_FOURCC_YVU420:
+      pf = PIPE_FORMAT_YV12;
+      break;
+
+   case __DRI_IMAGE_FOURCC_SARGB8888:
+   case __DRI_IMAGE_FOURCC_YUV410:
+   case __DRI_IMAGE_FOURCC_YUV411:
+   case __DRI_IMAGE_FOURCC_YUV422:
+   case __DRI_IMAGE_FOURCC_YUV444:
+   case __DRI_IMAGE_FOURCC_NV16:
+   case __DRI_IMAGE_FOURCC_YVU410:
+   case __DRI_IMAGE_FOURCC_YVU411:
+   case __DRI_IMAGE_FOURCC_YVU422:
+   case __DRI_IMAGE_FOURCC_YVU444:
+   default:
+      pf = PIPE_FORMAT_NONE;
+   }
+
+   return pf;
+}
+
 /**
  * DRI2 flush extension.
  */
@@ -260,10 +405,16 @@ 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_BGRA8888_UNORM:
+      case PIPE_FORMAT_RGBA8888_UNORM:
         depth = 32;
         break;
+      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:
@@ -339,9 +490,18 @@ 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;
       default:
          image_format = __DRI_IMAGE_FORMAT_NONE;
          break;
@@ -388,6 +548,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;
@@ -629,7 +792,8 @@ 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;
 
             /* Try to reuse the resource.
@@ -678,7 +842,7 @@ 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;
@@ -757,6 +921,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,
@@ -765,21 +944,6 @@ 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,
@@ -869,6 +1033,7 @@ dri2_create_image_from_name(__DRIscreen *_screen,
    memset(&whandle, 0, sizeof(whandle));
    whandle.type = DRM_API_HANDLE_TYPE_SHARED;
    whandle.handle = name;
+   whandle.modifier = DRM_FORMAT_MOD_INVALID;
 
    pf = dri2_format_to_pipe_format (format);
    if (pf == PIPE_FORMAT_NONE)
@@ -883,8 +1048,8 @@ dri2_create_image_from_name(__DRIscreen *_screen,
 static __DRIimage *
 dri2_create_image_from_fd(__DRIscreen *_screen,
                           int width, int height, int fourcc,
-                          int *fds, int num_fds, int *strides,
-                          int *offsets, unsigned *error,
+                          uint64_t modifier, int *fds, int num_fds,
+                          int *strides, int *offsets, unsigned *error,
                           int *dri_components, void *loaderPrivate)
 {
    struct winsys_handle whandles[3];
@@ -929,6 +1094,7 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
       whandles[i].handle = (unsigned)fds[i];
       whandles[i].stride = (unsigned)strides[i];
       whandles[i].offset = (unsigned)offsets[i];
+      whandles[i].modifier = modifier;
    }
 
    if (fourcc == __DRI_IMAGE_FOURCC_YVU420) {
@@ -952,22 +1118,12 @@ exit:
 }
 
 static __DRIimage *
-dri2_create_image_from_renderbuffer(__DRIcontext *context,
-                                   int renderbuffer, void *loaderPrivate)
-{
-   struct dri_context *ctx = dri_context(context);
-
-   if (!ctx->st->get_resource_for_egl_image)
-      return NULL;
-
-   /* TODO */
-   return NULL;
-}
-
-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)
 {
    struct dri_screen *screen = dri_screen(_screen);
    __DRIimage *img;
@@ -975,7 +1131,13 @@ dri2_create_image(__DRIscreen *_screen,
    unsigned tex_usage;
    enum pipe_format pf;
 
+   /* 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)
@@ -1006,7 +1168,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;
@@ -1022,6 +1193,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)
 {
@@ -1038,20 +1231,30 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
    switch (attrib) {
    case __DRI_IMAGE_ATTRIB_STRIDE:
       whandle.type = DRM_API_HANDLE_TYPE_KMS;
-      image->texture->screen->resource_get_handle(image->texture->screen,
-            NULL, image->texture, &whandle, usage);
+      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 = DRM_API_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,
-         NULL, image->texture, &whandle, usage);
+      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,
-         NULL, image->texture, &whandle, usage);
+      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:
@@ -1082,6 +1285,26 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
    case __DRI_IMAGE_ATTRIB_NUM_PLANES:
       *value = 1;
       return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_MODIFIER_UPPER:
+      whandle.type = DRM_API_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 = DRM_API_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;
    }
@@ -1111,15 +1334,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 *
@@ -1143,6 +1380,7 @@ dri2_from_names(__DRIscreen *screen, int width, int height, int format,
    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,
                                        1, &whandle, loaderPrivate);
@@ -1177,72 +1415,6 @@ dri2_from_planar(__DRIimage *image, int plane, void *loaderPrivate)
    return img;
 }
 
-static __DRIimage *
-dri2_create_from_texture(__DRIcontext *context, int target, unsigned texture,
-                         int depth, int level, unsigned *error,
-                         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;
-   }
-
-   img = CALLOC_STRUCT(__DRIimageRec);
-   if (!img) {
-      *error = __DRI_IMAGE_ERROR_BAD_ALLOC;
-      return NULL;
-   }
-
-   img->level = level;
-   img->layer = depth;
-   img->dri_format = driGLFormatToImageFormat(obj->Image[face][level]->TexFormat);
-
-   img->loader_private = loaderPrivate;
-
-   if (img->dri_format == __DRI_IMAGE_FORMAT_NONE) {
-      *error = __DRI_IMAGE_ERROR_BAD_PARAMETER;
-      free(img);
-      return NULL;
-   }
-
-   pipe_resource_reference(&img->texture, tex);
-
-   *error = __DRI_IMAGE_ERROR_SUCCESS;
-   return img;
-}
-
 static __DRIimage *
 dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
               int *fds, int num_fds, int *strides, int *offsets,
@@ -1252,7 +1424,8 @@ dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
    int dri_components;
 
    img = dri2_create_image_from_fd(screen, width, height, fourcc,
-                                   fds, num_fds, strides, offsets, NULL,
+                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
+                                   strides, offsets, NULL,
                                    &dri_components, loaderPrivate);
    if (img == NULL)
       return NULL;
@@ -1261,6 +1434,50 @@ dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
    return img;
 }
 
+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;
+   const unsigned bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+   int i, j;
+
+   for (i = 0, j = 0; (i < ARRAY_SIZE(fourcc_formats)) &&
+         (j < max || max == 0); i++) {
+      if (pscreen->is_format_supported(pscreen,
+                                       fourcc_to_pipe_format(
+                                          fourcc_formats[i]),
+                                       screen->target,
+                                       0, bind)) {
+         if (j < max)
+            formats[j] = fourcc_formats[i];
+         j++;
+      }
+   }
+   *count = j;
+   return true;
+}
+
+static boolean
+dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max,
+                             uint64_t *modifiers, unsigned int *external_only,
+                             int *count)
+{
+   struct dri_screen *screen = dri_screen(_screen);
+   struct pipe_screen *pscreen = screen->base.screen;
+   enum pipe_format format = fourcc_to_pipe_format(fourcc);
+   const unsigned usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+
+   if (pscreen->query_dmabuf_modifiers != NULL &&
+       pscreen->is_format_supported(pscreen, format, screen->target, 0, usage)) {
+      pscreen->query_dmabuf_modifiers(pscreen, format, max, modifiers,
+                                      external_only, count);
+      return true;
+   }
+   return false;
+}
+
 static __DRIimage *
 dri2_from_dma_bufs(__DRIscreen *screen,
                    int width, int height, int fourcc,
@@ -1277,7 +1494,8 @@ dri2_from_dma_bufs(__DRIscreen *screen,
    int dri_components;
 
    img = dri2_create_image_from_fd(screen, width, height, fourcc,
-                                   fds, num_fds, strides, offsets, error,
+                                   DRM_FORMAT_MOD_INVALID, fds, num_fds,
+                                   strides, offsets, error,
                                    &dri_components, loaderPrivate);
    if (img == NULL)
       return NULL;
@@ -1292,6 +1510,37 @@ dri2_from_dma_bufs(__DRIscreen *screen,
    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;
+   int dri_components;
+
+   img = dri2_create_image_from_fd(screen, width, height, fourcc,
+                                   modifier, fds, num_fds, strides, offsets,
+                                   error, &dri_components, 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;
+}
+
 static void
 dri2_blit_image(__DRIcontext *context, __DRIimage *dst, __DRIimage *src,
                 int dstx0, int dsty0, int dstwidth, int dstheight,
@@ -1378,13 +1627,6 @@ dri2_unmap_image(__DRIcontext *context, __DRIimage *image, void *data)
    pipe_transfer_unmap(pipe, (struct pipe_transfer *)data);
 }
 
-static void
-dri2_destroy_image(__DRIimage *img)
-{
-   pipe_resource_reference(&img->texture, NULL);
-   FREE(img);
-}
-
 static int
 dri2_get_capabilities(__DRIscreen *_screen)
 {
@@ -1395,7 +1637,7 @@ dri2_get_capabilities(__DRIscreen *_screen)
 
 /* The extension is modified during runtime if DRI_PRIME is detected */
 static __DRIimageExtension dri2ImageExtension = {
-    .base = { __DRI_IMAGE, 12 },
+    .base = { __DRI_IMAGE, 17 },
 
     .createImageFromName          = dri2_create_image_from_name,
     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
@@ -1413,6 +1655,12 @@ static __DRIimageExtension dri2ImageExtension = {
     .getCapabilities              = dri2_get_capabilities,
     .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 = {
@@ -1496,7 +1744,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.
@@ -1512,14 +1760,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;
       }
 
@@ -1540,7 +1788,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;
       }
 
@@ -1549,7 +1797,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;
       }
 
@@ -1559,7 +1807,7 @@ 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;
       }
 
@@ -1589,7 +1837,7 @@ 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;
       }
 
@@ -1602,19 +1850,19 @@ dri2_interop_export_object(__DRIcontext *_ctx,
        *    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);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_INVALID_MIP_LEVEL;
       }
 
       if (!st_finalize_texture(ctx, st->pipe, obj, 0)) {
-         mtx_unlock(&ctx->Shared->Mutex);
+         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. */
-         mtx_unlock(&ctx->Shared->Mutex);
+         simple_mtx_unlock(&ctx->Shared->Mutex);
          return MESA_GLINTEROP_INVALID_OBJECT;
       }
 
@@ -1654,7 +1902,7 @@ dri2_interop_export_object(__DRIcontext *_ctx,
 
    success = screen->resource_get_handle(screen, st->pipe, res, &whandle,
                                          usage);
-   mtx_unlock(&ctx->Shared->Mutex);
+   simple_mtx_unlock(&ctx->Shared->Mutex);
 
    if (!success)
       return MESA_GLINTEROP_OUT_OF_HOST_MEMORY;
@@ -1687,10 +1935,10 @@ dri2GalliumConfigQueryb(__DRIscreen *sPriv, const char *var,
 {
    struct dri_screen *screen = dri_screen(sPriv);
 
-   if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
+   if (!driCheckOption(&screen->dev->option_cache, var, DRI_BOOL))
       return dri2ConfigQueryExtension.configQueryb(sPriv, var, val);
 
-   *val = driQueryOptionb(&screen->optionCache, var);
+   *val = driQueryOptionb(&screen->dev->option_cache, var);
 
    return 0;
 }
@@ -1703,11 +1951,11 @@ dri2GalliumConfigQueryi(__DRIscreen *sPriv, const char *var, int *val)
 {
    struct dri_screen *screen = dri_screen(sPriv);
 
-   if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
-       !driCheckOption(&screen->optionCache, var, DRI_ENUM))
+   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->optionCache, var);
+    *val = driQueryOptioni(&screen->dev->option_cache, var);
 
     return 0;
 }
@@ -1720,10 +1968,10 @@ dri2GalliumConfigQueryf(__DRIscreen *sPriv, const char *var, float *val)
 {
    struct dri_screen *screen = dri_screen(sPriv);
 
-   if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
+   if (!driCheckOption(&screen->dev->option_cache, var, DRI_FLOAT))
       return dri2ConfigQueryExtension.configQueryf(sPriv, var, val);
 
-    *val = driQueryOptionf(&screen->optionCache, var);
+    *val = driQueryOptionf(&screen->dev->option_cache, var);
 
     return 0;
 }
@@ -1754,6 +2002,8 @@ static const __DRIextension *dri_screen_extensions[] = {
    &dri2ThrottleExtension.base,
    &dri2FenceExtension.base,
    &dri2InteropExtension.base,
+   &dri2NoErrorExtension.base,
+   &dri2FlushControlExtension.base,
    NULL
 };
 
@@ -1762,11 +2012,13 @@ 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,
+   &dri2FlushControlExtension.base,
    NULL
 };
 
@@ -1798,8 +2050,12 @@ dri2_init_screen(__DRIscreen * sPriv)
    if (screen->fd < 0 || (fd = fcntl(screen->fd, F_DUPFD_CLOEXEC, 3)) < 0)
       goto free_screen;
 
-   if (pipe_loader_drm_probe_fd(&screen->dev, fd))
+
+   if (pipe_loader_drm_probe_fd(&screen->dev, fd)) {
+      dri_init_options(screen);
+
       pscreen = pipe_loader_create_screen(screen->dev);
+   }
 
    if (!pscreen)
        goto release_pipe;
@@ -1812,6 +2068,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;
 
@@ -1819,6 +2079,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;
+         }
       }
    }
 
@@ -1829,7 +2095,7 @@ 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 destroy_screen;
 
@@ -1881,21 +2147,30 @@ dri_kms_init_screen(__DRIscreen * sPriv)
    if (screen->fd < 0 || (fd = fcntl(screen->fd, F_DUPFD_CLOEXEC, 3)) < 0)
       goto free_screen;
 
-   if (pipe_loader_sw_probe_kms(&screen->dev, fd))
+   if (pipe_loader_sw_probe_kms(&screen->dev, fd)) {
+      dri_init_options(screen);
       pscreen = pipe_loader_create_screen(screen->dev);
+   }
 
    if (!pscreen)
        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;
+      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 destroy_screen;
 
@@ -1936,6 +2211,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;
 }
@@ -1986,7 +2262,6 @@ const __DRIextension *galliumdrm_driver_extensions[] = {
     &driImageDriverExtension.base,
     &driDRI2Extension.base,
     &gallium_config_options.base,
-    &dri2FenceExtension.base,
     NULL
 };