Add exception handle for multithread case.
[platform/upstream/mesa.git] / src / egl / drivers / dri2 / egl_dri2.c
index adc272c..d04ed54 100644 (file)
@@ -65,6 +65,7 @@
 #include "util/libsync.h"
 #include "util/os_file.h"
 #include "util/u_atomic.h"
+#include "util/u_call_once.h"
 #include "util/u_vector.h"
 #include "mapi/glapi/glapi.h"
 #include "util/bitscan.h"
@@ -133,15 +134,19 @@ dri_set_background_context(void *loaderPrivate)
 }
 
 static void
+dri2_gl_flush_get(_glapi_proc *glFlush)
+{
+   *glFlush = _glapi_get_proc_address("glFlush");
+}
+
+static void
 dri2_gl_flush()
 {
    static void (*glFlush)(void);
-   static mtx_t glFlushMutex = _MTX_INITIALIZER_NP;
+   static util_once_flag once = UTIL_ONCE_FLAG_INIT;
 
-   mtx_lock(&glFlushMutex);
-   if (!glFlush)
-      glFlush = _glapi_get_proc_address("glFlush");
-   mtx_unlock(&glFlushMutex);
+   util_call_once_data(&once,
+      (util_call_once_data_func)dri2_gl_flush_get, &glFlush);
 
    /* if glFlush is not available things are horribly broken */
    if (!glFlush) {
@@ -153,12 +158,20 @@ dri2_gl_flush()
 }
 
 static GLboolean
-dri_is_thread_safe(void *loaderPrivate)
+dri_is_thread_safe(UNUSED void *loaderPrivate)
 {
+#ifdef HAVE_X11_PLATFORM
    struct dri2_egl_surface *dri2_surf = loaderPrivate;
-   UNUSED _EGLDisplay *display =  dri2_surf->base.Resource.Display;
 
-#ifdef HAVE_X11_PLATFORM
+   /* loader_dri3_blit_context_get creates a context with
+    * loaderPrivate being NULL. Enabling glthread for a blitting
+    * context isn't useful so return false.
+    */
+   if (!loaderPrivate)
+      return false;
+
+   _EGLDisplay *display =  dri2_surf->base.Resource.Display;
+
    Display *xdpy = (Display*)display->PlatformDisplay;
 
    /* Check Xlib is running in thread safe mode when running on EGL/X11-xlib
@@ -653,12 +666,9 @@ dri2_add_pbuffer_configs_for_visuals(_EGLDisplay *disp)
 GLboolean
 dri2_validate_egl_image(void *image, void *data)
 {
-   _EGLDisplay *disp = data;
-   _EGLImage *img;
-
-   egl_lock(disp);
-   img = _eglLookupImage(image, disp);
-   egl_unlock(disp);
+   _EGLDisplay *disp = _eglLockDisplay(data);
+   _EGLImage *img = _eglLookupImage(image, disp);
+   _eglUnlockDisplay(disp);
 
    if (img == NULL) {
       _eglError(EGL_BAD_PARAMETER, "dri2_validate_egl_image");
@@ -816,6 +826,13 @@ dri2_load_driver_common(_EGLDisplay *disp,
    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
    const __DRIextension **extensions;
 
+   /*This exception only happen in multithread case, when _eglAtExit is *
+    *called and disp is freed in main thread.                           */
+   if (dri2_dpy == NULL) {
+      _eglLog(_EGL_FATAL, "DRI2: disp is freed");
+      return EGL_FALSE;
+   }
+
    extensions = dri2_open_driver(disp);
    if (!extensions)
       return EGL_FALSE;
@@ -1024,7 +1041,10 @@ dri2_setup_screen(_EGLDisplay *disp)
 
    disp->Extensions.EXT_protected_surface =
       dri2_renderer_query_integer(dri2_dpy,
-                                  __DRI2_RENDERER_HAS_PROTECTED_CONTENT);
+                                  __DRI2_RENDERER_HAS_PROTECTED_SURFACE);
+   disp->Extensions.EXT_protected_content =
+      dri2_renderer_query_integer(dri2_dpy,
+                                  __DRI2_RENDERER_HAS_PROTECTED_CONTEXT);
 }
 
 void
