egl/android: support for EGL_KHR_partial_update
authorHarish Krupo <harish.krupo.kps@intel.com>
Fri, 9 Jun 2017 14:43:34 +0000 (20:13 +0530)
committerEric Engestrom <eric@engestrom.ch>
Sun, 11 Jun 2017 00:02:09 +0000 (01:02 +0100)
This patch adds support for the EGL_KHR_partial_update extension for
android platform. It passes 36/37 tests in dEQP for EGL_KHR_partial_update.
1 test not supported.

v2: add fallback for eglSetDamageRegionKHR (Tapani)

v3: The native_window_set_surface_damage call is available only from
    Android version 6.0. Reintroduce the ANDROID_VERSION guard and
    advertise extension only if version is >= 6.0. (Emil Velikov)

v4: use newly introduced ANDROID_API_LEVEL guard rather than
    ANDROID_VERSION guard to advertise the extension.The extension
    is advertised only if ANDROID_API_LEVEL >= 23 (Android 6.0 or
    greater). Add fallback function for platforms other than Android.
    Fix possible math overflow. (Emil Velikov)
    Return immediately when n_rects is 0. Place function's entrypoint
    in alphabetical order. (Eric Engestrom)

v5: Replace unnecessary calloc with malloc (Eric)
    Check for BAD_ALLOC error (Emil)
    Check for error in native_window_set_damage_region. (Emil, Tapani,
    Eric).

Signed-off-by: Harish Krupo <harish.krupo.kps@intel.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
16 files changed:
src/egl/drivers/dri2/egl_dri2.c
src/egl/drivers/dri2/egl_dri2.h
src/egl/drivers/dri2/egl_dri2_fallbacks.h
src/egl/drivers/dri2/platform_android.c
src/egl/drivers/dri2/platform_drm.c
src/egl/drivers/dri2/platform_surfaceless.c
src/egl/drivers/dri2/platform_wayland.c
src/egl/drivers/dri2/platform_x11.c
src/egl/drivers/dri2/platform_x11_dri3.c
src/egl/main/eglapi.c
src/egl/main/eglapi.h
src/egl/main/egldisplay.h
src/egl/main/eglentrypoint.h
src/egl/main/eglfallbacks.c
src/egl/main/eglsurface.c
src/egl/main/eglsurface.h

index 7175e827c9f43fbe12588861df5c68cdede904de..020a0bc6394dc60d7558366c6db71887e1071d01 100644 (file)
@@ -1511,6 +1511,14 @@ dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
    return dri2_dpy->vtbl->swap_buffers_region(drv, dpy, surf, numRects, rects);
 }
 
+static EGLBoolean
+dri2_set_damage_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
+                       EGLint *rects, EGLint n_rects)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
+   return dri2_dpy->vtbl->set_damage_region(drv, dpy, surf, rects, n_rects);
+}
+
 static EGLBoolean
 dri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
                      EGLint x, EGLint y, EGLint width, EGLint height)
@@ -3140,6 +3148,7 @@ _eglBuiltInDriverDRI2(const char *args)
    dri2_drv->base.API.SwapBuffers = dri2_swap_buffers;
    dri2_drv->base.API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
    dri2_drv->base.API.SwapBuffersRegionNOK = dri2_swap_buffers_region;
+   dri2_drv->base.API.SetDamageRegion = dri2_set_damage_region;
    dri2_drv->base.API.PostSubBufferNV = dri2_post_sub_buffer;
    dri2_drv->base.API.CopyBuffers = dri2_copy_buffers,
    dri2_drv->base.API.QueryBufferAge = dri2_query_buffer_age;
index a71b4489cde84593bc80d3e7c4811772cc56a637..f8c26a9d45e9502e8b8b930dac851d586c3cc6b4 100644 (file)
@@ -118,6 +118,10 @@ struct dri2_egl_display_vtbl {
                                           _EGLSurface *surface,
                                           const EGLint *rects, EGLint n_rects);
 
