st/dri: Don't close the drm fd on failure
[mesa.git] / src / gallium / state_trackers / dri / dri2.c
index c466de783797e79fd2aa183edf4d82f8b2c83166..5b7be64ba5a0bc1b5a4e24f4c69ba87845a9b308 100644 (file)
@@ -29,6 +29,7 @@
  */
 
 #include <xf86drm.h>
+#include <dlfcn.h>
 #include "util/u_memory.h"
 #include "util/u_inlines.h"
 #include "util/u_format.h"
@@ -42,6 +43,7 @@
 #include "dri_screen.h"
 #include "dri_context.h"
 #include "dri_drawable.h"
+#include "dri_query_renderer.h"
 #include "dri2_buffer.h"
 
 static int convert_fourcc(int format, int *dri_components_p)
@@ -75,6 +77,30 @@ static int convert_fourcc(int format, int *dri_components_p)
    return format;
 }
 
+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;
+   default:
+      return -1;
+   }
+   return format;
+}
+
 /**
  * DRI2 flush extension.
  */
@@ -162,10 +188,10 @@ dri2_drawable_get_buffers(struct dri_drawable *drawable,
        * may occur as the stvis->color_format.
        */
       switch(format) {
-      case PIPE_FORMAT_B8G8R8A8_UNORM:
+      case PIPE_FORMAT_BGRA8888_UNORM:
         depth = 32;
         break;
-      case PIPE_FORMAT_B8G8R8X8_UNORM:
+      case PIPE_FORMAT_BGRX8888_UNORM:
         depth = 24;
         break;
       case PIPE_FORMAT_B5G6R5_UNORM:
@@ -235,13 +261,13 @@ dri_image_drawable_get_buffers(struct dri_drawable *drawable,
       case PIPE_FORMAT_B5G6R5_UNORM:
          image_format = __DRI_IMAGE_FORMAT_RGB565;
          break;
-      case PIPE_FORMAT_B8G8R8X8_UNORM:
+      case PIPE_FORMAT_BGRX8888_UNORM:
          image_format = __DRI_IMAGE_FORMAT_XRGB8888;
          break;
-      case PIPE_FORMAT_B8G8R8A8_UNORM:
+      case PIPE_FORMAT_BGRA8888_UNORM:
          image_format = __DRI_IMAGE_FORMAT_ARGB8888;
          break;
-      case PIPE_FORMAT_R8G8B8A8_UNORM:
+      case PIPE_FORMAT_RGBA8888_UNORM:
          image_format = __DRI_IMAGE_FORMAT_ABGR8888;
          break;
       default:
@@ -288,10 +314,10 @@ dri2_allocate_buffer(__DRIscreen *sPriv,
 
    switch (format) {
       case 32:
-         pf = PIPE_FORMAT_B8G8R8A8_UNORM;
+         pf = PIPE_FORMAT_BGRA8888_UNORM;
          break;
       case 24:
-         pf = PIPE_FORMAT_B8G8R8X8_UNORM;
+         pf = PIPE_FORMAT_BGRX8888_UNORM;
          break;
       case 16:
          pf = PIPE_FORMAT_Z16_UNORM;
@@ -367,7 +393,7 @@ dri2_allocate_textures(struct dri_context *ctx,
    /* Image specific variables */
    struct __DRIimageList images;
    /* Dri2 specific variables */
-   __DRIbuffer *buffers;
+   __DRIbuffer *buffers = NULL;
    struct winsys_handle whandle;
    unsigned num_buffers = statts_count;
 
@@ -528,7 +554,7 @@ dri2_allocate_textures(struct dri_context *ctx,
 
          if (drawable->textures[statt]) {
             templ.format = drawable->textures[statt]->format;
-            templ.bind = drawable->textures[statt]->bind;
+            templ.bind = drawable->textures[statt]->bind & ~PIPE_BIND_SCANOUT;
             templ.nr_samples = drawable->stvis.samples;
 
             /* Try to reuse the resource.
@@ -698,13 +724,13 @@ dri2_create_image_from_winsys(__DRIscreen *_screen,
       pf = PIPE_FORMAT_B5G6R5_UNORM;
       break;
    case __DRI_IMAGE_FORMAT_XRGB8888:
-      pf = PIPE_FORMAT_B8G8R8X8_UNORM;
+      pf = PIPE_FORMAT_BGRX8888_UNORM;
       break;
    case __DRI_IMAGE_FORMAT_ARGB8888:
-      pf = PIPE_FORMAT_B8G8R8A8_UNORM;
+      pf = PIPE_FORMAT_BGRA8888_UNORM;
       break;
    case __DRI_IMAGE_FORMAT_ABGR8888:
-      pf = PIPE_FORMAT_R8G8B8A8_UNORM;
+      pf = PIPE_FORMAT_RGBA8888_UNORM;
       break;
    default:
       pf = PIPE_FORMAT_NONE;
@@ -819,13 +845,13 @@ dri2_create_image(__DRIscreen *_screen,
       pf = PIPE_FORMAT_B5G6R5_UNORM;
       break;
    case __DRI_IMAGE_FORMAT_XRGB8888:
-      pf = PIPE_FORMAT_B8G8R8X8_UNORM;
+      pf = PIPE_FORMAT_BGRX8888_UNORM;
       break;
    case __DRI_IMAGE_FORMAT_ARGB8888:
-      pf = PIPE_FORMAT_B8G8R8A8_UNORM;
+      pf = PIPE_FORMAT_BGRA8888_UNORM;
       break;
    case __DRI_IMAGE_FORMAT_ABGR8888:
-      pf = PIPE_FORMAT_R8G8B8A8_UNORM;
+      pf = PIPE_FORMAT_RGBA8888_UNORM;
       break;
    default:
       pf = PIPE_FORMAT_NONE;
@@ -908,6 +934,12 @@ dri2_query_image(__DRIimage *image, int attrib, int *value)
          return GL_FALSE;
       *value = image->dri_components;
       return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_FOURCC:
+      *value = convert_to_fourcc(image->dri_format);
+      return GL_TRUE;
+   case __DRI_IMAGE_ATTRIB_NUM_PLANES:
+      *value = 1;
+      return GL_TRUE;
    default:
       return GL_FALSE;
    }
@@ -1202,7 +1234,7 @@ dri2_get_capabilities(__DRIscreen *_screen)
 
 /* The extension is modified during runtime if DRI_PRIME is detected */
 static __DRIimageExtension dri2ImageExtension = {
-    .base = { __DRI_IMAGE, 10 },
+    .base = { __DRI_IMAGE, 11 },
 
     .createImageFromName          = dri2_create_image_from_name,
     .createImageFromRenderbuffer  = dri2_create_image_from_renderbuffer,
@@ -1220,6 +1252,160 @@ static __DRIimageExtension dri2ImageExtension = {
     .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
+};
+
+static const __DRIrobustnessExtension dri2Robustness = {
+   .base = { __DRI2_ROBUSTNESS, 1 }
+};
+
 /*
  * Backend function init_screen.
  */
@@ -1228,8 +1414,22 @@ static const __DRIextension *dri_screen_extensions[] = {
    &driTexBufferExtension.base,
    &dri2FlushExtension.base,
    &dri2ImageExtension.base,
+   &dri2RendererQueryExtension.base,
+   &dri2ConfigQueryExtension.base,
+   &dri2ThrottleExtension.base,
+   &dri2FenceExtension.base,
+   NULL
+};
+
+static const __DRIextension *dri_robust_screen_extensions[] = {
+   &driTexBufferExtension.base,
+   &dri2FlushExtension.base,
+   &dri2ImageExtension.base,
+   &dri2RendererQueryExtension.base,
    &dri2ConfigQueryExtension.base,
    &dri2ThrottleExtension.base,
+   &dri2FenceExtension.base,
+   &dri2Robustness.base,
    NULL
 };
 
@@ -1253,22 +1453,16 @@ dri2_init_screen(__DRIscreen * sPriv)
 
    screen->sPriv = sPriv;
    screen->fd = sPriv->fd;
+   pipe_mutex_init(screen->opencl_func_mutex);
 
    sPriv->driverPrivate = (void *)screen;
 
-#if GALLIUM_STATIC_TARGETS
-   pscreen = dd_create_screen(screen->fd);
-
-   throttle_ret = dd_configuration(DRM_CONF_THROTTLE);
-   dmabuf_ret = dd_configuration(DRM_CONF_SHARE_FD);
-#else
-   if (pipe_loader_drm_probe_fd(&screen->dev, screen->fd, true)) {
-      pscreen = pipe_loader_create_screen(screen->dev, PIPE_SEARCH_DIR);
+   if (pipe_loader_drm_probe_fd(&screen->dev, dup(screen->fd))) {
+      pscreen = pipe_loader_create_screen(screen->dev);
 
       throttle_ret = pipe_loader_configuration(screen->dev, DRM_CONF_THROTTLE);
       dmabuf_ret = pipe_loader_configuration(screen->dev, DRM_CONF_SHARE_FD);
    }
-#endif // GALLIUM_STATIC_TARGETS
 
    if (throttle_ret && throttle_ret->val.val_int != -1) {
       screen->throttling_enabled = TRUE;
@@ -1285,15 +1479,16 @@ dri2_init_screen(__DRIscreen * sPriv)
       }
    }
 
-   sPriv->extensions = dri_screen_extensions;
+   if (pscreen && pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) {
+      sPriv->extensions = dri_robust_screen_extensions;
+      screen->has_reset_status_query = true;
+   }
+   else
+      sPriv->extensions = dri_screen_extensions;
 
    /* dri_init_screen_helper checks pscreen for us */
 
-#if GALLIUM_STATIC_TARGETS
-   configs = dri_init_screen_helper(screen, pscreen, dd_driver_name());
-#else
    configs = dri_init_screen_helper(screen, pscreen, screen->dev->driver_name);
-#endif // GALLIUM_STATIC_TARGETS
    if (!configs)
       goto fail;
 
@@ -1305,10 +1500,8 @@ dri2_init_screen(__DRIscreen * sPriv)
    return configs;
 fail:
    dri_destroy_screen_helper(screen);
-#if !GALLIUM_STATIC_TARGETS
    if (screen->dev)
       pipe_loader_release(&screen->dev, 1);
-#endif // !GALLIUM_STATIC_TARGETS
    FREE(screen);
    return NULL;
 }
@@ -1321,12 +1514,11 @@ fail:
 static const __DRIconfig **
 dri_kms_init_screen(__DRIscreen * sPriv)
 {
-#if GALLIUM_STATIC_TARGETS
 #if defined(GALLIUM_SOFTPIPE)
-#if defined(DRI_TARGET)
    const __DRIconfig **configs;
    struct dri_screen *screen;
    struct pipe_screen *pscreen = NULL;
+   uint64_t cap;
 
    screen = CALLOC_STRUCT(dri_screen);
    if (!screen)
@@ -1337,7 +1529,15 @@ dri_kms_init_screen(__DRIscreen * sPriv)
 
    sPriv->driverPrivate = (void *)screen;
 
-   pscreen = kms_swrast_create_screen(screen->fd);
+   if (pipe_loader_sw_probe_kms(&screen->dev, dup(screen->fd)))
+      pscreen = pipe_loader_create_screen(screen->dev);
+
+   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;
+   }
+
    sPriv->extensions = dri_screen_extensions;
 
    /* dri_init_screen_helper checks pscreen for us */
@@ -1353,10 +1553,10 @@ dri_kms_init_screen(__DRIscreen * sPriv)
    return configs;
 fail:
    dri_destroy_screen_helper(screen);
+   if (screen->dev)
+      pipe_loader_release(&screen->dev, 1);
    FREE(screen);
-#endif // DRI_TARGET
 #endif // GALLIUM_SOFTPIPE
-#endif // GALLIUM_STATIC_TARGETS
    return NULL;
 }