From: Harish Krupo Date: Fri, 9 Jun 2017 14:43:34 +0000 (+0530) Subject: egl/android: support for EGL_KHR_partial_update X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=commitdiff_plain;h=9827547313c7239486efbd4067529575f98f1622 egl/android: support for EGL_KHR_partial_update 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 Reviewed-by: Emil Velikov Reviewed-by: Eric Engestrom Reviewed-by: Tapani Pälli --- diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 7175e827c9f..020a0bc6394 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -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; diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index a71b4489cde..f8c26a9d45e 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/egl_dri2_fallbacks.h b/src/egl/drivers/dri2/egl_dri2_fallbacks.h index 67a9c5034a2..d8363c9bdd7 100644 --- a/src/egl/drivers/dri2/egl_dri2_fallbacks.h +++ b/src/egl/drivers/dri2/egl_dri2_fallbacks.h @@ -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) diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c index 4c979351192..7a73419d148 100644 --- a/src/egl/drivers/dri2/platform_android.c +++ b/src/egl/drivers/dri2/platform_android.c @@ -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. diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c index 36c89fc832b..8b0562c75d2 100644 --- a/src/egl/drivers/dri2/platform_drm.c +++ b/src/egl/drivers/dri2/platform_drm.c @@ -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, diff --git a/src/egl/drivers/dri2/platform_surfaceless.c b/src/egl/drivers/dri2/platform_surfaceless.c index 6563e466c09..0eb3fb7505c 100644 --- a/src/egl/drivers/dri2/platform_surfaceless.c +++ b/src/egl/drivers/dri2/platform_surfaceless.c @@ -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, diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 15cc597111e..f746f0bfd1c 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -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, diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index 8d8c7cb4905..74d3a164b6a 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -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, diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c index 041da3208de..3148f4904e5 100644 --- a/src/egl/drivers/dri2/platform_x11_dri3.c +++ b/src/egl/drivers/dri2/platform_x11_dri3.c @@ -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, diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index e6355ace872..9b899d85244 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -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) { diff --git a/src/egl/main/eglapi.h b/src/egl/main/eglapi.h index cab3e9605a0..852a34584ea 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 9685bed360c..a13ff5bb1b1 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -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; diff --git a/src/egl/main/eglentrypoint.h b/src/egl/main/eglentrypoint.h index b9dca7ceda2..f7fe77410d5 100644 --- a/src/egl/main/eglentrypoint.h +++ b/src/egl/main/eglentrypoint.h @@ -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) diff --git a/src/egl/main/eglfallbacks.c b/src/egl/main/eglfallbacks.c index 017d337133e..1575ab5f793 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 5b3e83ee92c..8094912ba12 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->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"); diff --git a/src/egl/main/eglsurface.h b/src/egl/main/eglsurface.h index f13cf49741b..c53e8d00671 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 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;