@@ -1194,6 +1214,12 @@ dri2_initialize(_EGLDisplay *disp)
    case _EGL_PLATFORM_ANDROID:
       ret = dri2_initialize_android(disp);
       break;
+
+#ifdef HAVE_TIZEN_PLATFORM
+   case _EGL_PLATFORM_TIZEN:
+      ret = dri2_initialize_tizen(disp);
+      break;
+#endif
    default:
       unreachable("Callers ensure we cannot get here.");
       return EGL_FALSE;
@@ -1269,6 +1295,12 @@ dri2_display_destroy(_EGLDisplay *disp)
    case _EGL_PLATFORM_WAYLAND:
       dri2_teardown_wayland(dri2_dpy);
       break;
+
+#ifdef HAVE_TIZEN_PLATFORM
+   case _EGL_PLATFORM_TIZEN:
+      dri2_teardown_tizen(disp);
+      break;
+#endif
    default:
       /* TODO: add teardown for other platforms */
       break;
@@ -1478,6 +1510,11 @@ dri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx,
       ctx_attribs[pos++] = true;
    }
 
+   if (dri2_ctx->base.Protected) {
+      ctx_attribs[pos++] = __DRI_CTX_ATTRIB_PROTECTED;
+      ctx_attribs[pos++] = true;
+   }
+
    *num_attribs = pos;
 
    return true;
@@ -1822,17 +1859,17 @@ dri2_make_current(_EGLDisplay *disp, _EGLSurface *dsurf,
          old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false);
       }
 
-      dri2_dpy->core->unbindContext(old_cctx);
+      old_dri2_dpy->core->unbindContext(old_cctx);
 
       if (old_dsurf)
-         dri2_surf_update_fence_fd(old_ctx, disp, old_dsurf);
+         dri2_surf_update_fence_fd(old_ctx, old_disp, old_dsurf);
    }
 
    ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL;
    rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL;
    cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
 
