Message ID | 20180214003134.1552-8-keithp@keithp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tuesday, 2018-02-13 16:31:20 -0800, Keith Packard wrote: > This extension adds the ability to borrow an X RandR output for > temporary use directly by a Vulkan application. For DRM, we use the > Linux resource leasing mechanism. > > Signed-off-by: Keith Packard <keithp@keithp.com> > --- > configure.ac | 32 +++ > meson.build | 17 ++ > meson_options.txt | 7 + > src/vulkan/Makefile.am | 5 + > src/vulkan/wsi/meson.build | 7 + > src/vulkan/wsi/wsi_common_display.c | 472 ++++++++++++++++++++++++++++++++++++ > src/vulkan/wsi/wsi_common_display.h | 17 ++ > 7 files changed, 557 insertions(+) > > diff --git a/configure.ac b/configure.ac > index 46318365603..cf05d049c26 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -1547,6 +1547,7 @@ AM_CONDITIONAL(HAVE_APPLEDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = x > AM_CONDITIONAL(HAVE_LMSENSORS, test "x$enable_lmsensors" = xyes ) > AM_CONDITIONAL(HAVE_GALLIUM_EXTRA_HUD, test "x$enable_gallium_extra_hud" = xyes ) > AM_CONDITIONAL(HAVE_WINDOWSDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = xwindows ) > +AM_CONDITIONAL(HAVE_XLEASE, test "x$have_xlease" = xyes ) > > AC_ARG_ENABLE([shared-glapi], > [AS_HELP_STRING([--enable-shared-glapi], > @@ -1846,6 +1847,18 @@ if test x"$enable_dri3" = xyes; then > PKG_CHECK_MODULES([XCB_DRI3], [$dri3_modules]) > fi > > + > +if echo "$platforms" | grep -q 'x11' && echo "$platforms" | grep -q 'drm'; then > + have_xlease=yes > +else > + have_xlease=no > +fi > + > +if test x"$have_xlease" = xyes; then > + randr_modules="x11-xcb xcb-randr" > + PKG_CHECK_MODULES([XCB_RANDR], [$randr_modules]) > +fi > + > AM_CONDITIONAL(HAVE_PLATFORM_X11, echo "$platforms" | grep -q 'x11') > AM_CONDITIONAL(HAVE_PLATFORM_WAYLAND, echo "$platforms" | grep -q 'wayland') > AM_CONDITIONAL(HAVE_PLATFORM_DRM, echo "$platforms" | grep -q 'drm') > @@ -1853,6 +1866,25 @@ AM_CONDITIONAL(HAVE_PLATFORM_DISPLAY, echo "$platforms" | grep -q 'drm') > AM_CONDITIONAL(HAVE_PLATFORM_SURFACELESS, echo "$platforms" | grep -q 'surfaceless') > AM_CONDITIONAL(HAVE_PLATFORM_ANDROID, echo "$platforms" | grep -q 'android') > > +AC_ARG_ENABLE(xlib-lease, > + [AS_HELP_STRING([--enable-xlib-lease] > + [enable VK_acquire_xlib_display using X leases])], > + [enable_xlib_lease=$enableval], [enable_xlib_lease=auto]) > +case "x$enable_xlib_lease" in > +xyes) > + ;; > +xno) > + ;; > +*) > + if echo "$platforms" | grep -q 'x11' && echo "$platforms" | grep -q 'drm'; then > + enable_xlib_lease=yes > + else > + enable_xlib_lease=no > + fi > +esac > + > +AM_CONDITIONAL(HAVE_XLIB_LEASE, test "x$enable_xlib_lease" = xyes) > + > dnl > dnl More DRI setup > dnl > diff --git a/meson.build b/meson.build > index aeb7f5e2917..595b0f66cd7 100644 > --- a/meson.build > +++ b/meson.build > @@ -262,6 +262,19 @@ if _platforms != '' > egl_native_platform = _split[0] > endif > > +with_xlib_lease = get_option('xlib-lease') > +if with_xlib_lease == 'auto' > + if with_platform_x11 and with_platform_display > + with_xlib_lease = true > + else > + with_xlib_lease = false > + endif > +elif with_xlib_lease == 'true' > + with_xlib_lease = true > +else > + with_xlib_lease = false > +endif Can be simplified a bit: _xlib_lease = get_option('xlib-lease') if _xlib_lease == 'auto' with_xlib_lease = with_platform_x11 and with_platform_display else with_xlib_lease = _xlib_lease == 'true' endif (We also usually try to avoid changing the type of a var, and meson might start being more strict with types in future releases) > + > with_glx = get_option('glx') > if with_glx == 'auto' > if with_dri > @@ -1151,6 +1164,7 @@ dep_xcb_present = [] > dep_xcb_sync = [] > dep_xcb_xfixes = [] > dep_xshmfence = [] > +dep_xcb_xrandr = [] > if with_platform_x11 > if with_glx == 'xlib' or with_glx == 'gallium-xlib' > dep_x11 = dependency('x11') > @@ -1190,6 +1204,9 @@ if with_platform_x11 > if with_egl > dep_xcb_xfixes = dependency('xcb-xfixes') > endif > + if with_xlib_lease > + dep_xcb_xrandr = dependency('xcb-randr', version : '>= 1.12') > + endif > endif > > if get_option('gallium-extra-hud') > diff --git a/meson_options.txt b/meson_options.txt > index 7fafe2deaac..d38c9aa6149 100644 > --- a/meson_options.txt > +++ b/meson_options.txt > @@ -286,3 +286,10 @@ option( > value : '', > description : 'Comma delimited list of tools to build. choices : freedreno,glsl,intel,nir,nouveau or all' > ) > +option( > + 'xlib-lease', > + type : 'combo', > + value : 'auto', > + choices : ['auto', 'true', 'false'], > + description : 'Enable VK_EXT_acquire_xlib_display.' > +) > diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am > index c33ac5758f7..e96ef68972c 100644 > --- a/src/vulkan/Makefile.am > +++ b/src/vulkan/Makefile.am > @@ -64,6 +64,11 @@ AM_CPPFLAGS += \ > VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES) > endif > > +if HAVE_XLIB_LEASE > +AM_CPPFLAGS += \ > + -DVK_USE_PLATFORM_XLIB_XRANDR_EXT > +endif > + > BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES) > CLEANFILES = $(BUILT_SOURCES) > > diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build > index 743631a6113..5e3d43a2748 100644 > --- a/src/vulkan/wsi/meson.build > +++ b/src/vulkan/wsi/meson.build > @@ -67,6 +67,13 @@ if with_platform_display > ) > endif > > +if with_xlib_lease > + vulkan_wsi_deps += dep_xcb_xrandr > + vulkan_wsi_args += [ > + '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT', > + ] vulkan_wsi_args += '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT' with that, the meson part of this is Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> > +endif > + > libvulkan_wsi = static_library( > 'vulkan_wsi', > files_vulkan_wsi, > diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c > index 5c123e6465e..29d64b21aff 100644 > --- a/src/vulkan/wsi/wsi_common_display.c > +++ b/src/vulkan/wsi/wsi_common_display.c > @@ -32,6 +32,10 @@ > #include <math.h> > #include <xf86drm.h> > #include <xf86drmMode.h> > +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT > +#include <xcb/randr.h> > +#include <X11/Xlib-xcb.h> > +#endif > #include "util/hash_table.h" > #include "util/list.h" > > @@ -73,6 +77,9 @@ typedef struct wsi_display_connector { > bool active; > wsi_display_mode *current_mode; > drmModeModeInfo current_drm_mode; > +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT > + xcb_randr_output_t output; > +#endif > } wsi_display_connector; > > struct wsi_display { > @@ -1381,5 +1388,470 @@ wsi_release_display(VkPhysicalDevice physical_device, > close(wsi->master_fd); > wsi->master_fd = -1; > } > +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT > + wsi_display_connector_from_handle(display)->output = None; > +#endif > + > return VK_SUCCESS; > } > + > +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT > + > +static struct wsi_display_connector * > +wsi_display_find_output(struct wsi_device *wsi_device, > + RROutput output) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector; > + > + connector = NULL; > + LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) { > + if (connector->output == output) > + return connector; > + } > + > + return NULL; > +} > + > +/* > + * Given a RandR output, find the associated kernel connector_id by > + * looking at the CONNECTOR_ID property provided by the X server > + */ > + > +static uint32_t > +wsi_display_output_to_connector_id(xcb_connection_t *connection, > + xcb_atom_t *connector_id_atom_p, > + RROutput output) > +{ > + uint32_t connector_id = 0; > + xcb_atom_t connector_id_atom = *connector_id_atom_p; > + > + if (connector_id_atom == 0) { > + /* Go dig out the CONNECTOR_ID property */ > + xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection, > + true, > + 12, > + "CONNECTOR_ID"); > + xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection, > + ia_c, > + NULL); > + if (ia_r) { > + *connector_id_atom_p = connector_id_atom = ia_r->atom; > + free(ia_r); > + } > + } > + > + /* If there's an CONNECTOR_ID atom in the server, then there may be a CONNECTOR_ID property. Otherwise, > + * there will not be and we don't even need to bother. > + */ > + if (connector_id_atom) { > + > + xcb_randr_query_version_cookie_t qv_c = xcb_randr_query_version(connection, 1, 6); > + xcb_randr_get_output_property_cookie_t gop_c = xcb_randr_get_output_property(connection, > + output, > + connector_id_atom, > + 0, > + 0, > + 0xffffffffUL, > + 0, > + 0); > + xcb_randr_query_version_reply_t *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL); > + free(qv_r); > + xcb_randr_get_output_property_reply_t *gop_r = xcb_randr_get_output_property_reply(connection, > + gop_c, > + NULL); > + if (gop_r) { > + if (gop_r->num_items == 1 && gop_r->format == 32) > + memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4); > + free(gop_r); > + } > + } > + return connector_id; > +} > + > +static bool > +wsi_display_check_randr_version(xcb_connection_t *connection) > +{ > + xcb_randr_query_version_cookie_t qv_c = xcb_randr_query_version(connection, 1, 6); > + xcb_randr_query_version_reply_t *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL); > + bool ret = false; > + > + if (!qv_r) > + return false; > + > + /* Check for version 1.6 or newer */ > + ret = qv_r->major_version > 1 || (qv_r->major_version == 1 && qv_r->minor_version >= 6); > + > + free(qv_r); > + return ret; > +} > + > +/* > + * Given a kernel connector id, find the associated RandR output using the > + * CONNECTOR_ID property > + */ > + > +static xcb_randr_output_t > +wsi_display_connector_id_to_output(xcb_connection_t *connection, > + uint32_t connector_id) > +{ > + if (!wsi_display_check_randr_version(connection)) > + return 0; > + > + const xcb_setup_t *setup = xcb_get_setup(connection); > + > + xcb_atom_t connector_id_atom = 0; > + xcb_randr_output_t output = 0; > + > + /* Search all of the screens for the provided output */ > + xcb_screen_iterator_t iter; > + for (iter = xcb_setup_roots_iterator(setup); output == 0 && iter.rem; xcb_screen_next(&iter)) { > + > + xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root); > + xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); > + > + if (!gsr_r) > + return 0; > + > + xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); > + int o; > + > + for (o = 0; o < gsr_r->num_outputs; o++) { > + if (wsi_display_output_to_connector_id(connection, &connector_id_atom, ro[o]) == connector_id) { > + output = ro[o]; > + break; > + } > + } > + free(gsr_r); > + } > + return output; > +} > + > +/* > + * Given a RandR output, find out which screen it's associated with > + */ > +static xcb_window_t > +wsi_display_output_to_root(xcb_connection_t *connection, > + xcb_randr_output_t output) > +{ > + if (!wsi_display_check_randr_version(connection)) > + return 0; > + > + const xcb_setup_t *setup = xcb_get_setup(connection); > + xcb_window_t root = 0; > + > + /* Search all of the screens for the provided output */ > + xcb_screen_iterator_t iter; > + for (iter = xcb_setup_roots_iterator(setup); root == 0 && iter.rem; xcb_screen_next(&iter)) { > + xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root); > + xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); > + > + if (!gsr_r) > + return 0; > + > + xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); > + int o; > + > + for (o = 0; o < gsr_r->num_outputs; o++) { > + if (ro[o] == output) { > + root = iter.data->root; > + break; > + } > + } > + free(gsr_r); > + } > + return root; > +} > + > +static bool > +wsi_display_mode_matches_x(struct wsi_display_mode *wsi, > + xcb_randr_mode_info_t *xcb) > +{ > + return wsi->clock == (xcb->dot_clock + 500) / 1000 && > + wsi->hdisplay == xcb->width && > + wsi->hsync_start == xcb->hsync_start && > + wsi->hsync_end == xcb->hsync_end && > + wsi->htotal == xcb->htotal && > + wsi->hskew == xcb->hskew && > + wsi->vdisplay == xcb->height && > + wsi->vsync_start == xcb->vsync_start && > + wsi->vsync_end == xcb->vsync_end && > + wsi->vtotal == xcb->vtotal && > + wsi->flags == xcb->mode_flags; > +} > + > +static struct wsi_display_mode * > +wsi_display_find_x_mode(struct wsi_device *wsi_device, > + struct wsi_display_connector *connector, > + xcb_randr_mode_info_t *mode) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_mode *display_mode; > + > + LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) { > + if (display_mode->connector == connector && > + wsi_display_mode_matches_x(display_mode, mode)) > + return display_mode; > + } > + return NULL; > +} > + > +static VkResult > +wsi_display_register_x_mode(struct wsi_device *wsi_device, > + struct wsi_display_connector *connector, > + xcb_randr_mode_info_t *x_mode, > + bool preferred) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_mode *display_mode; > + > + display_mode = wsi_display_find_x_mode(wsi_device, connector, x_mode); > + > + if (display_mode) { > + display_mode->valid = true; > + return VK_SUCCESS; > + } > + > + display_mode = vk_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); > + if (!display_mode) > + return VK_ERROR_OUT_OF_HOST_MEMORY; > + > + display_mode->connector = connector; > + display_mode->valid = true; > + display_mode->preferred = preferred; > + display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */ > + display_mode->hdisplay = x_mode->width; > + display_mode->hsync_start = x_mode->hsync_start; > + display_mode->hsync_end = x_mode->hsync_end; > + display_mode->htotal = x_mode->htotal; > + display_mode->hskew = x_mode->hskew; > + display_mode->vdisplay = x_mode->height; > + display_mode->vsync_start = x_mode->vsync_start; > + display_mode->vsync_end = x_mode->vsync_end; > + display_mode->vtotal = x_mode->vtotal; > + display_mode->vscan = 0; > + if (x_mode->mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN) > + display_mode->vscan = 1; > + display_mode->flags = x_mode->mode_flags; > + > + LIST_ADDTAIL(&display_mode->list, &wsi->display_modes); > + return VK_SUCCESS; > +} > + > +static struct wsi_display_connector * > +wsi_display_get_output(struct wsi_device *wsi_device, > + xcb_connection_t *connection, > + RROutput output) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector; > + uint32_t connector_id; > + xcb_window_t root; > + xcb_randr_get_screen_resources_cookie_t src; > + xcb_randr_get_screen_resources_reply_t *srr; > + xcb_randr_get_output_info_cookie_t oic; > + xcb_randr_get_output_info_reply_t *oir; > + xcb_randr_mode_t *x_modes; > + int m; > + > + root = wsi_display_output_to_root(connection, output); > + if (!root) > + return NULL; > + > + src = xcb_randr_get_screen_resources(connection, root); > + oic = xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME); > + srr = xcb_randr_get_screen_resources_reply(connection, src, NULL); > + oir = xcb_randr_get_output_info_reply(connection, oic, NULL); > + > + /* See if we already have a connector for this output */ > + connector = wsi_display_find_output(wsi_device, output); > + > + if (!connector) { > + xcb_atom_t connector_id_atom = 0; > + > + /* > + * Go get the kernel connector ID for this X output > + */ > + connector_id = wsi_display_output_to_connector_id(connection, &connector_id_atom, output); > + > + /* Any X server with lease support will have this atom */ > + if (!connector_id) { > + free(oir); > + free(srr); > + return NULL; > + } > + > + if (!connector) { > + /* See if we already have a connector for this id */ > + connector = wsi_display_find_connector(wsi_device, connector_id); > + > + if (connector) > + connector->output = output; > + } > + } > + > + if (!connector) { > + connector = wsi_display_alloc_connector(wsi, connector_id); > + if (!connector) { > + free(oir); > + free(srr); > + return NULL; > + } > + LIST_ADDTAIL(&connector->list, &wsi->connectors); > + connector->output = output; > + } > + > + if (oir && srr) { > + /* Get X modes and add them */ > + > + connector->connected = oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED; > + > + wsi_display_invalidate_connector_modes(wsi_device, connector); > + > + x_modes = xcb_randr_get_output_info_modes(oir); > + for (m = 0; m < oir->num_modes; m++) { > + xcb_randr_mode_info_iterator_t i = xcb_randr_get_screen_resources_modes_iterator(srr); > + while (i.rem) { > + xcb_randr_mode_info_t *mi = i.data; > + if (mi->id == x_modes[m]) { > + VkResult result = wsi_display_register_x_mode(wsi_device, connector, mi, m < oir->num_preferred); > + if (result != VK_SUCCESS) { > + free(oir); > + free(srr); > + return NULL; > + } > + break; > + } > + xcb_randr_mode_info_next(&i); > + } > + } > + } > + > + free(oir); > + free(srr); > + return connector; > +} > + > +static xcb_randr_crtc_t > +wsi_display_find_crtc_for_output(xcb_connection_t *connection, > + xcb_window_t root, > + xcb_randr_output_t output) > +{ > + xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, root); > + xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); > + > + if (!gsr_r) > + return 0; > + > + xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r); > + xcb_randr_crtc_t idle_crtc = 0; > + xcb_randr_crtc_t active_crtc = 0; > + > + /* Find either a crtc already connected to the desired output or idle */ > + int c; > + for (c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) { > + xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp); > + xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(connection, gci_c, NULL); > + if (gci_r) { > + if (gci_r->mode) { > + int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r); > + xcb_randr_output_t *outputs = xcb_randr_get_crtc_info_outputs(gci_r); > + for (int o = 0; o < num_outputs; o++) > + if (outputs[o] == output && num_outputs == 1) { > + active_crtc = rc[c]; > + break; > + } > + } else if (idle_crtc == 0) { > + int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r); > + xcb_randr_output_t *possible = xcb_randr_get_crtc_info_possible(gci_r); > + for (int p = 0; p < num_possible; p++) > + if (possible[p] == output) { > + idle_crtc = rc[c]; > + break; > + } > + } > + free(gci_r); > + } > + } > + free(gsr_r); > + > + if (active_crtc) > + return active_crtc; > + return idle_crtc; > +} > + > +VkResult > +wsi_acquire_xlib_display(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + Display *dpy, > + VkDisplayKHR display) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + xcb_connection_t *connection = XGetXCBConnection(dpy); > + struct wsi_display_connector *connector = wsi_display_connector_from_handle(display); > + xcb_window_t root; > + > + if (!connector->output) { > + connector->output = wsi_display_connector_id_to_output(connection, connector->id); > + > + /* Check and see if we found the output */ > + if (!connector->output) > + return VK_ERROR_OUT_OF_DATE_KHR; > + } > + > + root = wsi_display_output_to_root(connection, connector->output); > + if (!root) > + return VK_ERROR_OUT_OF_DATE_KHR; > + > + xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection, > + root, > + connector->output); > + > + if (!crtc) > + return VK_ERROR_OUT_OF_DATE_KHR; > + > + xcb_randr_lease_t lease = xcb_generate_id(connection); > + xcb_randr_create_lease_cookie_t cl_c = xcb_randr_create_lease(connection, > + root, > + lease, > + 1, > + 1, > + &crtc, > + &connector->output); > + xcb_randr_create_lease_reply_t *cl_r = xcb_randr_create_lease_reply(connection, cl_c, NULL); > + if (!cl_r) > + return VK_ERROR_OUT_OF_DATE_KHR; > + > + int fd = -1; > + if (cl_r->nfd > 0) { > + int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r); > + > + fd = rcl_f[0]; > + } > + free (cl_r); > + if (fd < 0) > + return VK_ERROR_OUT_OF_DATE_KHR; > + > + wsi->master_fd = fd; > + > + return VK_SUCCESS; > +} > + > +VkResult > +wsi_get_randr_output_display(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + Display *dpy, > + RROutput output, > + VkDisplayKHR *display) > +{ > + xcb_connection_t *connection = XGetXCBConnection(dpy); > + struct wsi_display_connector *connector = wsi_display_get_output(wsi_device, connection, output); > + > + if (connector) > + *display = wsi_display_connector_to_handle(connector); > + else > + *display = NULL; > + return VK_SUCCESS; > +} > + > +#endif > diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h > index 5fbb6925e4a..1997c2a3c40 100644 > --- a/src/vulkan/wsi/wsi_common_display.h > +++ b/src/vulkan/wsi/wsi_common_display.h > @@ -74,4 +74,21 @@ wsi_release_display(VkPhysicalDevice physical_device, > struct wsi_device *wsi_device, > VkDisplayKHR display); > > + > +#if VK_USE_PLATFORM_XLIB_XRANDR_EXT > +VkResult > +wsi_acquire_xlib_display(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + Display *dpy, > + VkDisplayKHR display); > + > +VkResult > +wsi_get_randr_output_display(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + Display *dpy, > + RROutput output, > + VkDisplayKHR *display); > + > +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ > + > #endif > -- > 2.15.1 >
Eric Engestrom <eric.engestrom@imgtec.com> writes: > Can be simplified a bit: > > _xlib_lease = get_option('xlib-lease') > if _xlib_lease == 'auto' > with_xlib_lease = with_platform_x11 and with_platform_display > else > with_xlib_lease = _xlib_lease == 'true' > endif > > (We also usually try to avoid changing the type of a var, and meson might > start being more strict with types in future releases) I wondered about that in the places I copied my code from. Good to know there's a better practice. I've switched to using this form. >> +if with_xlib_lease >> + vulkan_wsi_deps += dep_xcb_xrandr >> + vulkan_wsi_args += [ >> + '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT', >> + ] > > vulkan_wsi_args += '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT' I switched all of the inappropriate usage to this form for six separate patches (three each for core/anv/radv by two extensions (DISPLAY and XLIB_XRANDR). > with that, the meson part of this is > Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> Awesome! Thanks for reviewing the build system bits; I'm just starting to use meson and every new change is a learning opportunity at this point.
diff --git a/configure.ac b/configure.ac index 46318365603..cf05d049c26 100644 --- a/configure.ac +++ b/configure.ac @@ -1547,6 +1547,7 @@ AM_CONDITIONAL(HAVE_APPLEDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = x AM_CONDITIONAL(HAVE_LMSENSORS, test "x$enable_lmsensors" = xyes ) AM_CONDITIONAL(HAVE_GALLIUM_EXTRA_HUD, test "x$enable_gallium_extra_hud" = xyes ) AM_CONDITIONAL(HAVE_WINDOWSDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = xwindows ) +AM_CONDITIONAL(HAVE_XLEASE, test "x$have_xlease" = xyes ) AC_ARG_ENABLE([shared-glapi], [AS_HELP_STRING([--enable-shared-glapi], @@ -1846,6 +1847,18 @@ if test x"$enable_dri3" = xyes; then PKG_CHECK_MODULES([XCB_DRI3], [$dri3_modules]) fi + +if echo "$platforms" | grep -q 'x11' && echo "$platforms" | grep -q 'drm'; then + have_xlease=yes +else + have_xlease=no +fi + +if test x"$have_xlease" = xyes; then + randr_modules="x11-xcb xcb-randr" + PKG_CHECK_MODULES([XCB_RANDR], [$randr_modules]) +fi + AM_CONDITIONAL(HAVE_PLATFORM_X11, echo "$platforms" | grep -q 'x11') AM_CONDITIONAL(HAVE_PLATFORM_WAYLAND, echo "$platforms" | grep -q 'wayland') AM_CONDITIONAL(HAVE_PLATFORM_DRM, echo "$platforms" | grep -q 'drm') @@ -1853,6 +1866,25 @@ AM_CONDITIONAL(HAVE_PLATFORM_DISPLAY, echo "$platforms" | grep -q 'drm') AM_CONDITIONAL(HAVE_PLATFORM_SURFACELESS, echo "$platforms" | grep -q 'surfaceless') AM_CONDITIONAL(HAVE_PLATFORM_ANDROID, echo "$platforms" | grep -q 'android') +AC_ARG_ENABLE(xlib-lease, + [AS_HELP_STRING([--enable-xlib-lease] + [enable VK_acquire_xlib_display using X leases])], + [enable_xlib_lease=$enableval], [enable_xlib_lease=auto]) +case "x$enable_xlib_lease" in +xyes) + ;; +xno) + ;; +*) + if echo "$platforms" | grep -q 'x11' && echo "$platforms" | grep -q 'drm'; then + enable_xlib_lease=yes + else + enable_xlib_lease=no + fi +esac + +AM_CONDITIONAL(HAVE_XLIB_LEASE, test "x$enable_xlib_lease" = xyes) + dnl dnl More DRI setup dnl diff --git a/meson.build b/meson.build index aeb7f5e2917..595b0f66cd7 100644 --- a/meson.build +++ b/meson.build @@ -262,6 +262,19 @@ if _platforms != '' egl_native_platform = _split[0] endif +with_xlib_lease = get_option('xlib-lease') +if with_xlib_lease == 'auto' + if with_platform_x11 and with_platform_display + with_xlib_lease = true + else + with_xlib_lease = false + endif +elif with_xlib_lease == 'true' + with_xlib_lease = true +else + with_xlib_lease = false +endif + with_glx = get_option('glx') if with_glx == 'auto' if with_dri @@ -1151,6 +1164,7 @@ dep_xcb_present = [] dep_xcb_sync = [] dep_xcb_xfixes = [] dep_xshmfence = [] +dep_xcb_xrandr = [] if with_platform_x11 if with_glx == 'xlib' or with_glx == 'gallium-xlib' dep_x11 = dependency('x11') @@ -1190,6 +1204,9 @@ if with_platform_x11 if with_egl dep_xcb_xfixes = dependency('xcb-xfixes') endif + if with_xlib_lease + dep_xcb_xrandr = dependency('xcb-randr', version : '>= 1.12') + endif endif if get_option('gallium-extra-hud') diff --git a/meson_options.txt b/meson_options.txt index 7fafe2deaac..d38c9aa6149 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -286,3 +286,10 @@ option( value : '', description : 'Comma delimited list of tools to build. choices : freedreno,glsl,intel,nir,nouveau or all' ) +option( + 'xlib-lease', + type : 'combo', + value : 'auto', + choices : ['auto', 'true', 'false'], + description : 'Enable VK_EXT_acquire_xlib_display.' +) diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am index c33ac5758f7..e96ef68972c 100644 --- a/src/vulkan/Makefile.am +++ b/src/vulkan/Makefile.am @@ -64,6 +64,11 @@ AM_CPPFLAGS += \ VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES) endif +if HAVE_XLIB_LEASE +AM_CPPFLAGS += \ + -DVK_USE_PLATFORM_XLIB_XRANDR_EXT +endif + BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES) CLEANFILES = $(BUILT_SOURCES) diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build index 743631a6113..5e3d43a2748 100644 --- a/src/vulkan/wsi/meson.build +++ b/src/vulkan/wsi/meson.build @@ -67,6 +67,13 @@ if with_platform_display ) endif +if with_xlib_lease + vulkan_wsi_deps += dep_xcb_xrandr + vulkan_wsi_args += [ + '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT', + ] +endif + libvulkan_wsi = static_library( 'vulkan_wsi', files_vulkan_wsi, diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c index 5c123e6465e..29d64b21aff 100644 --- a/src/vulkan/wsi/wsi_common_display.c +++ b/src/vulkan/wsi/wsi_common_display.c @@ -32,6 +32,10 @@ #include <math.h> #include <xf86drm.h> #include <xf86drmMode.h> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT +#include <xcb/randr.h> +#include <X11/Xlib-xcb.h> +#endif #include "util/hash_table.h" #include "util/list.h" @@ -73,6 +77,9 @@ typedef struct wsi_display_connector { bool active; wsi_display_mode *current_mode; drmModeModeInfo current_drm_mode; +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT + xcb_randr_output_t output; +#endif } wsi_display_connector; struct wsi_display { @@ -1381,5 +1388,470 @@ wsi_release_display(VkPhysicalDevice physical_device, close(wsi->master_fd); wsi->master_fd = -1; } +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT + wsi_display_connector_from_handle(display)->output = None; +#endif + return VK_SUCCESS; } + +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT + +static struct wsi_display_connector * +wsi_display_find_output(struct wsi_device *wsi_device, + RROutput output) +{ + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_connector *connector; + + connector = NULL; + LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) { + if (connector->output == output) + return connector; + } + + return NULL; +} + +/* + * Given a RandR output, find the associated kernel connector_id by + * looking at the CONNECTOR_ID property provided by the X server + */ + +static uint32_t +wsi_display_output_to_connector_id(xcb_connection_t *connection, + xcb_atom_t *connector_id_atom_p, + RROutput output) +{ + uint32_t connector_id = 0; + xcb_atom_t connector_id_atom = *connector_id_atom_p; + + if (connector_id_atom == 0) { + /* Go dig out the CONNECTOR_ID property */ + xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection, + true, + 12, + "CONNECTOR_ID"); + xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection, + ia_c, + NULL); + if (ia_r) { + *connector_id_atom_p = connector_id_atom = ia_r->atom; + free(ia_r); + } + } + + /* If there's an CONNECTOR_ID atom in the server, then there may be a CONNECTOR_ID property. Otherwise, + * there will not be and we don't even need to bother. + */ + if (connector_id_atom) { + + xcb_randr_query_version_cookie_t qv_c = xcb_randr_query_version(connection, 1, 6); + xcb_randr_get_output_property_cookie_t gop_c = xcb_randr_get_output_property(connection, + output, + connector_id_atom, + 0, + 0, + 0xffffffffUL, + 0, + 0); + xcb_randr_query_version_reply_t *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL); + free(qv_r); + xcb_randr_get_output_property_reply_t *gop_r = xcb_randr_get_output_property_reply(connection, + gop_c, + NULL); + if (gop_r) { + if (gop_r->num_items == 1 && gop_r->format == 32) + memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4); + free(gop_r); + } + } + return connector_id; +} + +static bool +wsi_display_check_randr_version(xcb_connection_t *connection) +{ + xcb_randr_query_version_cookie_t qv_c = xcb_randr_query_version(connection, 1, 6); + xcb_randr_query_version_reply_t *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL); + bool ret = false; + + if (!qv_r) + return false; + + /* Check for version 1.6 or newer */ + ret = qv_r->major_version > 1 || (qv_r->major_version == 1 && qv_r->minor_version >= 6); + + free(qv_r); + return ret; +} + +/* + * Given a kernel connector id, find the associated RandR output using the + * CONNECTOR_ID property + */ + +static xcb_randr_output_t +wsi_display_connector_id_to_output(xcb_connection_t *connection, + uint32_t connector_id) +{ + if (!wsi_display_check_randr_version(connection)) + return 0; + + const xcb_setup_t *setup = xcb_get_setup(connection); + + xcb_atom_t connector_id_atom = 0; + xcb_randr_output_t output = 0; + + /* Search all of the screens for the provided output */ + xcb_screen_iterator_t iter; + for (iter = xcb_setup_roots_iterator(setup); output == 0 && iter.rem; xcb_screen_next(&iter)) { + + xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root); + xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); + + if (!gsr_r) + return 0; + + xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); + int o; + + for (o = 0; o < gsr_r->num_outputs; o++) { + if (wsi_display_output_to_connector_id(connection, &connector_id_atom, ro[o]) == connector_id) { + output = ro[o]; + break; + } + } + free(gsr_r); + } + return output; +} + +/* + * Given a RandR output, find out which screen it's associated with + */ +static xcb_window_t +wsi_display_output_to_root(xcb_connection_t *connection, + xcb_randr_output_t output) +{ + if (!wsi_display_check_randr_version(connection)) + return 0; + + const xcb_setup_t *setup = xcb_get_setup(connection); + xcb_window_t root = 0; + + /* Search all of the screens for the provided output */ + xcb_screen_iterator_t iter; + for (iter = xcb_setup_roots_iterator(setup); root == 0 && iter.rem; xcb_screen_next(&iter)) { + xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root); + xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); + + if (!gsr_r) + return 0; + + xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); + int o; + + for (o = 0; o < gsr_r->num_outputs; o++) { + if (ro[o] == output) { + root = iter.data->root; + break; + } + } + free(gsr_r); + } + return root; +} + +static bool +wsi_display_mode_matches_x(struct wsi_display_mode *wsi, + xcb_randr_mode_info_t *xcb) +{ + return wsi->clock == (xcb->dot_clock + 500) / 1000 && + wsi->hdisplay == xcb->width && + wsi->hsync_start == xcb->hsync_start && + wsi->hsync_end == xcb->hsync_end && + wsi->htotal == xcb->htotal && + wsi->hskew == xcb->hskew && + wsi->vdisplay == xcb->height && + wsi->vsync_start == xcb->vsync_start && + wsi->vsync_end == xcb->vsync_end && + wsi->vtotal == xcb->vtotal && + wsi->flags == xcb->mode_flags; +} + +static struct wsi_display_mode * +wsi_display_find_x_mode(struct wsi_device *wsi_device, + struct wsi_display_connector *connector, + xcb_randr_mode_info_t *mode) +{ + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_mode *display_mode; + + LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) { + if (display_mode->connector == connector && + wsi_display_mode_matches_x(display_mode, mode)) + return display_mode; + } + return NULL; +} + +static VkResult +wsi_display_register_x_mode(struct wsi_device *wsi_device, + struct wsi_display_connector *connector, + xcb_randr_mode_info_t *x_mode, + bool preferred) +{ + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_mode *display_mode; + + display_mode = wsi_display_find_x_mode(wsi_device, connector, x_mode); + + if (display_mode) { + display_mode->valid = true; + return VK_SUCCESS; + } + + display_mode = vk_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!display_mode) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + display_mode->connector = connector; + display_mode->valid = true; + display_mode->preferred = preferred; + display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */ + display_mode->hdisplay = x_mode->width; + display_mode->hsync_start = x_mode->hsync_start; + display_mode->hsync_end = x_mode->hsync_end; + display_mode->htotal = x_mode->htotal; + display_mode->hskew = x_mode->hskew; + display_mode->vdisplay = x_mode->height; + display_mode->vsync_start = x_mode->vsync_start; + display_mode->vsync_end = x_mode->vsync_end; + display_mode->vtotal = x_mode->vtotal; + display_mode->vscan = 0; + if (x_mode->mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN) + display_mode->vscan = 1; + display_mode->flags = x_mode->mode_flags; + + LIST_ADDTAIL(&display_mode->list, &wsi->display_modes); + return VK_SUCCESS; +} + +static struct wsi_display_connector * +wsi_display_get_output(struct wsi_device *wsi_device, + xcb_connection_t *connection, + RROutput output) +{ + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_connector *connector; + uint32_t connector_id; + xcb_window_t root; + xcb_randr_get_screen_resources_cookie_t src; + xcb_randr_get_screen_resources_reply_t *srr; + xcb_randr_get_output_info_cookie_t oic; + xcb_randr_get_output_info_reply_t *oir; + xcb_randr_mode_t *x_modes; + int m; + + root = wsi_display_output_to_root(connection, output); + if (!root) + return NULL; + + src = xcb_randr_get_screen_resources(connection, root); + oic = xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME); + srr = xcb_randr_get_screen_resources_reply(connection, src, NULL); + oir = xcb_randr_get_output_info_reply(connection, oic, NULL); + + /* See if we already have a connector for this output */ + connector = wsi_display_find_output(wsi_device, output); + + if (!connector) { + xcb_atom_t connector_id_atom = 0; + + /* + * Go get the kernel connector ID for this X output + */ + connector_id = wsi_display_output_to_connector_id(connection, &connector_id_atom, output); + + /* Any X server with lease support will have this atom */ + if (!connector_id) { + free(oir); + free(srr); + return NULL; + } + + if (!connector) { + /* See if we already have a connector for this id */ + connector = wsi_display_find_connector(wsi_device, connector_id); + + if (connector) + connector->output = output; + } + } + + if (!connector) { + connector = wsi_display_alloc_connector(wsi, connector_id); + if (!connector) { + free(oir); + free(srr); + return NULL; + } + LIST_ADDTAIL(&connector->list, &wsi->connectors); + connector->output = output; + } + + if (oir && srr) { + /* Get X modes and add them */ + + connector->connected = oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED; + + wsi_display_invalidate_connector_modes(wsi_device, connector); + + x_modes = xcb_randr_get_output_info_modes(oir); + for (m = 0; m < oir->num_modes; m++) { + xcb_randr_mode_info_iterator_t i = xcb_randr_get_screen_resources_modes_iterator(srr); + while (i.rem) { + xcb_randr_mode_info_t *mi = i.data; + if (mi->id == x_modes[m]) { + VkResult result = wsi_display_register_x_mode(wsi_device, connector, mi, m < oir->num_preferred); + if (result != VK_SUCCESS) { + free(oir); + free(srr); + return NULL; + } + break; + } + xcb_randr_mode_info_next(&i); + } + } + } + + free(oir); + free(srr); + return connector; +} + +static xcb_randr_crtc_t +wsi_display_find_crtc_for_output(xcb_connection_t *connection, + xcb_window_t root, + xcb_randr_output_t output) +{ + xcb_randr_get_screen_resources_cookie_t gsr_c = xcb_randr_get_screen_resources(connection, root); + xcb_randr_get_screen_resources_reply_t *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); + + if (!gsr_r) + return 0; + + xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r); + xcb_randr_crtc_t idle_crtc = 0; + xcb_randr_crtc_t active_crtc = 0; + + /* Find either a crtc already connected to the desired output or idle */ + int c; + for (c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) { + xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp); + xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(connection, gci_c, NULL); + if (gci_r) { + if (gci_r->mode) { + int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r); + xcb_randr_output_t *outputs = xcb_randr_get_crtc_info_outputs(gci_r); + for (int o = 0; o < num_outputs; o++) + if (outputs[o] == output && num_outputs == 1) { + active_crtc = rc[c]; + break; + } + } else if (idle_crtc == 0) { + int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r); + xcb_randr_output_t *possible = xcb_randr_get_crtc_info_possible(gci_r); + for (int p = 0; p < num_possible; p++) + if (possible[p] == output) { + idle_crtc = rc[c]; + break; + } + } + free(gci_r); + } + } + free(gsr_r); + + if (active_crtc) + return active_crtc; + return idle_crtc; +} + +VkResult +wsi_acquire_xlib_display(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + Display *dpy, + VkDisplayKHR display) +{ + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + xcb_connection_t *connection = XGetXCBConnection(dpy); + struct wsi_display_connector *connector = wsi_display_connector_from_handle(display); + xcb_window_t root; + + if (!connector->output) { + connector->output = wsi_display_connector_id_to_output(connection, connector->id); + + /* Check and see if we found the output */ + if (!connector->output) + return VK_ERROR_OUT_OF_DATE_KHR; + } + + root = wsi_display_output_to_root(connection, connector->output); + if (!root) + return VK_ERROR_OUT_OF_DATE_KHR; + + xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection, + root, + connector->output); + + if (!crtc) + return VK_ERROR_OUT_OF_DATE_KHR; + + xcb_randr_lease_t lease = xcb_generate_id(connection); + xcb_randr_create_lease_cookie_t cl_c = xcb_randr_create_lease(connection, + root, + lease, + 1, + 1, + &crtc, + &connector->output); + xcb_randr_create_lease_reply_t *cl_r = xcb_randr_create_lease_reply(connection, cl_c, NULL); + if (!cl_r) + return VK_ERROR_OUT_OF_DATE_KHR; + + int fd = -1; + if (cl_r->nfd > 0) { + int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r); + + fd = rcl_f[0]; + } + free (cl_r); + if (fd < 0) + return VK_ERROR_OUT_OF_DATE_KHR; + + wsi->master_fd = fd; + + return VK_SUCCESS; +} + +VkResult +wsi_get_randr_output_display(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + Display *dpy, + RROutput output, + VkDisplayKHR *display) +{ + xcb_connection_t *connection = XGetXCBConnection(dpy); + struct wsi_display_connector *connector = wsi_display_get_output(wsi_device, connection, output); + + if (connector) + *display = wsi_display_connector_to_handle(connector); + else + *display = NULL; + return VK_SUCCESS; +} + +#endif diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h index 5fbb6925e4a..1997c2a3c40 100644 --- a/src/vulkan/wsi/wsi_common_display.h +++ b/src/vulkan/wsi/wsi_common_display.h @@ -74,4 +74,21 @@ wsi_release_display(VkPhysicalDevice physical_device, struct wsi_device *wsi_device, VkDisplayKHR display); + +#if VK_USE_PLATFORM_XLIB_XRANDR_EXT +VkResult +wsi_acquire_xlib_display(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + Display *dpy, + VkDisplayKHR display); + +VkResult +wsi_get_randr_output_display(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + Display *dpy, + RROutput output, + VkDisplayKHR *display); + +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ + #endif
This extension adds the ability to borrow an X RandR output for temporary use directly by a Vulkan application. For DRM, we use the Linux resource leasing mechanism. Signed-off-by: Keith Packard <keithp@keithp.com> --- configure.ac | 32 +++ meson.build | 17 ++ meson_options.txt | 7 + src/vulkan/Makefile.am | 5 + src/vulkan/wsi/meson.build | 7 + src/vulkan/wsi/wsi_common_display.c | 472 ++++++++++++++++++++++++++++++++++++ src/vulkan/wsi/wsi_common_display.h | 17 ++ 7 files changed, 557 insertions(+)