[Mesa-dev] [PATCH 3/3 v2] Implement choosing the device to use with DRI_PRIME
Axel Davy
axel.davy at ens.fr
Thu Nov 7 14:39:47 PST 2013
two formats are supported: DRI_PRIME="1" will tell Mesa
to choose an other card than the compositor card if possible,
while setting DRI_PRIME to the id_path_tag of a device (like
"pci-0000_02_00_0") tells Mesa to take the device with this
id_path_tag.
Signed-off-by: Axel Davy <axel.davy at ens.fr>
---
src/egl/drivers/dri2/platform_wayland.c | 180 ++++++++++++++++++++++++++++++--
1 file changed, 170 insertions(+), 10 deletions(-)
diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c
index b922ff5..747d745 100644
--- a/src/egl/drivers/dri2/platform_wayland.c
+++ b/src/egl/drivers/dri2/platform_wayland.c
@@ -40,6 +40,10 @@
#include <wayland-client.h>
#include "wayland-drm-client-protocol.h"
+#ifdef HAVE_LIBUDEV
+#include <libudev.h>
+#endif
+
enum wl_drm_format_flags {
HAS_ARGB8888 = 1,
HAS_XRGB8888 = 2,
@@ -656,6 +660,74 @@ is_fd_render_node(int fd)
return 0;
}
+#ifdef HAVE_LIBUDEV
+
+static char *
+get_render_node_from_id_path_tag(struct udev *udev, char* id_path_tag,
+ char another_tag)
+{
+ struct udev_device *device;
+ struct udev_enumerate *e;
+ struct udev_list_entry *entry;
+ const char *path, *id_path_tag_tmp;
+ char found = 0;
+
+ e = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(e, "drm");
+ udev_enumerate_add_match_sysname(e, "render*");
+
+ udev_enumerate_scan_devices(e);
+ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+ path = udev_list_entry_get_name(entry);
+ device = udev_device_new_from_syspath(udev, path);
+ if (!device)
+ continue;
+ id_path_tag_tmp = udev_device_get_property_value(device, "ID_PATH_TAG");
+ if (id_path_tag_tmp)
+ {
+ if((!another_tag && !strcmp(id_path_tag, id_path_tag_tmp))
+ || (another_tag && strcmp(id_path_tag, id_path_tag_tmp)))
+ {
+ found = 1;
+ break;
+ }
+ }
+ udev_device_unref(device);
+ }
+
+ if(found)
+ {
+ char* path = strdup(udev_device_get_devnode(device));
+ udev_device_unref(device);
+ return path;
+ }
+ return NULL;
+}
+
+static char *
+get_id_path_tag_from_fd(struct udev *udev, int fd)
+{
+ struct udev_device *device;
+ struct stat buf;
+ const char *id_path_tag_tmp;
+
+ if (fstat(fd, &buf) < 0) {
+ return NULL;
+ }
+
+ device = udev_device_new_from_devnum(udev, 'c', buf.st_rdev);
+
+ if(!device)
+ return NULL;
+ id_path_tag_tmp = udev_device_get_property_value(device, "ID_PATH_TAG");
+ if(!id_path_tag_tmp)
+ return NULL;
+
+ return strdup(id_path_tag_tmp);
+}
+
+#endif
+
static void
drm_handle_device(void *data, struct wl_drm *drm, const char *device)
{
@@ -737,13 +809,20 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
struct dri2_egl_display *dri2_dpy;
const __DRIconfig *config;
uint32_t types;
- int i, is_render_node;
+ int i, is_render_node, device_fd, is_different_device;
drm_magic_t magic;
static const unsigned int argb_masks[4] =
{ 0xff0000, 0xff00, 0xff, 0xff000000 };
static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 };
+ char* prime_device_name = NULL;
+ char* prime = NULL;
+ const char *dri_prime = getenv("DRI_PRIME");
+
+ if (dri_prime)
+ prime = strdup(dri_prime);
+
drv->API.CreateWindowSurface = dri2_create_window_surface;
drv->API.DestroySurface = dri2_destroy_surface;
drv->API.SwapBuffers = dri2_swap_buffers;
@@ -781,22 +860,102 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->device_name == NULL)
goto cleanup_drm;
+ if (prime && !(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME))
+ /* render-nodes are not supported */
+ {
+ free(prime);
+ prime = NULL;
+ }
+
#ifdef O_CLOEXEC
- dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
- if (dri2_dpy->fd == -1 && errno == EINVAL)
+ device_fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
+ if (device_fd == -1 && errno == EINVAL)
#endif
{
- dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
- if (dri2_dpy->fd != -1)
- fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
+ device_fd = open(dri2_dpy->device_name, O_RDWR);
+ if (device_fd != -1)
+ fcntl(device_fd, F_SETFD, fcntl(device_fd, F_GETFD) |
FD_CLOEXEC);
}
- if (dri2_dpy->fd == -1) {
+ if (device_fd == -1) {
_eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
dri2_dpy->device_name, strerror(errno));
+ free(prime);
goto cleanup_drm;
}
+ if(prime != NULL)
+ {
+#ifdef HAVE_LIBUDEV
+ struct udev* udev = udev_new();
+ char* device_id_path_tag;
+ char another_tag = 0;
+
+ if (!udev)
+ goto prime_clean;
+ device_id_path_tag = get_id_path_tag_from_fd(udev, device_fd);
+ if (!device_id_path_tag)
+ goto udev_clean;
+
+ is_different_device = 1;
+ /* two format are supported:
+ * "1": choose any other card than the card used by the compositor.
+ * id_path_tag: (for example "pci-0000_02_00_0") choose the card
+ * with this id_path_tag. */
+ if (!strcmp(prime,"1"))
+ {
+ free(prime);
+ prime = strdup(device_id_path_tag);
+ /* request a card with a different card than the compositor card */
+ another_tag = 1;
+ }
+ else if (!strcmp(device_id_path_tag, prime))
+ /* we want to get the render-node of the compositor card */
+ is_different_device = 0;
+
+ prime_device_name = get_render_node_from_id_path_tag(udev,
+ prime,
+ another_tag);
+ if (prime_device_name)
+ _eglLog(_EGL_DEBUG,"requested device found: %s",
+ prime_device_name);
+ else
+ _eglLog(_EGL_WARNING,"requested device not found.");
+ free(device_id_path_tag);
+ udev_clean:
+ udev_unref(udev);
+ prime_clean:
+#endif
+ free(prime);
+ }
+
+ if (prime_device_name != NULL)
+ {
+ close(device_fd);
+ free(dri2_dpy->device_name);
+ dri2_dpy->device_name = prime_device_name;
+#ifdef O_CLOEXEC
+ dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR | O_CLOEXEC);
+ if (dri2_dpy->fd == -1 && errno == EINVAL)
+#endif
+ {
+ dri2_dpy->fd = open(dri2_dpy->device_name, O_RDWR);
+ if (dri2_dpy->fd != -1)
+ fcntl(dri2_dpy->fd, F_SETFD, fcntl(dri2_dpy->fd, F_GETFD) |
+ FD_CLOEXEC);
+ }
+ if (dri2_dpy->fd == -1) {
+ _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
+ dri2_dpy->device_name, strerror(errno));
+ goto cleanup_drm;
+ }
+ }
+ else
+ {
+ is_different_device = 0;
+ dri2_dpy->fd = device_fd;
+ }
+
if (is_fd_render_node(dri2_dpy->fd))
{
_eglLog(_EGL_DEBUG, "wayland-egl: card is render-node");
@@ -809,7 +968,7 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
wl_drm_authenticate(dri2_dpy->wl_drm, magic);
is_render_node = 0;
}
- dri2_dpy->enable_tiling = 1;
+ dri2_dpy->enable_tiling = !is_different_device;
if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
goto cleanup_fd;
@@ -845,10 +1004,11 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
dri2_dpy->image->createImageFromFds == NULL)
{
dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
- if (is_render_node)
- goto cleanup_screen;
}
+ if (is_render_node && !(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME))
+ goto cleanup_screen;
+
types = EGL_WINDOW_BIT;
for (i = 0; dri2_dpy->driver_configs[i]; i++) {
config = dri2_dpy->driver_configs[i];
--
1.8.1.2
More information about the mesa-dev
mailing list