[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