From e013ce8d0d91f6558af50f285e6a96ab697ec90c Mon Sep 17 00:00:00 2001 From: Zhongmin Wu Date: Fri, 15 Sep 2017 18:32:42 +0100 Subject: [PATCH] egl: Allow creation of per surface out fence Add plumbing to allow creation of per display surface out fence. This can be used to implement explicit sync. One user of which is Android - which will be addressed with next commit. Signed-off-by: Zhongmin Wu Signed-off-by: Yogesh Marathe Reviewed-by: Emil Velikov Reviewed-by: Tomasz Figa [Emil Velikov: reorder so there's no intermetent regressions, split] Signed-off-by: Emil Velikov --- src/egl/drivers/dri2/egl_dri2.c | 72 +++++++++++++++++++++ src/egl/drivers/dri2/egl_dri2.h | 9 +++ src/egl/drivers/dri2/platform_android.c | 3 +- src/egl/drivers/dri2/platform_drm.c | 3 +- src/egl/drivers/dri2/platform_surfaceless.c | 3 +- src/egl/drivers/dri2/platform_wayland.c | 3 +- src/egl/drivers/dri2/platform_x11.c | 3 +- src/egl/drivers/dri2/platform_x11_dri3.c | 3 +- 8 files changed, 93 insertions(+), 6 deletions(-) diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 2667aa5d647..42bca61cfda 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -1388,6 +1388,45 @@ dri2_destroy_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx) return EGL_TRUE; } +EGLBoolean +dri2_init_surface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type, + _EGLConfig *conf, const EGLint *attrib_list, EGLBoolean enable_out_fence) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + + dri2_surf->out_fence_fd = -1; + dri2_surf->enable_out_fence = false; + if (dri2_dpy->fence && dri2_dpy->fence->base.version >= 2 && + dri2_dpy->fence->get_capabilities && + (dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen) & + __DRI_FENCE_CAP_NATIVE_FD)) { + dri2_surf->enable_out_fence = enable_out_fence; + } + + return _eglInitSurface(surf, dpy, type, conf, attrib_list); +} + +static void +dri2_surface_set_out_fence_fd( _EGLSurface *surf, int fence_fd) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + + if (dri2_surf->out_fence_fd >= 0) + close(dri2_surf->out_fence_fd); + + dri2_surf->out_fence_fd = fence_fd; +} + +void +dri2_fini_surface(_EGLSurface *surf) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + + dri2_surface_set_out_fence_fd(surf, -1); + dri2_surf->enable_out_fence = false; +} + static EGLBoolean dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) { @@ -1399,6 +1438,28 @@ dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) return dri2_dpy->vtbl->destroy_surface(drv, dpy, surf); } +static void +dri2_surf_update_fence_fd(_EGLContext *ctx, + _EGLDisplay *dpy, _EGLSurface *surf) +{ + __DRIcontext *dri_ctx = dri2_egl_context(ctx)->dri_context; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + int fence_fd = -1; + void *fence; + + if (!dri2_surf->enable_out_fence) + return; + + fence = dri2_dpy->fence->create_fence_fd(dri_ctx, -1); + if (fence) { + fence_fd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen, + fence); + dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, fence); + } + dri2_surface_set_out_fence_fd(surf, fence_fd); +} + /** * Called via eglMakeCurrent(), drv->API.MakeCurrent(). */ @@ -1435,6 +1496,9 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, if (old_ctx) { __DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context; + + if (old_dsurf) + dri2_surf_update_fence_fd(old_ctx, disp, old_dsurf); dri2_dpy->core->unbindContext(old_cctx); } @@ -1573,6 +1637,10 @@ static EGLBoolean dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + _EGLContext *ctx = _eglGetCurrentContext(); + + if (ctx && surf) + dri2_surf_update_fence_fd(ctx, dpy, surf); return dri2_dpy->vtbl->swap_buffers(drv, dpy, surf); } @@ -1582,6 +1650,10 @@ dri2_swap_buffers_with_damage(_EGLDriver *drv, _EGLDisplay *dpy, const EGLint *rects, EGLint n_rects) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); + _EGLContext *ctx = _eglGetCurrentContext(); + + if (ctx && surf) + dri2_surf_update_fence_fd(ctx, dpy, surf); return dri2_dpy->vtbl->swap_buffers_with_damage(drv, dpy, surf, rects, n_rects); } diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 4a52b490a87..10a41518172 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -327,6 +327,8 @@ struct dri2_egl_surface __DRIimage *front; unsigned int visual; #endif + int out_fence_fd; + EGLBoolean enable_out_fence; }; struct dri2_egl_config @@ -462,4 +464,11 @@ dri2_egl_surface_alloc_local_buffer(struct dri2_egl_surface *dri2_surf, void dri2_egl_surface_free_local_buffers(struct dri2_egl_surface *dri2_surf); +EGLBoolean +dri2_init_surface(_EGLSurface *surf, _EGLDisplay *dpy, EGLint type, + _EGLConfig *conf, const EGLint *attrib_list, EGLBoolean enable_out_fence); + +void +dri2_fini_surface(_EGLSurface *surf); + #endif /* EGL_DRI2_INCLUDED */ diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c index a864a2af3d7..38c1122339f 100644 --- a/src/egl/drivers/dri2/platform_android.c +++ b/src/egl/drivers/dri2/platform_android.c @@ -289,7 +289,7 @@ droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, return NULL; } - if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) + if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list, false)) goto cleanup_surface; if (type == EGL_WINDOW_BIT) { @@ -389,6 +389,7 @@ droid_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); + dri2_fini_surface(surf); free(dri2_surf); return EGL_TRUE; diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c index 0ccbd9a30a0..fbdf8b1672a 100644 --- a/src/egl/drivers/dri2/platform_drm.c +++ b/src/egl/drivers/dri2/platform_drm.c @@ -110,7 +110,7 @@ dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, return NULL; } - if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list)) + if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false)) goto cleanup_surf; surf = gbm_dri_surface(surface); @@ -178,6 +178,7 @@ dri2_drm_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) dri2_egl_surface_free_local_buffers(dri2_surf); + dri2_fini_surface(surf); free(surf); return EGL_TRUE; diff --git a/src/egl/drivers/dri2/platform_surfaceless.c b/src/egl/drivers/dri2/platform_surfaceless.c index 1091b4febdb..ff8f88d5375 100644 --- a/src/egl/drivers/dri2/platform_surfaceless.c +++ b/src/egl/drivers/dri2/platform_surfaceless.c @@ -124,7 +124,7 @@ dri2_surfaceless_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, return NULL; } - if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) + if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list, false)) goto cleanup_surface; config = dri2_get_dri_config(dri2_conf, type, @@ -165,6 +165,7 @@ surfaceless_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *sur dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); + dri2_fini_surface(surf); free(dri2_surf); return EGL_TRUE; } diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index eb10a7dd137..dc6fcc1d072 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -143,7 +143,7 @@ dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, return NULL; } - if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list)) + if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false)) goto cleanup_surf; if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) { @@ -296,6 +296,7 @@ dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper); wl_event_queue_destroy(dri2_surf->wl_queue); + dri2_fini_surface(surf); free(surf); return EGL_TRUE; diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index d80eee2969a..ab9a142f415 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -233,7 +233,7 @@ dri2_x11_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, return NULL; } - if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list)) + if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list, false)) goto cleanup_surf; dri2_surf->region = XCB_NONE; @@ -395,6 +395,7 @@ dri2_x11_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) if (surf->Type == EGL_PBUFFER_BIT) xcb_free_pixmap (dri2_dpy->conn, dri2_surf->drawable); + dri2_fini_surface(surf); free(surf); return EGL_TRUE; diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c index a83e7839528..45bb56ca17e 100644 --- a/src/egl/drivers/dri2/platform_x11_dri3.c +++ b/src/egl/drivers/dri2/platform_x11_dri3.c @@ -101,6 +101,7 @@ dri3_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) loader_dri3_drawable_fini(&dri3_surf->loader_drawable); + dri2_fini_surface(surf); free(surf); return EGL_TRUE; @@ -137,7 +138,7 @@ dri3_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, return NULL; } - if (!_eglInitSurface(&dri3_surf->surf.base, disp, type, conf, attrib_list)) + if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf, attrib_list, false)) goto cleanup_surf; if (type == EGL_PBUFFER_BIT) {