egl: add EGL_ANDROID_native_fence_sync
[mesa.git] / src / egl / main / eglapi.c
index 4568b8b9d7465e558c7a6e4810d80a8ec6552897..9950a7210f3db8df4d34c734bc89633141818050 100644 (file)
@@ -392,6 +392,11 @@ _eglGetPlatformDisplayCommon(EGLenum platform, void *native_display,
       dpy = _eglGetWaylandDisplay((struct wl_display*) native_display,
                                   attrib_list);
       break;
+#endif
+#ifdef HAVE_SURFACELESS_PLATFORM
+   case EGL_PLATFORM_SURFACELESS_MESA:
+      dpy = _eglGetSurfacelessDisplay(native_display, attrib_list);
+      break;
 #endif
    default:
       RETURN_EGL_ERROR(NULL, EGL_BAD_PARAMETER, NULL);
@@ -469,6 +474,7 @@ _eglCreateExtensionsString(_EGLDisplay *dpy)
    /* Please keep these sorted alphabetically. */
    _EGL_CHECK_EXTENSION(ANDROID_framebuffer_target);
    _EGL_CHECK_EXTENSION(ANDROID_image_native_buffer);
+   _EGL_CHECK_EXTENSION(ANDROID_native_fence_sync);
    _EGL_CHECK_EXTENSION(ANDROID_recordable);
 
    _EGL_CHECK_EXTENSION(CHROMIUM_sync_control);
@@ -729,7 +735,9 @@ eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_list,
 
    _EGL_CHECK_DISPLAY(disp, EGL_NO_CONTEXT, drv);
 
-   if (!config && !disp->Extensions.KHR_no_config_context)
+   if (config != EGL_NO_CONFIG_KHR)
+      _EGL_CHECK_CONFIG(disp, conf, EGL_NO_CONTEXT, drv);
+   else if (!disp->Extensions.KHR_no_config_context)
       RETURN_EGL_ERROR(disp, EGL_BAD_CONFIG, EGL_NO_CONTEXT);
 
    if (!share && share_list != EGL_NO_CONTEXT)
@@ -837,11 +845,30 @@ _eglCreateWindowSurfaceCommon(_EGLDisplay *disp, EGLConfig config,
    _EGLSurface *surf;
    EGLSurface ret;
 
-   _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
 
    if (native_window == NULL)
       RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
 
+#ifdef HAVE_SURFACELESS_PLATFORM
+   if (disp->Platform == _EGL_PLATFORM_SURFACELESS) {
+      /* From the EGL_MESA_platform_surfaceless spec (v1):
+       *
+       *    eglCreatePlatformWindowSurface fails when called with a <display>
+       *    that belongs to the surfaceless platform. It returns
+       *    EGL_NO_SURFACE and generates EGL_BAD_NATIVE_WINDOW. The
+       *    justification for this unconditional failure is that the
+       *    surfaceless platform has no native windows, and therefore the
+       *    <native_window> parameter is always invalid.
+       *
+       * This check must occur before checking the EGLConfig, which emits
+       * EGL_BAD_CONFIG.
+       */
+      RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+   }
+#endif
+
+   _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
+
    surf = drv->API.CreateWindowSurface(drv, disp, conf, native_window,
                                        attrib_list);
    ret = (surf) ? _eglLinkSurface(surf) : EGL_NO_SURFACE;
@@ -943,6 +970,22 @@ _eglCreatePixmapSurfaceCommon(_EGLDisplay *disp, EGLConfig config,
    _EGLSurface *surf;
    EGLSurface ret;
 
+#if HAVE_SURFACELESS_PLATFORM
+   if (disp->Platform == _EGL_PLATFORM_SURFACELESS) {
+      /* From the EGL_MESA_platform_surfaceless spec (v1):
+       *
+       *   [Like eglCreatePlatformWindowSurface,] eglCreatePlatformPixmapSurface
+       *   also fails when called with a <display> that belongs to the
+       *   surfaceless platform.  It returns EGL_NO_SURFACE and generates
+       *   EGL_BAD_NATIVE_PIXMAP.
+       *
+       * This check must occur before checking the EGLConfig, which emits
+       * EGL_BAD_CONFIG.
+       */
+      RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
+   }
+#endif
+
    _EGL_CHECK_CONFIG(disp, conf, EGL_NO_SURFACE, drv);
    surf = drv->API.CreatePixmapSurface(drv, disp, conf, native_pixmap,
                                        attrib_list);
@@ -1153,8 +1196,8 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
 
 
 static EGLBoolean
-eglSwapBuffersWithDamageCommon(_EGLDisplay *disp, _EGLSurface *surf,
-                               EGLint *rects, EGLint n_rects)
+_eglSwapBuffersWithDamageCommon(_EGLDisplay *disp, _EGLSurface *surf,
+                                EGLint *rects, EGLint n_rects)
 {
    _EGLContext *ctx = _eglGetCurrentContext();
    _EGLDriver *drv;
@@ -1182,7 +1225,7 @@ eglSwapBuffersWithDamageEXT(EGLDisplay dpy, EGLSurface surface,
    _EGLDisplay *disp = _eglLockDisplay(dpy);
    _EGLSurface *surf = _eglLookupSurface(surface, disp);
    _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE);
-   return eglSwapBuffersWithDamageCommon(disp, surf, rects, n_rects);
+   return _eglSwapBuffersWithDamageCommon(disp, surf, rects, n_rects);
 }
 
 static EGLBoolean EGLAPIENTRY
@@ -1192,7 +1235,7 @@ eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface,
    _EGLDisplay *disp = _eglLockDisplay(dpy);
    _EGLSurface *surf = _eglLookupSurface(surface, disp);
    _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE);
-   return eglSwapBuffersWithDamageCommon(disp, surf, rects, n_rects);
+   return _eglSwapBuffersWithDamageCommon(disp, surf, rects, n_rects);
 }
 
 EGLBoolean EGLAPIENTRY
@@ -1563,9 +1606,17 @@ _eglCreateSync(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list,
       RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
    }
 
+   /* If type is EGL_SYNC_FENCE and no context is current for the bound API
+    * (i.e., eglGetCurrentContext returns EGL_NO_CONTEXT ), an EGL_BAD_MATCH
+    * error is generated.
+    */
+   if (!ctx &&
+       (type == EGL_SYNC_FENCE_KHR || type == EGL_SYNC_NATIVE_FENCE_ANDROID))
+      RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
+
    /* return an error if the client API doesn't support GL_OES_EGL_sync */
-   if (!ctx || ctx->Resource.Display != disp ||
-       ctx->ClientAPI != EGL_OPENGL_ES_API)
+   if (ctx && (ctx->Resource.Display != disp ||
+       ctx->ClientAPI != EGL_OPENGL_ES_API))
       RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
 
    switch (type) {
@@ -1581,6 +1632,10 @@ _eglCreateSync(_EGLDisplay *disp, EGLenum type, const EGLAttrib *attrib_list,
       if (!disp->Extensions.KHR_cl_event2)
          RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR);
       break;
+   case EGL_SYNC_NATIVE_FENCE_ANDROID:
+      if (!disp->Extensions.ANDROID_native_fence_sync)
+         RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR);
+      break;
    default:
       RETURN_EGL_ERROR(disp, invalid_type_error, EGL_NO_SYNC_KHR);
    }
