[Mesa-dev] [PATCH mesa 01/21] vulkan: Add KHR_display extension using DRM [v4]

Jason Ekstrand jason at jlekstrand.net
Thu Apr 5 00:49:45 UTC 2018


I apologize for how nit-picky this is going to get but it's starting to
bother me...

Because it's nitpicky, I just made a bunch of changes and put it in a
couple of fixup commits:

https://gitlab.freedesktop.org/jekstrand/mesa/commit/98e9cbd3b46453254b1aeba1edf5aa1a22cce168
https://gitlab.freedesktop.org/jekstrand/mesa/commit/6e6ae7f9455f7c9040b59b384b6f939f4f9dcbed

The first one is clearly useful/convenient.  The second is just me making
it look more like other code in this area.  I'm not sure how much it
actually improves though. :/

On Wed, Mar 7, 2018 at 11:24 PM, Keith Packard <keithp at keithp.com> wrote:

> This adds support for the KHR_display extension support to the vulkan
> WSI layer. Driver support will be added separately.
>
> v2:
>         * fix double ;; in wsi_common_display.c
>
>         * Move mode list from wsi_display to wsi_display_connector
>
>         * Fix scope for wsi_display_mode andwsi_display_connector
>           allocs
>
>         * Switch all allocations to vk_zalloc instead of vk_alloc.
>
>         * Fix DRM failure in
>           wsi_display_get_physical_device_display_properties
>
>           When DRM fails, or when we don't have a master fd
>           (presumably due to application errors), just return 0
>           properties from this function, which is at least a valid
>           response.
>
>         * Use vk_outarray for all property queries
>
>           This is a bit less error-prone than open-coding the same
>           stuff.
>
>         * Remove VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR from surface caps
>
>           Until we have multi-plane support, we shouldn't pretend to
>           have any multi-plane semantics, even if undefined.
>
>         Suggested-by: Jason Ekstrand <jason at jlekstrand.net>
>
>         * Simplify addition of VK_USE_PLATFORM_DISPLAY_KHR to
>           vulkan_wsi_args
>
>         Suggested-by: Eric Engestrom <eric.engestrom at imgtec.com>
>
> v3:
>         Add separate 'display_fd' and 'render_fd' arguments to
>         wsi_device_init API. This allows drivers to use different FDs
>         for the different aspects of the device.
>
>         Use largest mode as display size when no preferred mode.
>
>         If the display doesn't provide a preferred mode, we'll assume
>         that the largest supported mode is the "physical size" of the
>         device and report that.
>
> v4:
>         Make wsi_image_state enumeration values uppercase.
>         Follow more common mesa conventions.
>
>         Remove 'render_fd' from wsi_device_init API.  The
>         wsi_common_display code doesn't use this fd at all, so stop
>         passing it in. This avoids any potential confusion over which
>         fd to use when creating display-relative object handles.
>
>         Remove call to wsi_create_prime_image which would never have
>         been reached as the necessary condition (use_prime_blit) is
>         never set.
>
>         whitespace cleanups in wsi_common_display.c
>
>         Suggested-by: Jason Ekstrand <jason at jlekstrand.net>
>
>         Add depth/bpp info to available surface formats.  Instead of
>         hard-coding depth 24 bpp 32 in the drmModeAddFB call, use the
>         requested format to find suitable values.
>
>         Destroy kernel buffers and FBs when swapchain is destroyed. We
>         were leaking both of these kernel objects across swapchain
>         destruction.
>
>         Note that wsi_display_wait_for_event waits for anything to
>         happen.  wsi_display_wait_for_event is simply a yield so that
>         the caller can then check to see if the desired state change
>         has occurred.
>
>         Record swapchain failures in chain for later return. If some
>         asynchronous swapchain activity fails, we need to tell the
>         application eventually. Record the failure in the swapchain
>         and report it at the next acquire_next_image or queue_present
>         call.
>
>         Fix error returns from wsi_display_setup_connector.  If a
>         malloc failed, then the result should be
>         VK_ERROR_OUT_OF_HOST_MEMORY. Otherwise, the associated ioctl
>         failed and we're either VT switched away, or our lease has
>         been revoked, in which case we should return
>         VK_ERROR_OUT_OF_DATE_KHR.
>
>         Make sure both sides of if/else brace use matches
>
>         Note that we assume drmModeSetCrtc is synchronous. Add a
>         comment explaining why we can idle any previous displayed
>         image as soon as the mode set returns.
>
>         Note that EACCES from drmModePageFlip means VT inactive.  When
>         vt switched away drmModePageFlip returns EACCES. Poll once a
>         second waiting until we get some other return value back.
>
>         Clean up after alloc failure in
>         wsi_display_surface_create_swapchain. Destroy any created
>         images, free the swapchain.
>
>         Remove physical_device from wsi_display_init_wsi. We never
>         need this value, so remove it from the API and from the
>         internal wsi_display structure.
>
>         Use drmModeAddFB2 in wsi_display_image_init.  This takes a drm
>         format instead of depth/bpp, which provides more control over
>         the format of the data.
>
> Signed-off-by: Keith Packard <keithp at keithp.com>
> ---
>  configure.ac                        |    1 +
>  meson.build                         |    4 +-
>  src/amd/vulkan/radv_device.c        |    8 +
>  src/amd/vulkan/radv_private.h       |    1 +
>  src/amd/vulkan/radv_wsi.c           |    3 +-
>  src/intel/vulkan/anv_device.c       |    4 +
>  src/intel/vulkan/anv_private.h      |    1 +
>  src/intel/vulkan/anv_wsi.c          |    3 +-
>  src/vulkan/Makefile.am              |    7 +
>  src/vulkan/Makefile.sources         |    4 +
>  src/vulkan/wsi/meson.build          |    8 +
>  src/vulkan/wsi/wsi_common.c         |   19 +-
>  src/vulkan/wsi/wsi_common.h         |    5 +-
>  src/vulkan/wsi/wsi_common_display.c | 1401 ++++++++++++++++++++++++++++++
> +++++
>  src/vulkan/wsi/wsi_common_display.h |   72 ++
>  src/vulkan/wsi/wsi_common_private.h |    9 +
>  16 files changed, 1544 insertions(+), 6 deletions(-)
>  create mode 100644 src/vulkan/wsi/wsi_common_display.c
>  create mode 100644 src/vulkan/wsi/wsi_common_display.h
>
> diff --git a/configure.ac b/configure.ac
> index 172da6b443c..7fcb3220eaa 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1856,6 +1856,7 @@ 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')
> +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')
>
> diff --git a/meson.build b/meson.build
> index 8a17d7f240a..788aed6e159 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -239,11 +239,12 @@ with_platform_wayland = false
>  with_platform_x11 = false
>  with_platform_drm = false
>  with_platform_surfaceless = false
> +with_platform_display = false
>  egl_native_platform = ''
>  _platforms = get_option('platforms')
>  if _platforms == 'auto'
>    if system_has_kms_drm
> -    _platforms = 'x11,wayland,drm,surfaceless'
> +    _platforms = 'x11,wayland,drm,surfaceless,display'
>    elif ['darwin', 'windows', 'cygwin'].contains(host_machine.system())
>      _platforms = 'x11,surfaceless'
>    elif ['haiku'].contains(host_machine.system())
> @@ -260,6 +261,7 @@ if _platforms != ''
>    with_platform_drm = _split.contains('drm')
>    with_platform_haiku = _split.contains('haiku')
>    with_platform_surfaceless = _split.contains('surfaceless')
> +  with_platform_display = _split.contains('display')
>    egl_native_platform = _split[0]
>  endif
>
> diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
> index 7a11e08f97c..35fd1ef6b29 100644
> --- a/src/amd/vulkan/radv_device.c
> +++ b/src/amd/vulkan/radv_device.c
> @@ -223,6 +223,7 @@ radv_physical_device_init(struct radv_physical_device
> *device,
>         VkResult result;
>         drmVersionPtr version;
>         int fd;
> +       int master_fd = -1;
>
>         fd = open(path, O_RDWR | O_CLOEXEC);
>         if (fd < 0)
> @@ -237,6 +238,8 @@ radv_physical_device_init(struct radv_physical_device
> *device,
>
>         if (strcmp(version->name, "amdgpu")) {
>                 drmFreeVersion(version);
> +               if (master_fd != -1)
> +                       close(master_fd);
>                 close(fd);
>                 return VK_ERROR_INCOMPATIBLE_DRIVER;
>         }
> @@ -254,6 +257,7 @@ radv_physical_device_init(struct radv_physical_device
> *device,
>                 goto fail;
>         }
>
> +       device->master_fd = master_fd;
>         device->local_fd = fd;
>         device->ws->query_info(device->ws, &device->rad_info);
>
> @@ -317,6 +321,8 @@ radv_physical_device_init(struct radv_physical_device
> *device,
>
>  fail:
>         close(fd);
> +       if (master_fd != -1)
> +               close(master_fd);
>         return result;
>  }
>
> @@ -327,6 +333,8 @@ radv_physical_device_finish(struct
> radv_physical_device *device)
>         device->ws->destroy(device->ws);
>         disk_cache_destroy(device->disk_cache);
>         close(device->local_fd);
> +       if (device->master_fd != -1)
> +               close(device->master_fd);
>  }
>
>  static void *
> diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
> index 0f8ddb2e106..35a161c3671 100644
> --- a/src/amd/vulkan/radv_private.h
> +++ b/src/amd/vulkan/radv_private.h
> @@ -281,6 +281,7 @@ struct radv_physical_device {
>         uint8_t
>  cache_uuid[VK_UUID_SIZE];
>
>         int local_fd;
> +       int master_fd;
>         struct wsi_device                       wsi_device;
>
>         bool has_rbplus; /* if RB+ register exist */
> diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
> index 927650480a6..2840b666727 100644
> --- a/src/amd/vulkan/radv_wsi.c
> +++ b/src/amd/vulkan/radv_wsi.c
> @@ -41,7 +41,8 @@ radv_init_wsi(struct radv_physical_device
> *physical_device)
>         return wsi_device_init(&physical_device->wsi_device,
>                                radv_physical_device_to_
> handle(physical_device),
>                                radv_wsi_proc_addr,
> -                              &physical_device->instance->alloc);
> +                              &physical_device->instance->alloc,
> +                              physical_device->master_fd);
>  }
>
>  void
> diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
> index d8c4e986316..ab61e0ce339 100644
> --- a/src/intel/vulkan/anv_device.c
> +++ b/src/intel/vulkan/anv_device.c
> @@ -282,6 +282,7 @@ anv_physical_device_init(struct anv_physical_device
> *device,
>  {
>     VkResult result;
>     int fd;
> +   int master_fd = -1;
>
>     brw_process_intel_debug_variable();
>
> @@ -444,10 +445,13 @@ anv_physical_device_init(struct anv_physical_device
> *device,
>
>  &device->supported_extensions);
>
>     device->local_fd = fd;
> +   device->master_fd = master_fd;
>     return VK_SUCCESS;
>
>  fail:
>     close(fd);
> +   if (master_fd != -1)
> +      close(master_fd);
>     return result;
>  }
>
> diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_
> private.h
> index ee533581ab4..b2d42e1313d 100644
> --- a/src/intel/vulkan/anv_private.h
> +++ b/src/intel/vulkan/anv_private.h
> @@ -809,6 +809,7 @@ struct anv_physical_device {
>
>      struct wsi_device                       wsi_device;
>      int                                         local_fd;
> +    int                                         master_fd;
>  };
>
>  struct anv_instance {
> diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
> index 20094f93e1f..a7efb1416fa 100644
> --- a/src/intel/vulkan/anv_wsi.c
> +++ b/src/intel/vulkan/anv_wsi.c
> @@ -48,7 +48,8 @@ anv_init_wsi(struct anv_physical_device *physical_device)
>     result = wsi_device_init(&physical_device->wsi_device,
>                              anv_physical_device_to_handle(
> physical_device),
>                              anv_wsi_proc_addr,
> -                            &physical_device->instance->alloc);
> +                            &physical_device->instance->alloc,
> +                            physical_device->master_fd);
>     if (result != VK_SUCCESS)
>        return result;
>
> diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
> index cbffd769fa4..075eb58c82c 100644
> --- a/src/vulkan/Makefile.am
> +++ b/src/vulkan/Makefile.am
> @@ -58,6 +58,13 @@ AM_CPPFLAGS += \
>  VULKAN_WSI_SOURCES += $(VULKAN_WSI_X11_FILES)
>  endif
>
> +if HAVE_PLATFORM_DISPLAY
> +AM_CPPFLAGS += \
> +       -DVK_USE_PLATFORM_DISPLAY_KHR
> +
> +VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> +endif
> +
>  CLEANFILES = $(BUILT_SOURCES)
>
>  WL_DRM_XML = $(top_srcdir)/src/egl/wayland/wayland-drm/wayland-drm.xml
> diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources
> index 101a94349c6..f0f6bcd4fd8 100644
> --- a/src/vulkan/Makefile.sources
> +++ b/src/vulkan/Makefile.sources
> @@ -19,6 +19,10 @@ VULKAN_WSI_X11_FILES := \
>         wsi/wsi_common_x11.c \
>         wsi/wsi_common_x11.h
>
> +VULKAN_WSI_DISPLAY_FILES := \
> +       wsi/wsi_common_display.c \
> +       wsi/wsi_common_display.h
> +
>  VULKAN_UTIL_FILES := \
>         util/vk_alloc.h \
>         util/vk_debug_report.c \
> diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build
> index 223c8ca357e..776e596984d 100644
> --- a/src/vulkan/wsi/meson.build
> +++ b/src/vulkan/wsi/meson.build
> @@ -59,6 +59,14 @@ if with_platform_wayland
>    ]
>  endif
>
> +if with_platform_display
> +  vulkan_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_KHR'
> +  files_vulkan_wsi += files(
> +    'wsi_common_display.c',
> +    'wsi_common_display.h',
> +  )
> +endif
> +
>  libvulkan_wsi = static_library(
>    'vulkan_wsi',
>    files_vulkan_wsi,
> diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c
> index edba13a13de..655fe59ab0f 100644
> --- a/src/vulkan/wsi/wsi_common.c
> +++ b/src/vulkan/wsi/wsi_common.c
> @@ -32,7 +32,8 @@ VkResult
>  wsi_device_init(struct wsi_device *wsi,
>                  VkPhysicalDevice pdevice,
>                  WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
> -                const VkAllocationCallbacks *alloc)
> +                const VkAllocationCallbacks *alloc,
> +                int display_fd)
>  {
>     VkResult result;
>
> @@ -95,6 +96,19 @@ wsi_device_init(struct wsi_device *wsi,
>     }
>  #endif
>
> +#ifdef VK_USE_PLATFORM_DISPLAY_KHR
> +   result = wsi_display_init_wsi(wsi, alloc, display_fd);
> +   if (result != VK_SUCCESS) {
> +#ifdef VK_USE_PLATFORM_WAYLAND_KHR
> +      wsi_wl_finish_wsi(wsi, alloc);
> +#endif
> +#ifdef VK_USE_PLATFORM_XCB_KHR
> +      wsi_x11_finish_wsi(wsi, alloc);
> +#endif
> +      return result;
> +   }
> +#endif
> +
>     return VK_SUCCESS;
>  }
>
> @@ -102,6 +116,9 @@ void
>  wsi_device_finish(struct wsi_device *wsi,
>                    const VkAllocationCallbacks *alloc)
>  {
> +#ifdef VK_USE_PLATFORM_DISPLAY_KHR
> +   wsi_display_finish_wsi(wsi, alloc);
> +#endif
>  #ifdef VK_USE_PLATFORM_WAYLAND_KHR
>     wsi_wl_finish_wsi(wsi, alloc);
>  #endif
> diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
> index 6cf729ba025..b8bbf4b80c4 100644
> --- a/src/vulkan/wsi/wsi_common.h
> +++ b/src/vulkan/wsi/wsi_common.h
> @@ -68,7 +68,7 @@ struct wsi_format_modifier_properties_list {
>
>  struct wsi_interface;
>
> -#define VK_ICD_WSI_PLATFORM_MAX 5
> +#define VK_ICD_WSI_PLATFORM_MAX 6
>
>  struct wsi_device {
>     VkPhysicalDevice pdevice;
> @@ -116,7 +116,8 @@ VkResult
>  wsi_device_init(struct wsi_device *wsi,
>                  VkPhysicalDevice pdevice,
>                  WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
> -                const VkAllocationCallbacks *alloc);
> +                const VkAllocationCallbacks *alloc,
> +                int display_fd);
>
>  void
>  wsi_device_finish(struct wsi_device *wsi,
> diff --git a/src/vulkan/wsi/wsi_common_display.c
> b/src/vulkan/wsi/wsi_common_display.c
> new file mode 100644
> index 00000000000..be31043f3de
> --- /dev/null
> +++ b/src/vulkan/wsi/wsi_common_display.c
> @@ -0,0 +1,1401 @@
> +/*
> + * Copyright © 2017 Keith Packard
> + *
> + * Permission to use, copy, modify, distribute, and sell this software
> and its
> + * documentation for any purpose is hereby granted without fee, provided
> that
> + * the above copyright notice appear in all copies and that both that
> copyright
> + * notice and this permission notice appear in supporting documentation,
> and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no
> representations
> + * about the suitability of this software for any purpose.  It is
> provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
> OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
> USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
> PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +#include "util/macros.h"
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <poll.h>
> +#include <stdbool.h>
> +#include <math.h>
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +#include <drm_fourcc.h>
> +#include "util/hash_table.h"
> +#include "util/list.h"
> +
> +#include "vk_util.h"
> +#include "wsi_common_private.h"
> +#include "wsi_common_display.h"
> +#include "wsi_common_queue.h"
> +
> +#if 0
> +#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
> +#define wsi_display_debug_code(...)     __VA_ARGS__
> +#else
> +#define wsi_display_debug(...)
> +#define wsi_display_debug_code(...)
> +#endif
> +
> +/* These have lifetime equal to the instance, so they effectively
> + * never go away. This means we must keep track of them separately
> + * from all other resources.
> + */
> +typedef struct wsi_display_mode {
> +   struct list_head             list;
> +   struct wsi_display_connector *connector;
> +   bool                         valid;          /* was found in most
> recent poll */
> +   bool                         preferred;
> +   uint32_t                     clock;          /* in kHz */
> +   uint16_t                     hdisplay, hsync_start, hsync_end, htotal,
> hskew;
> +   uint16_t                     vdisplay, vsync_start, vsync_end, vtotal,
> vscan;
> +   uint32_t                     flags;
> +} wsi_display_mode;
> +
> +typedef struct wsi_display_connector {
> +   struct list_head             list;
> +   struct wsi_display           *wsi;
> +   uint32_t                     id;
> +   uint32_t                     crtc_id;
> +   char                         *name;
> +   bool                         connected;
> +   bool                         active;
> +   struct list_head             display_modes;
> +   wsi_display_mode             *current_mode;
> +   drmModeModeInfo              current_drm_mode;
> +} wsi_display_connector;
> +
> +struct wsi_display {
> +   struct wsi_interface         base;
> +
> +   const VkAllocationCallbacks  *alloc;
> +
> +   int                          fd;
> +
> +   pthread_mutex_t              wait_mutex;
> +   pthread_cond_t               wait_cond;
> +   pthread_t                    wait_thread;
> +
> +   struct list_head             connectors;
> +};
> +
> +enum wsi_image_state {
> +   WSI_IMAGE_IDLE,
> +   WSI_IMAGE_DRAWING,
> +   WSI_IMAGE_QUEUED,
> +   WSI_IMAGE_FLIPPING,
> +   WSI_IMAGE_DISPLAYING
> +};
> +
> +struct wsi_display_image {
> +   struct wsi_image             base;
> +   struct wsi_display_swapchain *chain;
> +   enum wsi_image_state         state;
> +   uint32_t                     fb_id;
> +   uint32_t                     buffer[4];
> +   uint64_t                     flip_sequence;
> +};
> +
> +struct wsi_display_swapchain {
> +   struct wsi_swapchain         base;
> +   struct wsi_display           *wsi;
> +   VkIcdSurfaceDisplay          *surface;
> +   uint64_t                     flip_sequence;
> +   VkResult                     status;
> +   struct wsi_display_image     images[0];
> +};
> +
> +ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
> +ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
> +
> +static bool
> +wsi_display_mode_matches_drm(wsi_display_mode   *wsi,
> +                             drmModeModeInfoPtr drm)
> +{
> +   return wsi->clock == drm->clock &&
> +      wsi->hdisplay == drm->hdisplay &&
> +      wsi->hsync_start == drm->hsync_start &&
> +      wsi->hsync_end == drm->hsync_end &&
> +      wsi->htotal == drm->htotal &&
> +      wsi->hskew == drm->hskew &&
> +      wsi->vdisplay == drm->vdisplay &&
> +      wsi->vsync_start == drm->vsync_start &&
> +      wsi->vsync_end == drm->vsync_end &&
> +      wsi->vtotal == drm->vtotal &&
> +      wsi->vscan == drm->vscan &&
> +      wsi->flags == drm->flags;
> +}
> +
> +static double
> +wsi_display_mode_refresh(struct wsi_display_mode        *wsi)
> +{
> +   return (double) wsi->clock * 1000.0 / ((double) wsi->htotal * (double)
> wsi->vtotal * (double) (wsi->vscan + 1));
>

Please watch out for line lengths.  We generally try not to go over 80
characters unless wrapping would get super weird.


> +}
> +
> +static uint64_t wsi_get_current_monotonic(void)
> +{
> +   struct timespec tv;
> +
> +   clock_gettime(CLOCK_MONOTONIC, &tv);
> +   return tv.tv_nsec + tv.tv_sec*1000000000ull;
> +}
> +
> +static struct wsi_display_mode *
> +wsi_display_find_drm_mode(struct wsi_device                 *wsi_device,
> +                          struct wsi_display_connector      *connector,
> +                          drmModeModeInfoPtr                mode)
>

Also, we don't align variable/parameter names, just aligning the types to
the paren is sufficient.  In this particular case, I think it will fix the
80 character issue too.


> +{
> +   struct wsi_display_mode      *display_mode;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &connector->display_modes, list) {
> +      if (wsi_display_mode_matches_drm(display_mode, mode))
> +         return display_mode;
> +   }
> +   return NULL;
> +}
> +
> +static void
> +wsi_display_invalidate_connector_modes(struct wsi_device
> *wsi_device,
> +                                       struct wsi_display_connector
> *connector)
> +{
> +   struct wsi_display_mode      *display_mode;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &connector->display_modes, list)
> +      display_mode->valid = false;
> +}
> +
> +static VkResult
> +wsi_display_register_drm_mode(struct wsi_device            *wsi_device,
> +                              struct wsi_display_connector *connector,
> +                              drmModeModeInfoPtr           drm_mode)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
>

That's really long.


> +   struct wsi_display_mode      *display_mode;
>

This is 2018 and we don't care about compiling on VAX.  You can mix
declarations and code. :-)


