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.
If it isn't able to find the desired card ( no render-nodes, render-nodes not advertising ID_PATH_TAG, invalid ID_PATH_TAG), then the compositor card is used. Signed-off-by: Axel Davy <axel.d...@ens.fr> --- src/egl/drivers/dri2/platform_wayland.c | 168 ++++++++++++++++++++++++++++++-- 1 file changed, 160 insertions(+), 8 deletions(-) diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index b922ff5..3900771 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; @@ -782,21 +861,94 @@ dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) goto cleanup_drm; #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) + { +#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 +961,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; -- 1.8.1.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev