diff mbox

[07/21] vulkan: Add EXT_acquire_xlib_display

Message ID 20180214003134.1552-8-keithp@keithp.com (mailing list archive)
State New, archived
Headers show

Commit Message

Keith Packard Feb. 14, 2018, 12:31 a.m. UTC
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(+)

Comments

Eric Engestrom Feb. 14, 2018, 12:13 p.m. UTC | #1
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
>
Keith Packard Feb. 15, 2018, 8:26 p.m. UTC | #2
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 mbox

Patch

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