st/dri: replace format conversion functions with single mapping table
[mesa.git] / src / gallium / state_trackers / dri / dri2.c
index 31d17d46c2935e0b9b86be0ab78802066bef02fc..6fc07e42f746862eb7b6011eff2676a2a037839b 100644 (file)
@@ -29,7 +29,6 @@
  */
 
 #include <xf86drm.h>
-#include <fcntl.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_util.h"
+
 #include "dri_helpers.h"
 #include "dri_drawable.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_ABGR2101010,
-   __DRI_IMAGE_FOURCC_XBGR2101010,
-   __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
+struct dri2_buffer
+{
+   __DRIbuffer base;
+   struct pipe_resource *resource;
 };
 
-static int convert_fourcc(int format, int *dri_components_p)
+static inline struct dri2_buffer *
+dri2_buffer(__DRIbuffer * driBufferPriv)
 {
-   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;
-   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_ABGR2101010:
-      format = __DRI_IMAGE_FORMAT_ABGR2101010;
-      dri_components = __DRI_IMAGE_COMPONENTS_RGBA;
-      break;
-   case __DRI_IMAGE_FOURCC_XBGR2101010:
-      format = __DRI_IMAGE_FORMAT_XBGR2101010;
-      dri_components = __DRI_IMAGE_COMPONENTS_RGB;
-      break;
-   case __DRI_IMAGE_FOURCC_R8:
-      format = __DRI_IMAGE_FORMAT_R8;
-      dri_components = __DRI_IMAGE_COMPONENTS_R;
-      break;
-   case __DRI_IMAGE_FOURCC_GR88:
-      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-
-    * planar YUV it gets to figure out the remaining planes on it's
-    * own.
-    */
-   case __DRI_IMAGE_FOURCC_YUV420:
-   case __DRI_IMAGE_FOURCC_YVU420:
-      format = __DRI_IMAGE_FORMAT_R8;
-      dri_components = __DRI_IMAGE_COMPONENTS_Y_U_V;
-      break;
-   case __DRI_IMAGE_FOURCC_NV12:
-      format = __DRI_IMAGE_FORMAT_R8;
-      dri_components = __DRI_IMAGE_COMPONENTS_Y_UV;
-      break;
-   default:
-      return -1;
-   }
-   *dri_components_p = dri_components;
-   return format;
+   return (struct dri2_buffer *) driBufferPriv;
 }
 
-/* NOTE this probably isn't going to do the right thing for YUV images
- * (but I think the same can be said for intel_query_image()).  I think
- * only needed for exporting dmabuf's, so I think I won't loose much
- * sleep over it.
- */
-static int convert_to_fourcc(int format)
-{
-   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;
-   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_ABGR2101010:
-      format = __DRI_IMAGE_FOURCC_ABGR2101010;
-      break;
-   case __DRI_IMAGE_FORMAT_XBGR2101010:
-      format = __DRI_IMAGE_FOURCC_XBGR2101010;
-      break;
-   case __DRI_IMAGE_FORMAT_R8:
-      format = __DRI_IMAGE_FOURCC_R8;
-      break;
-   case __DRI_IMAGE_FORMAT_GR88:
-      format = __DRI_IMAGE_FOURCC_GR88;
-      break;
-   default:
-      return -1;
-   }
-   return format;
-}
+struct dri2_format_mapping {
+   int dri_fourcc;
+   int dri_format;
+   int dri_components;
+   enum pipe_format pipe_format;
+};
 
-static enum pipe_format dri2_format_to_pipe_format (int format)
-{
-   enum pipe_format pf;
+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 },
+};
 
