diff options
Diffstat (limited to 'src/egl/drivers/dri2')
-rw-r--r-- | src/egl/drivers/dri2/egl_dri2.c | 141 | ||||
-rw-r--r-- | src/egl/drivers/dri2/egl_dri2.h | 6 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_android.c | 20 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_drm.c | 1 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_surfaceless.c | 1 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_wayland.c | 17 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_x11.c | 17 | ||||
-rw-r--r-- | src/egl/drivers/dri2/platform_x11_dri3.c | 12 |
8 files changed, 170 insertions, 45 deletions
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index fe33ecd..c6d4fb5 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -242,6 +242,15 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, return NULL; break; + case __DRI_ATTRIB_MAX_PBUFFER_WIDTH: + _eglSetConfigKey(&base, EGL_MAX_PBUFFER_WIDTH, + _EGL_MAX_PBUFFER_WIDTH); + break; + case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT: + _eglSetConfigKey(&base, EGL_MAX_PBUFFER_HEIGHT, + _EGL_MAX_PBUFFER_HEIGHT); + break; + default: key = dri2_to_egl_attribute_map[attrib]; if (key != 0) @@ -320,6 +329,15 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, surface_type &= ~EGL_PIXMAP_BIT; } + /* No support for pbuffer + MSAA for now. + * + * XXX TODO: pbuffer + MSAA does not work and causes crashes. + * See QT bugreport: https://bugreports.qt.io/browse/QTBUG-47509 + */ + if (base.Samples) { + surface_type &= ~EGL_PBUFFER_BIT; + } + conf->base.SurfaceType |= surface_type; return conf; @@ -758,64 +776,99 @@ dri2_create_screen(_EGLDisplay *disp) /** * Called via eglInitialize(), GLX_drv->API.Initialize(). + * + * This must be guaranteed to be called exactly once, even if eglInitialize is + * called many times (without a eglTerminate in between). */ static EGLBoolean dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp) { + EGLBoolean ret = EGL_FALSE; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + /* In the case where the application calls eglMakeCurrent(context1), + * eglTerminate, then eglInitialize again (without a call to eglReleaseThread + * or eglMakeCurrent(NULL) before that), dri2_dpy structure is still + * initialized, as we need it to be able to free context1 correctly. + * + * It would probably be safest to forcibly release the display with + * dri2_display_release, to make sure the display is reinitialized correctly. + * However, the EGL spec states that we need to keep a reference to the + * current context (so we cannot call dri2_make_current(NULL)), and therefore + * we would leak context1 as we would be missing the old display connection + * to free it up correctly. + */ + if (dri2_dpy) { + dri2_dpy->ref_count++; + return EGL_TRUE; + } + /* not until swrast_dri is supported */ if (disp->Options.UseFallback) return EGL_FALSE; + /* Nothing to initialize for a test only display */ + if (disp->Options.TestOnly) + return EGL_TRUE; + switch (disp->Platform) { #ifdef HAVE_SURFACELESS_PLATFORM case _EGL_PLATFORM_SURFACELESS: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_surfaceless(drv, disp); + ret = dri2_initialize_surfaceless(drv, disp); + break; #endif - #ifdef HAVE_X11_PLATFORM case _EGL_PLATFORM_X11: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_x11(drv, disp); + ret = dri2_initialize_x11(drv, disp); + break; #endif - #ifdef HAVE_DRM_PLATFORM case _EGL_PLATFORM_DRM: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_drm(drv, disp); + ret = dri2_initialize_drm(drv, disp); + break; #endif #ifdef HAVE_WAYLAND_PLATFORM case _EGL_PLATFORM_WAYLAND: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_wayland(drv, disp); + ret = dri2_initialize_wayland(drv, disp); + break; #endif #ifdef HAVE_ANDROID_PLATFORM case _EGL_PLATFORM_ANDROID: - if (disp->Options.TestOnly) - return EGL_TRUE; - return dri2_initialize_android(drv, disp); + ret = dri2_initialize_android(drv, disp); + break; #endif - default: _eglLog(_EGL_WARNING, "No EGL platform enabled."); return EGL_FALSE; } + + if (ret) { + dri2_dpy = dri2_egl_display(disp); + + if (!dri2_dpy) { + return EGL_FALSE; + } + + dri2_dpy->ref_count++; + } + + return ret; } /** - * Called via eglTerminate(), drv->API.Terminate(). + * Decrement display reference count, and free up display if necessary. */ -static EGLBoolean -dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) -{ +static void +dri2_display_release(_EGLDisplay *disp) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); unsigned i; - _eglReleaseDisplayResources(drv, disp); + assert(dri2_dpy->ref_count > 0); + dri2_dpy->ref_count--; + + if (dri2_dpy->ref_count > 0) + return; + _eglCleanupDisplay(disp); if (dri2_dpy->own_dri_screen) @@ -870,6 +923,21 @@ dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) } free(dri2_dpy); disp->DriverData = NULL; +} + +/** + * Called via eglTerminate(), drv->API.Terminate(). + * + * This must be guaranteed to be called exactly once, even if eglTerminate is + * called many times (without a eglInitialize in between). + */ +static EGLBoolean +dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp) +{ + /* Release all non-current Context/Surfaces. */ + _eglReleaseDisplayResources(drv, disp); + + dri2_display_release(disp); return EGL_TRUE; } @@ -1189,10 +1257,16 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, _EGLSurface *tmp_dsurf, *tmp_rsurf; __DRIdrawable *ddraw, *rdraw; __DRIcontext *cctx; + EGLBoolean unbind; + + if (!dri2_dpy) + return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent"); /* make new bindings */ - if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) + if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) { + /* _eglBindContext already sets the EGL error (in _eglCheckMakeCurrent) */ return EGL_FALSE; + } /* flush before context switch */ if (old_ctx && dri2_drv->glFlush) @@ -1207,14 +1281,21 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, dri2_dpy->core->unbindContext(old_cctx); } - if ((cctx == NULL && ddraw == NULL && rdraw == NULL) || - dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) { + unbind = (cctx == NULL && ddraw == NULL && rdraw == NULL); + + if (unbind || dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) { if (old_dsurf) drv->API.DestroySurface(drv, disp, old_dsurf); if (old_rsurf) drv->API.DestroySurface(drv, disp, old_rsurf); - if (old_ctx) + + if (!unbind) + dri2_dpy->ref_count++; + if (old_ctx) { + EGLDisplay old_disp = _eglGetDisplayHandle(old_ctx->Resource.Display); drv->API.DestroyContext(drv, disp, old_ctx); + dri2_display_release(old_disp); + } return EGL_TRUE; } else { @@ -1232,7 +1313,11 @@ dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf, _eglPutSurface(old_rsurf); _eglPutContext(old_ctx); - return EGL_FALSE; + /* dri2_dpy->core->bindContext failed. We cannot tell for sure why, but + * setting the error to EGL_BAD_MATCH is surely better than leaving it + * as EGL_SUCCESS. + */ + return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); } } diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 925294b..6099bc2 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -80,8 +80,6 @@ #include "eglimage.h" #include "eglsync.h" -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - struct wl_buffer; struct dri2_egl_driver @@ -177,6 +175,10 @@ struct dri2_egl_display const __DRI2interopExtension *interop; int fd; + /* dri2_initialize/dri2_terminate increment/decrement this count, so does + * dri2_make_current (tracks if there are active contexts/surfaces). */ + int ref_count; + int own_device; int swap_available; int invalidate_available; diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c index 87bd19b..351fd0f 100644 --- a/src/egl/drivers/dri2/platform_android.c +++ b/src/egl/drivers/dri2/platform_android.c @@ -29,7 +29,7 @@ #include <errno.h> #include <dlfcn.h> - +#include <fcntl.h> #if 0 #include <xf86drm.h> #endif @@ -170,6 +170,8 @@ droid_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf) static EGLBoolean droid_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf) { + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + /* To avoid blocking other EGL calls, release the display mutex before * we enter droid_window_enqueue_buffer() and re-acquire the mutex upon * return. @@ -200,6 +202,12 @@ droid_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_sur dri2_surf->buffer = NULL; mtx_lock(&disp->Mutex); + + if (dri2_surf->dri_image) { + dri2_dpy->image->destroyImage(dri2_surf->dri_image); + dri2_surf->dri_image = NULL; + } + return EGL_TRUE; } @@ -291,6 +299,8 @@ droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, dri2_surf->base.GLColorspace); + if (!config) + goto cleanup_surface; if (dri2_dpy->dri2) { dri2_surf->dri_drawable = @@ -384,6 +394,9 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) int fourcc, pitch; int offset = 0, fd; + if (dri2_surf->dri_image) + return 0; + if (!dri2_surf->buffer) return -1; @@ -442,10 +455,8 @@ droid_image_get_buffers(__DRIdrawable *driDrawable, static EGLBoolean droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) { - struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); - _EGLContext *ctx; if (dri2_surf->base.Type != EGL_WINDOW_BIT) return EGL_TRUE; @@ -986,7 +997,7 @@ droid_open_device(void) fd = -1; } - return (fd >= 0) ? dup(fd) : -1; + return (fd >= 0) ? fcntl(fd, F_DUPFD_CLOEXEC, 3) : -1; } /* support versions < JellyBean */ @@ -1134,6 +1145,7 @@ cleanup_device: close(dri2_dpy->fd); cleanup_display: free(dri2_dpy); + dpy->DriverData = NULL; return _eglError(EGL_NOT_INITIALIZED, err); } diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c index 9373496..1ce282f 100644 --- a/src/egl/drivers/dri2/platform_drm.c +++ b/src/egl/drivers/dri2/platform_drm.c @@ -726,5 +726,6 @@ cleanup: close(fd); free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } diff --git a/src/egl/drivers/dri2/platform_surfaceless.c b/src/egl/drivers/dri2/platform_surfaceless.c index e0ddc12..323a8d7 100644 --- a/src/egl/drivers/dri2/platform_surfaceless.c +++ b/src/egl/drivers/dri2/platform_surfaceless.c @@ -157,6 +157,7 @@ cleanup_driver: close(dri2_dpy->fd); cleanup_display: free(dri2_dpy); + disp->DriverData = NULL; return _eglError(EGL_NOT_INITIALIZED, err); } diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index ff0d5c8..1a295d5 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -118,6 +118,13 @@ resize_callback(struct wl_egl_window *wl_win, void *data) (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); } +static void +destroy_window_callback(void *data) +{ + struct dri2_egl_surface *dri2_surf = data; + dri2_surf->wl_win = NULL; +} + /** * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). */ @@ -159,6 +166,7 @@ dri2_wl_create_surface(_EGLDriver *drv, _EGLDisplay *disp, dri2_surf->wl_win->private = dri2_surf; dri2_surf->wl_win->resize_callback = resize_callback; + dri2_surf->wl_win->destroy_window_callback = destroy_window_callback; dri2_surf->base.Width = -1; dri2_surf->base.Height = -1; @@ -257,8 +265,11 @@ dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) if (dri2_surf->throttle_callback) wl_callback_destroy(dri2_surf->throttle_callback); - dri2_surf->wl_win->private = NULL; - dri2_surf->wl_win->resize_callback = NULL; + if (dri2_surf->wl_win) { + dri2_surf->wl_win->private = NULL; + dri2_surf->wl_win->resize_callback = NULL; + dri2_surf->wl_win->destroy_window_callback = NULL; + } free(surf); @@ -1238,6 +1249,7 @@ dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp) wl_event_queue_destroy(dri2_dpy->wl_queue); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } @@ -1883,6 +1895,7 @@ dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) wl_event_queue_destroy(dri2_dpy->wl_queue); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index c0a4005..792cabe 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -1231,6 +1231,7 @@ dri2_initialize_x11_swrast(_EGLDriver *drv, _EGLDisplay *disp) xcb_disconnect(dri2_dpy->conn); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } @@ -1302,15 +1303,13 @@ dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) dri2_dpy->screen = DefaultScreen(dpy); } - if (xcb_connection_has_error(dri2_dpy->conn)) { + if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) { _eglLog(_EGL_WARNING, "DRI3: xcb_connect failed"); goto cleanup_dpy; } - if (dri2_dpy->conn) { - if (!dri3_x11_connect(dri2_dpy)) - goto cleanup_conn; - } + if (!dri3_x11_connect(dri2_dpy)) + goto cleanup_conn; if (!dri2_load_driver_dri3(disp)) goto cleanup_conn; @@ -1338,10 +1337,8 @@ dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) disp->Extensions.WL_bind_wayland_display = EGL_TRUE; #endif - if (dri2_dpy->conn) { - if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false)) - goto cleanup_configs; - } + if (!dri2_x11_add_configs_for_visuals(dri2_dpy, disp, false)) + goto cleanup_configs; dri2_dpy->loader_dri3_ext.core = dri2_dpy->core; dri2_dpy->loader_dri3_ext.image_driver = dri2_dpy->image_driver; @@ -1370,6 +1367,7 @@ dri2_initialize_x11_dri3(_EGLDriver *drv, _EGLDisplay *disp) xcb_disconnect(dri2_dpy->conn); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } @@ -1467,6 +1465,7 @@ dri2_initialize_x11_dri2(_EGLDriver *drv, _EGLDisplay *disp) xcb_disconnect(dri2_dpy->conn); cleanup_dpy: free(dri2_dpy); + disp->DriverData = NULL; return EGL_FALSE; } diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c index 9363a8a..69bfcd8 100644 --- a/src/egl/drivers/dri2/platform_x11_dri3.c +++ b/src/egl/drivers/dri2/platform_x11_dri3.c @@ -103,6 +103,17 @@ egl_dri3_get_dri_context(struct loader_dri3_drawable *draw) return dri2_ctx->dri_context; } +static __DRIscreen * +egl_dri3_get_dri_screen(struct loader_dri3_drawable *draw) +{ + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_context *dri2_ctx; + if (!ctx) + return NULL; + dri2_ctx = dri2_egl_context(ctx); + return dri2_egl_display(dri2_ctx->base.Resource.Display)->dri_screen; +} + static void egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags) { @@ -119,6 +130,7 @@ static struct loader_dri3_vtable egl_dri3_vtable = { .set_drawable_size = egl_dri3_set_drawable_size, .in_current_context = egl_dri3_in_current_context, .get_dri_context = egl_dri3_get_dri_context, + .get_dri_screen = egl_dri3_get_dri_screen, .flush_drawable = egl_dri3_flush_drawable, .show_fps = NULL, }; |