> +
> +   display_mode = wsi_display_find_drm_mode(wsi_device, connector,
> drm_mode);
> +
> +   if (display_mode) {
> +      display_mode->valid = true;
> +      return VK_SUCCESS;
> +   }
> +
> +   display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
> 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
> +   if (!display_mode)
> +      return VK_ERROR_OUT_OF_HOST_MEMORY;
> +
> +   display_mode->connector = connector;
> +   display_mode->valid = true;
> +   display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED)
> != 0;
> +   display_mode->clock = drm_mode->clock; /* kHz */
> +   display_mode->hdisplay = drm_mode->hdisplay;
> +   display_mode->hsync_start = drm_mode->hsync_start;
> +   display_mode->hsync_end = drm_mode->hsync_end;
> +   display_mode->htotal = drm_mode->htotal;
> +   display_mode->hskew = drm_mode->hskew;
> +   display_mode->vdisplay = drm_mode->vdisplay;
> +   display_mode->vsync_start = drm_mode->vsync_start;
> +   display_mode->vsync_end = drm_mode->vsync_end;
> +   display_mode->vtotal = drm_mode->vtotal;
> +   display_mode->vscan = drm_mode->vscan;
> +   display_mode->flags = drm_mode->flags;
> +
> +   LIST_ADDTAIL(&display_mode->list, &connector->display_modes);
> +   return VK_SUCCESS;
> +}
> +
> +/*
> + * Update our information about a specific connector
> + */
> +
> +static struct wsi_display_connector *
> +wsi_display_find_connector(struct wsi_device    *wsi_device,
> +                          uint32_t              connector_id)
> +{
> +   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->id == connector_id)
> +         return connector;
> +   }
> +
> +   return NULL;
> +}
> +
> +static struct wsi_display_connector *
> +wsi_display_alloc_connector(struct wsi_display  *wsi,
> +                            uint32_t            connector_id)
> +{
> +   struct wsi_display_connector *connector;
> +
> +   connector = vk_zalloc(wsi->alloc, sizeof (struct
> wsi_display_connector), 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
> +   connector->id = connector_id;
> +   connector->wsi = wsi;
> +   connector->active = false;
> +   /* XXX use EDID name */
> +   connector->name = "monitor";
> +   LIST_INITHEAD(&connector->display_modes);
> +   return connector;
> +}
> +
> +static struct wsi_display_connector *
> +wsi_display_get_connector(struct wsi_device             *wsi_device,
> +                          uint32_t                      connector_id)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_connector *connector;
> +   drmModeConnectorPtr          drm_connector;
> +   VkResult                     result;
> +   int                          m;
> +
> +   if (wsi->fd < 0)
> +      return NULL;
> +
> +   drm_connector = drmModeGetConnector(wsi->fd, connector_id);
> +   if (!drm_connector)
> +      return NULL;
> +
> +   connector = wsi_display_find_connector(wsi_device, connector_id);
> +
> +   if (!connector) {
> +      connector = wsi_display_alloc_connector(wsi, connector_id);
> +      if (!connector) {
> +         drmModeFreeConnector(drm_connector);
> +         return NULL;
> +      }
> +      LIST_ADDTAIL(&connector->list, &wsi->connectors);
> +   }
> +
> +   connector->connected = drm_connector->connection !=
> DRM_MODE_DISCONNECTED;
> +
> +   /* Mark all connector modes as invalid */
> +   wsi_display_invalidate_connector_modes(wsi_device, connector);
> +
> +   /*
> +    * List current modes, adding new ones and marking existing ones as
> +    * valid
> +    */
> +   for (m = 0; m < drm_connector->count_modes; m++) {
> +      result = wsi_display_register_drm_mode(wsi_device,
> +                                             connector,
> +                                             &drm_connector->modes[m]);
> +      if (result != VK_SUCCESS) {
> +         drmModeFreeConnector(drm_connector);
> +         return NULL;
> +      }
> +   }
> +
> +   drmModeFreeConnector(drm_connector);
> +
> +   return connector;
> +}
> +
> +#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
> +
> +static uint32_t
> +mode_size(struct wsi_display_mode *mode) {
> +   /* fortunately, these are both uint16_t, so this is easy */
> +   return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay;
> +}
> +
> +static void
> +wsi_display_fill_in_display_properties(struct wsi_device
> *wsi_device,
> +                                       struct wsi_display_connector
>  *connector,
> +                                       VkDisplayPropertiesKHR
>  *properties)
> +{
> +   struct wsi_display_mode      *display_mode, *preferred_mode = NULL,
> *largest_mode = NULL;
> +
> +   properties->display = wsi_display_connector_to_handle(connector);
> +   properties->displayName = connector->name;
> +
> +   /* Find the preferred mode and assume that's the physical resolution.
> If
> +    * there isn't a preferred mode, find the largest mode and use that.
> +    */
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &connector->display_modes, list) {
> +      if (display_mode->valid && (largest_mode == NULL ||
> mode_size(display_mode) > mode_size(largest_mode)))
> +         largest_mode = display_mode;
> +      if (display_mode->valid && display_mode->preferred) {
> +         preferred_mode = display_mode;
> +         break;
> +      }
> +   }
> +
> +   if (preferred_mode) {
> +      properties->physicalResolution.width = preferred_mode->hdisplay;
> +      properties->physicalResolution.height = preferred_mode->vdisplay;
> +   } else if (largest_mode) {
> +      properties->physicalResolution.width = largest_mode->hdisplay;
> +      properties->physicalResolution.height = largest_mode->vdisplay;
> +   } else {
> +      properties->physicalResolution.width = 1024;
> +      properties->physicalResolution.height = 768;
> +   }
> +
> +   /* Make up physical size based on 96dpi */
> +   properties->physicalDimensions.width = floor(properties->physicalResolution.width
> * MM_PER_PIXEL + 0.5);
> +   properties->physicalDimensions.height = floor(properties->physicalResolution.height
> * MM_PER_PIXEL + 0.5);
> +
> +   properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_
> BIT_KHR;
> +   properties->persistentContent = 0;
> +}
> +
> +/*
> + * Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display)
> + */
> +VkResult
> +wsi_display_get_physical_device_display_properties(VkPhysicalDevice
>        physical_device,
> +                                                   struct wsi_device
>       *wsi_device,
> +                                                   uint32_t
>        *property_count,
> +
>  VkDisplayPropertiesKHR       *properties)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   drmModeResPtr                mode_res;
> +
> +   if (wsi->fd < 0)
> +      goto bail;
> +
> +   mode_res = drmModeGetResources(wsi->fd);
> +
> +   if (!mode_res)
> +      goto bail;
> +
> +   VK_OUTARRAY_MAKE(conn, properties, property_count);
> +
> +   /* Get current information */
> +
> +   for (int c = 0; c < mode_res->count_connectors; c++) {
> +      struct wsi_display_connector *connector =
> +         wsi_display_get_connector(wsi_device, mode_res->connectors[c]);
> +
> +      if (!connector) {
> +         drmModeFreeResources(mode_res);
> +         return VK_ERROR_OUT_OF_HOST_MEMORY;
> +      }
> +
> +      if (connector->connected) {
> +         vk_outarray_append(&conn, prop) {
> +            wsi_display_fill_in_display_properties(wsi_device,
> +                                                   connector,
> +                                                   prop);
> +         }
> +      }
> +   }
> +
> +   drmModeFreeResources(mode_res);
> +
> +   return vk_outarray_status(&conn);
> +
> +bail:
> +   *property_count = 0;
> +   return VK_SUCCESS;
> +}
> +
> +/*
> + * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
> + */
> +VkResult
> +wsi_display_get_physical_device_display_plane_properties(VkPhysicalDevice
>              physical_device,
> +                                                         struct
> wsi_device              *wsi_device,
> +                                                         uint32_t
>                *property_count,
> +
>  VkDisplayPlanePropertiesKHR    *properties)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_connector *connector;
> +
> +   VK_OUTARRAY_MAKE(conn, properties, property_count);
> +
> +   int stack_index = 0;
> +
> +   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
> +      vk_outarray_append(&conn, prop) {
> +         if (connector && connector->active) {
> +            prop->currentDisplay = wsi_display_connector_to_
> handle(connector);
> +            prop->currentStackIndex = stack_index++;
> +         } else {
> +            prop->currentDisplay = NULL;
> +            prop->currentStackIndex = 0;
> +         }
> +      }
> +   }
> +   return vk_outarray_status(&conn);
> +}
> +
> +/*
> + * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display)
> + */
> +
> +VkResult
> +wsi_display_get_display_plane_supported_displays(VkPhysicalDevice
>        physical_device,
> +                                                 struct wsi_device
>       *wsi_device,
> +                                                 uint32_t
>        plane_index,
> +                                                 uint32_t
>        *display_count,
> +                                                 VkDisplayKHR
>        *displays)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_connector *connector;
> +
> +   VK_OUTARRAY_MAKE(conn, displays, display_count);
> +
> +   int c = 0;
> +
> +   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
> +      if (c == plane_index) {
> +         vk_outarray_append(&conn, display) {
> +            *display = wsi_display_connector_to_handle(connector);
> +         }
> +      }
> +      c++;
> +   }
> +   return vk_outarray_status(&conn);
> +}
> +
> +/*
> + * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
> + */
> +
> +VkResult
> +wsi_display_get_display_mode_properties(VkPhysicalDevice
>  physical_device,
> +                                        struct wsi_device
> *wsi_device,
> +                                        VkDisplayKHR
>  display,
> +                                        uint32_t
>  *property_count,
> +                                        VkDisplayModePropertiesKHR
>  *properties)
> +{
> +   struct wsi_display_connector *connector = wsi_display_connector_from_
> handle(display);
> +   struct wsi_display_mode      *display_mode;
> +
> +   VK_OUTARRAY_MAKE(conn, properties, property_count);
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &connector->display_modes, list) {
> +      if (display_mode->valid) {
> +         vk_outarray_append(&conn, prop) {
> +            prop->displayMode = wsi_display_mode_to_handle(display_mode);
> +            prop->parameters.visibleRegion.width =
> display_mode->hdisplay;
> +            prop->parameters.visibleRegion.height =
> display_mode->vdisplay;
> +            prop->parameters.refreshRate = (uint32_t)
> (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
> +         }
> +      }
> +   }
> +   return vk_outarray_status(&conn);
> +}
> +
> +/*
> + * Implement vkGetDisplayPlaneCapabilities
> + */
> +VkResult
> +wsi_get_display_plane_capabilities(VkPhysicalDevice
>  physical_device,
> +                                   struct wsi_device
> *wsi_device,
> +                                   VkDisplayModeKHR
>  mode_khr,
> +                                   uint32_t
>  plane_index,
> +                                   VkDisplayPlaneCapabilitiesKHR
> *capabilities)
> +{
> +   struct wsi_display_mode      *mode = wsi_display_mode_from_handle(
> mode_khr);
> +
> +   /* XXX use actual values */
> +   capabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
> +   capabilities->minSrcPosition.x = 0;
> +   capabilities->minSrcPosition.y = 0;
> +   capabilities->maxSrcPosition.x = 0;
> +   capabilities->maxSrcPosition.y = 0;
> +   capabilities->minSrcExtent.width = mode->hdisplay;
> +   capabilities->minSrcExtent.height = mode->vdisplay;
> +   capabilities->maxSrcExtent.width = mode->hdisplay;
> +   capabilities->maxSrcExtent.height = mode->vdisplay;
> +   capabilities->minDstPosition.x = 0;
> +   capabilities->minDstPosition.y = 0;
> +   capabilities->maxDstPosition.x = 0;
> +   capabilities->maxDstPosition.y = 0;
> +   capabilities->minDstExtent.width = mode->hdisplay;
> +   capabilities->minDstExtent.height = mode->vdisplay;
> +   capabilities->maxDstExtent.width = mode->hdisplay;
> +   capabilities->maxDstExtent.height = mode->vdisplay;
> +   return VK_SUCCESS;
> +}
> +
> +VkResult
> +wsi_create_display_surface(VkInstance instance,
> +                           const VkAllocationCallbacks   *allocator,
> +                           const VkDisplaySurfaceCreateInfoKHR
> *create_info,
> +                           VkSurfaceKHR *surface_khr)
> +{
> +   VkIcdSurfaceDisplay *surface;
> +
> +   surface = vk_zalloc(allocator, sizeof *surface, 8,
> +                       VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
> +   if (surface == NULL)
> +      return VK_ERROR_OUT_OF_HOST_MEMORY;
> +
> +   surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY;
> +
> +   surface->displayMode = create_info->displayMode;
> +   surface->planeIndex = create_info->planeIndex;
> +   surface->planeStackIndex = create_info->planeStackIndex;
> +   surface->transform = create_info->transform;
> +   surface->globalAlpha = create_info->globalAlpha;
> +   surface->alphaMode = create_info->alphaMode;
> +   surface->imageExtent = create_info->imageExtent;
> +
> +   *surface_khr = VkIcdSurfaceBase_to_handle(&surface->base);
> +   return VK_SUCCESS;
> +}
> +
> +
> +static VkResult
> +wsi_display_surface_get_support(VkIcdSurfaceBase *surface,
> +                                struct wsi_device *wsi_device,
> +                                const VkAllocationCallbacks *allocator,
> +                                uint32_t queueFamilyIndex,
> +                                int local_fd,
> +                                VkBool32* pSupported)
> +{
> +   *pSupported = VK_TRUE;
> +   return VK_SUCCESS;
> +}
> +
> +static VkResult
> +wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base,
> +                                     VkSurfaceCapabilitiesKHR* caps)
> +{
> +   VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
> +   wsi_display_mode *mode = wsi_display_mode_from_handle(
> surface->displayMode);
> +
> +   caps->currentExtent.width = mode->hdisplay;
> +   caps->currentExtent.height = mode->vdisplay;
> +
> +   /* XXX Figure out extents based on driver capabilities */
> +   caps->maxImageExtent = caps->minImageExtent = caps->currentExtent;
> +
> +   caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
> +
> +   caps->minImageCount = 2;
> +   caps->maxImageCount = 0;
> +
> +   caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
> +   caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
> +   caps->maxImageArrayLayers = 1;
> +   caps->supportedUsageFlags =
> +      VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
> +      VK_IMAGE_USAGE_SAMPLED_BIT |
> +      VK_IMAGE_USAGE_TRANSFER_DST_BIT |
> +      VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
> +
> +   return VK_SUCCESS;
> +}
> +
> +static VkResult
> +wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
> +                                      const void *info_next,
> +                                      VkSurfaceCapabilities2KHR *caps)
> +{
> +   assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
> +
> +   return wsi_display_surface_get_capabilities(icd_surface,
> &caps->surfaceCapabilities);
> +}
> +
> +static const struct {
> +   VkFormat     format;
> +   uint32_t     drm_format;
> +} available_surface_formats[] = {
> +   { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888
> },
> +   { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format =
> DRM_FORMAT_XRGB8888 },
> +};
> +
> +static VkResult
> +wsi_display_surface_get_formats(VkIcdSurfaceBase        *icd_surface,
> +                                struct wsi_device       *wsi_device,
> +                                uint32_t
> *surface_format_count,
> +                                VkSurfaceFormatKHR      *surface_formats)
> +{
> +   VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
> +
> +   for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
> +      vk_outarray_append(&out, f) {
> +         f->format = available_surface_formats[i].format;
> +         f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
> +      }
> +   }
> +
> +   return vk_outarray_status(&out);
> +}
> +
> +static VkResult
> +wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
> +                                 struct wsi_device *wsi_device,
> +                                 const void *info_next,
> +                                 uint32_t *surface_format_count,
> +                                 VkSurfaceFormat2KHR *surface_formats)
> +{
> +   VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
> +
> +   for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
> +      vk_outarray_append(&out, f) {
> +         assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
> +         f->surfaceFormat.format = available_surface_formats[i].format;
> +         f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
> +      }
> +   }
> +
> +   return vk_outarray_status(&out);
> +}
> +
> +static const VkPresentModeKHR available_present_modes[] = {
> +   VK_PRESENT_MODE_FIFO_KHR,
> +};
> +
> +static VkResult
> +wsi_display_surface_get_present_modes(VkIcdSurfaceBase  *surface,
> +                                      uint32_t
> *present_mode_count,
> +                                      VkPresentModeKHR  *present_modes)
> +{
> +   VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count);
> +
> +   for (unsigned int c = 0; c < ARRAY_SIZE(available_present_modes);
> c++) {
> +      vk_outarray_append(&conn, present) {
> +         *present = available_present_modes[c];
> +      }
> +   }
> +
> +   return vk_outarray_status(&conn);
> +}
> +
> +static void
> +wsi_display_destroy_buffer(struct wsi_display *wsi,
> +                           uint32_t buffer)
> +{
> +   (void) drmIoctl(wsi->fd, DRM_IOCTL_MODE_DESTROY_DUMB,
> +                   &((struct drm_mode_destroy_dumb) { .handle = buffer
> }));
> +}
> +
> +static VkResult
> +wsi_display_image_init(VkDevice                         device_h,
> +                       struct wsi_swapchain             *drv_chain,
> +                       const VkSwapchainCreateInfoKHR   *create_info,
> +                       const VkAllocationCallbacks      *allocator,
> +                       struct wsi_display_image         *image)
> +{
> +   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)
> drv_chain;
> +   struct wsi_display           *wsi = chain->wsi;
> +   VkResult                     result;
> +   int                          ret;
> +   uint32_t                     drm_format = 0;
> +
> +   for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
> +      if (create_info->imageFormat == available_surface_formats[i].format)
> {
> +         drm_format = available_surface_formats[i].drm_format;
> +         break;
> +      }
> +   }
> +
> +   /* the application provided an invalid format, bail */
> +   if (drm_format == 0)
> +      return VK_ERROR_DEVICE_LOST;
> +
> +   result = wsi_create_native_image(&chain->base, create_info,
> +                                    0, NULL, NULL,
> +                                    &image->base);
> +   if (result != VK_SUCCESS)
> +      return result;
> +
> +   memset(image->buffer, 0, sizeof (image->buffer));
> +
> +   for (unsigned int i = 0; i < image->base.num_planes; i++) {
> +      ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i],
> &image->buffer[i]);
> +
> +      close(image->base.fds[i]);
> +      image->base.fds[i] = -1;
> +      if (ret < 0)
> +         goto fail_handle;
> +   }
> +
> +   image->chain = chain;
> +   image->state = WSI_IMAGE_IDLE;
> +   image->fb_id = 0;
> +
> +   ret = drmModeAddFB2(wsi->fd,
> +                       create_info->imageExtent.width,
> +                       create_info->imageExtent.height,
> +                       drm_format,
> +                       image->buffer,
> +                       image->base.row_pitches,
> +                       image->base.offsets,
> +                       &image->fb_id, 0);
> +
> +   if (ret)
> +      goto fail_fb;
> +
> +   return VK_SUCCESS;
> +
> +fail_fb:
> +fail_handle:
> +   for (unsigned int i = 0; i < image->base.num_planes; i++) {
> +      if (image->buffer[i])
> +         wsi_display_destroy_buffer(wsi, image->buffer[i]);
> +      if (image->base.fds[i] != -1) {
> +         close(image->base.fds[i]);
> +         image->base.fds[i] = -1;
> +      }
> +   }
> +
> +   wsi_destroy_image(&chain->base, &image->base);
> +
> +   return VK_ERROR_OUT_OF_HOST_MEMORY;
> +}
> +
> +static void
> +wsi_display_image_finish(struct wsi_swapchain           *drv_chain,
> +                         const VkAllocationCallbacks    *allocator,
> +                         struct wsi_display_image       *image)
> +{
> +   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)
> drv_chain;
> +   struct wsi_display           *wsi = chain->wsi;
> +
> +   drmModeRmFB(wsi->fd, image->fb_id);
> +   for (unsigned int i = 0; i < image->base.num_planes; i++)
> +      wsi_display_destroy_buffer(wsi, image->buffer[i]);
> +   wsi_destroy_image(&chain->base, &image->base);
> +}
> +
> +static VkResult
> +wsi_display_swapchain_destroy(struct wsi_swapchain
> *drv_chain,
> +                              const VkAllocationCallbacks
>  *allocator)
> +{
> +   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)
> drv_chain;
> +
> +   for (uint32_t i = 0; i < chain->base.image_count; i++)
> +      wsi_display_image_finish(drv_chain, allocator, &chain->images[i]);
> +   vk_free(allocator, chain);
> +   return VK_SUCCESS;
> +}
> +
> +static struct wsi_image *
> +wsi_display_get_wsi_image(struct wsi_swapchain  *drv_chain,
> +                          uint32_t              image_index)
> +{
> +   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)
> drv_chain;
> +
> +   return &chain->images[image_index].base;
> +}
> +
> +static void
> +wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
> +{
> +   struct wsi_display_swapchain *chain = active_image->chain;
> +
> +   wsi_display_debug("idle everyone but %ld\n", active_image -
> &(chain->images[0]));
> +   for (uint32_t i = 0; i < chain->base.image_count; i++)
> +      if (chain->images[i].state == WSI_IMAGE_DISPLAYING &&
> &chain->images[i] != active_image) {
> +         wsi_display_debug("idle %d\n", i);
> +         chain->images[i].state = WSI_IMAGE_IDLE;
> +      }
> +}
> +
> +static VkResult
> +_wsi_display_queue_next(struct wsi_swapchain     *drv_chain);
> +
> +static void
> +wsi_display_page_flip_handler2(int              fd,
> +                               unsigned int     frame,
> +                               unsigned int     sec,
> +                               unsigned int     usec,
> +                               uint32_t         crtc_id,
> +                               void             *data)
> +{
> +   struct wsi_display_image     *image = data;
> +   struct wsi_display_swapchain *chain = image->chain;
> +   VkResult                     status;
> +
> +   wsi_display_debug("image %ld displayed at %d\n", image -
> &(image->chain->images[0]), frame);
> +   image->state = WSI_IMAGE_DISPLAYING;
> +   wsi_display_idle_old_displaying(image);
> +   status = _wsi_display_queue_next(&(chain->base));
> +   if (status != VK_SUCCESS)
> +      chain->status = status;
> +}
> +
> +static void wsi_display_page_flip_handler(int fd, unsigned int frame,
> +                                          unsigned int sec, unsigned int
> usec, void *data)
> +{
> +   wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
> +}
> +
> +static drmEventContext event_context = {
> +   .version = DRM_EVENT_CONTEXT_VERSION,
> +   .page_flip_handler = wsi_display_page_flip_handler,
> +#if DRM_EVENT_CONTEXT_VERSION >= 3
> +   .page_flip_handler2 = wsi_display_page_flip_handler2,
> +#endif
> +};
> +
> +static void *
> +wsi_display_wait_thread(void *data)
> +{
> +   struct wsi_display   *wsi = data;
> +   struct pollfd pollfd = {
> +      .fd = wsi->fd,
> +      .events = POLLIN
> +   };
> +   int ret;
> +
> +   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
> +   for (;;) {
> +      ret = poll(&pollfd, 1, -1);
> +      if (ret > 0) {
> +         pthread_mutex_lock(&wsi->wait_mutex);
> +         (void) drmHandleEvent(wsi->fd, &event_context);
> +         pthread_mutex_unlock(&wsi->wait_mutex);
> +         pthread_cond_broadcast(&wsi->wait_cond);
> +      }
> +   }
> +   return NULL;
> +}
> +
> +static int
> +wsi_display_start_wait_thread(struct wsi_display        *wsi)
> +{
> +   if (!wsi->wait_thread) {
> +      int ret = pthread_create(&wsi->wait_thread, NULL,
> wsi_display_wait_thread, wsi);
> +      if (ret)
> +         return ret;
> +   }
> +   return 0;
> +}
> +
> +/*
> + * Wait for at least one event from the kernel to be processed.
> + * Call with wait_mutex held
> + */
> +static int
> +wsi_display_wait_for_event(struct wsi_display           *wsi,
> +                           uint64_t                     timeout_ns)
> +{
> +   int ret;
> +
> +   ret = wsi_display_start_wait_thread(wsi);
> +
> +   if (ret)
> +      return ret;
> +
> +   struct timespec abs_timeout = {
> +      .tv_sec = timeout_ns / ((uint64_t) 1000 * (uint64_t) 1000 *
> (uint64_t) 1000),
> +      .tv_nsec = timeout_ns % ((uint64_t) 1000 * (uint64_t) 1000 *
> (uint64_t) 1000)
> +   };
> +
> +   ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex,
> &abs_timeout);
> +
> +   wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(),
> ret);
> +   return ret;
> +}
> +
> +static VkResult
> +wsi_display_acquire_next_image(struct wsi_swapchain     *drv_chain,
> +                               uint64_t                 timeout,
> +                               VkSemaphore              semaphore,
> +                               uint32_t                 *image_index)
> +{
> +   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain
> *)drv_chain;
> +   struct wsi_display           *wsi = chain->wsi;
> +   int                          ret = 0;
> +   VkResult                     result = VK_SUCCESS;
> +
> +   /* Bail early if the swapchain is broken */
> +   if (chain->status != VK_SUCCESS)
> +      return chain->status;
> +
> +   if (timeout != 0 && timeout != UINT64_MAX)
> +      timeout += wsi_get_current_monotonic();
> +
> +   pthread_mutex_lock(&wsi->wait_mutex);
> +   for (;;) {
> +      for (uint32_t i = 0; i < chain->base.image_count; i++) {
> +         if (chain->images[i].state == WSI_IMAGE_IDLE) {
> +            *image_index = i;
> +            wsi_display_debug("image %d available\n", i);
> +            chain->images[i].state = WSI_IMAGE_DRAWING;
> +            result = VK_SUCCESS;
> +            goto done;
> +         }
> +         wsi_display_debug("image %d state %d\n", i,
> chain->images[i].state);
> +      }
> +
> +      if (ret == ETIMEDOUT) {
> +         result = VK_TIMEOUT;
> +         goto done;
> +      }
> +
> +      ret = wsi_display_wait_for_event(wsi, timeout);
> +
> +      if (ret && ret != ETIMEDOUT) {
> +         result = VK_ERROR_OUT_OF_DATE_KHR;
> +         goto done;
> +      }
> +   }
> +done:
> +   pthread_mutex_unlock(&wsi->wait_mutex);
> +
> +   if (result != VK_SUCCESS)
> +      return result;
> +
> +   return chain->status;
> +}
> +
> +/*
> + * Check whether there are any other connectors driven by this crtc
> + */
> +static bool
> +wsi_display_crtc_solo(struct wsi_display        *wsi,
> +                      drmModeResPtr             mode_res,
> +                      drmModeConnectorPtr       connector,
> +                      uint32_t                  crtc_id)
> +{
> +   int                  c, e;
> +
> +   /* See if any other connectors share the same encoder */
> +   for (c = 0; c < mode_res->count_connectors; c++) {
> +      if (mode_res->connectors[c] == connector->connector_id)
> +         continue;
> +
> +      drmModeConnectorPtr other_connector = drmModeGetConnector(wsi->fd,
> mode_res->connectors[c]);
> +      if (other_connector) {
> +         bool match = (other_connector->encoder_id ==
> connector->encoder_id);
> +         drmModeFreeConnector(other_connector);
> +         if (match)
> +            return false;
> +      }
> +   }
> +
> +   /* See if any other encoders share the same crtc */
> +   for (e = 0; e < mode_res->count_encoders; e++) {
> +      if (mode_res->encoders[e] == connector->encoder_id)
> +         continue;
> +
> +      drmModeEncoderPtr other_encoder = drmModeGetEncoder(wsi->fd,
> mode_res->encoders[e]);
> +      if (other_encoder) {
> +         bool match = (other_encoder->crtc_id == crtc_id);
> +         drmModeFreeEncoder(other_encoder);
> +         if (match)
> +            return false;
> +      }
> +   }
> +   return true;
> +}
> +
> +/*
> + * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
> + * currently driving this connector and not any others. Settle for a CRTC
> + * which is currently idle.
> + */
> +static uint32_t
> +wsi_display_select_crtc(struct wsi_display_connector    *connector,
> +                        drmModeResPtr                   mode_res,
> +                        drmModeConnectorPtr             drm_connector)
> +{
> +   struct wsi_display   *wsi = connector->wsi;
> +   int                  c;
> +   uint32_t             crtc_id;
> +
> +   /* See what CRTC is currently driving this connector */
> +   if (drm_connector->encoder_id) {
> +      drmModeEncoderPtr encoder = drmModeGetEncoder(wsi->fd,
> drm_connector->encoder_id);
> +      if (encoder) {
> +         crtc_id = encoder->crtc_id;
> +         drmModeFreeEncoder(encoder);
> +         if (crtc_id) {
> +            if (wsi_display_crtc_solo(wsi, mode_res, drm_connector,
> crtc_id))
> +               return crtc_id;
> +         }
> +      }
> +   }
> +   crtc_id = 0;
> +   for (c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
> +      drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
> +      if (crtc && crtc->buffer_id == 0)
> +         crtc_id = crtc->crtc_id;
> +      drmModeFreeCrtc(crtc);
> +   }
> +   return crtc_id;
> +}
> +
> +static VkResult
> +wsi_display_setup_connector(wsi_display_connector       *connector,
> +                            wsi_display_mode            *display_mode)
> +{
> +   struct wsi_display   *wsi = connector->wsi;
> +   drmModeModeInfoPtr   drm_mode;
> +   drmModeConnectorPtr  drm_connector;
> +   drmModeResPtr        mode_res;
> +   VkResult             result;
> +   int                  m;
> +
> +   if (connector->current_mode == display_mode && connector->crtc_id)
> +      return VK_SUCCESS;
> +
> +   mode_res = drmModeGetResources(wsi->fd);
> +   if (!mode_res) {
> +      if (errno == ENOMEM)
> +         result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      else
> +         result = VK_ERROR_OUT_OF_DATE_KHR;
> +      goto bail;
> +   }
> +
> +   drm_connector = drmModeGetConnectorCurrent(wsi->fd, connector->id);
> +   if (!drm_connector) {
> +      if (errno == ENOMEM)
> +         result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      else
> +         result = VK_ERROR_OUT_OF_DATE_KHR;
> +      goto bail_mode_res;
> +   }
> +
> +   /* Pick a CRTC if we don't have one */
> +   if (!connector->crtc_id) {
> +      connector->crtc_id = wsi_display_select_crtc(connector, mode_res,
> drm_connector);
> +      if (!connector->crtc_id) {
> +         result = VK_ERROR_OUT_OF_DATE_KHR;
> +         goto bail_connector;
> +      }
> +   }
> +
> +   if (connector->current_mode != display_mode) {
> +
> +      /* Find the drm mode cooresponding to the requested VkDisplayMode */
> +      drm_mode = NULL;
> +      for (m = 0; m < drm_connector->count_modes; m++) {
> +         drm_mode = &drm_connector->modes[m];
> +         if (wsi_display_mode_matches_drm(display_mode, drm_mode))
> +            break;
> +         drm_mode = NULL;
> +      }
> +
> +      if (!drm_mode) {
> +         result = VK_ERROR_OUT_OF_DATE_KHR;
> +         goto bail_connector;
> +      }
> +
> +      connector->current_mode = display_mode;
> +      connector->current_drm_mode = *drm_mode;
> +   }
> +
> +   result = VK_SUCCESS;
> +
> +bail_connector:
> +   drmModeFreeConnector(drm_connector);
> +bail_mode_res:
> +   drmModeFreeResources(mode_res);
> +bail:
> +   return result;
> +
> +}
> +
> +/*
> + * Check to see if the kernel has no flip queued and if there's an image
> + * waiting to be displayed.
> + */
> +static VkResult
> +_wsi_display_queue_next(struct wsi_swapchain     *drv_chain)
> +{
> +   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)
> drv_chain;
> +   struct wsi_display           *wsi = chain->wsi;
> +   uint32_t                     i;
> +   struct wsi_display_image     *image = NULL;
> +   VkIcdSurfaceDisplay          *surface = chain->surface;
> +   wsi_display_mode             *display_mode =
> wsi_display_mode_from_handle(surface->displayMode);
> +   wsi_display_connector        *connector = display_mode->connector;
> +   int                          ret;
> +   VkResult                     result;
> +
> +   if (wsi->fd < 0)
> +      return VK_ERROR_INITIALIZATION_FAILED;
> +
> +   if (display_mode != connector->current_mode)
> +      connector->active = false;
> +
> +   for (;;) {
> +      /* Check to see if there is an image to display, or if some image
> is already queued */
> +
> +      for (i = 0; i < chain->base.image_count; i++) {
> +         struct wsi_display_image  *tmp_image = &chain->images[i];
> +
> +         switch (tmp_image->state) {
> +         case WSI_IMAGE_FLIPPING:
> +            /* already flipping, don't send another to the kernel yet */
> +            return VK_SUCCESS;
> +         case WSI_IMAGE_QUEUED:
> +            /* find the oldest queued */
> +            if (!image || tmp_image->flip_sequence < image->flip_sequence)
> +               image = tmp_image;
> +            break;
> +         default:
> +            break;
> +         }
> +      }
> +
> +      if (!image)
> +         return VK_SUCCESS;
> +
> +      if (connector->active) {
> +         ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
> +                               DRM_MODE_PAGE_FLIP_EVENT, image);
> +         if (ret == 0) {
> +            image->state = WSI_IMAGE_FLIPPING;
> +            return VK_SUCCESS;
> +         }
> +         wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
> +      } else {
> +         ret = -EINVAL;
> +      }
> +
> +      if (ret) {
> +         switch(-ret) {
> +         case EINVAL:
> +
> +            result = wsi_display_setup_connector(connector,
> display_mode);
> +
> +            if (result != VK_SUCCESS) {
> +               image->state = WSI_IMAGE_IDLE;
> +               return result;
> +            }
> +
> +            /* XXX allow setting of position */
> +
> +            ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
> image->fb_id, 0, 0,
> +                                 &connector->id, 1,
> &connector->current_drm_mode);
> +
> +            if (ret == 0) {
> +               image->state = WSI_IMAGE_DISPLAYING;
> +
> +               /* Assume that the mode set is synchronous and that any
> +                * previous image is now idle.
> +                */
> +               wsi_display_idle_old_displaying(image);
> +               connector->active = true;
> +               return VK_SUCCESS;
> +            }
> +            break;
> +         case EACCES:
> +
> +            /* Some other VT is currently active. Sit here waiting for
> +             * our VT to become active again by polling once a second
> +             */
> +            usleep(1000 * 1000);
> +            connector->active = false;
> +            break;
> +         default:
> +            connector->active = false;
> +            image->state = WSI_IMAGE_IDLE;
> +            return VK_ERROR_OUT_OF_DATE_KHR;
> +         }
> +      }
> +   }
> +}
> +
> +static VkResult
> +wsi_display_queue_present(struct wsi_swapchain          *drv_chain,
> +                          uint32_t                      image_index,
> +                          const VkPresentRegionKHR      *damage)
> +{
> +   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)
> drv_chain;
> +   struct wsi_display           *wsi = chain->wsi;
> +   struct wsi_display_image     *image = &chain->images[image_index];
> +   VkResult                     result;
> +
> +   /* Bail early if the swapchain is broken */
> +   if (chain->status != VK_SUCCESS)
> +      return chain->status;
> +
> +   assert(image->state == WSI_IMAGE_DRAWING);
> +   wsi_display_debug("present %d\n", image_index);
> +
> +   pthread_mutex_lock(&wsi->wait_mutex);
> +
> +   image->flip_sequence = ++chain->flip_sequence;
> +   image->state = WSI_IMAGE_QUEUED;
> +
> +   result = _wsi_display_queue_next(drv_chain);
> +   if (result != VK_SUCCESS)
> +      chain->status = result;
> +
> +   pthread_mutex_unlock(&wsi->wait_mutex);
> +
> +   if (result != VK_SUCCESS)
> +      return result;
> +
> +   return chain->status;
> +}
> +
> +static VkResult
> +wsi_display_surface_create_swapchain(VkIcdSurfaceBase
>  *icd_surface,
> +                                     VkDevice
>  device,
> +                                     struct wsi_device
> *wsi_device,
> +                                     int
> local_fd,
> +                                     const VkSwapchainCreateInfoKHR
>  *create_info,
> +                                     const VkAllocationCallbacks
> *allocator,
> +                                     struct wsi_swapchain
>  **swapchain_out)
> +{
> +   struct wsi_display *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   VkResult result;
> +
> +   assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_
> CREATE_INFO_KHR);
> +
> +   struct wsi_display_swapchain *chain;
> +   const unsigned num_images = create_info->minImageCount;
> +   size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
> +
> +   chain = vk_zalloc(allocator, size, 8,
> +                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
> +
> +   if (chain == NULL)
> +      return VK_ERROR_OUT_OF_HOST_MEMORY;
> +
> +   result = wsi_swapchain_init(wsi_device, &chain->base, device,
> +                               create_info, allocator);
> +
> +   chain->base.destroy = wsi_display_swapchain_destroy;
> +   chain->base.get_wsi_image = wsi_display_get_wsi_image;
> +   chain->base.acquire_next_image = wsi_display_acquire_next_image;
> +   chain->base.queue_present = wsi_display_queue_present;
> +   chain->base.present_mode = create_info->presentMode;
> +   chain->base.image_count = num_images;
> +
> +   chain->wsi = wsi;
> +   chain->status = VK_SUCCESS;
> +
> +   chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
> +
> +   for (uint32_t image = 0; image < chain->base.image_count; image++) {
> +      result = wsi_display_image_init(device, &chain->base, create_info,
> allocator,
> +                                      &chain->images[image]);
> +      if (result != VK_SUCCESS) {
> +         while (image > 0) {
> +            --image;
> +            wsi_display_image_finish(&chain->base, allocator,
> &chain->images[image]);
> +         }
> +         vk_free(allocator, chain);
> +         goto fail_init_images;
> +      }
> +   }
> +
> +   *swapchain_out = &chain->base;
> +
> +   return VK_SUCCESS;
> +
> +fail_init_images:
> +   return result;
> +}
> +
> +VkResult
> +wsi_display_init_wsi(struct wsi_device *wsi_device,
> +                     const VkAllocationCallbacks *alloc,
> +                     int display_fd)
> +{
> +   struct wsi_display *wsi;
> +   VkResult result;
> +
> +   wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
> +                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
> +   if (!wsi) {
> +      result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      goto fail;
> +   }
> +
> +   wsi->fd = display_fd;
> +
> +   pthread_mutex_init(&wsi->wait_mutex, NULL);
> +   wsi->alloc = alloc;
> +
> +   LIST_INITHEAD(&wsi->connectors);
> +
> +   pthread_condattr_t condattr;
> +   int ret;
> +
> +   ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
> +   if (ret) {
> +      result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      goto fail_mutex;
> +   }
> +
> +   ret = pthread_condattr_init(&condattr);
> +   if (ret) {
> +      result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      goto fail_condattr;
> +   }
> +
> +   ret = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
> +   if (ret) {
> +      result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      goto fail_setclock;
> +   }
> +
> +   ret = pthread_cond_init(&wsi->wait_cond, &condattr);
> +   if (ret) {
> +      result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      goto fail_cond;
> +   }
> +
> +   pthread_condattr_destroy(&condattr);
> +
> +   wsi->base.get_support = wsi_display_surface_get_support;
> +   wsi->base.get_capabilities = wsi_display_surface_get_capabilities;
> +   wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
> +   wsi->base.get_formats = wsi_display_surface_get_formats;
> +   wsi->base.get_formats2 = wsi_display_surface_get_formats2;
> +   wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
> +   wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
> +
> +   wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
> +
> +   return VK_SUCCESS;
> +
> +fail_cond:
> +fail_setclock:
> +   pthread_condattr_destroy(&condattr);
> +fail_condattr:
> +   pthread_mutex_destroy(&wsi->wait_mutex);
> +fail_mutex:
> +   vk_free(alloc, wsi);
> +fail:
> +   return result;
> +}
> +
> +void
> +wsi_display_finish_wsi(struct wsi_device *wsi_device,
> +                       const VkAllocationCallbacks *alloc)
> +{
> +   struct wsi_display *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +
> +   if (wsi) {
> +
> +      struct wsi_display_connector *connector, *connector_storage;
> +      LIST_FOR_EACH_ENTRY_SAFE(connector, connector_storage,
> &wsi->connectors, list) {
> +         struct wsi_display_mode *mode, *mode_storage;
> +         LIST_FOR_EACH_ENTRY_SAFE(mode, mode_storage,
> &connector->display_modes, list) {
> +            vk_free(wsi->alloc, mode);
> +         }
> +         vk_free(wsi->alloc, connector);
> +      }
> +
> +      pthread_mutex_lock(&wsi->wait_mutex);
> +      if (wsi->wait_thread) {
> +         pthread_cancel(wsi->wait_thread);
> +         pthread_join(wsi->wait_thread, NULL);
> +      }
> +      pthread_mutex_unlock(&wsi->wait_mutex);
> +      pthread_mutex_destroy(&wsi->wait_mutex);
> +      pthread_cond_destroy(&wsi->wait_cond);
> +
> +      vk_free(alloc, wsi);
> +   }
> +}
> diff --git a/src/vulkan/wsi/wsi_common_display.h
> b/src/vulkan/wsi/wsi_common_display.h
> new file mode 100644
> index 00000000000..b414a226293
> --- /dev/null
> +++ b/src/vulkan/wsi/wsi_common_display.h
> @@ -0,0 +1,72 @@
> +/*
> + * Copyright © 2017 Keith Packard
> + *
> + * Permission to use, copy, modify, distribute, and sell this software
> and its
> + * documentation for any purpose is hereby granted without fee, provided
> that
> + * the above copyright notice appear in all copies and that both that
> copyright
> + * notice and this permission notice appear in supporting documentation,
> and
> + * that the name of the copyright holders not be used in advertising or
> + * publicity pertaining to distribution of the software without specific,
> + * written prior permission.  The copyright holders make no
> representations
> + * about the suitability of this software for any purpose.  It is
> provided "as
> + * is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> SOFTWARE,
> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
> OR
> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
> USE,
> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
> PERFORMANCE
> + * OF THIS SOFTWARE.
> + */
> +
> +#ifndef WSI_COMMON_DISPLAY_H
> +#define WSI_COMMON_DISPLAY_H
> +
> +#include "wsi_common.h"
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +
> +#define typed_memcpy(dest, src, count) ({ \
> +   STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \
> +   memcpy((dest), (src), (count) * sizeof(*(src))); \
> +})
> +
> +VkResult
> +wsi_display_get_physical_device_display_properties(VkPhysicalDevice
>        physical_device,
> +                                                   struct wsi_device
>       *wsi_device,
> +                                                   uint32_t
>        *property_count,
> +
>  VkDisplayPropertiesKHR       *properties);
> +VkResult
> +wsi_display_get_physical_device_display_plane_properties(VkPhysicalDevice
>              physical_device,
> +                                                         struct
> wsi_device              *wsi_device,
> +                                                         uint32_t
>                *property_count,
> +
>  VkDisplayPlanePropertiesKHR    *properties);
> +
> +VkResult
> +wsi_display_get_display_plane_supported_displays(VkPhysicalDevice
>        physical_device,
> +                                                 struct wsi_device
>       *wsi_device,
> +                                                 uint32_t
>        plane_index,
> +                                                 uint32_t
>        *display_count,
> +                                                 VkDisplayKHR
>        *displays);
> +VkResult
> +wsi_display_get_display_mode_properties(VkPhysicalDevice
>  physical_device,
> +                                        struct wsi_device
> *wsi_device,
> +                                        VkDisplayKHR
>  display,
> +                                        uint32_t
>  *property_count,
> +                                        VkDisplayModePropertiesKHR
>  *properties);
> +
> +VkResult
> +wsi_get_display_plane_capabilities(VkPhysicalDevice
>  physical_device,
> +                                   struct wsi_device
> *wsi_device,
> +                                    VkDisplayModeKHR
> mode_khr,
> +                                    uint32_t
> plane_index,
> +                                    VkDisplayPlaneCapabilitiesKHR
>  *capabilities);
> +
> +VkResult
> +wsi_create_display_surface(VkInstance instance,
> +                           const VkAllocationCallbacks *pAllocator,
> +                           const VkDisplaySurfaceCreateInfoKHR
> *pCreateInfo,
> +                           VkSurfaceKHR *pSurface);
> +
> +#endif
> diff --git a/src/vulkan/wsi/wsi_common_private.h
> b/src/vulkan/wsi/wsi_common_private.h
> index b608119b969..6993750aac4 100644
> --- a/src/vulkan/wsi/wsi_common_private.h
> +++ b/src/vulkan/wsi/wsi_common_private.h
> @@ -140,6 +140,15 @@ void wsi_wl_finish_wsi(struct wsi_device *wsi_device,
>                         const VkAllocationCallbacks *alloc);
>
>
> +VkResult
> +wsi_display_init_wsi(struct wsi_device *wsi_device,
> +                     const VkAllocationCallbacks *alloc,
> +                     int display_fd);
> +
> +void
> +wsi_display_finish_wsi(struct wsi_device *wsi_device,
> +                       const VkAllocationCallbacks *alloc);
> +
>  #define WSI_DEFINE_NONDISP_HANDLE_CASTS(__wsi_type, __VkType)
>   \
>
>   \
>     static inline struct __wsi_type *
>  \
> --
> 2.16.2
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20180404/63dcc5f9/attachment-0001.html>


More information about the mesa-dev mailing list