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 <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>
This commit is contained in:

committed by
Eric Engestrom

parent
f3c0bbe18a
commit
9827547313
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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.
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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");
|
||||
|
@@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user