+   EGLBoolean (*set_damage_region)(_EGLDriver *drv, _EGLDisplay *dpy,
+                                   _EGLSurface *surface,
+                                   const EGLint *rects, EGLint n_rects);
+
    EGLBoolean (*swap_buffers_region)(_EGLDriver *drv, _EGLDisplay *dpy,
                                      _EGLSurface *surf, EGLint numRects,
                                      const EGLint *rects);
index 67a9c5034a255fa9c3fc992dedb1e7da26cbb520..d8363c9bdd72f296e59353b878570681a9050517 100644 (file)
@@ -95,6 +95,14 @@ dri2_fallback_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy,
    return EGL_FALSE;
 }
 
+static inline EGLBoolean
+dri2_fallback_set_damage_region(_EGLDriver *drv, _EGLDisplay *dpy,
+                                _EGLSurface *surf,
+                                const EGLint *rects, EGLint n_rects)
+{
+   return EGL_FALSE;
+}
+
 static inline EGLint
 dri2_fallback_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy,
                                _EGLSurface *surf)
index 4c979351192cd181e55c4357063a3c345ed0b033..7a73419d14899d6c17da111b58eb11c178f10db3 100644 (file)
@@ -656,6 +656,45 @@ droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
    return EGL_TRUE;
 }
 
+#if ANDROID_API_LEVEL >= 23
+static EGLBoolean
+droid_set_damage_region(_EGLDriver *drv,
+                        _EGLDisplay *disp,
+                        _EGLSurface *draw, const EGLint* rects, EGLint n_rects)
+{
+   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
+   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
+   android_native_rect_t* droid_rects = NULL;
+   int ret;
+
+   if (n_rects == 0)
+      return EGL_TRUE;
+
+   droid_rects = malloc(n_rects * sizeof(android_native_rect_t));
+   if (droid_rects == NULL) {
+     _eglError(EGL_BAD_ALLOC, "eglSetDamageRegionKHR");
+     return EGL_FALSE;
+   }
+
+   for (EGLint num_drects = 0; num_drects < n_rects; num_drects++) {
+      EGLint i = num_drects * 4;
+      droid_rects[num_drects].left = rects[i];
+      droid_rects[num_drects].bottom = rects[i + 1];
+      droid_rects[num_drects].right = rects[i] + rects[i + 2];
+      droid_rects[num_drects].top = rects[i + 1] + rects[i + 3];
+   }
+
+   /*
+    * XXX/TODO: Need to check for other return values
+    */
+
+   ret = native_window_set_surface_damage(dri2_surf->window, droid_rects, n_rects);
+   free(droid_rects);
+
+   return ret == 0 ? EGL_TRUE : EGL_FALSE;
+}
+#endif
+
 static _EGLImage *
 droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
                                      struct ANativeWindowBuffer *buf, int fd)
@@ -1066,6 +1105,11 @@ static const struct dri2_egl_display_vtbl droid_display_vtbl = {
    .swap_buffers = droid_swap_buffers,
    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
    .swap_buffers_region = dri2_fallback_swap_buffers_region,
+#if ANDROID_API_LEVEL >= 23
+   .set_damage_region = droid_set_damage_region,
+#else
+   .set_damage_region = dri2_fallback_set_damage_region,
+#endif
    .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri2_fallback_copy_buffers,
    .query_buffer_age = droid_query_buffer_age,
@@ -1176,6 +1220,9 @@ dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *dpy)
    dpy->Extensions.ANDROID_image_native_buffer = EGL_TRUE;
    dpy->Extensions.ANDROID_recordable = EGL_TRUE;
    dpy->Extensions.EXT_buffer_age = EGL_TRUE;
