summaryrefslogtreecommitdiffstats
path: root/src/egl/drivers/dri2
diff options
context:
space:
mode:
Diffstat (limited to 'src/egl/drivers/dri2')
-rw-r--r--src/egl/drivers/dri2/egl_dri2.c141
-rw-r--r--src/egl/drivers/dri2/egl_dri2.h6
-rw-r--r--src/egl/drivers/dri2/platform_android.c20
-rw-r--r--src/egl/drivers/dri2/platform_drm.c1
-rw-r--r--src/egl/drivers/dri2/platform_surfaceless.c1
-rw-r--r--src/egl/drivers/dri2/platform_wayland.c17
-rw-r--r--src/egl/drivers/dri2/platform_x11.c17
-rw-r--r--src/egl/drivers/dri2/platform_x11_dri3.c12
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,
};