[PATCH 3/7] vulkan: Add EXT_acquire_xlib_display
Dylan Baker
dylan at pnwbakers.com
Tue Feb 13 00:16:07 UTC 2018
Quoting Keith Packard (2018-02-09 20:45:12)
> 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 at keithp.com>
> ---
> configure.ac | 25 ++
> meson.build | 17 ++
> meson_options.txt | 7 +
> src/amd/vulkan/Makefile.am | 7 +
> src/amd/vulkan/meson.build | 7 +
> src/amd/vulkan/radv_extensions.py | 11 +-
> src/amd/vulkan/radv_wsi_display.c | 30 +++
> src/intel/Makefile.vulkan.am | 7 +
> src/intel/vulkan/anv_extensions.py | 1 +
> src/intel/vulkan/anv_extensions_gen.py | 10 +-
> src/intel/vulkan/anv_wsi_display.c | 30 +++
> src/intel/vulkan/meson.build | 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 ++
> 16 files changed, 650 insertions(+), 10 deletions(-)
>
> diff --git a/configure.ac b/configure.ac
> index 46318365603..9effd15e8c5 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,11 @@ if test x"$enable_dri3" = xyes; then
> PKG_CHECK_MODULES([XCB_DRI3], [$dri3_modules])
> 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 +1859,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';
> + 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
You could simplify this to
with_xlib_lease = with_platform_x11 and with_platform_display
> +elif with_xlib_lease == 'true'
We should probably error here if we don't have the correct platforms.
> + 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/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
> index 061b8144b88..94ece06e99e 100644
> --- a/src/amd/vulkan/Makefile.am
> +++ b/src/amd/vulkan/Makefile.am
> @@ -81,7 +81,14 @@ AM_CPPFLAGS += \
> -DVK_USE_PLATFORM_DISPLAY_KHR
>
> VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> +endif
> +
> +if HAVE_XLIB_LEASE
> +AM_CPPFLAGS += \
> + -DVK_USE_PLATFORM_XLIB_XRANDR_EXT \
> + $(XCB_RANDR_CFLAGS)
>
> +VULKAN_LIB_DEPS += $(XCB_RANDR_LIBS)
> endif
>
> if HAVE_PLATFORM_X11
> diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
> index b7bb1075e7d..0b92a1763a1 100644
> --- a/src/amd/vulkan/meson.build
> +++ b/src/amd/vulkan/meson.build
> @@ -119,6 +119,13 @@ if with_platform_display
> libradv_files += files('radv_wsi_display.c')
> endif
>
> +if with_xlib_lease
> + radv_deps += dep_xcb_xrandr
Since this is a stub when not building, we don't we just put his in the deps
unconditionally
> + radv_flags += [
> + '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
> + ]
no [] needed here.
> +endif
> +
> libvulkan_radeon = shared_library(
> 'vulkan_radeon',
> [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
> diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
> index f784681ff57..2d804afed35 100644
> --- a/src/amd/vulkan/radv_extensions.py
> +++ b/src/amd/vulkan/radv_extensions.py
> @@ -83,6 +83,7 @@ EXTENSIONS = [
> Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'),
> Extension('VK_KHR_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
> Extension('VK_EXT_direct_mode_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
> + Extension('VK_EXT_acquire_xlib_display', 1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
> Extension('VK_KHX_multiview', 1, '!ANDROID'),
> Extension('VK_EXT_debug_report', 9, True),
> Extension('VK_EXT_discard_rectangles', 1, True),
> @@ -170,12 +171,12 @@ _TEMPLATE = Template(COPYRIGHT + """
> #include "vk_util.h"
>
> /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
> -#ifdef VK_USE_PLATFORM_${platform}_KHR
> -# undef VK_USE_PLATFORM_${platform}_KHR
> -# define VK_USE_PLATFORM_${platform}_KHR true
> +%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']:
> +#ifdef VK_USE_PLATFORM_${platform}
> +# undef VK_USE_PLATFORM_${platform}
> +# define VK_USE_PLATFORM_${platform} true
> #else
> -# define VK_USE_PLATFORM_${platform}_KHR false
> +# define VK_USE_PLATFORM_${platform} false
> #endif
> %endfor
>
> diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
> index 0051f5ac865..9b76ce623b0 100644
> --- a/src/amd/vulkan/radv_wsi_display.c
> +++ b/src/amd/vulkan/radv_wsi_display.c
> @@ -152,3 +152,33 @@ radv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
> &pdevice->wsi_device,
> display);
> }
> +
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +VkResult
> +radv_AcquireXlibDisplayEXT(VkPhysicalDevice physical_device,
> + Display *dpy,
> + VkDisplayKHR display)
> +{
> + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> + return wsi_acquire_xlib_display(physical_device,
> + &pdevice->wsi_device,
> + dpy,
> + display);
> +}
> +
> +VkResult
> +radv_GetRandROutputDisplayEXT(VkPhysicalDevice physical_device,
> + Display *dpy,
> + RROutput output,
> + VkDisplayKHR *display)
> +{
> + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> + return wsi_get_randr_output_display(physical_device,
> + &pdevice->wsi_device,
> + dpy,
> + output,
> + display);
> +}
> +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
> diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
> index 7c428a799d7..0f0d3815097 100644
> --- a/src/intel/Makefile.vulkan.am
> +++ b/src/intel/Makefile.vulkan.am
> @@ -194,6 +194,13 @@ VULKAN_CPPFLAGS += \
> VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> endif
>
> +if HAVE_XLIB_LEASE
> +VULKAN_CPPFLAGS += \
> + -DVK_USE_PLATFORM_XLIB_XRANDR_EXT \
> + $(XCB_RANDR_CFLAGS)
> +VULKAN_LIB_DEPS += $(XCB_RANDR_LIBS)
> +endif
> +
> noinst_LTLIBRARIES += vulkan/libvulkan_common.la
> vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
> vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS)
> diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
> index 633e378e605..32a240acdcb 100644
> --- a/src/intel/vulkan/anv_extensions.py
> +++ b/src/intel/vulkan/anv_extensions.py
> @@ -85,6 +85,7 @@ EXTENSIONS = [
> Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'),
> Extension('VK_KHR_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
> Extension('VK_EXT_direct_mode_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
> + Extension('VK_EXT_acquire_xlib_display', 1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
> Extension('VK_KHX_multiview', 1, True),
> Extension('VK_EXT_debug_report', 8, True),
> Extension('VK_EXT_external_memory_dma_buf', 1, True),
> diff --git a/src/intel/vulkan/anv_extensions_gen.py b/src/intel/vulkan/anv_extensions_gen.py
> index 84d07f9767a..025907aff72 100644
> --- a/src/intel/vulkan/anv_extensions_gen.py
> +++ b/src/intel/vulkan/anv_extensions_gen.py
> @@ -113,12 +113,12 @@ _TEMPLATE_C = Template(COPYRIGHT + """
> #include "vk_util.h"
>
> /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
> -#ifdef VK_USE_PLATFORM_${platform}_KHR
> -# undef VK_USE_PLATFORM_${platform}_KHR
> -# define VK_USE_PLATFORM_${platform}_KHR true
> +%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']:
> +#ifdef VK_USE_PLATFORM_${platform}
> +# undef VK_USE_PLATFORM_${platform}
> +# define VK_USE_PLATFORM_${platform} true
> #else
> -# define VK_USE_PLATFORM_${platform}_KHR false
> +# define VK_USE_PLATFORM_${platform} false
> #endif
> %endfor
>
> diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
> index e6f67f7dec9..e87aed49f7d 100644
> --- a/src/intel/vulkan/anv_wsi_display.c
> +++ b/src/intel/vulkan/anv_wsi_display.c
> @@ -138,3 +138,33 @@ anv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
> &pdevice->wsi_device,
> display);
> }
> +
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +VkResult
> +anv_AcquireXlibDisplayEXT(VkPhysicalDevice physical_device,
> + Display *dpy,
> + VkDisplayKHR display)
> +{
> + ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> + return wsi_acquire_xlib_display(physical_device,
> + &pdevice->wsi_device,
> + dpy,
> + display);
> +}
> +
> +VkResult
> +anv_GetRandROutputDisplayEXT(VkPhysicalDevice physical_device,
> + Display *dpy,
> + RROutput output,
> + VkDisplayKHR *display)
> +{
> + ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> + return wsi_get_randr_output_display(physical_device,
> + &pdevice->wsi_device,
> + dpy,
> + output,
> + display);
> +}
> +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
> diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
> index 2e2ab8f7ecd..d3ab5ac8a64 100644
> --- a/src/intel/vulkan/meson.build
> +++ b/src/intel/vulkan/meson.build
> @@ -178,6 +178,13 @@ if with_platform_display
> libanv_files += files('anv_wsi_display.c')
> endif
>
> +if with_xlib_lease
> + anv_deps += dep_xcb_xrandr
> + anv_flags += [
> + '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
> + ]
> +endif
Same here
> +
> libanv_common = static_library(
> 'anv_common',
> [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h],
> 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
ditto
> +
> 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
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: signature
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20180212/475560a1/attachment-0001.sig>
More information about the dri-devel
mailing list