@@ -1653,7 +1708,8 @@ eglDestroySync(EGLDisplay dpy, EGLSync sync)
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
    assert(disp->Extensions.KHR_reusable_sync ||
-          disp->Extensions.KHR_fence_sync);
+          disp->Extensions.KHR_fence_sync ||
+          disp->Extensions.ANDROID_native_fence_sync);
 
    _eglUnlinkSync(s);
    ret = drv->API.DestroySyncKHR(drv, disp, s);
@@ -1674,7 +1730,8 @@ eglClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout)
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
    assert(disp->Extensions.KHR_reusable_sync ||
-          disp->Extensions.KHR_fence_sync);
+          disp->Extensions.KHR_fence_sync ||
+          disp->Extensions.ANDROID_native_fence_sync);
 
    if (s->SyncStatus == EGL_SIGNALED_KHR)
       RETURN_EGL_EVAL(disp, EGL_CONDITION_SATISFIED_KHR);
@@ -1773,7 +1830,8 @@ _eglGetSyncAttribCommon(_EGLDisplay *disp, _EGLSync *s, EGLint attribute, EGLAtt
 
    _EGL_CHECK_SYNC(disp, s, EGL_FALSE, drv);
    assert(disp->Extensions.KHR_reusable_sync ||
-          disp->Extensions.KHR_fence_sync);
+          disp->Extensions.KHR_fence_sync ||
+          disp->Extensions.ANDROID_native_fence_sync);
    ret = drv->API.GetSyncAttrib(drv, disp, s, attribute, value);
 
    RETURN_EGL_EVAL(disp, ret);
