434 lines
14 KiB
Diff
434 lines
14 KiB
Diff
From db015d5fd0ded075e759677c047c581151bb1b52 Mon Sep 17 00:00:00 2001
|
|
From: Brendan King <Brendan.King@imgtec.com>
|
|
Date: Tue, 9 Mar 2021 17:15:30 +0000
|
|
Subject: [PATCH 50/67] dri: preserve the original FD for driver use.
|
|
|
|
If an application uses a different GPU from the default, allow the
|
|
file descriptor (FD) for that original GPU/display to be preserved
|
|
for use by drivers. Drivers may wish to use the original FD to
|
|
allocate shared surfaces, to ensure the surface properties are
|
|
compatible with the original GPU/display (e.g. for X11 or Wayland).
|
|
|
|
This feature is only available on platforms that choose to support
|
|
it, by implementing the new getDisplayFD function in the DRI image,
|
|
and DRI2 loader extensions.
|
|
|
|
If the feature is available, drivers can obtain the original FD
|
|
by calling the getDisplayFD function in the relevant loader extension.
|
|
Drivers should check the FD is valid before use (i.e. not -1). If
|
|
the FD is valid, it may be equal to the current GPU FD if a different
|
|
GPU is not being used. The FD is owned by the platform, not the
|
|
driver, and the platform is responsible for closing it.
|
|
|
|
The feature is currently supported by the Wayland, and DRI3 based
|
|
X11 EGL and GLX platforms.
|
|
---
|
|
include/GL/internal/dri_interface.h | 26 +++++++++++++++++--
|
|
src/egl/drivers/dri2/egl_dri2.c | 10 +++++++
|
|
src/egl/drivers/dri2/egl_dri2.h | 1 +
|
|
src/egl/drivers/dri2/platform_wayland.c | 31 ++++++++++++++++++++--
|
|
src/egl/drivers/dri2/platform_x11.c | 3 +++
|
|
src/egl/drivers/dri2/platform_x11_dri3.c | 27 ++++++++++++++++++-
|
|
src/glx/dri3_glx.c | 33 ++++++++++++++++++++++--
|
|
src/glx/dri3_priv.h | 1 +
|
|
8 files changed, 125 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h
|
|
index 888a117d56e..2fb440feb50 100644
|
|
--- a/include/GL/internal/dri_interface.h
|
|
+++ b/include/GL/internal/dri_interface.h
|
|
@@ -1146,7 +1146,7 @@ struct __DRIbufferRec {
|
|
};
|
|
|
|
#define __DRI_DRI2_LOADER "DRI_DRI2Loader"
|
|
-#define __DRI_DRI2_LOADER_VERSION 5
|
|
+#define __DRI_DRI2_LOADER_VERSION 6
|
|
|
|
enum dri_loader_cap {
|
|
/* Whether the loader handles RGBA channel ordering correctly. If not,
|
|
@@ -1227,6 +1227,17 @@ struct __DRIdri2LoaderExtensionRec {
|
|
* \since 5
|
|
*/
|
|
void (*destroyLoaderImageState)(void *loaderPrivate);
|
|
+
|
|
+ /**
|
|
+ * Get the display FD
|
|
+ *
|
|
+ * Get the FD of the display device.
|
|
+ *
|
|
+ * \param loaderPrivate The last parameter of createNewScreen or
|
|
+ * createNewScreen2.
|
|
+ * \since 6
|
|
+ */
|
|
+ int (*getDisplayFD)(void *loaderPrivate);
|
|
};
|
|
|
|
/**
|
|
@@ -2131,7 +2142,7 @@ struct __DRIimageList {
|
|
};
|
|
|
|
#define __DRI_IMAGE_LOADER "DRI_IMAGE_LOADER"
|
|
-#define __DRI_IMAGE_LOADER_VERSION 4
|
|
+#define __DRI_IMAGE_LOADER_VERSION 5
|
|
|
|
struct __DRIimageLoaderExtensionRec {
|
|
__DRIextension base;
|
|
@@ -2199,6 +2210,17 @@ struct __DRIimageLoaderExtensionRec {
|
|
* \since 4
|
|
*/
|
|
void (*destroyLoaderImageState)(void *loaderPrivate);
|
|
+
|
|
+ /**
|
|
+ * Get the display FD
|
|
+ *
|
|
+ * Get the FD of the display device.
|
|
+ *
|
|
+ * \param loaderPrivate The last parameter of createNewScreen or
|
|
+ * createNewScreen2.
|
|
+ * \since 5
|
|
+ */
|
|
+ int (*getDisplayFD)(void *loaderPrivate);
|
|
};
|
|
|
|
/**
|
|
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
|
|
index c4a49cae592..1df53ef011c 100644
|
|
--- a/src/egl/drivers/dri2/egl_dri2.c
|
|
+++ b/src/egl/drivers/dri2/egl_dri2.c
|
|
@@ -1367,6 +1367,16 @@ dri2_display_destroy(_EGLDisplay *disp)
|
|
break;
|
|
}
|
|
|
|
+ switch (disp->Platform) {
|
|
+ case _EGL_PLATFORM_WAYLAND:
|
|
+ case _EGL_PLATFORM_X11:
|
|
+ if (dri2_dpy->fd_dpy >= 0 && dri2_dpy->fd_dpy != dri2_dpy->fd)
|
|
+ close(dri2_dpy->fd_dpy);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
if (dri2_dpy->fd >= 0)
|
|
close(dri2_dpy->fd);
|
|
|
|
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
|
|
index 141df1b1732..af03caee623 100644
|
|
--- a/src/egl/drivers/dri2/egl_dri2.h
|
|
+++ b/src/egl/drivers/dri2/egl_dri2.h
|
|
@@ -230,6 +230,7 @@ struct dri2_egl_display
|
|
const __DRIconfigOptionsExtension *configOptions;
|
|
const __DRImutableRenderBufferDriverExtension *mutable_render_buffer;
|
|
int fd;
|
|
+ int fd_dpy;
|
|
|
|
/* dri2_initialize/dri2_terminate increment/decrement this count, so does
|
|
* dri2_make_current (tracks if there are active contexts/surfaces). */
|
|
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
|
|
index 06272d4081e..b393e058770 100644
|
|
--- a/src/egl/drivers/dri2/platform_wayland.c
|
|
+++ b/src/egl/drivers/dri2/platform_wayland.c
|
|
@@ -44,6 +44,7 @@
|
|
#include "loader.h"
|
|
#include "util/u_vector.h"
|
|
#include "util/anon_file.h"
|
|
+#include "util/os_file.h"
|
|
#include "eglglobals.h"
|
|
|
|
#include <wayland-egl-backend.h>
|
|
@@ -973,21 +974,32 @@ dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
|
|
}
|
|
}
|
|
|
|
+static int
|
|
+dri2_wl_get_display_fd(void *loaderPrivate)
|
|
+{
|
|
+ _EGLDisplay *disp = loaderPrivate;
|
|
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
+
|
|
+ return dri2_dpy->fd_dpy;
|
|
+}
|
|
+
|
|
static const __DRIdri2LoaderExtension dri2_loader_extension = {
|
|
- .base = { __DRI_DRI2_LOADER, 4 },
|
|
+ .base = { __DRI_DRI2_LOADER, 6 },
|
|
|
|
.getBuffers = dri2_wl_get_buffers,
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
|
.getBuffersWithFormat = dri2_wl_get_buffers_with_format,
|
|
.getCapability = dri2_wl_get_capability,
|
|
+ .getDisplayFD = dri2_wl_get_display_fd,
|
|
};
|
|
|
|
static const __DRIimageLoaderExtension image_loader_extension = {
|
|
- .base = { __DRI_IMAGE_LOADER, 2 },
|
|
+ .base = { __DRI_IMAGE_LOADER, 5 },
|
|
|
|
.getBuffers = image_get_buffers,
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
|
.getCapability = dri2_wl_get_capability,
|
|
+ .getDisplayFD = dri2_wl_get_display_fd,
|
|
};
|
|
|
|
static void
|
|
@@ -1640,12 +1652,14 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp)
|
|
{
|
|
_EGLDevice *dev;
|
|
struct dri2_egl_display *dri2_dpy;
|
|
+ int fd_old;
|
|
|
|
dri2_dpy = calloc(1, sizeof *dri2_dpy);
|
|
if (!dri2_dpy)
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
dri2_dpy->fd = -1;
|
|
+ dri2_dpy->fd_dpy = -1;
|
|
disp->DriverData = (void *) dri2_dpy;
|
|
if (disp->PlatformDisplay == NULL) {
|
|
dri2_dpy->wl_dpy = wl_display_connect(NULL);
|
|
@@ -1690,8 +1704,20 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp)
|
|
(roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated))
|
|
goto cleanup;
|
|
|
|
+ fd_old = dri2_dpy->fd;
|
|
+ dri2_dpy->fd_dpy = os_dupfd_cloexec(dri2_dpy->fd);
|
|
dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
|
|
&dri2_dpy->is_different_gpu);
|
|
+ if (dri2_dpy->fd == fd_old) {
|
|
+ if (dri2_dpy->fd_dpy != -1)
|
|
+ close(dri2_dpy->fd_dpy);
|
|
+
|
|
+ dri2_dpy->fd_dpy = dri2_dpy->fd;
|
|
+ } else if (dri2_dpy->fd_dpy == -1) {
|
|
+ _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to dup display FD");
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
dev = _eglAddDevice(dri2_dpy->fd, false);
|
|
if (!dev) {
|
|
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
|
|
@@ -2236,6 +2262,7 @@ dri2_initialize_wayland_swrast(_EGLDisplay *disp)
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
dri2_dpy->fd = -1;
|
|
+ dri2_dpy->fd_dpy = -1;
|
|
disp->DriverData = (void *) dri2_dpy;
|
|
if (disp->PlatformDisplay == NULL) {
|
|
dri2_dpy->wl_dpy = wl_display_connect(NULL);
|
|
diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c
|
|
index 5ffdf132184..5cf3ce2a369 100644
|
|
--- a/src/egl/drivers/dri2/platform_x11.c
|
|
+++ b/src/egl/drivers/dri2/platform_x11.c
|
|
@@ -1277,6 +1277,7 @@ dri2_initialize_x11_swrast(_EGLDisplay *disp)
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
dri2_dpy->fd = -1;
|
|
+ dri2_dpy->fd_dpy = -1;
|
|
if (!dri2_get_xcb_connection(disp, dri2_dpy))
|
|
goto cleanup;
|
|
|
|
@@ -1364,6 +1365,7 @@ dri2_initialize_x11_dri3(_EGLDisplay *disp)
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
dri2_dpy->fd = -1;
|
|
+ dri2_dpy->fd_dpy = -1;
|
|
if (!dri2_get_xcb_connection(disp, dri2_dpy))
|
|
goto cleanup;
|
|
|
|
@@ -1472,6 +1474,7 @@ dri2_initialize_x11_dri2(_EGLDisplay *disp)
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
dri2_dpy->fd = -1;
|
|
+ dri2_dpy->fd_dpy = -1;
|
|
if (!dri2_get_xcb_connection(disp, dri2_dpy))
|
|
goto cleanup;
|
|
|
|
diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c
|
|
index e117105fcb6..0babf9f867e 100644
|
|
--- a/src/egl/drivers/dri2/platform_x11_dri3.c
|
|
+++ b/src/egl/drivers/dri2/platform_x11_dri3.c
|
|
@@ -32,6 +32,7 @@
|
|
|
|
#include <xf86drm.h>
|
|
#include "util/macros.h"
|
|
+#include "util/os_file.h"
|
|
|
|
#include "egl_dri2.h"
|
|
#include "platform_x11_dri3.h"
|
|
@@ -414,11 +415,21 @@ dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)
|
|
_eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");
|
|
}
|
|
|
|
+static int
|
|
+dri3_get_display_fd(void *loaderPrivate)
|
|
+{
|
|
+ _EGLDisplay *disp = loaderPrivate;
|
|
+ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
+
|
|
+ return dri2_dpy->fd_dpy;
|
|
+}
|
|
+
|
|
const __DRIimageLoaderExtension dri3_image_loader_extension = {
|
|
- .base = { __DRI_IMAGE_LOADER, 1 },
|
|
+ .base = { __DRI_IMAGE_LOADER, 5 },
|
|
|
|
.getBuffers = loader_dri3_get_buffers,
|
|
.flushFrontBuffer = dri3_flush_front_buffer,
|
|
+ .getDisplayFD = dri3_get_display_fd,
|
|
};
|
|
|
|
static EGLBoolean
|
|
@@ -537,6 +548,7 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
|
|
xcb_xfixes_query_version_cookie_t xfixes_query_cookie;
|
|
xcb_generic_error_t *error;
|
|
const xcb_query_extension_reply_t *extension;
|
|
+ int fd_old;
|
|
|
|
xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);
|
|
xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);
|
|
@@ -616,12 +628,25 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy)
|
|
return EGL_FALSE;
|
|
}
|
|
|
|
+ fd_old = dri2_dpy->fd;
|
|
+ dri2_dpy->fd_dpy = os_dupfd_cloexec(dri2_dpy->fd);
|
|
dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);
|
|
+ if (dri2_dpy->fd == fd_old) {
|
|
+ if (dri2_dpy->fd_dpy != -1)
|
|
+ close(dri2_dpy->fd_dpy);
|
|
+
|
|
+ dri2_dpy->fd_dpy = dri2_dpy->fd;
|
|
+ } else if (dri2_dpy->fd_dpy == -1) {
|
|
+ _eglLog(_EGL_WARNING, "DRI3: failed to dup display FD");
|
|
+ close(dri2_dpy->fd);
|
|
+ return EGL_FALSE;
|
|
+ }
|
|
|
|
dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
|
|
if (!dri2_dpy->driver_name) {
|
|
_eglLog(_EGL_WARNING, "DRI3: No driver found");
|
|
close(dri2_dpy->fd);
|
|
+ close(dri2_dpy->fd_dpy);
|
|
return EGL_FALSE;
|
|
}
|
|
|
|
diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c
|
|
index db1b079663f..1ed6b60ffe8 100644
|
|
--- a/src/glx/dri3_glx.c
|
|
+++ b/src/glx/dri3_glx.c
|
|
@@ -77,6 +77,7 @@
|
|
#include "dri3_priv.h"
|
|
#include "loader.h"
|
|
#include "dri2.h"
|
|
+#include "util/os_file.h"
|
|
|
|
static struct dri3_drawable *
|
|
loader_drawable_to_dri3_drawable(struct loader_dri3_drawable *draw) {
|
|
@@ -529,6 +530,14 @@ dri3_flush_swap_buffers(__DRIdrawable *driDrawable, void *loaderPrivate)
|
|
loader_dri3_swapbuffer_barrier(draw);
|
|
}
|
|
|
|
+static int
|
|
+dri3_get_display_fd(void *loaderPrivate)
|
|
+{
|
|
+ struct dri3_screen *psc = (struct dri3_screen *)loaderPrivate;
|
|
+
|
|
+ return psc->fd_dpy;
|
|
+}
|
|
+
|
|
static void
|
|
dri_set_background_context(void *loaderPrivate)
|
|
{
|
|
@@ -548,11 +557,12 @@ dri_is_thread_safe(void *loaderPrivate)
|
|
/* The image loader extension record for DRI3
|
|
*/
|
|
static const __DRIimageLoaderExtension imageLoaderExtension = {
|
|
- .base = { __DRI_IMAGE_LOADER, 3 },
|
|
+ .base = { __DRI_IMAGE_LOADER, 5 },
|
|
|
|
.getBuffers = loader_dri3_get_buffers,
|
|
.flushFrontBuffer = dri3_flush_front_buffer,
|
|
.flushSwapBuffers = dri3_flush_swap_buffers,
|
|
+ .getDisplayFD = dri3_get_display_fd,
|
|
};
|
|
|
|
const __DRIuseInvalidateExtension dri3UseInvalidate = {
|
|
@@ -618,6 +628,10 @@ dri3_destroy_screen(struct glx_screen *base)
|
|
loader_dri3_close_screen(psc->driScreen);
|
|
(*psc->core->destroyScreen) (psc->driScreen);
|
|
driDestroyConfigs(psc->driver_configs);
|
|
+
|
|
+ if (psc->fd_dpy != psc->fd)
|
|
+ close(psc->fd_dpy);
|
|
+
|
|
close(psc->fd);
|
|
free(psc);
|
|
}
|
|
@@ -842,8 +856,9 @@ dri3_create_screen(int screen, struct glx_display * priv)
|
|
struct dri3_screen *psc;
|
|
__GLXDRIscreen *psp;
|
|
struct glx_config *configs = NULL, *visuals = NULL;
|
|
- char *driverName, *driverNameDisplayGPU, *tmp;
|
|
+ char *driverName = NULL, *driverNameDisplayGPU, *tmp;
|
|
int i;
|
|
+ int fd_old;
|
|
|
|
psc = calloc(1, sizeof *psc);
|
|
if (psc == NULL)
|
|
@@ -851,6 +866,7 @@ dri3_create_screen(int screen, struct glx_display * priv)
|
|
|
|
psc->fd = -1;
|
|
psc->fd_display_gpu = -1;
|
|
+ psc->fd_dpy = -1;
|
|
|
|
if (!glx_screen_init(&psc->base, screen, priv)) {
|
|
free(psc);
|
|
@@ -871,12 +887,23 @@ dri3_create_screen(int screen, struct glx_display * priv)
|
|
return NULL;
|
|
}
|
|
|
|
+ fd_old = psc->fd;
|
|
+ psc->fd_dpy = os_dupfd_cloexec(psc->fd);
|
|
psc->fd_display_gpu = fcntl(psc->fd, F_DUPFD_CLOEXEC, 3);
|
|
psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu);
|
|
if (!psc->is_different_gpu) {
|
|
close(psc->fd_display_gpu);
|
|
psc->fd_display_gpu = -1;
|
|
}
|
|
+ if (psc->fd == fd_old) {
|
|
+ if (psc->fd_dpy != -1)
|
|
+ close(psc->fd_dpy);
|
|
+
|
|
+ psc->fd_dpy = psc->fd;
|
|
+ } else if (psc->fd_dpy == -1) {
|
|
+ ErrorMessageF("Unable to dup the display FD");
|
|
+ goto handle_error;
|
|
+ }
|
|
|
|
driverName = loader_get_driver_for_fd(psc->fd);
|
|
if (!driverName) {
|
|
@@ -1049,6 +1076,8 @@ handle_error:
|
|
if (psc->driScreenDisplayGPU)
|
|
psc->core->destroyScreen(psc->driScreenDisplayGPU);
|
|
psc->driScreenDisplayGPU = NULL;
|
|
+ if (psc->fd_dpy >= 0 && psc->fd_dpy != psc->fd)
|
|
+ close(psc->fd_dpy);
|
|
if (psc->fd >= 0)
|
|
close(psc->fd);
|
|
if (psc->fd_display_gpu >= 0)
|
|
diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h
|
|
index c0e833c16ef..b3dccf28c06 100644
|
|
--- a/src/glx/dri3_priv.h
|
|
+++ b/src/glx/dri3_priv.h
|
|
@@ -107,6 +107,7 @@ struct dri3_screen {
|
|
|
|
void *driver;
|
|
int fd;
|
|
+ int fd_dpy;
|
|
bool is_different_gpu;
|
|
|
|
/* fd for display GPU in case of prime */
|
|
--
|
|
2.25.1
|
|
|