+#if ANDROID_API_LEVEL >= 23
+   dpy->Extensions.KHR_partial_update = EGL_TRUE;
+#endif
 
    /* Fill vtbl last to prevent accidentally calling virtual function during
     * initialization.
index 36c89fc832b83eb37c9d7b728c3a5dd2e87f6f39..8b0562c75d209c36c90897de2f8cd1f406ae463b 100644 (file)
@@ -658,6 +658,7 @@ static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = {
    .swap_buffers = dri2_drm_swap_buffers,
    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
    .swap_buffers_region = dri2_fallback_swap_buffers_region,
+   .set_damage_region = dri2_fallback_set_damage_region,
    .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri2_fallback_copy_buffers,
    .query_buffer_age = dri2_drm_query_buffer_age,
index 6563e466c0905e73b08e59ead5c01ee4559bfe7c..0eb3fb7505c444314467951b3912dc559c1f67dd 100644 (file)
@@ -237,6 +237,7 @@ static const struct dri2_egl_display_vtbl dri2_surfaceless_display_vtbl = {
    .swap_buffers = surfaceless_swap_buffers,
    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
    .swap_buffers_region = dri2_fallback_swap_buffers_region,
+   .set_damage_region = dri2_fallback_set_damage_region,
    .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri2_fallback_copy_buffers,
    .query_buffer_age = dri2_fallback_query_buffer_age,
index 15cc597111eabd6d28b78ad62cf07c744e556027..f746f0bfd1c52f876fafcc6a9f51855362552b08 100644 (file)
@@ -1080,6 +1080,7 @@ static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
    .swap_buffers = dri2_wl_swap_buffers,
    .swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
    .swap_buffers_region = dri2_fallback_swap_buffers_region,
+   .set_damage_region = dri2_fallback_set_damage_region,
    .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri2_fallback_copy_buffers,
    .query_buffer_age = dri2_wl_query_buffer_age,
index 8d8c7cb4905b4f5dd5e1461cb10b0a59499c9516..74d3a164b6a634127d00a99ff10cd9e47bf5b134 100644 (file)
@@ -1140,6 +1140,7 @@ static const struct dri2_egl_display_vtbl dri2_x11_swrast_display_vtbl = {
    .create_image = dri2_fallback_create_image_khr,
    .swap_interval = dri2_fallback_swap_interval,
    .swap_buffers = dri2_x11_swap_buffers,
+   .set_damage_region = dri2_fallback_set_damage_region,
    .swap_buffers_region = dri2_fallback_swap_buffers_region,
    .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri2_x11_copy_buffers,
@@ -1161,6 +1162,7 @@ static const struct dri2_egl_display_vtbl dri2_x11_display_vtbl = {
    .swap_buffers = dri2_x11_swap_buffers,
    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
    .swap_buffers_region = dri2_x11_swap_buffers_region,
+   .set_damage_region = dri2_fallback_set_damage_region,
    .post_sub_buffer = dri2_x11_post_sub_buffer,
    .copy_buffers = dri2_x11_copy_buffers,
    .query_buffer_age = dri2_fallback_query_buffer_age,
index 041da3208de8aad923dc21e9cb58b9a36c2b6ba4..3148f4904e50c6e2e03aaeaf6d191ccf00565467 100644 (file)
@@ -458,6 +458,7 @@ struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {
    .swap_buffers = dri3_swap_buffers,
    .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
    .swap_buffers_region = dri2_fallback_swap_buffers_region,
+   .set_damage_region = dri2_fallback_set_damage_region,
    .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri3_copy_buffers,
    .query_buffer_age = dri3_query_buffer_age,
index e6355ace872bd4761149c9530526885a89c69a1c..9b899d852447c0a8b2c8c9951151ddceefe014aa 100644 (file)
@@ -506,6 +506,7 @@ _eglCreateExtensionsString(_EGLDisplay *dpy)
    _EGL_CHECK_EXTENSION(KHR_image_base);
    _EGL_CHECK_EXTENSION(KHR_image_pixmap);
    _EGL_CHECK_EXTENSION(KHR_no_config_context);
+   _EGL_CHECK_EXTENSION(KHR_partial_update);
    _EGL_CHECK_EXTENSION(KHR_reusable_sync);
    _EGL_CHECK_EXTENSION(KHR_surfaceless_context);
    if (dpy->Extensions.EXT_swap_buffers_with_damage)
@@ -1235,6 +1236,15 @@ eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
 
    ret = drv->API.SwapBuffers(drv, disp, surf);
 
+   /* EGL_KHR_partial_update
+    * Frame boundary successfully reached,
+    * reset damage region and reset BufferAgeRead
+    */
+   if (ret) {
+      surf->SetDamageRegionCalled = EGL_FALSE;
+      surf->BufferAgeRead = EGL_FALSE;
+   }
+
    RETURN_EGL_EVAL(disp, ret);
 }
 
