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) Signed-off-by: Harish Krupo <harish.krupo....@intel.com> --- src/egl/drivers/dri2/egl_dri2.c | 12 +++++ src/egl/drivers/dri2/egl_dri2.h | 4 ++ src/egl/drivers/dri2/platform_android.c | 33 +++++++++++++ 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 +++++ 10 files changed, 161 insertions(+) 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..0752e330b4 100644 --- a/src/egl/drivers/dri2/platform_android.c +++ b/src/egl/drivers/dri2/platform_android.c @@ -651,6 +651,37 @@ 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 + } + + native_window_set_surface_damage(dri2_surf->window, droid_rects, n_rects); + + 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 +1132,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 +1233,7 @@ 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; + dpy->Extensions.KHR_partial_update = EGL_TRUE; /* 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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev