<div dir="ltr"><div><div>I apologize for how nit-picky this is going to get but it's starting to bother me...<br><br></div>Because it's nitpicky, I just made a bunch of changes and put it in a couple of fixup commits:<br><br><a href="https://gitlab.freedesktop.org/jekstrand/mesa/commit/98e9cbd3b46453254b1aeba1edf5aa1a22cce168">https://gitlab.freedesktop.org/jekstrand/mesa/commit/98e9cbd3b46453254b1aeba1edf5aa1a22cce168</a><br><a href="https://gitlab.freedesktop.org/jekstrand/mesa/commit/6e6ae7f9455f7c9040b59b384b6f939f4f9dcbed">https://gitlab.freedesktop.org/jekstrand/mesa/commit/6e6ae7f9455f7c9040b59b384b6f939f4f9dcbed</a><br><br></div>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. :/<br><div><div><div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Mar 7, 2018 at 11:24 PM, Keith Packard <span dir="ltr"><<a href="mailto:keithp@keithp.com" target="_blank">keithp@keithp.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This adds support for the KHR_display extension support to the vulkan<br>
WSI layer. Driver support will be added separately.<br>
<br>
v2:<br>
        * fix double ;; in wsi_common_display.c<br>
<br>
        * Move mode list from wsi_display to wsi_display_connector<br>
<br>
        * Fix scope for wsi_display_mode andwsi_display_connector<br>
          allocs<br>
<br>
        * Switch all allocations to vk_zalloc instead of vk_alloc.<br>
<br>
        * Fix DRM failure in<br>
          wsi_display_get_physical_<wbr>device_display_properties<br>
<br>
          When DRM fails, or when we don't have a master fd<br>
          (presumably due to application errors), just return 0<br>
          properties from this function, which is at least a valid<br>
          response.<br>
<br>
        * Use vk_outarray for all property queries<br>
<br>
          This is a bit less error-prone than open-coding the same<br>
          stuff.<br>
<br>
        * Remove VK_COMPOSITE_ALPHA_INHERIT_<wbr>BIT_KHR from surface caps<br>
<br>
          Until we have multi-plane support, we shouldn't pretend to<br>
          have any multi-plane semantics, even if undefined.<br>
<br>
        Suggested-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
<br>
        * Simplify addition of VK_USE_PLATFORM_DISPLAY_KHR to<br>
          vulkan_wsi_args<br>
<br>
        Suggested-by: Eric Engestrom <<a href="mailto:eric.engestrom@imgtec.com">eric.engestrom@imgtec.com</a>><br>
<br>
v3:<br>
        Add separate 'display_fd' and 'render_fd' arguments to<br>
        wsi_device_init API. This allows drivers to use different FDs<br>
        for the different aspects of the device.<br>
<br>
        Use largest mode as display size when no preferred mode.<br>
<br>
        If the display doesn't provide a preferred mode, we'll assume<br>
        that the largest supported mode is the "physical size" of the<br>
        device and report that.<br>
<br>
v4:<br>
        Make wsi_image_state enumeration values uppercase.<br>
        Follow more common mesa conventions.<br>
<br>
        Remove 'render_fd' from wsi_device_init API.  The<br>
        wsi_common_display code doesn't use this fd at all, so stop<br>
        passing it in. This avoids any potential confusion over which<br>
        fd to use when creating display-relative object handles.<br>
<br>
        Remove call to wsi_create_prime_image which would never have<br>
        been reached as the necessary condition (use_prime_blit) is<br>
        never set.<br>
<br>
        whitespace cleanups in wsi_common_display.c<br>
<br>
        Suggested-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
<br>
        Add depth/bpp info to available surface formats.  Instead of<br>
        hard-coding depth 24 bpp 32 in the drmModeAddFB call, use the<br>
        requested format to find suitable values.<br>
<br>
        Destroy kernel buffers and FBs when swapchain is destroyed. We<br>
        were leaking both of these kernel objects across swapchain<br>
        destruction.<br>
<br>
        Note that wsi_display_wait_for_event waits for anything to<br>
        happen.  wsi_display_wait_for_event is simply a yield so that<br>
        the caller can then check to see if the desired state change<br>
        has occurred.<br>
<br>
        Record swapchain failures in chain for later return. If some<br>
        asynchronous swapchain activity fails, we need to tell the<br>
        application eventually. Record the failure in the swapchain<br>
        and report it at the next acquire_next_image or queue_present<br>
        call.<br>
<br>
        Fix error returns from wsi_display_setup_connector.  If a<br>
        malloc failed, then the result should be<br>
        VK_ERROR_OUT_OF_HOST_MEMORY. Otherwise, the associated ioctl<br>
        failed and we're either VT switched away, or our lease has<br>
        been revoked, in which case we should return<br>
        VK_ERROR_OUT_OF_DATE_KHR.<br>
<br>
        Make sure both sides of if/else brace use matches<br>
<br>
        Note that we assume drmModeSetCrtc is synchronous. Add a<br>
        comment explaining why we can idle any previous displayed<br>
        image as soon as the mode set returns.<br>
<br>
        Note that EACCES from drmModePageFlip means VT inactive.  When<br>
        vt switched away drmModePageFlip returns EACCES. Poll once a<br>
        second waiting until we get some other return value back.<br>
<br>
        Clean up after alloc failure in<br>
        wsi_display_surface_create_<wbr>swapchain. Destroy any created<br>
        images, free the swapchain.<br>
<br>
        Remove physical_device from wsi_display_init_wsi. We never<br>
        need this value, so remove it from the API and from the<br>
        internal wsi_display structure.<br>
<br>
        Use drmModeAddFB2 in wsi_display_image_init.  This takes a drm<br>
        format instead of depth/bpp, which provides more control over<br>
        the format of the data.<br>
<br>
Signed-off-by: Keith Packard <<a href="mailto:keithp@keithp.com">keithp@keithp.com</a>><br>
---<br>
 <a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a>                        |    1 +<br>
 meson.build                         |    4 +-<br>
 src/amd/vulkan/radv_device.c        |    8 +<br>
 src/amd/vulkan/radv_private.h       |    1 +<br>
 src/amd/vulkan/radv_wsi.c           |    3 +-<br>
 src/intel/vulkan/anv_device.c       |    4 +<br>
 src/intel/vulkan/anv_private.h      |    1 +<br>
 src/intel/vulkan/anv_wsi.c          |    3 +-<br>
 src/vulkan/Makefile.am              |    7 +<br>
 src/vulkan/Makefile.sources         |    4 +<br>
 src/vulkan/wsi/meson.build          |    8 +<br>
 src/vulkan/wsi/wsi_common.c         |   19 +-<br>
 src/vulkan/wsi/wsi_common.h         |    5 +-<br>
 src/vulkan/wsi/wsi_common_<wbr>display.c | 1401 ++++++++++++++++++++++++++++++<wbr>+++++<br>
 src/vulkan/wsi/wsi_common_<wbr>display.h |   72 ++<br>
 src/vulkan/wsi/wsi_common_<wbr>private.h |    9 +<br>
 16 files changed, 1544 insertions(+), 6 deletions(-)<br>
 create mode 100644 src/vulkan/wsi/wsi_common_<wbr>display.c<br>
 create mode 100644 src/vulkan/wsi/wsi_common_<wbr>display.h<br>
<br>
diff --git a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a> b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
index 172da6b443c..7fcb3220eaa 100644<br>
--- a/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
+++ b/<a href="http://configure.ac" rel="noreferrer" target="_blank">configure.ac</a><br>
@@ -1856,6 +1856,7 @@ fi<br>
 AM_CONDITIONAL(HAVE_PLATFORM_<wbr>X11, echo "$platforms" | grep -q 'x11')<br>
 AM_CONDITIONAL(HAVE_PLATFORM_<wbr>WAYLAND, echo "$platforms" | grep -q 'wayland')<br>
 AM_CONDITIONAL(HAVE_PLATFORM_<wbr>DRM, echo "$platforms" | grep -q 'drm')<br>
+AM_CONDITIONAL(HAVE_PLATFORM_<wbr>DISPLAY, echo "$platforms" | grep -q 'drm')<br>
 AM_CONDITIONAL(HAVE_PLATFORM_<wbr>SURFACELESS, echo "$platforms" | grep -q 'surfaceless')<br>
 AM_CONDITIONAL(HAVE_PLATFORM_<wbr>ANDROID, echo "$platforms" | grep -q 'android')<br>
<br>
diff --git a/meson.build b/meson.build<br>
index 8a17d7f240a..788aed6e159 100644<br>
--- a/meson.build<br>
+++ b/meson.build<br>
@@ -239,11 +239,12 @@ with_platform_wayland = false<br>
 with_platform_x11 = false<br>
 with_platform_drm = false<br>
 with_platform_surfaceless = false<br>
+with_platform_display = false<br>
 egl_native_platform = ''<br>
 _platforms = get_option('platforms')<br>
 if _platforms == 'auto'<br>
   if system_has_kms_drm<br>
-    _platforms = 'x11,wayland,drm,surfaceless'<br>
+    _platforms = 'x11,wayland,drm,surfaceless,<wbr>display'<br>
   elif ['darwin', 'windows', 'cygwin'].contains(host_<wbr>machine.system())<br>
     _platforms = 'x11,surfaceless'<br>
   elif ['haiku'].contains(host_<wbr>machine.system())<br>
@@ -260,6 +261,7 @@ if _platforms != ''<br>
   with_platform_drm = _split.contains('drm')<br>
   with_platform_haiku = _split.contains('haiku')<br>
   with_platform_surfaceless = _split.contains('surfaceless')<br>
+  with_platform_display = _split.contains('display')<br>
   egl_native_platform = _split[0]<br>
 endif<br>