@@ -1259,6 +1269,15 @@ _eglSwapBuffersWithDamageCommon(_EGLDisplay *disp, _EGLSurface *surf,
 
    ret = drv->API.SwapBuffersWithDamageEXT(drv, disp, surf, rects, n_rects);
 
+   /* EGL_KHR_partial_update
+    * Frame boundary successfully reached,
+    * reset damage region and reset BufferAgeRead
+    */
+   if (ret) {
+      surf->SetDamageRegionCalled = EGL_FALSE;
+      surf->BufferAgeRead = EGL_FALSE;
+   }
+
    RETURN_EGL_EVAL(disp, ret);
 }
 
@@ -1282,6 +1301,70 @@ eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface,
    return _eglSwapBuffersWithDamageCommon(disp, surf, rects, n_rects);
 }
 
+/**
+ * If the width of the passed rect is greater than the surface's
+ * width then it is clamped to the width of the surface. Same with
+ * height.
+ */
+
+static void
+_eglSetDamageRegionKHRClampRects(_EGLDisplay* disp, _EGLSurface* surf,
+                                 EGLint *rects, EGLint n_rects)
+{
+   EGLint i;
+   EGLint surf_height = surf->Height;
+   EGLint surf_width = surf->Width;
+
+   for (i = 0; i < (4 * n_rects); i += 4) {
+      EGLint x, y, rect_width, rect_height;
+      x = rects[i];
+      y = rects[i + 1];
+      rect_width = rects[i + 2];
+      rect_height = rects[i + 3];
+
+      if (rect_width > surf_width - x)
+         rects[i + 2] = surf_width - x;
+
+      if (rect_height > surf_height - y)
+         rects[i + 3] = surf_height - y;
+   }
+}
+
+static EGLBoolean EGLAPIENTRY
+eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface,
+                      EGLint *rects, EGLint n_rects)
+{
+   _EGLDisplay *disp = _eglLockDisplay(dpy);
+   _EGLSurface *surf = _eglLookupSurface(surface, disp);
+   _EGL_FUNC_START(disp, EGL_OBJECT_SURFACE_KHR, surf, EGL_FALSE);
+   _EGLContext *ctx = _eglGetCurrentContext();
+   _EGLDriver *drv;
+   EGLBoolean ret;
+   _EGL_CHECK_SURFACE(disp, surf, EGL_FALSE, drv);
+
+   if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+       surf->Type != EGL_WINDOW_BIT ||
+       ctx->DrawSurface != surf ||
+       surf->SwapBehavior != EGL_BUFFER_DESTROYED)
+      RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_FALSE);
+
+   /* If the damage region is already set or
+    * buffer age is not queried between
+    * frame boundaries, throw bad access error
+    */
+
+   if (surf->SetDamageRegionCalled || !surf->BufferAgeRead)
+      RETURN_EGL_ERROR(disp, EGL_BAD_ACCESS, EGL_FALSE);
+
+   _eglSetDamageRegionKHRClampRects(disp, surf, rects, n_rects);
+   ret = drv->API.SetDamageRegion(drv, disp, surf, rects, n_rects);
+
+   if (ret)
+      surf->SetDamageRegionCalled = EGL_TRUE;
+
+   RETURN_EGL_EVAL(disp, ret);
+}
+
 EGLBoolean EGLAPIENTRY
 eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
 {
index cab3e9605a0082b25ddababdfba8fe0f5d43e871..852a34584ea9b4ac41991eb8e6e76085a186ca4b 100644 (file)
@@ -110,6 +110,8 @@ struct _egl_api
                              _EGLSurface *draw);
    EGLBoolean (*CopyBuffers)(_EGLDriver *drv, _EGLDisplay *dpy,
                              _EGLSurface *surface, void *native_pixmap_target);