@@ -1816,6 +1874,29 @@ eglGetSyncAttribKHR(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLint *valu
    return result;
 }
 
+static EGLint EGLAPIENTRY
+eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSync sync)
+{
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLSync *s = _eglLookupSync(sync, disp);
+   _EGLDriver *drv;
+   EGLBoolean ret;
+
+   _EGL_FUNC_START(disp, EGL_OBJECT_SYNC_KHR, s, EGL_FALSE);
+
+   /* the spec doesn't seem to specify what happens if the fence
+    * type is not EGL_SYNC_NATIVE_FENCE_ANDROID, but this seems
+    * sensible:
+    */
+   if (!(s && (s->Type == EGL_SYNC_NATIVE_FENCE_ANDROID)))
+      RETURN_EGL_ERROR(disp, EGL_BAD_PARAMETER, EGL_NO_NATIVE_FENCE_FD_ANDROID);
+
+   _EGL_CHECK_SYNC(disp, s, EGL_NO_NATIVE_FENCE_FD_ANDROID, drv);
+   assert(disp->Extensions.ANDROID_native_fence_sync);
+   ret = drv->API.DupNativeFenceFDANDROID(drv, disp, s);
+
+   RETURN_EGL_EVAL(disp, ret);
+}
 
 static EGLBoolean EGLAPIENTRY
 eglSwapBuffersRegionNOK(EGLDisplay dpy, EGLSurface surface,
@@ -2291,6 +2372,7 @@ eglGetProcAddress(const char *procname)
       { "eglLabelObjectKHR", (_EGLProc) eglLabelObjectKHR },
       { "eglDebugMessageControlKHR", (_EGLProc) eglDebugMessageControlKHR },
       { "eglQueryDebugKHR", (_EGLProc) eglQueryDebugKHR },
+      { "eglDupNativeFenceFDANDROID", (_EGLProc) eglDupNativeFenceFDANDROID },
       { NULL, NULL }
    };
    EGLint i;
@@ -2342,7 +2424,7 @@ _eglLockDisplayInterop(EGLDisplay dpy, EGLContext context,
    return MESA_GLINTEROP_SUCCESS;
 }
 
-int
+PUBLIC int
 MesaGLInteropEGLQueryDeviceInfo(EGLDisplay dpy, EGLContext context,
                                 struct mesa_glinterop_device_info *out)
 {
@@ -2364,7 +2446,7 @@ MesaGLInteropEGLQueryDeviceInfo(EGLDisplay dpy, EGLContext context,
    return ret;
 }
 
-int
+PUBLIC int
 MesaGLInteropEGLExportObject(EGLDisplay dpy, EGLContext context,
                              struct mesa_glinterop_export_in *in,
                              struct mesa_glinterop_export_out *out)