[Mesa-dev] [PATCH v3] egl/android: support for EGL_KHR_partial_update

Harish Krupo harish.krupo.kps at intel.com
Mon Jun 5 14:07:55 UTC 2017


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)

Signed-off-by: Harish Krupo <harish.krupo.kps at intel.com>
---
 Android.common.mk                       |  3 +-
 Android.mk                              |  2 +
 src/egl/drivers/dri2/egl_dri2.c         | 12 +++++
 src/egl/drivers/dri2/egl_dri2.h         |  4 ++
 src/egl/drivers/dri2/platform_android.c | 37 ++++++++++++++
 src/egl/main/eglapi.c                   | 87 +++++++++++++++++++++++++++++++++
 src/egl/main/eglapi.h                   |  2 +
 src/egl/main/egldisplay.h               |  1 +
 src/egl/main/eglentrypoint.h            |  1 +
 src/egl/main/eglfallbacks.c             |  1 +
 src/egl/main/eglsurface.c               |  8 +++
 src/egl/main/eglsurface.h               | 12 +++++
 12 files changed, 169 insertions(+), 1 deletion(-)

diff --git a/Android.common.mk b/Android.common.mk
index d9b198a956..4777ea8bd9 100644
--- a/Android.common.mk
+++ b/Android.common.mk
@@ -39,7 +39,8 @@ LOCAL_CFLAGS += \
 	-Wno-initializer-overrides \
 	-Wno-mismatched-tags \
 	-DPACKAGE_VERSION=\"$(MESA_VERSION)\" \
-	-DPACKAGE_BUGREPORT=\"https://bugs.freedesktop.org/enter_bug.cgi?product=Mesa\"
+	-DPACKAGE_BUGREPORT=\"https://bugs.freedesktop.org/enter_bug.cgi?product=Mesa\" \
+	-DANDROID_VERSION=0x0$(MESA_ANDROID_MAJOR_VERSION)0$(MESA_ANDROID_MINOR_VERSION)
 
 # XXX: The following __STDC_*_MACROS defines should not be needed.
 # It's likely due to a bug elsewhere, but let's temporarily add them
diff --git a/Android.mk b/Android.mk
index de37f4600f..2a5f2a2989 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,6 +32,8 @@
 MESA_TOP := $(call my-dir)
 
 MESA_ANDROID_MAJOR_VERSION := $(word 1, $(subst ., , $(PLATFORM_VERSION)))
+MESA_ANDROID_MINOR_VERSION := $(word 2, $(subst ., , $(PLATFORM_VERSION)))
+
 ifneq ($(filter 2 4, $(MESA_ANDROID_MAJOR_VERSION)),)
 $(error "Android 4.4 and earlier not supported")
 endif
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 0be7132ac5..c58efbf4d6 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -1464,6 +1464,17 @@ dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
 }
 
 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);
+   if (dri2_dpy->vtbl->set_damage_region)
+      return dri2_dpy->vtbl->set_damage_region(drv, dpy, surf, rects, n_rects);
+
+   return EGL_FALSE;
+}
+
+static EGLBoolean
 dri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
                      EGLint x, EGLint y, EGLint width, EGLint height)
 {
@@ -2958,6 +2969,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;
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
index fdeffb3a85..d2aeda2c83 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -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);
diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c
index 1ae779e59c..8e9530b7ed 100644
--- a/src/egl/drivers/dri2/platform_android.c
+++ b/src/egl/drivers/dri2/platform_android.c
@@ -651,6 +651,39 @@ droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
    return EGL_TRUE;
 }
 
+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;
+   if (n_rects != 0)
+      droid_rects = (android_native_rect_t *)
+         calloc(n_rects, sizeof(android_native_rect_t));
+
+   EGLint surfWidth = dri2_surf->base.Width;
+   EGLint surfHeight = dri2_surf->base.Height;
+   EGLint dIndex;
+
+   for (dIndex = 0; dIndex < n_rects; dIndex++) {
+      EGLint i = dIndex * 4;
+      droid_rects[dIndex].left = rects[i]; // left == x
+      droid_rects[dIndex].bottom = rects[i + 1]; // bottom == y
+      droid_rects[dIndex].right = rects[i] + rects[i + 2]; // left + width
+      droid_rects[dIndex].top = rects[i + 1] + rects[i + 3]; // bottom + height
+   }
+
+#if ANDROID_VERSION >= 0x600
+   native_window_set_surface_damage(dri2_surf->window, droid_rects, n_rects);
+#endif
+
+   free(droid_rects);
+
+   return EGL_TRUE;
+}
+
 static _EGLImage *
 droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
                                      struct ANativeWindowBuffer *buf, int fd)
@@ -1101,6 +1134,7 @@ static 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,
+   .set_damage_region = droid_set_damage_region,
    .post_sub_buffer = dri2_fallback_post_sub_buffer,
    .copy_buffers = dri2_fallback_copy_buffers,
    .query_buffer_age = droid_query_buffer_age,
