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:
Harish Krupo
2017-06-09 20:13:34 +05:30
committed by Eric Engestrom
parent f3c0bbe18a
commit 9827547313
16 changed files with 183 additions and 0 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)

View File

@@ -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.

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -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,

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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");

View File

@@ -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;