<br>
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c<br>
index 7a11e08f97c..35fd1ef6b29 100644<br>
--- a/src/amd/vulkan/radv_device.c<br>
+++ b/src/amd/vulkan/radv_device.c<br>
@@ -223,6 +223,7 @@ radv_physical_device_init(<wbr>struct radv_physical_device *device,<br>
        VkResult result;<br>
        drmVersionPtr version;<br>
        int fd;<br>
+       int master_fd = -1;<br>
<br>
        fd = open(path, O_RDWR | O_CLOEXEC);<br>
        if (fd < 0)<br>
@@ -237,6 +238,8 @@ radv_physical_device_init(<wbr>struct radv_physical_device *device,<br>
<br>
        if (strcmp(version->name, "amdgpu")) {<br>
                drmFreeVersion(version);<br>
+               if (master_fd != -1)<br>
+                       close(master_fd);<br>
                close(fd);<br>
                return VK_ERROR_INCOMPATIBLE_DRIVER;<br>
        }<br>
@@ -254,6 +257,7 @@ radv_physical_device_init(<wbr>struct radv_physical_device *device,<br>
                goto fail;<br>
        }<br>
<br>
+       device->master_fd = master_fd;<br>
        device->local_fd = fd;<br>
        device->ws->query_info(device-<wbr>>ws, &device->rad_info);<br>
<br>
@@ -317,6 +321,8 @@ radv_physical_device_init(<wbr>struct radv_physical_device *device,<br>
<br>
 fail:<br>
        close(fd);<br>
+       if (master_fd != -1)<br>
+               close(master_fd);<br>
        return result;<br>
 }<br>
<br>
@@ -327,6 +333,8 @@ radv_physical_device_finish(<wbr>struct radv_physical_device *device)<br>
        device->ws->destroy(device-><wbr>ws);<br>
        disk_cache_destroy(device-><wbr>disk_cache);<br>
        close(device->local_fd);<br>
+       if (device->master_fd != -1)<br>
+               close(device->master_fd);<br>
 }<br>
<br>
 static void *<br>
diff --git a/src/amd/vulkan/radv_private.<wbr>h b/src/amd/vulkan/radv_private.<wbr>h<br>
index 0f8ddb2e106..35a161c3671 100644<br>
--- a/src/amd/vulkan/radv_private.<wbr>h<br>
+++ b/src/amd/vulkan/radv_private.<wbr>h<br>
@@ -281,6 +281,7 @@ struct radv_physical_device {<br>
        uint8_t                                     cache_uuid[VK_UUID_SIZE];<br>
<br>
        int local_fd;<br>
+       int master_fd;<br>
        struct wsi_device                       wsi_device;<br>
<br>
        bool has_rbplus; /* if RB+ register exist */<br>
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c<br>
index 927650480a6..2840b666727 100644<br>
--- a/src/amd/vulkan/radv_wsi.c<br>
+++ b/src/amd/vulkan/radv_wsi.c<br>
@@ -41,7 +41,8 @@ radv_init_wsi(struct radv_physical_device *physical_device)<br>
        return wsi_device_init(&physical_<wbr>device->wsi_device,<br>
                               radv_physical_device_to_<wbr>handle(physical_device),<br>
                               radv_wsi_proc_addr,<br>
-                              &physical_device->instance-><wbr>alloc);<br>
+                              &physical_device->instance-><wbr>alloc,<br>
+                              physical_device->master_fd);<br>
 }<br>
<br>
 void<br>
diff --git a/src/intel/vulkan/anv_device.<wbr>c b/src/intel/vulkan/anv_device.<wbr>c<br>
index d8c4e986316..ab61e0ce339 100644<br>
--- a/src/intel/vulkan/anv_device.<wbr>c<br>
+++ b/src/intel/vulkan/anv_device.<wbr>c<br>
@@ -282,6 +282,7 @@ anv_physical_device_init(<wbr>struct anv_physical_device *device,<br>
 {<br>
    VkResult result;<br>
    int fd;<br>
+   int master_fd = -1;<br>
<br>
    brw_process_intel_debug_<wbr>variable();<br>
<br>
@@ -444,10 +445,13 @@ anv_physical_device_init(<wbr>struct anv_physical_device *device,<br>
                                                 &device->supported_extensions)<wbr>;<br>
<br>
    device->local_fd = fd;<br>
+   device->master_fd = master_fd;<br>
    return VK_SUCCESS;<br>
<br>
 fail:<br>
    close(fd);<br>
+   if (master_fd != -1)<br>
+      close(master_fd);<br>
    return result;<br>
 }<br>
<br>
diff --git a/src/intel/vulkan/anv_<wbr>private.h b/src/intel/vulkan/anv_<wbr>private.h<br>
index ee533581ab4..b2d42e1313d 100644<br>
--- a/src/intel/vulkan/anv_<wbr>private.h<br>
+++ b/src/intel/vulkan/anv_<wbr>private.h<br>
@@ -809,6 +809,7 @@ struct anv_physical_device {<br>
<br>
     struct wsi_device                       wsi_device;<br>
     int                                         local_fd;<br>
+    int                                         master_fd;<br>
 };<br>
<br>
 struct anv_instance {<br>
diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c<br>
index 20094f93e1f..a7efb1416fa 100644<br>
--- a/src/intel/vulkan/anv_wsi.c<br>
+++ b/src/intel/vulkan/anv_wsi.c<br>
@@ -48,7 +48,8 @@ anv_init_wsi(struct anv_physical_device *physical_device)<br>
    result = wsi_device_init(&physical_<wbr>device->wsi_device,<br>
                             anv_physical_device_to_handle(<wbr>physical_device),<br>
                             anv_wsi_proc_addr,<br>
-                            &physical_device->instance-><wbr>alloc);<br>
+                            &physical_device->instance-><wbr>alloc,<br>
+                            physical_device->master_fd);<br>
    if (result != VK_SUCCESS)<br>
       return result;<br>
<br>
diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am<br>
index cbffd769fa4..075eb58c82c 100644<br>
--- a/src/vulkan/Makefile.am<br>
+++ b/src/vulkan/Makefile.am<br>
@@ -58,6 +58,13 @@ AM_CPPFLAGS += \<br>
 VULKAN_WSI_SOURCES += $(VULKAN_WSI_X11_FILES)<br>
 endif<br>
<br>
+if HAVE_PLATFORM_DISPLAY<br>
+AM_CPPFLAGS += \<br>
+       -DVK_USE_PLATFORM_DISPLAY_KHR<br>
+<br>
+VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)<br>
+endif<br>
+<br>
 CLEANFILES = $(BUILT_SOURCES)<br>
<br>
 WL_DRM_XML = $(top_srcdir)/src/egl/wayland/<wbr>wayland-drm/wayland-drm.xml<br>
diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources<br>
index 101a94349c6..f0f6bcd4fd8 100644<br>
--- a/src/vulkan/Makefile.sources<br>
+++ b/src/vulkan/Makefile.sources<br>
@@ -19,6 +19,10 @@ VULKAN_WSI_X11_FILES := \<br>
        wsi/wsi_common_x11.c \<br>
        wsi/wsi_common_x11.h<br>
<br>
+VULKAN_WSI_DISPLAY_FILES := \<br>
+       wsi/wsi_common_display.c \<br>
+       wsi/wsi_common_display.h<br>
+<br>
 VULKAN_UTIL_FILES := \<br>
        util/vk_alloc.h \<br>
        util/vk_debug_report.c \<br>
diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build<br>
index 223c8ca357e..776e596984d 100644<br>
--- a/src/vulkan/wsi/meson.build<br>
+++ b/src/vulkan/wsi/meson.build<br>
@@ -59,6 +59,14 @@ if with_platform_wayland<br>
   ]<br>
 endif<br>
<br>
+if with_platform_display<br>
+  vulkan_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_<wbr>KHR'<br>
+  files_vulkan_wsi += files(<br>
+    'wsi_common_display.c',<br>
+    'wsi_common_display.h',<br>
+  )<br>
+endif<br>
+<br>
 libvulkan_wsi = static_library(<br>
   'vulkan_wsi',<br>
   files_vulkan_wsi,<br>
diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c<br>
index edba13a13de..655fe59ab0f 100644<br>
--- a/src/vulkan/wsi/wsi_common.c<br>
+++ b/src/vulkan/wsi/wsi_common.c<br>
@@ -32,7 +32,8 @@ VkResult<br>
 wsi_device_init(struct wsi_device *wsi,<br>
                 VkPhysicalDevice pdevice,<br>
                 WSI_FN_<wbr>GetPhysicalDeviceProcAddr proc_addr,<br>
-                const VkAllocationCallbacks *alloc)<br>
+                const VkAllocationCallbacks *alloc,<br>
+                int display_fd)<br>
 {<br>
    VkResult result;<br>
<br>
@@ -95,6 +96,19 @@ wsi_device_init(struct wsi_device *wsi,<br>
    }<br>
 #endif<br>
<br>
+#ifdef VK_USE_PLATFORM_DISPLAY_KHR<br>
+   result = wsi_display_init_wsi(wsi, alloc, display_fd);<br>
+   if (result != VK_SUCCESS) {<br>
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR<br>
+      wsi_wl_finish_wsi(wsi, alloc);<br>
+#endif<br>
+#ifdef VK_USE_PLATFORM_XCB_KHR<br>
+      wsi_x11_finish_wsi(wsi, alloc);<br>
+#endif<br>
+      return result;<br>
+   }<br>
+#endif<br>
+<br>
    return VK_SUCCESS;<br>
 }<br>