@@ -1201,6 +1235,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_VERSION >= 0x600
+   dpy->Extensions.KHR_partial_update = EGL_TRUE;
+#endif
 
    /* Fill vtbl last to prevent accidentally calling virtual function during
     * initialization.
diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c
index 9cea2f41ff..0da07e6e1f 100644
--- a/src/egl/main/eglapi.c
+++ b/src/egl/main/eglapi.c
@@ -505,6 +505,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)
@@ -1234,6 +1235,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->SetDamageRegion = EGL_FALSE;
+      surf->BufferAgeRead = EGL_FALSE;
+   }
+
    RETURN_EGL_EVAL(disp, ret);
 }
 
@@ -1258,6 +1268,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->SetDamageRegion = EGL_FALSE;
+      surf->BufferAgeRead = EGL_FALSE;
+   }
+
    RETURN_EGL_EVAL(disp, ret);
 }
 
@@ -1281,6 +1300,74 @@ 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 surfHeight = surf->Height;
+   EGLint surfWidth = surf->Width;
+
+   for (i = 0; i < (4 * n_rects); i += 4) {
+      EGLint x, y, rectWidth, rectHeight;
+      x = rects[i];
+      y = rects[i + 1];
+      rectWidth = rects[i + 2];
+      rectHeight = rects[i + 3];
+
+      if (rectWidth + x > surfWidth)
+         rects[i + 2] = surfWidth - x;
+
+      if (rectHeight + y > surfHeight)
+         rects[i + 3] = surfHeight - 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 between
+    * frame boundaries, throw bad access error
+    */
+   if (surf->SetDamageRegion)
+      RETURN_EGL_ERROR(disp, EGL_BAD_ACCESS, EGL_FALSE);
+
+   /* If the buffer age has not been queried before
+    * setting the damage region, between
+    * frame boundaries, throw bad access error
+    */
+   if (! 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->SetDamageRegion = EGL_TRUE;
+
+   RETURN_EGL_EVAL(disp, ret);
+}
+
 EGLBoolean EGLAPIENTRY
 eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
 {
diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h
index 710c5d860a..ebd31da3e5 100644
--- a/src/egl/main/eglapi.h
+++ b/src/egl/main/eglapi.h
@@ -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,
diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h
index 4d3d96e174..d3c48ace5c 100644
--- a/src/egl/main/egldisplay.h
+++ b/src/egl/main/egldisplay.h
@@ -117,6 +117,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;
diff --git a/src/egl/main/eglentrypoint.h b/src/egl/main/eglentrypoint.h
index e6318b9311..ea97e86291 100644
--- a/src/egl/main/eglentrypoint.h
+++ b/src/egl/main/eglentrypoint.h
@@ -67,6 +67,7 @@ EGL_ENTRYPOINT(eglSwapBuffers)
 EGL_ENTRYPOINT(eglSwapBuffersRegionNOK)
 EGL_ENTRYPOINT(eglSwapBuffersWithDamageEXT)
 EGL_ENTRYPOINT(eglSwapBuffersWithDamageKHR)
+EGL_ENTRYPOINT(eglSetDamageRegionKHR)
 EGL_ENTRYPOINT(eglSwapInterval)
 EGL_ENTRYPOINT(eglTerminate)
 EGL_ENTRYPOINT(eglUnbindWaylandDisplayWL)
diff --git a/src/egl/main/eglfallbacks.c b/src/egl/main/eglfallbacks.c
index 017d337133..1575ab5f79 100644
--- a/src/egl/main/eglfallbacks.c
+++ b/src/egl/main/eglfallbacks.c
@@ -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;
diff --git a/src/egl/main/eglsurface.c b/src/egl/main/eglsurface.c
index e935c83271..e42e815828 100644
--- a/src/egl/main/eglsurface.c
+++ b/src/egl/main/eglsurface.c
@@ -317,6 +317,8 @@ _eglInitSurface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type,
    surf->AspectRatio = EGL_UNKNOWN;
 
    surf->PostSubBufferSupportedNV = EGL_FALSE;
+   surf->SetDamageRegion = EGL_FALSE;
+   surf->BufferAgeRead = EGL_FALSE;
 
    /* the default swap interval is 1 */
    _eglClampSwapInterval(surf, 1);
@@ -409,7 +411,13 @@ _eglQuerySurface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surface,
          _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
          return EGL_FALSE;
       }
+      _EGLContext *ctx = _eglGetCurrentContext();
+      if (_eglGetContextHandle(ctx) == EGL_NO_CONTEXT || ctx->DrawSurface != surface) {
+         _eglError(EGL_BAD_SURFACE, "eglQuerySurface");
+         return EGL_FALSE;
+      }
       *value = drv->API.QueryBufferAge(drv, dpy, surface);
+      surface->BufferAgeRead = EGL_TRUE;
       break;
    default:
       _eglError(EGL_BAD_ATTRIBUTE, "eglQuerySurface");
diff --git a/src/egl/main/eglsurface.h b/src/egl/main/eglsurface.h
index f13cf49741..c7be4088a1 100644
--- a/src/egl/main/eglsurface.h
+++ b/src/egl/main/eglsurface.h
@@ -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 SetDamageRegion;
+
+   /* 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;
 
-- 
2.12.2



More information about the mesa-dev mailing list