diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 02c187e5fe7..3a64f3a5b64 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -1385,6 +1385,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) { @@ -1396,6 +1435,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(). */ @@ -1432,6 +1493,8 @@ 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); } @@ -1570,6 +1633,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); } @@ -1579,6 +1646,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..d08a8b22b7d 100644 --- a/src/egl/drivers/dri2/platform_android.c +++ b/src/egl/drivers/dri2/platform_android.c @@ -229,19 +229,18 @@ droid_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_sur */ mtx_unlock(&disp->Mutex); - /* Queue the buffer without a sync fence. This informs the ANativeWindow - * that it may access the buffer immediately. + /* Queue the buffer with stored out fence fd. The ANativeWindow or buffer + * consumer may choose to wait for the fence to signal before accessing + * it. If fence fd value is -1, buffer can be accessed by consumer + * immediately. Consumer or application shouldn't rely on timestamp + * associated with fence if the fence fd is -1. * - * From ANativeWindow::dequeueBuffer: - * - * The fenceFd argument specifies a libsync fence file descriptor for - * a fence that must signal before the buffer can be accessed. If - * the buffer can be accessed immediately then a value of -1 should - * be used. The caller must not use the file descriptor after it - * is passed to queueBuffer, and the ANativeWindow implementation - * is responsible for closing it. + * Ownership of fd is transferred to consumer after queueBuffer and the + * consumer is responsible for closing it. Caller must not use the fd + * after passing it to queueBuffer. */ - int fence_fd = -1; + int fence_fd = dri2_surf->out_fence_fd; + dri2_surf->out_fence_fd = -1; dri2_surf->window->queueBuffer(dri2_surf->window, dri2_surf->buffer, fence_fd); @@ -263,8 +262,11 @@ static void droid_window_cancel_buffer(struct dri2_egl_surface *dri2_surf) { int ret; + int fence_fd = dri2_surf->out_fence_fd; - ret = dri2_surf->window->cancelBuffer(dri2_surf->window, dri2_surf->buffer, -1); + dri2_surf->out_fence_fd = -1; + ret = dri2_surf->window->cancelBuffer(dri2_surf->window, + dri2_surf->buffer, fence_fd); if (ret < 0) { _eglLog(_EGL_WARNING, "ANativeWindow::cancelBuffer failed"); dri2_surf->base.Lost = EGL_TRUE; @@ -289,7 +291,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, true)) goto cleanup_surface; if (type == EGL_WINDOW_BIT) { @@ -389,6 +391,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 bf2adbf63bd..81e346ba798 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -142,7 +142,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) { @@ -295,6 +295,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 062c8a4e198..cfdf76ee8d1 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -232,7 +232,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; @@ -394,6 +394,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 290b1504732..1e326984dd1 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->base, disp, type, conf, attrib_list)) + if (!dri2_init_surface(&dri3_surf->base, disp, type, conf, attrib_list, false)) goto cleanup_surf; if (type == EGL_PBUFFER_BIT) {