-   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_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_XBGR2101010:
-      pf = PIPE_FORMAT_R10G10B10X2_UNORM;
-      break;
-   case __DRI_IMAGE_FORMAT_ABGR2101010:
-      pf = PIPE_FORMAT_R10G10B10A2_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;
+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 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_ABGR2101010:
-      pf = PIPE_FORMAT_R10G10B10A2_UNORM;
-      break;
-   case __DRI_IMAGE_FOURCC_XBGR2101010:
-      pf = PIPE_FORMAT_R10G10B10X2_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;
+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 pf;
+   return NULL;
 }
 
 /**
@@ -511,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;
@@ -620,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, 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;
@@ -806,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]);
       }
    }
@@ -831,6 +624,7 @@ dri2_allocate_textures(struct dri_context *ctx,
             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)
@@ -882,10 +676,12 @@ dri2_allocate_textures(struct dri_context *ctx,
 
          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];
          }
 
@@ -982,7 +778,7 @@ dri2_update_tex_buffer(struct dri_drawable *drawable,
 
 static __DRIimage *
 dri2_create_image_from_winsys(__DRIscreen *_screen,
-                              int width, int height, int format,
+                              int width, int height, enum pipe_format pf,
                               int num_handles, struct winsys_handle *whandle,
                               void *loaderPrivate)
 {
@@ -990,14 +786,28 @@ dri2_create_image_from_winsys(__DRIscreen *_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;
 
-   tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
+   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;
 
-   pf = dri2_format_to_pipe_format (format);
-   if (pf == PIPE_FORMAT_NONE)
+      if (pscreen->is_format_supported(pscreen, pf, screen->target, 0, 0,
+                                       PIPE_BIND_SAMPLER_VIEW))
+         tex_usage |= PIPE_BIND_SAMPLER_VIEW;
+   }
+
+   if (!tex_usage)
       return NULL;
 
    img = CALLOC_STRUCT(__DRIimageRec);
@@ -1038,7 +848,7 @@ dri2_create_image_from_winsys(__DRIscreen *_screen,
       }
 
       tex = pscreen->resource_from_handle(pscreen,
-            &templ, &whandle[i], PIPE_HANDLE_USAGE_READ_WRITE);
+            &templ, &whandle[i], PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
       if (!tex) {
          pipe_resource_reference(&img->texture, NULL);
          FREE(img);
@@ -1051,7 +861,6 @@ dri2_create_image_from_winsys(__DRIscreen *_screen,
 
    img->level = 0;
    img->layer = 0;
-   img->dri_format = format;
    img->use = 0;
    img->loader_private = loaderPrivate;
 
@@ -1063,22 +872,31 @@ 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;
 
-   pf = dri2_format_to_pipe_format (format);
-   if (pf == PIPE_FORMAT_NONE)
+   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);
+
+   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,
-                                        1, &whandle, loaderPrivate);
+   return img;
 }
 
 static __DRIimage *
@@ -1086,14 +904,19 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
                           int width, int height, int fourcc,
                           uint64_t modifier, int *fds, int num_fds,
                           int *strides, int *offsets, unsigned *error,
-                          int *dri_components, void *loaderPrivate)
+                          void *loaderPrivate)
 {
    struct winsys_handle whandles[3];
-   int format;
+   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;
+   }
+
    switch (fourcc) {
    case __DRI_IMAGE_FOURCC_YUV420:
    case __DRI_IMAGE_FOURCC_YVU420:
@@ -1112,12 +935,6 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
       goto exit;
    }
 
-   format = convert_fourcc(fourcc, dri_components);
-   if (format == -1) {
-      err = __DRI_IMAGE_ERROR_BAD_MATCH;
-      goto exit;
-   }
-
    memset(whandles, 0, sizeof(whandles));
 
    for (i = 0; i < num_fds; i++) {
@@ -1126,7 +943,7 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
          goto exit;
       }
 
-      whandles[i].type = DRM_API_HANDLE_TYPE_FD;
+      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];
@@ -1139,12 +956,19 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
       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, format,
+   img = dri2_create_image_from_winsys(_screen, width, height, map->pipe_format,
                                        num_fds, whandles, loaderPrivate);
-   if(img == NULL)
+   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)
@@ -1161,11 +985,14 @@ dri2_create_image_common(__DRIscreen *_screen,
                          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.
@@ -1186,17 +1013,13 @@ dri2_create_image_common(__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;
@@ -1222,6 +1045,7 @@ dri2_create_image_common(__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;
 
@@ -1258,43 +1082,43 @@ 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;
+      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 = DRM_API_HANDLE_TYPE_KMS;
+      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;
+      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;
+      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;
+      whandle.type= WINSYS_HANDLE_TYPE_FD;
       if (!image->texture->screen->resource_get_handle(image->texture->screen,
             NULL, image->texture, &whandle, usage))
          return GL_FALSE;
@@ -1316,13 +1140,23 @@ 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 = DRM_API_HANDLE_TYPE_KMS;
+      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))
@@ -1332,7 +1166,7 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
       *value = (whandle.modifier >> 32) & 0xffffffff;
       return GL_TRUE;
    case __DRI_IMAGE_ATTRIB_MODIFIER_LOWER:
-      whandle.type = DRM_API_HANDLE_TYPE_KMS;
+      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))
@@ -1400,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)
+   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,
+   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;
 }
 
@@ -1456,18 +1292,9 @@ dri2_from_fds(__DRIscreen *screen, int width, int height, int fourcc,
               int *fds, int num_fds, int *strides, int *offsets,
               void *loaderPrivate)
 {
-   __DRIimage *img;
-   int dri_components;
-
-   img = dri2_create_image_from_fd(screen, width, height, fourcc,
+   return dri2_create_image_from_fd(screen, width, height, fourcc,
                                    DRM_FORMAT_MOD_INVALID, fds, num_fds,
-                                   strides, offsets, NULL,
-                                   &dri_components, loaderPrivate);
-   if (img == NULL)
-      return NULL;
-
-   img->dri_components = dri_components;
-   return img;
+                                   strides, offsets, NULL, loaderPrivate);
 }
 
 static boolean
@@ -1476,18 +1303,26 @@ dri2_query_dma_buf_formats(__DRIscreen *_screen, int max, int *formats,
 {
    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)) &&
+   for (i = 0, j = 0; (i < ARRAY_SIZE(dri2_format_table)) &&
          (j < max || max == 0); i++) {
-      if (pscreen->is_format_supported(pscreen,
-                                       fourcc_to_pipe_format(
-                                          fourcc_formats[i]),
-                                       screen->target,
-                                       0, bind)) {
+      const struct dri2_format_mapping *map = &dri2_format_table[i];
+
+      /* 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 (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] = fourcc_formats[i];
+            formats[j] = map->dri_fourcc;
          j++;
       }
    }
@@ -1502,11 +1337,19 @@ dri2_query_dma_buf_modifiers(__DRIscreen *_screen, int fourcc, int max,
 {
    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;
+   const struct dri2_format_mapping *map = dri2_get_mapping_by_fourcc(fourcc);
+   enum pipe_format format;
+
+   if (!map)
+      return false;
+
+   format = map->pipe_format;
 
    if (pscreen->query_dmabuf_modifiers != NULL &&
-       pscreen->is_format_supported(pscreen, format, screen->target, 0, usage)) {
+       (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;
@@ -1527,12 +1370,10 @@ dri2_from_dma_bufs(__DRIscreen *screen,
                    void *loaderPrivate)
 {
    __DRIimage *img;
-   int dri_components;
 
    img = dri2_create_image_from_fd(screen, width, height, fourcc,
                                    DRM_FORMAT_MOD_INVALID, fds, num_fds,
-                                   strides, offsets, error,
-                                   &dri_components, loaderPrivate);
+                                   strides, offsets, error, loaderPrivate);
    if (img == NULL)
       return NULL;
 
@@ -1540,7 +1381,6 @@ dri2_from_dma_bufs(__DRIscreen *screen,
    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;
@@ -1559,11 +1399,10 @@ dri2_from_dma_bufs2(__DRIscreen *screen,
                     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);
+                                   error, loaderPrivate);
    if (img == NULL)
       return NULL;
 
@@ -1571,7 +1410,6 @@ dri2_from_dma_bufs2(__DRIscreen *screen,
    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;
@@ -1930,21 +1768,19 @@ 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, st->pipe, res, &whandle,
                                          usage);
@@ -2079,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;
 
    screen = CALLOC_STRUCT(dri_screen);
    if (!screen)
@@ -2091,11 +1926,7 @@ dri2_init_screen(__DRIscreen * sPriv)
 
    sPriv->driverPrivate = (void *)screen;
 
-   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, screen->fd)) {
       dri_init_options(screen);
 
       pscreen = pipe_loader_create_screen(screen->dev);
@@ -2156,10 +1987,7 @@ destroy_screen:
 release_pipe:
    if (screen->dev)
       pipe_loader_release(&screen->dev, 1);
-   else
-      close(fd);
 
-free_screen:
    FREE(screen);
    return NULL;
 }
@@ -2177,7 +2005,6 @@ dri_kms_init_screen(__DRIscreen * sPriv)
    struct dri_screen *screen;
    struct pipe_screen *pscreen = NULL;
    uint64_t cap;
-   int fd;
 
    screen = CALLOC_STRUCT(dri_screen);
    if (!screen)
@@ -2188,10 +2015,7 @@ dri_kms_init_screen(__DRIscreen * sPriv)
 
    sPriv->driverPrivate = (void *)screen;
 
-   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, screen->fd)) {
       dri_init_options(screen);
       pscreen = pipe_loader_create_screen(screen->dev);
    }
@@ -2208,8 +2032,10 @@ dri_kms_init_screen(__DRIscreen * sPriv)
       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;
+      if (pscreen->query_dmabuf_modifiers) {
+         dri2ImageExtension.queryDmaBufFormats = dri2_query_dma_buf_formats;
+         dri2ImageExtension.queryDmaBufModifiers = dri2_query_dma_buf_modifiers;
+      }
    }
 
    sPriv->extensions = dri_screen_extensions;
@@ -2231,10 +2057,7 @@ destroy_screen:
 release_pipe:
    if (screen->dev)
       pipe_loader_release(&screen->dev, 1);
-   else
-      close(fd);
 
-free_screen:
    FREE(screen);
 #endif // GALLIUM_SOFTPIPE
    return NULL;