+   EGLBoolean (*SetDamageRegion)(_EGLDriver *drv, _EGLDisplay *dpy,
+                                 _EGLSurface *surface, EGLint *rects, EGLint n_rects);
 
    /* misc functions */
    EGLBoolean (*WaitClient)(_EGLDriver *drv, _EGLDisplay *dpy,
index 9685bed360c25de729741933b245dbcaaf591459..a13ff5bb1b179a2b94ab8d15a299448c9432f433 100644 (file)
@@ -118,6 +118,7 @@ struct _egl_extensions
    EGLBoolean KHR_image_base;
    EGLBoolean KHR_image_pixmap;
    EGLBoolean KHR_no_config_context;
+   EGLBoolean KHR_partial_update;
    EGLBoolean KHR_reusable_sync;
    EGLBoolean KHR_surfaceless_context;
    EGLBoolean KHR_wait_sync;
index b9dca7ceda282fdb305a9526978cff78f17c1e66..f7fe77410d5c907df6a4138973fba8bb3db7c0ff 100644 (file)
@@ -63,6 +63,7 @@ EGL_ENTRYPOINT(eglQuerySurface)
 EGL_ENTRYPOINT(eglQueryWaylandBufferWL)
 EGL_ENTRYPOINT(eglReleaseTexImage)
 EGL_ENTRYPOINT(eglReleaseThread)
+EGL_ENTRYPOINT(eglSetDamageRegionKHR)
 EGL_ENTRYPOINT(eglSignalSyncKHR)
 EGL_ENTRYPOINT(eglSurfaceAttrib)
 EGL_ENTRYPOINT(eglSwapBuffers)
index 017d337133e6e09e33e752543b3948eda25900d3..1575ab5f7939952a150377b8cafcb396df913b7a 100644 (file)
@@ -77,6 +77,7 @@ _eglInitDriverFallbacks(_EGLDriver *drv)
    drv->API.ReleaseTexImage = (void*) _eglReturnFalse;
    drv->API.CopyBuffers = (void*) _eglReturnFalse;
    drv->API.SwapBuffers = (void*) _eglReturnFalse;
+   drv->API.SetDamageRegion = (void*) _eglReturnFalse;
    drv->API.SwapInterval = _eglSwapInterval;
 
    drv->API.WaitClient = (void*) _eglReturnFalse;
index 5b3e83ee92c3df4554f01d8fe3f9757c4a69a2b3..8094912ba122683bf1a7bde3bfe67e68d8e7cc88 100644 (file)
@@ -317,6 +317,8 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
    surf->AspectRatio = EGL_UNKNOWN;
 
    surf->PostSubBufferSupportedNV = EGL_FALSE;
+   surf->SetDamageRegionCalled = EGL_FALSE;
+   surf->BufferAgeRead = EGL_FALSE;
 
    /* the default swap interval is 1 */
    _eglClampSwapInterval(surf, 1);
@@ -409,11 +411,18 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
          _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
          return EGL_FALSE;
       }
+      _EGLContext *ctx = _eglGetCurrentContext();
       EGLint result = drv->API.QueryBufferAge(drv, dpy, surface);
       /* error happened */
       if (result < 0)
          return EGL_FALSE;
+      if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT ||
+          ctx->DrawSurface != surface) {
+         _eglError(EGL_BAD_SURFACE, "eglQuerySurface");
+         return EGL_FALSE;
+      }
       *value = result;
+      surface->BufferAgeRead = EGL_TRUE;
       break;
    default:
       _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
index f13cf49741b4872bd41740250989079f8027c9d8..c53e8d00671f6814c7c5b3599051920c7f92af29 100644 (file)
@@ -82,6 +82,18 @@ struct _egl_surface
 
    EGLint SwapInterval;
 
+   /* EGL_KHR_partial_update
+    * True if the damage region is already set
+    * between frame boundaries.
+    */
+   EGLBoolean SetDamageRegionCalled;
+
+   /* EGL_KHR_partial_update
+    * True if the buffer age is read by the client
+    * between frame boundaries.
+    */
+   EGLBoolean BufferAgeRead;
+
    /* True if the surface is bound to an OpenGL ES texture */
    EGLBoolean BoundToTexture;