-   if (cctx || ddraw || rdraw) {
+   if (cctx) {
       if (!dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
          _EGLContext *tmp_ctx;
 
@@ -2434,8 +2471,6 @@ dri2_get_sync_values_chromium(_EGLDisplay *disp, _EGLSurface *surf,
    if (dri2_dpy->vtbl->get_sync_values)
       ret = dri2_dpy->vtbl->get_sync_values(disp, surf, ust, msc, sbc);
 
-   mtx_unlock(&dri2_dpy->lock);
-
    return ret;
 }
 
@@ -2560,8 +2595,6 @@ dri2_query_surface(_EGLDisplay *disp, _EGLSurface *surf,
       ret = dri2_dpy->vtbl->query_surface(disp, surf, attribute, value);
    }
 
-   mtx_unlock(&dri2_dpy->lock);
-
    return ret;
 }
 
@@ -2900,7 +2933,7 @@ dri2_query_dma_buf_modifiers(_EGLDisplay *disp, EGLint format,
       return dri2_egl_error_unlock(dri2_dpy, EGL_BAD_PARAMETER, "invalid value for max count of formats");
 
    if (max > 0 && modifiers == NULL)
-      dri2_egl_error_unlock(dri2_dpy, EGL_BAD_PARAMETER, "invalid modifiers array");
+      return dri2_egl_error_unlock(dri2_dpy, EGL_BAD_PARAMETER, "invalid modifiers array");
 
    if (dri2_dpy->image->base.version < 15 ||
        dri2_dpy->image->queryDmaBufModifiers == NULL) {
@@ -2944,6 +2977,7 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx,
    uint64_t modifier;
    bool has_modifier = false;
    unsigned error;
+   EGLint egl_error;
 
    /**
     * The spec says:
@@ -3031,7 +3065,10 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx,
             &error,
             NULL);
    }
-   dri2_create_image_khr_texture_error(error);
+
+   egl_error = egl_error_from_dri_image_error(error);
+   if (egl_error != EGL_SUCCESS)
+      _eglError(egl_error, "createImageFromDmaBufs failed");
 
    if (!dri_image)
       return EGL_NO_IMAGE_KHR;
@@ -3452,6 +3489,94 @@ dri2_query_wayland_buffer_wl(_EGLDisplay *disp, struct wl_resource *buffer_resou
 }
 #endif
 
+#ifdef HAVE_TIZEN_PLATFORM
+static EGLBoolean
+tizen_bind_wayland_display_wl(_EGLDisplay *disp,
+                              struct wl_display *wl_dpy)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+
+   (void) wl_dpy;
+
+   if (!dri2_dpy->tpl_display)
+     return EGL_FALSE;
+
+   if (!tpl_display_get_native_handle(dri2_dpy->tpl_display))
+     return EGL_FALSE;
+
+   return EGL_TRUE;
+}
+
+static EGLBoolean
+tizen_unbind_wayland_display_wl(_EGLDisplay *disp,
+                                struct wl_display *wl_dpy)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+
+   (void) wl_dpy;
+
+   if (!dri2_dpy->tpl_display)
+     return EGL_FALSE;
+
+   if (!tpl_display_get_native_handle(dri2_dpy->tpl_display))
+     return EGL_FALSE;
+
+   return EGL_TRUE;
+}
+
+static EGLBoolean
+tizen_query_wayland_buffer_wl(_EGLDisplay *disp,
+                              struct wl_resource *buffer_resource,
+                              EGLint attribute, EGLint *value)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   tbm_format tbm_format = 0;
+   int width = 0, height = 0;
+   tpl_result_t res;
+
+   if (!dri2_dpy->tpl_display)
+     return EGL_FALSE;
+
+   if (!tpl_display_get_native_handle(dri2_dpy->tpl_display))
+     return EGL_FALSE;
+
+   res = tpl_display_get_native_pixmap_info(dri2_dpy->tpl_display,
+                                            (tpl_handle_t)buffer_resource,
+                                            &width, &height, &tbm_format);
+   if (res != TPL_ERROR_NONE)
+     return EGL_FALSE;
+
+   switch (attribute) {
+   case EGL_TEXTURE_FORMAT:
+      switch (tbm_format) {
+      case TBM_FORMAT_ARGB8888:
+         *value = EGL_TEXTURE_RGBA;
+         return EGL_TRUE;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wswitch"
+      case TBM_FORMAT_XRGB8888:
+      case TBM_FORMAT_RGB565:
+#pragma GCC diagnostic pop
+         *value = EGL_TEXTURE_RGB;
+         return EGL_TRUE;
+      default:
+         break;
+      }
+      break;
+   case EGL_WIDTH:
+      *value = width;
+      return EGL_TRUE;
+   case EGL_HEIGHT:
+      *value = height;
+      return EGL_TRUE;
+   default:
+      break;
+   }
+
+   return EGL_FALSE;
+}
+#endif
+
 static void
 dri2_egl_ref_sync(struct dri2_egl_sync *sync)
 {
@@ -3467,10 +3592,17 @@ dri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy,
       case EGL_SYNC_REUSABLE_KHR:
          cnd_destroy(&dri2_sync->cond);
          break;
+#ifdef HAVE_TIZEN_PLATFORM
+      case EGL_SYNC_NATIVE_FENCE_TIZEN:
+         if (dri2_sync->base.SyncFd != EGL_NO_NATIVE_FENCE_FD_TIZEN)
+            close(dri2_sync->base.SyncFd);
+         break;
+#else
       case EGL_SYNC_NATIVE_FENCE_ANDROID:
          if (dri2_sync->base.SyncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID)
             close(dri2_sync->base.SyncFd);
          break;
+#endif
       default:
          break;
       }
@@ -3558,7 +3690,8 @@ dri2_create_sync(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list)
       dri2_sync->base.SyncStatus = EGL_UNSIGNALED_KHR;
       break;
 
-   case EGL_SYNC_NATIVE_FENCE_ANDROID:
+#ifdef HAVE_TIZEN_PLATFORM
+   case EGL_SYNC_NATIVE_FENCE_TIZEN:
       if (dri2_dpy->fence->create_fence_fd) {
          dri2_sync->fence = dri2_dpy->fence->create_fence_fd(
                                     dri2_ctx->dri_context,
@@ -3570,6 +3703,20 @@ dri2_create_sync(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list)
       }
       break;
    }
+#else
+   case EGL_SYNC_NATIVE_FENCE_ANDROID:
+      if (dri2_dpy->fence->create_fence_fd) {
+         dri2_sync->fence = dri2_dpy->fence->create_fence_fd(
+                                    dri2_ctx->dri_context,
+                                    dri2_sync->base.SyncFd);
+      }
+      if (!dri2_sync->fence) {
+         _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
+         free(dri2_sync);
+         return NULL;
+      }
+      break;
+#endif
 
    p_atomic_set(&dri2_sync->refcount, 1);
    mtx_unlock(&dri2_dpy->lock);
@@ -3642,6 +3789,31 @@ dri2_dup_native_fence_fd(_EGLDisplay *disp, _EGLSync *sync)
    return os_dupfd_cloexec(sync->SyncFd);
 }
 
+static EGLint
+dri2_dup_native_fence_fd_tizen(_EGLDisplay *dpy, _EGLSync *sync)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
+
+   assert(sync->Type == EGL_SYNC_NATIVE_FENCE_TIZEN);
+
+   if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_TIZEN) {
+      /* try to retrieve the actual native fence fd.. if rendering is
+       * not flushed this will just return -1, aka NO_NATIVE_FENCE_FD:
+       */
+      sync->SyncFd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen,
+                                                   dri2_sync->fence);
+   }
+
+   if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_TIZEN) {
+      /* if native fence fd still not created, return an error: */
+      _eglError(EGL_BAD_PARAMETER, "eglDupNativeFenceFDTIZEN");
+      return EGL_NO_NATIVE_FENCE_FD_TIZEN;
+   }
+
+   return dup(sync->SyncFd);
+}
+
 static void
 dri2_set_blob_cache_funcs(_EGLDisplay *disp,
                           EGLSetBlobFuncANDROID set,
@@ -3677,7 +3849,11 @@ dri2_client_wait_sync(_EGLDisplay *disp, _EGLSync *sync,
 
    switch (sync->Type) {
    case EGL_SYNC_FENCE_KHR:
+#ifdef HAVE_TIZEN_PLATFORM
+   case EGL_SYNC_NATIVE_FENCE_TIZEN:
+#else
    case EGL_SYNC_NATIVE_FENCE_ANDROID:
+#endif
    case EGL_SYNC_CL_EVENT_KHR:
       if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL,
                                          dri2_sync->fence, wait_flags,
@@ -3810,6 +3986,20 @@ dri2_interop_export_object(_EGLDisplay *disp, _EGLContext *ctx,
    return dri2_dpy->interop->export_object(dri2_ctx->dri_context, in, out);
 }
 
+static int
+dri2_interop_flush_objects(_EGLDisplay *disp, _EGLContext *ctx,
+                           unsigned count, struct mesa_glinterop_export_in *objects,
+                           GLsync *sync)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
+
+   if (!dri2_dpy->interop || dri2_dpy->interop->base.version < 2)
+      return MESA_GLINTEROP_UNSUPPORTED;
+
+   return dri2_dpy->interop->flush_objects(dri2_ctx->dri_context, count, objects, sync);
+}
+
 const _EGLDriver _eglDriver = {
    .Initialize = dri2_initialize,
    .Terminate = dri2_terminate,
@@ -3852,6 +4042,11 @@ const _EGLDriver _eglDriver = {
    .UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl,
    .QueryWaylandBufferWL = dri2_query_wayland_buffer_wl,
 #endif
+#ifdef HAVE_TIZEN_PLATFORM
+   .BindWaylandDisplayWL = tizen_bind_wayland_display_wl,
+   .UnbindWaylandDisplayWL = tizen_unbind_wayland_display_wl,
+   .QueryWaylandBufferWL = tizen_query_wayland_buffer_wl,
+ #endif
    .GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium,
    .GetMscRateANGLE = dri2_get_msc_rate_angle,
    .CreateSyncKHR = dri2_create_sync,
@@ -3861,6 +4056,8 @@ const _EGLDriver _eglDriver = {
    .DestroySyncKHR = dri2_destroy_sync,
    .GLInteropQueryDeviceInfo = dri2_interop_query_device_info,
    .GLInteropExportObject = dri2_interop_export_object,
+   .GLInteropFlushObjects = dri2_interop_flush_objects,
    .DupNativeFenceFDANDROID = dri2_dup_native_fence_fd,
+   .DupNativeFenceFDTIZEN = dri2_dup_native_fence_fd_tizen,
    .SetBlobCacheFuncsANDROID = dri2_set_blob_cache_funcs,
 };