<br>
@@ -102,6 +116,9 @@ void<br>
 wsi_device_finish(struct wsi_device *wsi,<br>
                   const VkAllocationCallbacks *alloc)<br>
 {<br>
+#ifdef VK_USE_PLATFORM_DISPLAY_KHR<br>
+   wsi_display_finish_wsi(wsi, alloc);<br>
+#endif<br>
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR<br>
    wsi_wl_finish_wsi(wsi, alloc);<br>
 #endif<br>
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h<br>
index 6cf729ba025..b8bbf4b80c4 100644<br>
--- a/src/vulkan/wsi/wsi_common.h<br>
+++ b/src/vulkan/wsi/wsi_common.h<br>
@@ -68,7 +68,7 @@ struct wsi_format_modifier_<wbr>properties_list {<br>
<br>
 struct wsi_interface;<br>
<br>
-#define VK_ICD_WSI_PLATFORM_MAX 5<br>
+#define VK_ICD_WSI_PLATFORM_MAX 6<br>
<br>
 struct wsi_device {<br>
    VkPhysicalDevice pdevice;<br>
@@ -116,7 +116,8 @@ VkResult<br>
 wsi_device_init(struct wsi_device *wsi,<br>
                 VkPhysicalDevice pdevice,<br>
                 WSI_FN_<wbr>GetPhysicalDeviceProcAddr proc_addr,<br>
-                const VkAllocationCallbacks *alloc);<br>
+                const VkAllocationCallbacks *alloc,<br>
+                int display_fd);<br>
<br>
 void<br>
 wsi_device_finish(struct wsi_device *wsi,<br>
diff --git a/src/vulkan/wsi/wsi_common_<wbr>display.c b/src/vulkan/wsi/wsi_common_<wbr>display.c<br>
new file mode 100644<br>
index 00000000000..be31043f3de<br>
--- /dev/null<br>
+++ b/src/vulkan/wsi/wsi_common_<wbr>display.c<br>
@@ -0,0 +1,1401 @@<br>
+/*<br>
+ * Copyright © 2017 Keith Packard<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission.  The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose.  It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#include "util/macros.h"<br>
+#include <stdlib.h><br>
+#include <stdio.h><br>
+#include <unistd.h><br>
+#include <errno.h><br>
+#include <string.h><br>
+#include <fcntl.h><br>
+#include <poll.h><br>
+#include <stdbool.h><br>
+#include <math.h><br>
+#include <xf86drm.h><br>
+#include <xf86drmMode.h><br>
+#include <drm_fourcc.h><br>
+#include "util/hash_table.h"<br>
+#include "util/list.h"<br>
+<br>
+#include "vk_util.h"<br>
+#include "wsi_common_private.h"<br>
+#include "wsi_common_display.h"<br>
+#include "wsi_common_queue.h"<br>
+<br>
+#if 0<br>
+#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)<br>
+#define wsi_display_debug_code(...)     __VA_ARGS__<br>
+#else<br>
+#define wsi_display_debug(...)<br>
+#define wsi_display_debug_code(...)<br>
+#endif<br>
+<br>
+/* These have lifetime equal to the instance, so they effectively<br>
+ * never go away. This means we must keep track of them separately<br>
+ * from all other resources.<br>
+ */<br>
+typedef struct wsi_display_mode {<br>
+   struct list_head             list;<br>
+   struct wsi_display_connector *connector;<br>
+   bool                         valid;          /* was found in most recent poll */<br>
+   bool                         preferred;<br>
+   uint32_t                     clock;          /* in kHz */<br>
+   uint16_t                     hdisplay, hsync_start, hsync_end, htotal, hskew;<br>
+   uint16_t                     vdisplay, vsync_start, vsync_end, vtotal, vscan;<br>
+   uint32_t                     flags;<br>
+} wsi_display_mode;<br>
+<br>
+typedef struct wsi_display_connector {<br>
+   struct list_head             list;<br>
+   struct wsi_display           *wsi;<br>
+   uint32_t                     id;<br>
+   uint32_t                     crtc_id;<br>
+   char                         *name;<br>
+   bool                         connected;<br>
+   bool                         active;<br>
+   struct list_head             display_modes;<br>
+   wsi_display_mode             *current_mode;<br>
+   drmModeModeInfo              current_drm_mode;<br>
+} wsi_display_connector;<br>
+<br>
+struct wsi_display {<br>
+   struct wsi_interface         base;<br>
+<br>
+   const VkAllocationCallbacks  *alloc;<br>
+<br>
+   int                          fd;<br>
+<br>
+   pthread_mutex_t              wait_mutex;<br>
+   pthread_cond_t               wait_cond;<br>
+   pthread_t                    wait_thread;<br>
+<br>
+   struct list_head             connectors;<br>
+};<br>
+<br>
+enum wsi_image_state {<br>
+   WSI_IMAGE_IDLE,<br>
+   WSI_IMAGE_DRAWING,<br>
+   WSI_IMAGE_QUEUED,<br>
+   WSI_IMAGE_FLIPPING,<br>
+   WSI_IMAGE_DISPLAYING<br>
+};<br>
+<br>
+struct wsi_display_image {<br>
+   struct wsi_image             base;<br>
+   struct wsi_display_swapchain *chain;<br>
+   enum wsi_image_state         state;<br>
+   uint32_t                     fb_id;<br>
+   uint32_t                     buffer[4];<br>
+   uint64_t                     flip_sequence;<br>
+};<br>
+<br>
+struct wsi_display_swapchain {<br>
+   struct wsi_swapchain         base;<br>
+   struct wsi_display           *wsi;<br>
+   VkIcdSurfaceDisplay          *surface;<br>
+   uint64_t                     flip_sequence;<br>
+   VkResult                     status;<br>
+   struct wsi_display_image     images[0];<br>
+};<br>
+<br>
+ICD_DEFINE_NONDISP_HANDLE_<wbr>CASTS(wsi_display_mode, VkDisplayModeKHR)<br>
+ICD_DEFINE_NONDISP_HANDLE_<wbr>CASTS(wsi_display_connector, VkDisplayKHR)<br>
+<br>
+static bool<br>
+wsi_display_mode_matches_drm(<wbr>wsi_display_mode   *wsi,<br>
+                             drmModeModeInfoPtr drm)<br>
+{<br>
+   return wsi->clock == drm->clock &&<br>
+      wsi->hdisplay == drm->hdisplay &&<br>
+      wsi->hsync_start == drm->hsync_start &&<br>
+      wsi->hsync_end == drm->hsync_end &&<br>
+      wsi->htotal == drm->htotal &&<br>
+      wsi->hskew == drm->hskew &&<br>
+      wsi->vdisplay == drm->vdisplay &&<br>
+      wsi->vsync_start == drm->vsync_start &&<br>
+      wsi->vsync_end == drm->vsync_end &&<br>
+      wsi->vtotal == drm->vtotal &&<br>
+      wsi->vscan == drm->vscan &&<br>
+      wsi->flags == drm->flags;<br>
+}<br>
+<br>
+static double<br>
+wsi_display_mode_refresh(<wbr>struct wsi_display_mode        *wsi)<br>
+{<br>
+   return (double) wsi->clock * 1000.0 / ((double) wsi->htotal * (double) wsi->vtotal * (double) (wsi->vscan + 1));<br></blockquote><div><br></div><div>Please watch out for line lengths.  We generally try not to go over 80 characters unless wrapping would get super weird.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+}<br>
+<br>
+static uint64_t wsi_get_current_monotonic(<wbr>void)<br>
+{<br>
+   struct timespec tv;<br>
+<br>
+   clock_gettime(CLOCK_MONOTONIC, &tv);<br>
+   return tv.tv_nsec + tv.tv_sec*1000000000ull;<br>
+}<br>
+<br>
+static struct wsi_display_mode *<br>
+wsi_display_find_drm_mode(<wbr>struct wsi_device                 *wsi_device,<br>
+                          struct wsi_display_connector      *connector,<br>
+                          drmModeModeInfoPtr                mode)<br></blockquote><div><br></div><div>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.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+{<br>
+   struct wsi_display_mode      *display_mode;<br>
+<br>
+   LIST_FOR_EACH_ENTRY(display_<wbr>mode, &connector->display_modes, list) {<br>
+      if (wsi_display_mode_matches_drm(<wbr>display_mode, mode))<br>
+         return display_mode;<br>
+   }<br>
+   return NULL;<br>
+}<br>
+<br>
+static void<br>
+wsi_display_invalidate_<wbr>connector_modes(struct wsi_device            *wsi_device,<br>
+                                       struct wsi_display_connector *connector)<br>
+{<br>
+   struct wsi_display_mode      *display_mode;<br>
+<br>
+   LIST_FOR_EACH_ENTRY(display_<wbr>mode, &connector->display_modes, list)<br>
+      display_mode->valid = false;<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_register_drm_<wbr>mode(struct wsi_device            *wsi_device,<br>
+                              struct wsi_display_connector *connector,<br>
+                              drmModeModeInfoPtr           drm_mode)<br>
+{<br>
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br></blockquote><div><br></div><div>That's really long.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+   struct wsi_display_mode      *display_mode;<br></blockquote><div><br></div><div>This is 2018 and we don't care about compiling on VAX.  You can mix declarations and code. :-)<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+   display_mode = wsi_display_find_drm_mode(wsi_<wbr>device, connector, drm_mode);<br>
+<br>
+   if (display_mode) {<br>
+      display_mode->valid = true;<br>
+      return VK_SUCCESS;<br>
+   }<br>
+<br>
+   display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_<wbr>INSTANCE);<br>
+   if (!display_mode)<br>
+      return VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+<br>
+   display_mode->connector = connector;<br>
+   display_mode->valid = true;<br>
+   display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0;<br>
+   display_mode->clock = drm_mode->clock; /* kHz */<br>
+   display_mode->hdisplay = drm_mode->hdisplay;<br>
+   display_mode->hsync_start = drm_mode->hsync_start;<br>
+   display_mode->hsync_end = drm_mode->hsync_end;<br>
+   display_mode->htotal = drm_mode->htotal;<br>
+   display_mode->hskew = drm_mode->hskew;<br>
+   display_mode->vdisplay = drm_mode->vdisplay;<br>
+   display_mode->vsync_start = drm_mode->vsync_start;<br>
+   display_mode->vsync_end = drm_mode->vsync_end;<br>
+   display_mode->vtotal = drm_mode->vtotal;<br>
+   display_mode->vscan = drm_mode->vscan;<br>
+   display_mode->flags = drm_mode->flags;<br>
+<br>
+   LIST_ADDTAIL(&display_mode-><wbr>list, &connector->display_modes);<br>
+   return VK_SUCCESS;<br>
+}<br>
+<br>
+/*<br>
+ * Update our information about a specific connector<br>
+ */<br>
+<br>
+static struct wsi_display_connector *<br>
+wsi_display_find_connector(<wbr>struct wsi_device    *wsi_device,<br>
+                          uint32_t              connector_id)<br>
+{<br>
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br>
+   struct wsi_display_connector *connector;<br>
+<br>
+   connector = NULL;<br>
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {<br>
+      if (connector->id == connector_id)<br>
+         return connector;<br>
+   }<br>
+<br>
+   return NULL;<br>
+}<br>
+<br>
+static struct wsi_display_connector *<br>
+wsi_display_alloc_connector(<wbr>struct wsi_display  *wsi,<br>
+                            uint32_t            connector_id)<br>
+{<br>
+   struct wsi_display_connector *connector;<br>
+<br>
+   connector = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector), 8, VK_SYSTEM_ALLOCATION_SCOPE_<wbr>INSTANCE);<br>
+   connector->id = connector_id;<br>
+   connector->wsi = wsi;<br>
+   connector->active = false;<br>
+   /* XXX use EDID name */<br>
+   connector->name = "monitor";<br>
+   LIST_INITHEAD(&connector-><wbr>display_modes);<br>
+   return connector;<br>
+}<br>
+<br>
+static struct wsi_display_connector *<br>
+wsi_display_get_connector(<wbr>struct wsi_device             *wsi_device,<br>
+                          uint32_t                      connector_id)<br>
+{<br>
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br>
+   struct wsi_display_connector *connector;<br>
+   drmModeConnectorPtr          drm_connector;<br>
+   VkResult                     result;<br>
+   int                          m;<br>
+<br>
+   if (wsi->fd < 0)<br>
+      return NULL;<br>
+<br>
+   drm_connector = drmModeGetConnector(wsi->fd, connector_id);<br>
+   if (!drm_connector)<br>
+      return NULL;<br>
+<br>
+   connector = wsi_display_find_connector(<wbr>wsi_device, connector_id);<br>
+<br>
+   if (!connector) {<br>
+      connector = wsi_display_alloc_connector(<wbr>wsi, connector_id);<br>
+      if (!connector) {<br>
+         drmModeFreeConnector(drm_<wbr>connector);<br>
+         return NULL;<br>
+      }<br>
+      LIST_ADDTAIL(&connector->list, &wsi->connectors);<br>
+   }<br>
+<br>
+   connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED;<br>
+<br>
+   /* Mark all connector modes as invalid */<br>
+   wsi_display_invalidate_<wbr>connector_modes(wsi_device, connector);<br>
+<br>
+   /*<br>
+    * List current modes, adding new ones and marking existing ones as<br>
+    * valid<br>
+    */<br>
+   for (m = 0; m < drm_connector->count_modes; m++) {<br>
+      result = wsi_display_register_drm_mode(<wbr>wsi_device,<br>
+                                             connector,<br>
+                                             &drm_connector->modes[m]);<br>
+      if (result != VK_SUCCESS) {<br>
+         drmModeFreeConnector(drm_<wbr>connector);<br>
+         return NULL;<br>
+      }<br>
+   }<br>
+<br>
+   drmModeFreeConnector(drm_<wbr>connector);<br>
+<br>
+   return connector;<br>
+}<br>
+<br>
+#define MM_PER_PIXEL     (1.0/96.0 * 25.4)<br>
+<br>
+static uint32_t<br>
+mode_size(struct wsi_display_mode *mode) {<br>
+   /* fortunately, these are both uint16_t, so this is easy */<br>
+   return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay;<br>
+}<br>
+<br>
+static void<br>
+wsi_display_fill_in_display_<wbr>properties(struct wsi_device                *wsi_device,<br>
+                                       struct wsi_display_connector     *connector,<br>
+                                       VkDisplayPropertiesKHR           *properties)<br>
+{<br>
+   struct wsi_display_mode      *display_mode, *preferred_mode = NULL, *largest_mode = NULL;<br>
+<br>
+   properties->display = wsi_display_connector_to_<wbr>handle(connector);<br>
+   properties->displayName = connector->name;<br>
+<br>
+   /* Find the preferred mode and assume that's the physical resolution. If<br>
+    * there isn't a preferred mode, find the largest mode and use that.<br>
+    */<br>
+<br>
+   LIST_FOR_EACH_ENTRY(display_<wbr>mode, &connector->display_modes, list) {<br>
+      if (display_mode->valid && (largest_mode == NULL || mode_size(display_mode) > mode_size(largest_mode)))<br>
+         largest_mode = display_mode;<br>
+      if (display_mode->valid && display_mode->preferred) {<br>
+         preferred_mode = display_mode;<br>
+         break;<br>
+      }<br>
+   }<br>
+<br>
+   if (preferred_mode) {<br>
+      properties-><wbr>physicalResolution.width = preferred_mode->hdisplay;<br>
+      properties-><wbr>physicalResolution.height = preferred_mode->vdisplay;<br>
+   } else if (largest_mode) {<br>
+      properties-><wbr>physicalResolution.width = largest_mode->hdisplay;<br>
+      properties-><wbr>physicalResolution.height = largest_mode->vdisplay;<br>
+   } else {<br>
+      properties-><wbr>physicalResolution.width = 1024;<br>
+      properties-><wbr>physicalResolution.height = 768;<br>
+   }<br>
+<br>
+   /* Make up physical size based on 96dpi */<br>
+   properties-><wbr>physicalDimensions.width = floor(properties-><wbr>physicalResolution.width * MM_PER_PIXEL + 0.5);<br>
+   properties-><wbr>physicalDimensions.height = floor(properties-><wbr>physicalResolution.height * MM_PER_PIXEL + 0.5);<br>
+<br>
+   properties-><wbr>supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_<wbr>BIT_KHR;<br>
+   properties->persistentContent = 0;<br>
+}<br>
+<br>
+/*<br>
+ * Implement vkGetPhysicalDeviceDisplayProp<wbr>ertiesKHR (VK_KHR_display)<br>
+ */<br>
+VkResult<br>
+wsi_display_get_physical_<wbr>device_display_properties(<wbr>VkPhysicalDevice             physical_device,<br>
+                                                   struct wsi_device            *wsi_device,<br>
+                                                   uint32_t                     *property_count,<br>
+                                                   VkDisplayPropertiesKHR       *properties)<br>
+{<br>
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br>
+   drmModeResPtr                mode_res;<br>
+<br>
+   if (wsi->fd < 0)<br>
+      goto bail;<br>
+<br>
+   mode_res = drmModeGetResources(wsi->fd);<br>
+<br>
+   if (!mode_res)<br>
+      goto bail;<br>
+<br>
+   VK_OUTARRAY_MAKE(conn, properties, property_count);<br>
+<br>
+   /* Get current information */<br>
+<br>
+   for (int c = 0; c < mode_res->count_connectors; c++) {<br>
+      struct wsi_display_connector *connector =<br>
+         wsi_display_get_connector(wsi_<wbr>device, mode_res->connectors[c]);<br>
+<br>
+      if (!connector) {<br>
+         drmModeFreeResources(mode_res)<wbr>;<br>
+         return VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      }<br>
+<br>
+      if (connector->connected) {<br>
+         vk_outarray_append(&conn, prop) {<br>
+            wsi_display_fill_in_display_<wbr>properties(wsi_device,<br>
+                                                   connector,<br>
+                                                   prop);<br>
+         }<br>
+      }<br>
+   }<br>
+<br>
+   drmModeFreeResources(mode_res)<wbr>;<br>
+<br>
+   return vk_outarray_status(&conn);<br>
+<br>
+bail:<br>
+   *property_count = 0;<br>
+   return VK_SUCCESS;<br>
+}<br>
+<br>
+/*<br>
+ * Implement vkGetPhysicalDeviceDisplayPlan<wbr>ePropertiesKHR (VK_KHR_display<br>
+ */<br>
+VkResult<br>
+wsi_display_get_physical_<wbr>device_display_plane_<wbr>properties(VkPhysicalDevice               physical_device,<br>
+                                                         struct wsi_device              *wsi_device,<br>
+                                                         uint32_t                       *property_count,<br>
+                                                         VkDisplayPlanePropertiesKHR    *properties)<br>
+{<br>
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br>
+   struct wsi_display_connector *connector;<br>
+<br>
+   VK_OUTARRAY_MAKE(conn, properties, property_count);<br>
+<br>
+   int stack_index = 0;<br>
+<br>
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {<br>
+      vk_outarray_append(&conn, prop) {<br>
+         if (connector && connector->active) {<br>
+            prop->currentDisplay = wsi_display_connector_to_<wbr>handle(connector);<br>
+            prop->currentStackIndex = stack_index++;<br>
+         } else {<br>
+            prop->currentDisplay = NULL;<br>
+            prop->currentStackIndex = 0;<br>
+         }<br>
+      }<br>
+   }<br>
+   return vk_outarray_status(&conn);<br>
+}<br>
+<br>
+/*<br>
+ * Implement vkGetDisplayPlaneSupportedDisp<wbr>laysKHR (VK_KHR_display)<br>
+ */<br>
+<br>
+VkResult<br>
+wsi_display_get_display_<wbr>plane_supported_displays(<wbr>VkPhysicalDevice               physical_device,<br>
+                                                 struct wsi_device              *wsi_device,<br>
+                                                 uint32_t                       plane_index,<br>
+                                                 uint32_t                       *display_count,<br>
+                                                 VkDisplayKHR                   *displays)<br>
+{<br>
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br>
+   struct wsi_display_connector *connector;<br>
+<br>
+   VK_OUTARRAY_MAKE(conn, displays, display_count);<br>
+<br>
+   int c = 0;<br>
+<br>
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {<br>
+      if (c == plane_index) {<br>
+         vk_outarray_append(&conn, display) {<br>
+            *display = wsi_display_connector_to_<wbr>handle(connector);<br>
+         }<br>
+      }<br>
+      c++;<br>
+   }<br>
+   return vk_outarray_status(&conn);<br>
+}<br>
+<br>
+/*<br>
+ * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)<br>
+ */<br>
+<br>
+VkResult<br>
+wsi_display_get_display_mode_<wbr>properties(VkPhysicalDevice               physical_device,<br>
+                                        struct wsi_device              *wsi_device,<br>
+                                        VkDisplayKHR                   display,<br>
+                                        uint32_t                       *property_count,<br>
+                                        VkDisplayModePropertiesKHR     *properties)<br>
+{<br>
+   struct wsi_display_connector *connector = wsi_display_connector_from_<wbr>handle(display);<br>
+   struct wsi_display_mode      *display_mode;<br>
+<br>
+   VK_OUTARRAY_MAKE(conn, properties, property_count);<br>
+<br>
+   LIST_FOR_EACH_ENTRY(display_<wbr>mode, &connector->display_modes, list) {<br>
+      if (display_mode->valid) {<br>
+         vk_outarray_append(&conn, prop) {<br>
+            prop->displayMode = wsi_display_mode_to_handle(<wbr>display_mode);<br>
+            prop->parameters.<wbr>visibleRegion.width = display_mode->hdisplay;<br>
+            prop->parameters.<wbr>visibleRegion.height = display_mode->vdisplay;<br>
+            prop->parameters.refreshRate = (uint32_t) (wsi_display_mode_refresh(<wbr>display_mode) * 1000 + 0.5);<br>
+         }<br>
+      }<br>
+   }<br>
+   return vk_outarray_status(&conn);<br>
+}<br>
+<br>
+/*<br>
+ * Implement vkGetDisplayPlaneCapabilities<br>
+ */<br>
+VkResult<br>
+wsi_get_display_plane_<wbr>capabilities(VkPhysicalDevice                     physical_device,<br>
+                                   struct wsi_device                    *wsi_device,<br>
+                                   VkDisplayModeKHR                     mode_khr,<br>
+                                   uint32_t                             plane_index,<br>
+                                   VkDisplayPlaneCapabilitiesKHR        *capabilities)<br>
+{<br>
+   struct wsi_display_mode      *mode = wsi_display_mode_from_handle(<wbr>mode_khr);<br>
+<br>
+   /* XXX use actual values */<br>
+   capabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_<wbr>BIT_KHR;<br>
+   capabilities->minSrcPosition.x = 0;<br>
+   capabilities->minSrcPosition.y = 0;<br>
+   capabilities->maxSrcPosition.x = 0;<br>
+   capabilities->maxSrcPosition.y = 0;<br>
+   capabilities->minSrcExtent.<wbr>width = mode->hdisplay;<br>
+   capabilities->minSrcExtent.<wbr>height = mode->vdisplay;<br>
+   capabilities->maxSrcExtent.<wbr>width = mode->hdisplay;<br>
+   capabilities->maxSrcExtent.<wbr>height = mode->vdisplay;<br>
+   capabilities->minDstPosition.x = 0;<br>
+   capabilities->minDstPosition.y = 0;<br>
+   capabilities->maxDstPosition.x = 0;<br>
+   capabilities->maxDstPosition.y = 0;<br>
+   capabilities->minDstExtent.<wbr>width = mode->hdisplay;<br>
+   capabilities->minDstExtent.<wbr>height = mode->vdisplay;<br>
+   capabilities->maxDstExtent.<wbr>width = mode->hdisplay;<br>
+   capabilities->maxDstExtent.<wbr>height = mode->vdisplay;<br>
+   return VK_SUCCESS;<br>
+}<br>
+<br>
+VkResult<br>
+wsi_create_display_surface(<wbr>VkInstance instance,<br>
+                           const VkAllocationCallbacks   *allocator,<br>
+                           const VkDisplaySurfaceCreateInfoKHR *create_info,<br>
+                           VkSurfaceKHR *surface_khr)<br>
+{<br>
+   VkIcdSurfaceDisplay *surface;<br>
+<br>
+   surface = vk_zalloc(allocator, sizeof *surface, 8,<br>
+                       VK_SYSTEM_ALLOCATION_SCOPE_<wbr>OBJECT);<br>
+   if (surface == NULL)<br>
+      return VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+<br>
+   surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY;<br>
+<br>
+   surface->displayMode = create_info->displayMode;<br>
+   surface->planeIndex = create_info->planeIndex;<br>
+   surface->planeStackIndex = create_info->planeStackIndex;<br>
+   surface->transform = create_info->transform;<br>
+   surface->globalAlpha = create_info->globalAlpha;<br>
+   surface->alphaMode = create_info->alphaMode;<br>
+   surface->imageExtent = create_info->imageExtent;<br>
+<br>
+   *surface_khr = VkIcdSurfaceBase_to_handle(&<wbr>surface->base);<br>
+   return VK_SUCCESS;<br>
+}<br>
+<br>
+<br>
+static VkResult<br>
+wsi_display_surface_get_<wbr>support(VkIcdSurfaceBase *surface,<br>
+                                struct wsi_device *wsi_device,<br>
+                                const VkAllocationCallbacks *allocator,<br>
+                                uint32_t queueFamilyIndex,<br>
+                                int local_fd,<br>
+                                VkBool32* pSupported)<br>
+{<br>
+   *pSupported = VK_TRUE;<br>
+   return VK_SUCCESS;<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_surface_get_<wbr>capabilities(VkIcdSurfaceBase *surface_base,<br>
+                                     VkSurfaceCapabilitiesKHR* caps)<br>
+{<br>
+   VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;<br>
+   wsi_display_mode *mode = wsi_display_mode_from_handle(<wbr>surface->displayMode);<br>
+<br>
+   caps->currentExtent.width = mode->hdisplay;<br>
+   caps->currentExtent.height = mode->vdisplay;<br>
+<br>
+   /* XXX Figure out extents based on driver capabilities */<br>
+   caps->maxImageExtent = caps->minImageExtent = caps->currentExtent;<br>
+<br>
+   caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_<wbr>KHR;<br>
+<br>
+   caps->minImageCount = 2;<br>
+   caps->maxImageCount = 0;<br>
+<br>
+   caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_<wbr>BIT_KHR;<br>
+   caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_<wbr>BIT_KHR;<br>
+   caps->maxImageArrayLayers = 1;<br>
+   caps->supportedUsageFlags =<br>
+      VK_IMAGE_USAGE_TRANSFER_SRC_<wbr>BIT |<br>
+      VK_IMAGE_USAGE_SAMPLED_BIT |<br>
+      VK_IMAGE_USAGE_TRANSFER_DST_<wbr>BIT |<br>
+      VK_IMAGE_USAGE_COLOR_<wbr>ATTACHMENT_BIT;<br>
+<br>
+   return VK_SUCCESS;<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_surface_get_<wbr>capabilities2(VkIcdSurfaceBase *icd_surface,<br>
+                                      const void *info_next,<br>
+                                      VkSurfaceCapabilities2KHR *caps)<br>
+{<br>
+   assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_<wbr>CAPABILITIES_2_KHR);<br>
+<br>
+   return wsi_display_surface_get_<wbr>capabilities(icd_surface, &caps->surfaceCapabilities);<br>
+}<br>
+<br>
+static const struct {<br>
+   VkFormat     format;<br>
+   uint32_t     drm_format;<br>
+} available_surface_formats[] = {<br>
+   { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 },<br>
+   { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 },<br>
+};<br>
+<br>
+static VkResult<br>
+wsi_display_surface_get_<wbr>formats(VkIcdSurfaceBase        *icd_surface,<br>
+                                struct wsi_device       *wsi_device,<br>
+                                uint32_t                *surface_format_count,<br>
+                                VkSurfaceFormatKHR      *surface_formats)<br>
+{<br>
+   VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);<br>
+<br>
+   for (unsigned i = 0; i < ARRAY_SIZE(available_surface_<wbr>formats); i++) {<br>
+      vk_outarray_append(&out, f) {<br>
+         f->format = available_surface_formats[i].<wbr>format;<br>
+         f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_<wbr>KHR;<br>
+      }<br>
+   }<br>
+<br>
+   return vk_outarray_status(&out);<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_surface_get_<wbr>formats2(VkIcdSurfaceBase *surface,<br>
+                                 struct wsi_device *wsi_device,<br>
+                                 const void *info_next,<br>
+                                 uint32_t *surface_format_count,<br>
+                                 VkSurfaceFormat2KHR *surface_formats)<br>
+{<br>
+   VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);<br>
+<br>
+   for (unsigned i = 0; i < ARRAY_SIZE(available_surface_<wbr>formats); i++) {<br>
+      vk_outarray_append(&out, f) {<br>
+         assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_<wbr>FORMAT_2_KHR);<br>
+         f->surfaceFormat.format = available_surface_formats[i].<wbr>format;<br>
+         f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_<wbr>KHR;<br>
+      }<br>
+   }<br>
+<br>
+   return vk_outarray_status(&out);<br>
+}<br>
+<br>
+static const VkPresentModeKHR available_present_modes[] = {<br>
+   VK_PRESENT_MODE_FIFO_KHR,<br>
+};<br>
+<br>
+static VkResult<br>
+wsi_display_surface_get_<wbr>present_modes(VkIcdSurfaceBase  *surface,<br>
+                                      uint32_t          *present_mode_count,<br>
+                                      VkPresentModeKHR  *present_modes)<br>
+{<br>
+   VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count);<br>
+<br>
+   for (unsigned int c = 0; c < ARRAY_SIZE(available_present_<wbr>modes); c++) {<br>
+      vk_outarray_append(&conn, present) {<br>
+         *present = available_present_modes[c];<br>
+      }<br>
+   }<br>
+<br>
+   return vk_outarray_status(&conn);<br>
+}<br>
+<br>
+static void<br>
+wsi_display_destroy_buffer(<wbr>struct wsi_display *wsi,<br>
+                           uint32_t buffer)<br>
+{<br>
+   (void) drmIoctl(wsi->fd, DRM_IOCTL_MODE_DESTROY_DUMB,<br>
+                   &((struct drm_mode_destroy_dumb) { .handle = buffer }));<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_image_init(<wbr>VkDevice                         device_h,<br>
+                       struct wsi_swapchain             *drv_chain,<br>
+                       const VkSwapchainCreateInfoKHR   *create_info,<br>
+                       const VkAllocationCallbacks      *allocator,<br>
+                       struct wsi_display_image         *image)<br>
+{<br>
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;<br>
+   struct wsi_display           *wsi = chain->wsi;<br>
+   VkResult                     result;<br>
+   int                          ret;<br>
+   uint32_t                     drm_format = 0;<br>
+<br>
+   for (unsigned i = 0; i < ARRAY_SIZE(available_surface_<wbr>formats); i++) {<br>
+      if (create_info->imageFormat == available_surface_formats[i].<wbr>format) {<br>
+         drm_format = available_surface_formats[i].<wbr>drm_format;<br>
+         break;<br>
+      }<br>
+   }<br>
+<br>
+   /* the application provided an invalid format, bail */<br>
+   if (drm_format == 0)<br>
+      return VK_ERROR_DEVICE_LOST;<br>
+<br>
+   result = wsi_create_native_image(&<wbr>chain->base, create_info,<br>
+                                    0, NULL, NULL,<br>
+                                    &image->base);<br>
+   if (result != VK_SUCCESS)<br>
+      return result;<br>
+<br>
+   memset(image->buffer, 0, sizeof (image->buffer));<br>
+<br>
+   for (unsigned int i = 0; i < image->base.num_planes; i++) {<br>
+      ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i], &image->buffer[i]);<br>
+<br>
+      close(image->base.fds[i]);<br>
+      image->base.fds[i] = -1;<br>
+      if (ret < 0)<br>
+         goto fail_handle;<br>
+   }<br>
+<br>
+   image->chain = chain;<br>
+   image->state = WSI_IMAGE_IDLE;<br>
+   image->fb_id = 0;<br>
+<br>
+   ret = drmModeAddFB2(wsi->fd,<br>
+                       create_info->imageExtent.<wbr>width,<br>
+                       create_info->imageExtent.<wbr>height,<br>
+                       drm_format,<br>
+                       image->buffer,<br>
+                       image->base.row_pitches,<br>
+                       image->base.offsets,<br>
+                       &image->fb_id, 0);<br>
+<br>
+   if (ret)<br>
+      goto fail_fb;<br>
+<br>
+   return VK_SUCCESS;<br>
+<br>
+fail_fb:<br>
+fail_handle:<br>
+   for (unsigned int i = 0; i < image->base.num_planes; i++) {<br>
+      if (image->buffer[i])<br>
+         wsi_display_destroy_buffer(<wbr>wsi, image->buffer[i]);<br>
+      if (image->base.fds[i] != -1) {<br>
+         close(image->base.fds[i]);<br>
+         image->base.fds[i] = -1;<br>
+      }<br>
+   }<br>
+<br>
+   wsi_destroy_image(&chain-><wbr>base, &image->base);<br>
+<br>
+   return VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+}<br>
+<br>
+static void<br>
+wsi_display_image_finish(<wbr>struct wsi_swapchain           *drv_chain,<br>
+                         const VkAllocationCallbacks    *allocator,<br>
+                         struct wsi_display_image       *image)<br>
+{<br>
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;<br>
+   struct wsi_display           *wsi = chain->wsi;<br>
+<br>
+   drmModeRmFB(wsi->fd, image->fb_id);<br>
+   for (unsigned int i = 0; i < image->base.num_planes; i++)<br>
+      wsi_display_destroy_buffer(<wbr>wsi, image->buffer[i]);<br>
+   wsi_destroy_image(&chain-><wbr>base, &image->base);<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_swapchain_<wbr>destroy(struct wsi_swapchain              *drv_chain,<br>
+                              const VkAllocationCallbacks       *allocator)<br>
+{<br>
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;<br>
+<br>
+   for (uint32_t i = 0; i < chain->base.image_count; i++)<br>
+      wsi_display_image_finish(drv_<wbr>chain, allocator, &chain->images[i]);<br>
+   vk_free(allocator, chain);<br>
+   return VK_SUCCESS;<br>
+}<br>
+<br>
+static struct wsi_image *<br>
+wsi_display_get_wsi_image(<wbr>struct wsi_swapchain  *drv_chain,<br>
+                          uint32_t              image_index)<br>
+{<br>
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;<br>
+<br>
+   return &chain->images[image_index].<wbr>base;<br>
+}<br>
+<br>
+static void<br>
+wsi_display_idle_old_<wbr>displaying(struct wsi_display_image *active_image)<br>
+{<br>
+   struct wsi_display_swapchain *chain = active_image->chain;<br>
+<br>
+   wsi_display_debug("idle everyone but %ld\n", active_image - &(chain->images[0]));<br>
+   for (uint32_t i = 0; i < chain->base.image_count; i++)<br>
+      if (chain->images[i].state == WSI_IMAGE_DISPLAYING && &chain->images[i] != active_image) {<br>
+         wsi_display_debug("idle %d\n", i);<br>
+         chain->images[i].state = WSI_IMAGE_IDLE;<br>
+      }<br>
+}<br>
+<br>
+static VkResult<br>
+_wsi_display_queue_next(<wbr>struct wsi_swapchain     *drv_chain);<br>
+<br>
+static void<br>
+wsi_display_page_flip_<wbr>handler2(int              fd,<br>
+                               unsigned int     frame,<br>
+                               unsigned int     sec,<br>
+                               unsigned int     usec,<br>
+                               uint32_t         crtc_id,<br>
+                               void             *data)<br>
+{<br>
+   struct wsi_display_image     *image = data;<br>
+   struct wsi_display_swapchain *chain = image->chain;<br>
+   VkResult                     status;<br>
+<br>
+   wsi_display_debug("image %ld displayed at %d\n", image - &(image->chain->images[0]), frame);<br>
+   image->state = WSI_IMAGE_DISPLAYING;<br>
+   wsi_display_idle_old_<wbr>displaying(image);<br>
+   status = _wsi_display_queue_next(&(<wbr>chain->base));<br>
+   if (status != VK_SUCCESS)<br>
+      chain->status = status;<br>
+}<br>
+<br>
+static void wsi_display_page_flip_handler(<wbr>int fd, unsigned int frame,<br>
+                                          unsigned int sec, unsigned int usec, void *data)<br>
+{<br>
+   wsi_display_page_flip_<wbr>handler2(fd, frame, sec, usec, 0, data);<br>
+}<br>
+<br>
+static drmEventContext event_context = {<br>
+   .version = DRM_EVENT_CONTEXT_VERSION,<br>
+   .page_flip_handler = wsi_display_page_flip_handler,<br>
+#if DRM_EVENT_CONTEXT_VERSION >= 3<br>
+   .page_flip_handler2 = wsi_display_page_flip_<wbr>handler2,<br>
+#endif<br>
+};<br>
+<br>
+static void *<br>
+wsi_display_wait_thread(void *data)<br>
+{<br>
+   struct wsi_display   *wsi = data;<br>
+   struct pollfd pollfd = {<br>
+      .fd = wsi->fd,<br>
+      .events = POLLIN<br>
+   };<br>
+   int ret;<br>
+<br>
+   pthread_setcanceltype(PTHREAD_<wbr>CANCEL_ASYNCHRONOUS, NULL);<br>
+   for (;;) {<br>
+      ret = poll(&pollfd, 1, -1);<br>
+      if (ret > 0) {<br>
+         pthread_mutex_lock(&wsi->wait_<wbr>mutex);<br>
+         (void) drmHandleEvent(wsi->fd, &event_context);<br>
+         pthread_mutex_unlock(&wsi-><wbr>wait_mutex);<br>
+         pthread_cond_broadcast(&wsi-><wbr>wait_cond);<br>
+      }<br>
+   }<br>
+   return NULL;<br>
+}<br>
+<br>
+static int<br>
+wsi_display_start_wait_<wbr>thread(struct wsi_display        *wsi)<br>
+{<br>
+   if (!wsi->wait_thread) {<br>
+      int ret = pthread_create(&wsi->wait_<wbr>thread, NULL, wsi_display_wait_thread, wsi);<br>
+      if (ret)<br>
+         return ret;<br>
+   }<br>
+   return 0;<br>
+}<br>
+<br>
+/*<br>
+ * Wait for at least one event from the kernel to be processed.<br>
+ * Call with wait_mutex held<br>
+ */<br>
+static int<br>
+wsi_display_wait_for_event(<wbr>struct wsi_display           *wsi,<br>
+                           uint64_t                     timeout_ns)<br>
+{<br>
+   int ret;<br>
+<br>
+   ret = wsi_display_start_wait_thread(<wbr>wsi);<br>
+<br>
+   if (ret)<br>
+      return ret;<br>
+<br>
+   struct timespec abs_timeout = {<br>
+      .tv_sec = timeout_ns / ((uint64_t) 1000 * (uint64_t) 1000 * (uint64_t) 1000),<br>
+      .tv_nsec = timeout_ns % ((uint64_t) 1000 * (uint64_t) 1000 * (uint64_t) 1000)<br>
+   };<br>
+<br>
+   ret = pthread_cond_timedwait(&wsi-><wbr>wait_cond, &wsi->wait_mutex, &abs_timeout);<br>
+<br>
+   wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);<br>
+   return ret;<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_acquire_next_<wbr>image(struct wsi_swapchain     *drv_chain,<br>
+                               uint64_t                 timeout,<br>
+                               VkSemaphore              semaphore,<br>
+                               uint32_t                 *image_index)<br>
+{<br>
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)drv_chain;<br>
+   struct wsi_display           *wsi = chain->wsi;<br>
+   int                          ret = 0;<br>
+   VkResult                     result = VK_SUCCESS;<br>
+<br>
+   /* Bail early if the swapchain is broken */<br>
+   if (chain->status != VK_SUCCESS)<br>
+      return chain->status;<br>
+<br>
+   if (timeout != 0 && timeout != UINT64_MAX)<br>
+      timeout += wsi_get_current_monotonic();<br>
+<br>
+   pthread_mutex_lock(&wsi->wait_<wbr>mutex);<br>
+   for (;;) {<br>
+      for (uint32_t i = 0; i < chain->base.image_count; i++) {<br>
+         if (chain->images[i].state == WSI_IMAGE_IDLE) {<br>
+            *image_index = i;<br>
+            wsi_display_debug("image %d available\n", i);<br>
+            chain->images[i].state = WSI_IMAGE_DRAWING;<br>
+            result = VK_SUCCESS;<br>
+            goto done;<br>
+         }<br>
+         wsi_display_debug("image %d state %d\n", i, chain->images[i].state);<br>
+      }<br>
+<br>
+      if (ret == ETIMEDOUT) {<br>
+         result = VK_TIMEOUT;<br>
+         goto done;<br>
+      }<br>
+<br>
+      ret = wsi_display_wait_for_event(<wbr>wsi, timeout);<br>
+<br>
+      if (ret && ret != ETIMEDOUT) {<br>
+         result = VK_ERROR_OUT_OF_DATE_KHR;<br>
+         goto done;<br>
+      }<br>
+   }<br>
+done:<br>
+   pthread_mutex_unlock(&wsi-><wbr>wait_mutex);<br>
+<br>
+   if (result != VK_SUCCESS)<br>
+      return result;<br>
+<br>
+   return chain->status;<br>
+}<br>
+<br>
+/*<br>
+ * Check whether there are any other connectors driven by this crtc<br>
+ */<br>
+static bool<br>
+wsi_display_crtc_solo(struct wsi_display        *wsi,<br>
+                      drmModeResPtr             mode_res,<br>
+                      drmModeConnectorPtr       connector,<br>
+                      uint32_t                  crtc_id)<br>
+{<br>
+   int                  c, e;<br>
+<br>
+   /* See if any other connectors share the same encoder */<br>
+   for (c = 0; c < mode_res->count_connectors; c++) {<br>
+      if (mode_res->connectors[c] == connector->connector_id)<br>
+         continue;<br>
+<br>
+      drmModeConnectorPtr other_connector = drmModeGetConnector(wsi->fd, mode_res->connectors[c]);<br>
+      if (other_connector) {<br>
+         bool match = (other_connector->encoder_id == connector->encoder_id);<br>
+         drmModeFreeConnector(other_<wbr>connector);<br>
+         if (match)<br>
+            return false;<br>
+      }<br>
+   }<br>
+<br>
+   /* See if any other encoders share the same crtc */<br>
+   for (e = 0; e < mode_res->count_encoders; e++) {<br>
+      if (mode_res->encoders[e] == connector->encoder_id)<br>
+         continue;<br>
+<br>
+      drmModeEncoderPtr other_encoder = drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);<br>
+      if (other_encoder) {<br>
+         bool match = (other_encoder->crtc_id == crtc_id);<br>
+         drmModeFreeEncoder(other_<wbr>encoder);<br>
+         if (match)<br>
+            return false;<br>
+      }<br>
+   }<br>
+   return true;<br>
+}<br>
+<br>
+/*<br>
+ * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is<br>
+ * currently driving this connector and not any others. Settle for a CRTC<br>
+ * which is currently idle.<br>
+ */<br>
+static uint32_t<br>
+wsi_display_select_crtc(<wbr>struct wsi_display_connector    *connector,<br>
+                        drmModeResPtr                   mode_res,<br>
+                        drmModeConnectorPtr             drm_connector)<br>
+{<br>
+   struct wsi_display   *wsi = connector->wsi;<br>
+   int                  c;<br>
+   uint32_t             crtc_id;<br>
+<br>
+   /* See what CRTC is currently driving this connector */<br>
+   if (drm_connector->encoder_id) {<br>
+      drmModeEncoderPtr encoder = drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);<br>
+      if (encoder) {<br>
+         crtc_id = encoder->crtc_id;<br>
+         drmModeFreeEncoder(encoder);<br>
+         if (crtc_id) {<br>
+            if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))<br>
+               return crtc_id;<br>
+         }<br>
+      }<br>
+   }<br>
+   crtc_id = 0;<br>
+   for (c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {<br>
+      drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);<br>
+      if (crtc && crtc->buffer_id == 0)<br>
+         crtc_id = crtc->crtc_id;<br>
+      drmModeFreeCrtc(crtc);<br>
+   }<br>
+   return crtc_id;<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_setup_connector(<wbr>wsi_display_connector       *connector,<br>
+                            wsi_display_mode            *display_mode)<br>
+{<br>
+   struct wsi_display   *wsi = connector->wsi;<br>
+   drmModeModeInfoPtr   drm_mode;<br>
+   drmModeConnectorPtr  drm_connector;<br>
+   drmModeResPtr        mode_res;<br>
+   VkResult             result;<br>
+   int                  m;<br>
+<br>
+   if (connector->current_mode == display_mode && connector->crtc_id)<br>
+      return VK_SUCCESS;<br>
+<br>
+   mode_res = drmModeGetResources(wsi->fd);<br>
+   if (!mode_res) {<br>
+      if (errno == ENOMEM)<br>
+         result = VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      else<br>
+         result = VK_ERROR_OUT_OF_DATE_KHR;<br>
+      goto bail;<br>
+   }<br>
+<br>
+   drm_connector = drmModeGetConnectorCurrent(<wbr>wsi->fd, connector->id);<br>
+   if (!drm_connector) {<br>
+      if (errno == ENOMEM)<br>
+         result = VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      else<br>
+         result = VK_ERROR_OUT_OF_DATE_KHR;<br>
+      goto bail_mode_res;<br>
+   }<br>
+<br>
+   /* Pick a CRTC if we don't have one */<br>
+   if (!connector->crtc_id) {<br>
+      connector->crtc_id = wsi_display_select_crtc(<wbr>connector, mode_res, drm_connector);<br>
+      if (!connector->crtc_id) {<br>
+         result = VK_ERROR_OUT_OF_DATE_KHR;<br>
+         goto bail_connector;<br>
+      }<br>
+   }<br>
+<br>
+   if (connector->current_mode != display_mode) {<br>
+<br>
+      /* Find the drm mode cooresponding to the requested VkDisplayMode */<br>
+      drm_mode = NULL;<br>
+      for (m = 0; m < drm_connector->count_modes; m++) {<br>
+         drm_mode = &drm_connector->modes[m];<br>
+         if (wsi_display_mode_matches_drm(<wbr>display_mode, drm_mode))<br>
+            break;<br>
+         drm_mode = NULL;<br>
+      }<br>
+<br>
+      if (!drm_mode) {<br>
+         result = VK_ERROR_OUT_OF_DATE_KHR;<br>
+         goto bail_connector;<br>
+      }<br>
+<br>
+      connector->current_mode = display_mode;<br>
+      connector->current_drm_mode = *drm_mode;<br>
+   }<br>
+<br>
+   result = VK_SUCCESS;<br>
+<br>
+bail_connector:<br>
+   drmModeFreeConnector(drm_<wbr>connector);<br>
+bail_mode_res:<br>
+   drmModeFreeResources(mode_res)<wbr>;<br>
+bail:<br>
+   return result;<br>
+<br>
+}<br>
+<br>
+/*<br>
+ * Check to see if the kernel has no flip queued and if there's an image<br>
+ * waiting to be displayed.<br>
+ */<br>
+static VkResult<br>
+_wsi_display_queue_next(<wbr>struct wsi_swapchain     *drv_chain)<br>
+{<br>
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;<br>
+   struct wsi_display           *wsi = chain->wsi;<br>
+   uint32_t                     i;<br>
+   struct wsi_display_image     *image = NULL;<br>
+   VkIcdSurfaceDisplay          *surface = chain->surface;<br>
+   wsi_display_mode             *display_mode = wsi_display_mode_from_handle(<wbr>surface->displayMode);<br>
+   wsi_display_connector        *connector = display_mode->connector;<br>
+   int                          ret;<br>
+   VkResult                     result;<br>
+<br>
+   if (wsi->fd < 0)<br>
+      return VK_ERROR_INITIALIZATION_<wbr>FAILED;<br>
+<br>
+   if (display_mode != connector->current_mode)<br>
+      connector->active = false;<br>
+<br>
+   for (;;) {<br>
+      /* Check to see if there is an image to display, or if some image is already queued */<br>
+<br>
+      for (i = 0; i < chain->base.image_count; i++) {<br>
+         struct wsi_display_image  *tmp_image = &chain->images[i];<br>
+<br>
+         switch (tmp_image->state) {<br>
+         case WSI_IMAGE_FLIPPING:<br>
+            /* already flipping, don't send another to the kernel yet */<br>
+            return VK_SUCCESS;<br>
+         case WSI_IMAGE_QUEUED:<br>
+            /* find the oldest queued */<br>
+            if (!image || tmp_image->flip_sequence < image->flip_sequence)<br>
+               image = tmp_image;<br>
+            break;<br>
+         default:<br>
+            break;<br>
+         }<br>
+      }<br>
+<br>
+      if (!image)<br>
+         return VK_SUCCESS;<br>
+<br>
+      if (connector->active) {<br>
+         ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,<br>
+                               DRM_MODE_PAGE_FLIP_EVENT, image);<br>
+         if (ret == 0) {<br>
+            image->state = WSI_IMAGE_FLIPPING;<br>
+            return VK_SUCCESS;<br>
+         }<br>
+         wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));<br>
+      } else {<br>
+         ret = -EINVAL;<br>
+      }<br>
+<br>
+      if (ret) {<br>
+         switch(-ret) {<br>
+         case EINVAL:<br>
+<br>
+            result = wsi_display_setup_connector(<wbr>connector, display_mode);<br>
+<br>
+            if (result != VK_SUCCESS) {<br>
+               image->state = WSI_IMAGE_IDLE;<br>
+               return result;<br>
+            }<br>
+<br>
+            /* XXX allow setting of position */<br>
+<br>
+            ret = drmModeSetCrtc(wsi->fd, connector->crtc_id, image->fb_id, 0, 0,<br>
+                                 &connector->id, 1, &connector->current_drm_mode);<br>
+<br>
+            if (ret == 0) {<br>
+               image->state = WSI_IMAGE_DISPLAYING;<br>
+<br>
+               /* Assume that the mode set is synchronous and that any<br>
+                * previous image is now idle.<br>
+                */<br>
+               wsi_display_idle_old_<wbr>displaying(image);<br>
+               connector->active = true;<br>
+               return VK_SUCCESS;<br>
+            }<br>
+            break;<br>
+         case EACCES:<br>
+<br>
+            /* Some other VT is currently active. Sit here waiting for<br>
+             * our VT to become active again by polling once a second<br>
+             */<br>
+            usleep(1000 * 1000);<br>
+            connector->active = false;<br>
+            break;<br>
+         default:<br>
+            connector->active = false;<br>
+            image->state = WSI_IMAGE_IDLE;<br>
+            return VK_ERROR_OUT_OF_DATE_KHR;<br>
+         }<br>
+      }<br>
+   }<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_queue_present(<wbr>struct wsi_swapchain          *drv_chain,<br>
+                          uint32_t                      image_index,<br>
+                          const VkPresentRegionKHR      *damage)<br>
+{<br>
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;<br>
+   struct wsi_display           *wsi = chain->wsi;<br>
+   struct wsi_display_image     *image = &chain->images[image_index];<br>
+   VkResult                     result;<br>
+<br>
+   /* Bail early if the swapchain is broken */<br>
+   if (chain->status != VK_SUCCESS)<br>
+      return chain->status;<br>
+<br>
+   assert(image->state == WSI_IMAGE_DRAWING);<br>
+   wsi_display_debug("present %d\n", image_index);<br>
+<br>
+   pthread_mutex_lock(&wsi->wait_<wbr>mutex);<br>
+<br>
+   image->flip_sequence = ++chain->flip_sequence;<br>
+   image->state = WSI_IMAGE_QUEUED;<br>
+<br>
+   result = _wsi_display_queue_next(drv_<wbr>chain);<br>
+   if (result != VK_SUCCESS)<br>
+      chain->status = result;<br>
+<br>
+   pthread_mutex_unlock(&wsi-><wbr>wait_mutex);<br>
+<br>
+   if (result != VK_SUCCESS)<br>
+      return result;<br>
+<br>
+   return chain->status;<br>
+}<br>
+<br>
+static VkResult<br>
+wsi_display_surface_create_<wbr>swapchain(VkIcdSurfaceBase                   *icd_surface,<br>
+                                     VkDevice                           device,<br>
+                                     struct wsi_device                  *wsi_device,<br>
+                                     int                                local_fd,<br>
+                                     const VkSwapchainCreateInfoKHR     *create_info,<br>
+                                     const VkAllocationCallbacks        *allocator,<br>
+                                     struct wsi_swapchain               **swapchain_out)<br>
+{<br>
+   struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br>
+   VkResult result;<br>
+<br>
+   assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_<wbr>CREATE_INFO_KHR);<br>
+<br>
+   struct wsi_display_swapchain *chain;<br>
+   const unsigned num_images = create_info->minImageCount;<br>
+   size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);<br>
+<br>
+   chain = vk_zalloc(allocator, size, 8,<br>
+                    VK_SYSTEM_ALLOCATION_SCOPE_<wbr>OBJECT);<br>
+<br>
+   if (chain == NULL)<br>
+      return VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+<br>
+   result = wsi_swapchain_init(wsi_device, &chain->base, device,<br>
+                               create_info, allocator);<br>
+<br>
+   chain->base.destroy = wsi_display_swapchain_destroy;<br>
+   chain->base.get_wsi_image = wsi_display_get_wsi_image;<br>
+   chain->base.acquire_next_image = wsi_display_acquire_next_<wbr>image;<br>
+   chain->base.queue_present = wsi_display_queue_present;<br>
+   chain->base.present_mode = create_info->presentMode;<br>
+   chain->base.image_count = num_images;<br>
+<br>
+   chain->wsi = wsi;<br>
+   chain->status = VK_SUCCESS;<br>
+<br>
+   chain->surface = (VkIcdSurfaceDisplay *) icd_surface;<br>
+<br>
+   for (uint32_t image = 0; image < chain->base.image_count; image++) {<br>
+      result = wsi_display_image_init(device, &chain->base, create_info, allocator,<br>
+                                      &chain->images[image]);<br>
+      if (result != VK_SUCCESS) {<br>
+         while (image > 0) {<br>
+            --image;<br>
+            wsi_display_image_finish(&<wbr>chain->base, allocator, &chain->images[image]);<br>
+         }<br>
+         vk_free(allocator, chain);<br>
+         goto fail_init_images;<br>
+      }<br>
+   }<br>
+<br>
+   *swapchain_out = &chain->base;<br>
+<br>
+   return VK_SUCCESS;<br>
+<br>
+fail_init_images:<br>
+   return result;<br>
+}<br>
+<br>
+VkResult<br>
+wsi_display_init_wsi(struct wsi_device *wsi_device,<br>
+                     const VkAllocationCallbacks *alloc,<br>
+                     int display_fd)<br>
+{<br>
+   struct wsi_display *wsi;<br>
+   VkResult result;<br>
+<br>
+   wsi = vk_zalloc(alloc, sizeof(*wsi), 8,<br>
+                   VK_SYSTEM_ALLOCATION_SCOPE_<wbr>INSTANCE);<br>
+   if (!wsi) {<br>
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      goto fail;<br>
+   }<br>
+<br>
+   wsi->fd = display_fd;<br>
+<br>
+   pthread_mutex_init(&wsi->wait_<wbr>mutex, NULL);<br>
+   wsi->alloc = alloc;<br>
+<br>
+   LIST_INITHEAD(&wsi-><wbr>connectors);<br>
+<br>
+   pthread_condattr_t condattr;<br>
+   int ret;<br>
+<br>
+   ret = pthread_mutex_init(&wsi->wait_<wbr>mutex, NULL);<br>
+   if (ret) {<br>
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      goto fail_mutex;<br>
+   }<br>
+<br>
+   ret = pthread_condattr_init(&<wbr>condattr);<br>
+   if (ret) {<br>
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      goto fail_condattr;<br>
+   }<br>
+<br>
+   ret = pthread_condattr_setclock(&<wbr>condattr, CLOCK_MONOTONIC);<br>
+   if (ret) {<br>
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      goto fail_setclock;<br>
+   }<br>
+<br>
+   ret = pthread_cond_init(&wsi->wait_<wbr>cond, &condattr);<br>
+   if (ret) {<br>
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;<br>
+      goto fail_cond;<br>
+   }<br>
+<br>
+   pthread_condattr_destroy(&<wbr>condattr);<br>
+<br>
+   wsi->base.get_support = wsi_display_surface_get_<wbr>support;<br>
+   wsi->base.get_capabilities = wsi_display_surface_get_<wbr>capabilities;<br>
+   wsi->base.get_capabilities2 = wsi_display_surface_get_<wbr>capabilities2;<br>
+   wsi->base.get_formats = wsi_display_surface_get_<wbr>formats;<br>
+   wsi->base.get_formats2 = wsi_display_surface_get_<wbr>formats2;<br>
+   wsi->base.get_present_modes = wsi_display_surface_get_<wbr>present_modes;<br>
+   wsi->base.create_swapchain = wsi_display_surface_create_<wbr>swapchain;<br>
+<br>
+   wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY] = &wsi->base;<br>
+<br>
+   return VK_SUCCESS;<br>
+<br>
+fail_cond:<br>
+fail_setclock:<br>
+   pthread_condattr_destroy(&<wbr>condattr);<br>
+fail_condattr:<br>
+   pthread_mutex_destroy(&wsi-><wbr>wait_mutex);<br>
+fail_mutex:<br>
+   vk_free(alloc, wsi);<br>
+fail:<br>
+   return result;<br>
+}<br>
+<br>
+void<br>
+wsi_display_finish_wsi(struct wsi_device *wsi_device,<br>
+                       const VkAllocationCallbacks *alloc)<br>
+{<br>
+   struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_<wbr>PLATFORM_DISPLAY];<br>
+<br>
+   if (wsi) {<br>
+<br>
+      struct wsi_display_connector *connector, *connector_storage;<br>
+      LIST_FOR_EACH_ENTRY_SAFE(<wbr>connector, connector_storage, &wsi->connectors, list) {<br>
+         struct wsi_display_mode *mode, *mode_storage;<br>
+         LIST_FOR_EACH_ENTRY_SAFE(mode, mode_storage, &connector->display_modes, list) {<br>
+            vk_free(wsi->alloc, mode);<br>
+         }<br>
+         vk_free(wsi->alloc, connector);<br>
+      }<br>
+<br>
+      pthread_mutex_lock(&wsi->wait_<wbr>mutex);<br>
+      if (wsi->wait_thread) {<br>
+         pthread_cancel(wsi->wait_<wbr>thread);<br>
+         pthread_join(wsi->wait_thread, NULL);<br>
+      }<br>
+      pthread_mutex_unlock(&wsi-><wbr>wait_mutex);<br>
+      pthread_mutex_destroy(&wsi-><wbr>wait_mutex);<br>
+      pthread_cond_destroy(&wsi-><wbr>wait_cond);<br>
+<br>
+      vk_free(alloc, wsi);<br>
+   }<br>
+}<br>
diff --git a/src/vulkan/wsi/wsi_common_<wbr>display.h b/src/vulkan/wsi/wsi_common_<wbr>display.h<br>
new file mode 100644<br>
index 00000000000..b414a226293<br>
--- /dev/null<br>
+++ b/src/vulkan/wsi/wsi_common_<wbr>display.h<br>
@@ -0,0 +1,72 @@<br>
+/*<br>
+ * Copyright © 2017 Keith Packard<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and its<br>
+ * documentation for any purpose is hereby granted without fee, provided that<br>
+ * the above copyright notice appear in all copies and that both that copyright<br>
+ * notice and this permission notice appear in supporting documentation, and<br>
+ * that the name of the copyright holders not be used in advertising or<br>
+ * publicity pertaining to distribution of the software without specific,<br>
+ * written prior permission.  The copyright holders make no representations<br>
+ * about the suitability of this software for any purpose.  It is provided "as<br>
+ * is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,<br>
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO<br>
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR<br>
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,<br>
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER<br>
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE<br>
+ * OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#ifndef WSI_COMMON_DISPLAY_H<br>
+#define WSI_COMMON_DISPLAY_H<br>
+<br>
+#include "wsi_common.h"<br>
+#include <xf86drm.h><br>
+#include <xf86drmMode.h><br>
+<br>
+#define typed_memcpy(dest, src, count) ({ \<br>
+   STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \<br>
+   memcpy((dest), (src), (count) * sizeof(*(src))); \<br>
+})<br>
+<br>
+VkResult<br>
+wsi_display_get_physical_<wbr>device_display_properties(<wbr>VkPhysicalDevice             physical_device,<br>
+                                                   struct wsi_device            *wsi_device,<br>
+                                                   uint32_t                     *property_count,<br>
+                                                   VkDisplayPropertiesKHR       *properties);<br>
+VkResult<br>
+wsi_display_get_physical_<wbr>device_display_plane_<wbr>properties(VkPhysicalDevice               physical_device,<br>
+                                                         struct wsi_device              *wsi_device,<br>
+                                                         uint32_t                       *property_count,<br>
+                                                         VkDisplayPlanePropertiesKHR    *properties);<br>
+<br>
+VkResult<br>
+wsi_display_get_display_<wbr>plane_supported_displays(<wbr>VkPhysicalDevice               physical_device,<br>
+                                                 struct wsi_device              *wsi_device,<br>
+                                                 uint32_t                       plane_index,<br>
+                                                 uint32_t                       *display_count,<br>
+                                                 VkDisplayKHR                   *displays);<br>
+VkResult<br>
+wsi_display_get_display_mode_<wbr>properties(VkPhysicalDevice               physical_device,<br>
+                                        struct wsi_device              *wsi_device,<br>
+                                        VkDisplayKHR                   display,<br>
+                                        uint32_t                       *property_count,<br>
+                                        VkDisplayModePropertiesKHR     *properties);<br>
+<br>
+VkResult<br>
+wsi_get_display_plane_<wbr>capabilities(VkPhysicalDevice                     physical_device,<br>
+                                   struct wsi_device                    *wsi_device,<br>
+                                    VkDisplayModeKHR                    mode_khr,<br>
+                                    uint32_t                            plane_index,<br>
+                                    VkDisplayPlaneCapabilitiesKHR       *capabilities);<br>
+<br>
+VkResult<br>
+wsi_create_display_surface(<wbr>VkInstance instance,<br>
+                           const VkAllocationCallbacks *pAllocator,<br>
+                           const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,<br>
+                           VkSurfaceKHR *pSurface);<br>
+<br>
+#endif<br>
diff --git a/src/vulkan/wsi/wsi_common_<wbr>private.h b/src/vulkan/wsi/wsi_common_<wbr>private.h<br>
index b608119b969..6993750aac4 100644<br>
--- a/src/vulkan/wsi/wsi_common_<wbr>private.h<br>
+++ b/src/vulkan/wsi/wsi_common_<wbr>private.h<br>
@@ -140,6 +140,15 @@ void wsi_wl_finish_wsi(struct wsi_device *wsi_device,<br>
                        const VkAllocationCallbacks *alloc);<br>
<br>
<br>
+VkResult<br>
+wsi_display_init_wsi(struct wsi_device *wsi_device,<br>
+                     const VkAllocationCallbacks *alloc,<br>
+                     int display_fd);<br>
+<br>
+void<br>
+wsi_display_finish_wsi(struct wsi_device *wsi_device,<br>
+                       const VkAllocationCallbacks *alloc);<br>
+<br>
 #define WSI_DEFINE_NONDISP_HANDLE_<wbr>CASTS(__wsi_type, __VkType)              \<br>
                                                                            \<br>
    static inline struct __wsi_type *                                       \<br>
<span class="gmail-HOEnZb"><font color="#888888">--<br>
2.16.2<br>
<br>
______________________________<wbr>_________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div></div></div></div>