All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7] vulkan: Add direct display extensions
@ 2018-02-10  4:45 Keith Packard
  2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
                   ` (6 more replies)
  0 siblings, 7 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: dri-devel

Here's a series of extensions necessary to perform reasonable direct
display operations, either directly through DRM with no window system,
or using RandR and Linux leases.

There's one new extension, MESA_query_timestamp which performs the
same operation as glGetInteger64v(GL_TIMESTAMP, &timestamp) -- it gets
the current GPU tick using an immediate register read so that the
application can correlate GPU and CPU times. I'd love to be able to
have a single call that got both CPU and GPU times so we could put
that in the kernel, but there's no standard timestamp for the various
winsys layers (although most (all?) appear to use MONOTONIC currently,
at least on Linux).

I've refactored this series so that each patch adds a single
extension, and the code for each extension is generally grouped
together. I did not split the code in the new wsi_common_display.c
apart; it's all related to implementing various modes related to
KHR_display, so I didn't see a good place to break it apart that
wouldn't end up with a bunch of extra complexity.

-keith

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
@ 2018-02-10  4:45 ` Keith Packard
  2018-02-12 15:27   ` Eric Engestrom
                     ` (3 more replies)
  2018-02-10  4:45 ` [PATCH 2/7] vulkan: Add EXT_direct_mode_display Keith Packard
                   ` (5 subsequent siblings)
  6 siblings, 4 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel

This adds support for the KHR_display extension to the anv and radv
Vulkan drivers. The drivers now attempt to open the master DRM node
when the KHR_display extension is requested so that the common winsys
code can perform the necessary operations.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 configure.ac                           |    1 +
 meson.build                            |    4 +-
 src/amd/vulkan/Makefile.am             |    8 +
 src/amd/vulkan/Makefile.sources        |    3 +
 src/amd/vulkan/meson.build             |    7 +
 src/amd/vulkan/radv_device.c           |   28 +-
 src/amd/vulkan/radv_extensions.py      |    7 +-
 src/amd/vulkan/radv_private.h          |    2 +
 src/amd/vulkan/radv_wsi.c              |    3 +-
 src/amd/vulkan/radv_wsi_display.c      |  143 ++++
 src/intel/Makefile.sources             |    3 +
 src/intel/Makefile.vulkan.am           |    7 +
 src/intel/vulkan/anv_device.c          |   18 +-
 src/intel/vulkan/anv_extensions.py     |    1 +
 src/intel/vulkan/anv_extensions_gen.py |    5 +-
 src/intel/vulkan/anv_wsi.c             |    3 +-
 src/intel/vulkan/anv_wsi_display.c     |  129 +++
 src/intel/vulkan/meson.build           |    7 +
 src/vulkan/Makefile.am                 |    7 +
 src/vulkan/Makefile.sources            |    4 +
 src/vulkan/wsi/meson.build             |   10 +
 src/vulkan/wsi/wsi_common.c            |   19 +-
 src/vulkan/wsi/wsi_common.h            |    5 +-
 src/vulkan/wsi/wsi_common_display.c    | 1368 ++++++++++++++++++++++++++++++++
 src/vulkan/wsi/wsi_common_display.h    |   72 ++
 src/vulkan/wsi/wsi_common_private.h    |   10 +
 26 files changed, 1858 insertions(+), 16 deletions(-)
 create mode 100644 src/amd/vulkan/radv_wsi_display.c
 create mode 100644 src/intel/vulkan/anv_wsi_display.c
 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 8ed606c7694..46318365603 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1849,6 +1849,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 b39e2f8ab96..aeb7f5e2917 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'
   else
@@ -257,6 +258,7 @@ if _platforms != ''
   with_platform_wayland = _split.contains('wayland')
   with_platform_drm = _split.contains('drm')
   with_platform_surfaceless = _split.contains('surfaceless')
+  with_platform_display = _split.contains('display')
   egl_native_platform = _split[0]
 endif
 
diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
index 61025968942..061b8144b88 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -76,6 +76,14 @@ VULKAN_LIB_DEPS = \
 	$(DLOPEN_LIBS) \
 	-lm
 
+if HAVE_PLATFORM_DISPLAY
+AM_CPPFLAGS += \
+	-DVK_USE_PLATFORM_DISPLAY_KHR
+
+VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
+
+endif
+
 if HAVE_PLATFORM_X11
 AM_CPPFLAGS += \
 	$(XCB_DRI3_CFLAGS) \
diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources
index a510d88d965..618a6cdaed0 100644
--- a/src/amd/vulkan/Makefile.sources
+++ b/src/amd/vulkan/Makefile.sources
@@ -78,6 +78,9 @@ VULKAN_WSI_WAYLAND_FILES := \
 VULKAN_WSI_X11_FILES := \
 	radv_wsi_x11.c
 
+VULKAN_WSI_DISPLAY_FILES := \
+	radv_wsi_display.c
+
 VULKAN_GENERATED_FILES := \
 	radv_entrypoints.c \
 	radv_entrypoints.h \
diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
index 0a7b7c0bf3c..b7bb1075e7d 100644
--- a/src/amd/vulkan/meson.build
+++ b/src/amd/vulkan/meson.build
@@ -112,6 +112,13 @@ if with_platform_wayland
   libradv_files += files('radv_wsi_wayland.c')
 endif
 
+if with_platform_display
+  radv_flags += [
+    '-DVK_USE_PLATFORM_DISPLAY_KHR',
+  ]
+  libradv_files += files('radv_wsi_display.c')
+endif
+
 libvulkan_radeon = shared_library(
   'vulkan_radeon',
   [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index 09bb382eeb8..adf33eb35dc 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -191,9 +191,26 @@ radv_physical_device_init(struct radv_physical_device *device,
 	const char *path = drm_device->nodes[DRM_NODE_RENDER];
 	VkResult result;
 	drmVersionPtr version;
-	int fd;
-
-	fd = open(path, O_RDWR | O_CLOEXEC);
+	int fd = -1;
+
+        if (instance->khr_display_requested) {
+                fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC);
+                if (fd >= 0) {
+                        uint32_t accel_working = 0;
+                        struct drm_amdgpu_info request = {
+                                .return_pointer = (uintptr_t)&accel_working,
+                                .return_size = sizeof(accel_working),
+                                .query = AMDGPU_INFO_ACCEL_WORKING
+                        };
+
+                        if (drmCommandWrite(fd, DRM_AMDGPU_INFO, &request, sizeof (struct drm_amdgpu_info)) < 0 || !accel_working) {
+                                close(fd);
+                                fd = -1;
+                        }
+                }
+        }
+        if (fd < 0)
+                fd = open(path, O_RDWR | O_CLOEXEC);
 	if (fd < 0)
 		return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
 
@@ -209,6 +226,7 @@ radv_physical_device_init(struct radv_physical_device *device,
 		close(fd);
 		return VK_ERROR_INCOMPATIBLE_DRIVER;
 	}
+
 	drmFreeVersion(version);
 
 	device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
@@ -387,6 +405,7 @@ VkResult radv_CreateInstance(
 {
 	struct radv_instance *instance;
 	VkResult result;
+        bool khr_display_requested = false;
 
 	assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
 
@@ -411,6 +430,8 @@ VkResult radv_CreateInstance(
 	        const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i];
 		if (!radv_instance_extension_supported(ext_name))
 			return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT);
+                if (strcmp(ext_name, VK_KHR_DISPLAY_EXTENSION_NAME) == 0)
+                        khr_display_requested = true;
 	}
 
 	instance = vk_zalloc2(&default_alloc, pAllocator, sizeof(*instance), 8,
@@ -427,6 +448,7 @@ VkResult radv_CreateInstance(
 
 	instance->apiVersion = client_version;
 	instance->physicalDeviceCount = -1;
+        instance->khr_display_requested = khr_display_requested;
 
 	result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
 	if (result != VK_SUCCESS) {
diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index d761895d3a0..24cab8cbb39 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -81,6 +81,7 @@ EXTENSIONS = [
     Extension('VK_KHR_wayland_surface',                   6, 'VK_USE_PLATFORM_WAYLAND_KHR'),
     Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
+    Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, '!ANDROID'),
     Extension('VK_EXT_debug_report',                      9, True),
     Extension('VK_EXT_discard_rectangles',                1, True),
@@ -168,7 +169,7 @@ _TEMPLATE = Template(COPYRIGHT + """
 #include "vk_util.h"
 
 /* Convert the VK_USE_PLATFORM_* defines to booleans */
-%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
+%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
 #ifdef VK_USE_PLATFORM_${platform}_KHR
 #   undef VK_USE_PLATFORM_${platform}_KHR
 #   define VK_USE_PLATFORM_${platform}_KHR true
@@ -187,7 +188,9 @@ _TEMPLATE = Template(COPYRIGHT + """
 
 #define RADV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
                          VK_USE_PLATFORM_XCB_KHR || \\
-                         VK_USE_PLATFORM_XLIB_KHR)
+                         VK_USE_PLATFORM_XLIB_KHR || \\
+                         VK_USE_PLATFORM_DISPLAY_KHR)
+
 
 bool
 radv_instance_extension_supported(const char *name)
diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
index be9e8f43964..1e3719bcc4f 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -75,6 +75,7 @@ typedef uint32_t xcb_window_t;
 #include "radv_entrypoints.h"
 
 #include "wsi_common.h"
+#include "wsi_common_display.h"
 
 #define ATI_VENDOR_ID 0x1002
 
@@ -300,6 +301,7 @@ struct radv_instance {
 	uint64_t perftest_flags;
 
 	struct vk_debug_report_instance             debug_report_callbacks;
+        bool                                        khr_display_requested;
 };
 
 VkResult radv_init_wsi(struct radv_physical_device *physical_device);
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
index e016e837102..5ec872a63d0 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->local_fd);
 }
 
 void
diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
new file mode 100644
index 00000000000..b0a4db0344b
--- /dev/null
+++ b/src/amd/vulkan/radv_wsi_display.c
@@ -0,0 +1,143 @@
+/*
+ * 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 <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "radv_private.h"
+#include "radv_cs.h"
+#include "util/disk_cache.h"
+#include "util/strtod.h"
+#include "vk_util.h"
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <amdgpu.h>
+#include <amdgpu_drm.h>
+#include "winsys/amdgpu/radv_amdgpu_winsys_public.h"
+#include "ac_llvm_util.h"
+#include "vk_format.h"
+#include "sid.h"
+#include "util/debug.h"
+#include "wsi_common_display.h"
+
+#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
+
+VkResult
+radv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice             physical_device,
+                                           uint32_t                     *property_count,
+                                           VkDisplayPropertiesKHR       *properties)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_properties(physical_device,
+                                                             &pdevice->wsi_device,
+                                                             property_count,
+                                                             properties);
+}
+
+VkResult
+radv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice                physical_device,
+                                                uint32_t                        *property_count,
+                                                VkDisplayPlanePropertiesKHR     *properties)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_plane_properties(physical_device,
+                                                                   &pdevice->wsi_device,
+                                                                   property_count,
+                                                                   properties);
+}
+
+VkResult
+radv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice               physical_device,
+                                         uint32_t                       plane_index,
+                                         uint32_t                       *display_count,
+                                         VkDisplayKHR                   *displays)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_plane_supported_displays(physical_device,
+                                                           &pdevice->wsi_device,
+                                                           plane_index,
+                                                           display_count,
+                                                           displays);
+}
+
+
+VkResult
+radv_GetDisplayModePropertiesKHR(VkPhysicalDevice               physical_device,
+                                 VkDisplayKHR                   display,
+                                 uint32_t                       *property_count,
+                                 VkDisplayModePropertiesKHR     *properties)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_mode_properties(physical_device,
+                                                  &pdevice->wsi_device,
+                                                  display,
+                                                  property_count,
+                                                  properties);
+}
+
+VkResult
+radv_CreateDisplayModeKHR(VkPhysicalDevice                      physical_device,
+                          VkDisplayKHR                          display,
+                          const VkDisplayModeCreateInfoKHR      *create_info,
+                          const VkAllocationCallbacks           *allocator,
+                          VkDisplayModeKHR                      *mode)
+{
+   return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+
+VkResult
+radv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice                    physical_device,
+                                    VkDisplayModeKHR                    mode_khr,
+                                    uint32_t                            plane_index,
+                                    VkDisplayPlaneCapabilitiesKHR       *capabilities)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_get_display_plane_capabilities(physical_device,
+                                             &pdevice->wsi_device,
+                                             mode_khr,
+                                             plane_index,
+                                             capabilities);
+}
+
+VkResult
+radv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instance,
+                                  const VkDisplaySurfaceCreateInfoKHR   *create_info,
+                                  const VkAllocationCallbacks           *allocator,
+                                  VkSurfaceKHR                          *surface)
+{
+   RADV_FROM_HANDLE(radv_instance, instance, _instance);
+   const VkAllocationCallbacks *alloc;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &instance->alloc;
+
+   return wsi_create_display_surface(_instance, alloc, create_info, surface);
+}
diff --git a/src/intel/Makefile.sources b/src/intel/Makefile.sources
index 9595bf42582..6c142729d94 100644
--- a/src/intel/Makefile.sources
+++ b/src/intel/Makefile.sources
@@ -240,6 +240,9 @@ VULKAN_WSI_WAYLAND_FILES := \
 VULKAN_WSI_X11_FILES := \
 	vulkan/anv_wsi_x11.c
 
+VULKAN_WSI_DISPLAY_FILES := \
+	vulkan/anv_wsi_display.c
+
 VULKAN_GEM_FILES := \
 	vulkan/anv_gem.c
 
diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
index 23fa877e77d..7c428a799d7 100644
--- a/src/intel/Makefile.vulkan.am
+++ b/src/intel/Makefile.vulkan.am
@@ -187,6 +187,13 @@ VULKAN_SOURCES += $(VULKAN_WSI_WAYLAND_FILES)
 VULKAN_LIB_DEPS += $(WAYLAND_CLIENT_LIBS)
 endif
 
+if HAVE_PLATFORM_DISPLAY
+VULKAN_CPPFLAGS += \
+	-DVK_USE_PLATFORM_DISPLAY_KHR
+
+VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
+endif
+
 noinst_LTLIBRARIES += vulkan/libvulkan_common.la
 vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
 vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS)
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 86c1bdc1d51..9614907fda3 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -277,14 +277,25 @@ anv_physical_device_init_uuids(struct anv_physical_device *device)
 static VkResult
 anv_physical_device_init(struct anv_physical_device *device,
                          struct anv_instance *instance,
-                         const char *path)
+                         const char *primary_path,
+                         const char *render_path)
 {
    VkResult result;
-   int fd;
+   int fd = -1;
+   const char *path;
 
    brw_process_intel_debug_variable();
 
-   fd = open(path, O_RDWR | O_CLOEXEC);
+   if (instance->enabled_extensions.KHR_display) {
+      path = primary_path;
+      fd = open(path, O_RDWR | O_CLOEXEC);
+   }
+
+   if (fd < 0) {
+      path = render_path;
+      fd = open(path, O_RDWR | O_CLOEXEC);
+   }
+
    if (fd < 0)
       return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
 
@@ -652,6 +663,7 @@ anv_enumerate_devices(struct anv_instance *instance)
 
          result = anv_physical_device_init(&instance->physicalDevice,
                         instance,
+                        devices[i]->nodes[DRM_NODE_PRIMARY],
                         devices[i]->nodes[DRM_NODE_RENDER]);
          if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
             break;
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 581921e62a1..978a219e2b2 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -83,6 +83,7 @@ EXTENSIONS = [
     Extension('VK_KHR_wayland_surface',                   6, 'VK_USE_PLATFORM_WAYLAND_KHR'),
     Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
+    Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, True),
     Extension('VK_EXT_debug_report',                      8, True),
     Extension('VK_EXT_external_memory_dma_buf',           1, True),
diff --git a/src/intel/vulkan/anv_extensions_gen.py b/src/intel/vulkan/anv_extensions_gen.py
index 33827ecd015..84d07f9767a 100644
--- a/src/intel/vulkan/anv_extensions_gen.py
+++ b/src/intel/vulkan/anv_extensions_gen.py
@@ -113,7 +113,7 @@ _TEMPLATE_C = Template(COPYRIGHT + """
 #include "vk_util.h"
 
 /* Convert the VK_USE_PLATFORM_* defines to booleans */
-%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
+%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
 #ifdef VK_USE_PLATFORM_${platform}_KHR
 #   undef VK_USE_PLATFORM_${platform}_KHR
 #   define VK_USE_PLATFORM_${platform}_KHR true
@@ -132,7 +132,8 @@ _TEMPLATE_C = Template(COPYRIGHT + """
 
 #define ANV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
                          VK_USE_PLATFORM_XCB_KHR || \\
-                         VK_USE_PLATFORM_XLIB_KHR)
+                         VK_USE_PLATFORM_XLIB_KHR || \\
+                         VK_USE_PLATFORM_DISPLAY_KHR)
 
 const VkExtensionProperties anv_instance_extensions[ANV_INSTANCE_EXTENSION_COUNT] = {
 %for ext in instance_extensions:
diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
index 6082c3dd093..f86d83589ea 100644
--- a/src/intel/vulkan/anv_wsi.c
+++ b/src/intel/vulkan/anv_wsi.c
@@ -39,7 +39,8 @@ anv_init_wsi(struct anv_physical_device *physical_device)
    return 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->local_fd);
 }
 
 void
diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
new file mode 100644
index 00000000000..9b00d7f02e4
--- /dev/null
+++ b/src/intel/vulkan/anv_wsi_display.c
@@ -0,0 +1,129 @@
+/*
+ * 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 "anv_private.h"
+#include "wsi_common.h"
+#include "vk_format_info.h"
+#include "vk_util.h"
+#include "wsi_common_display.h"
+
+#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
+
+VkResult
+anv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice             physical_device,
+                                           uint32_t                     *property_count,
+                                           VkDisplayPropertiesKHR       *properties)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_properties(physical_device,
+                                                             &pdevice->wsi_device,
+                                                             property_count,
+                                                             properties);
+}
+
+VkResult
+anv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice                physical_device,
+                                                uint32_t                        *property_count,
+                                                VkDisplayPlanePropertiesKHR     *properties)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_plane_properties(physical_device,
+                                                                   &pdevice->wsi_device,
+                                                                   property_count,
+                                                                   properties);
+}
+
+VkResult
+anv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice               physical_device,
+                                         uint32_t                       plane_index,
+                                         uint32_t                       *display_count,
+                                         VkDisplayKHR                   *displays)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_plane_supported_displays(physical_device,
+                                                           &pdevice->wsi_device,
+                                                           plane_index,
+                                                           display_count,
+                                                           displays);
+}
+
+
+VkResult
+anv_GetDisplayModePropertiesKHR(VkPhysicalDevice               physical_device,
+                                 VkDisplayKHR                   display,
+                                 uint32_t                       *property_count,
+                                 VkDisplayModePropertiesKHR     *properties)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_mode_properties(physical_device,
+                                                  &pdevice->wsi_device,
+                                                  display,
+                                                  property_count,
+                                                  properties);
+}
+
+VkResult
+anv_CreateDisplayModeKHR(VkPhysicalDevice                      physical_device,
+                          VkDisplayKHR                          display,
+                          const VkDisplayModeCreateInfoKHR      *create_info,
+                          const VkAllocationCallbacks           *allocator,
+                          VkDisplayModeKHR                      *mode)
+{
+   return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+
+VkResult
+anv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice                    physical_device,
+                                    VkDisplayModeKHR                    mode_khr,
+                                    uint32_t                            plane_index,
+                                    VkDisplayPlaneCapabilitiesKHR       *capabilities)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_get_display_plane_capabilities(physical_device,
+                                             &pdevice->wsi_device,
+                                             mode_khr,
+                                             plane_index,
+                                             capabilities);
+}
+
+VkResult
+anv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instance,
+                                  const VkDisplaySurfaceCreateInfoKHR   *create_info,
+                                  const VkAllocationCallbacks           *allocator,
+                                  VkSurfaceKHR                          *surface)
+{
+   ANV_FROM_HANDLE(anv_instance, instance, _instance);
+   const VkAllocationCallbacks *alloc;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &instance->alloc;
+
+   return wsi_create_display_surface(_instance, alloc, create_info, surface);
+}
diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
index 69ec26e19b6..2e2ab8f7ecd 100644
--- a/src/intel/vulkan/meson.build
+++ b/src/intel/vulkan/meson.build
@@ -171,6 +171,13 @@ if with_platform_wayland
   libanv_files += files('anv_wsi_wayland.c')
 endif
 
+if with_platform_display
+  anv_flags += [
+    '-DVK_USE_PLATFORM_DISPLAY_KHR',
+  ]
+  libanv_files += files('anv_wsi_display.c')
+endif
+
 libanv_common = static_library(
   'anv_common',
   [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h],
diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
index 037436c1cd7..c33ac5758f7 100644
--- a/src/vulkan/Makefile.am
+++ b/src/vulkan/Makefile.am
@@ -57,6 +57,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
+
 BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES)
 CLEANFILES = $(BUILT_SOURCES)
 
diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources
index a0a24ce7de8..3642c7662c4 100644
--- a/src/vulkan/Makefile.sources
+++ b/src/vulkan/Makefile.sources
@@ -17,6 +17,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 bd0fd3cc53e..743631a6113 100644
--- a/src/vulkan/wsi/meson.build
+++ b/src/vulkan/wsi/meson.build
@@ -57,6 +57,16 @@ 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 90ed07b7857..c0a285e5814 100644
--- a/src/vulkan/wsi/wsi_common.c
+++ b/src/vulkan/wsi/wsi_common.c
@@ -29,7 +29,8 @@ VkResult
 wsi_device_init(struct wsi_device *wsi,
                 VkPhysicalDevice pdevice,
                 WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
-                const VkAllocationCallbacks *alloc)
+                const VkAllocationCallbacks *alloc,
+                int device_fd)
 {
    VkResult result;
 
@@ -89,6 +90,19 @@ wsi_device_init(struct wsi_device *wsi,
    }
 #endif
 
+#ifdef VK_USE_PLATFORM_DISPLAY_KHR
+   result = wsi_display_init_wsi(wsi, alloc, pdevice, device_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;
 }
 
@@ -96,6 +110,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 3e0d3be1c24..1cb6aaebca0 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -50,7 +50,7 @@ struct wsi_memory_allocate_info {
 
 struct wsi_interface;
 
-#define VK_ICD_WSI_PLATFORM_MAX 5
+#define VK_ICD_WSI_PLATFORM_MAX 6
 
 struct wsi_device {
    VkPhysicalDeviceMemoryProperties memory_props;
@@ -93,7 +93,8 @@ VkResult
 wsi_device_init(struct wsi_device *wsi,
                 VkPhysicalDevice pdevice,
                 WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
-                const VkAllocationCallbacks *alloc);
+                const VkAllocationCallbacks *alloc,
+                int device_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..2732b1dd721
--- /dev/null
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -0,0 +1,1368 @@
+/*
+ * 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 "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;
+   wsi_display_mode             *current_mode;
+   drmModeModeInfo              current_drm_mode;
+} wsi_display_connector;
+
+struct wsi_display {
+   struct wsi_interface         base;
+
+   const VkAllocationCallbacks  *alloc;
+   VkPhysicalDevice             physical_device;
+
+   int                          master_fd;
+   int                          render_fd;
+
+   pthread_mutex_t              wait_mutex;
+   pthread_cond_t               wait_cond;
+   pthread_t                    wait_thread;
+
+   struct list_head             connectors;
+
+   struct list_head             display_modes;
+};
+
+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;
+   uint64_t                     flip_sequence;
+};
+
+struct wsi_display_swapchain {
+   struct wsi_swapchain         base;
+   struct wsi_display           *wsi;
+   VkIcdSurfaceDisplay          *surface;
+   uint64_t                     flip_sequence;
+   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));
+}
+
+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)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode;
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->connector == connector &&
+          wsi_display_mode_matches_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           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode;
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list)
+      if (display_mode->connector == connector)
+         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];
+   struct wsi_display_mode      *display_mode;
+
+   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_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!display_mode)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   display_mode->connector = connector;
+   display_mode->valid = true;
+   display_mode->preferred = (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, &wsi->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_alloc(wsi->alloc, sizeof (struct wsi_display_connector), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   memset(connector, '\0', sizeof (*connector));
+   connector->id = connector_id;
+   connector->wsi = wsi;
+   connector->active = false;
+   /* XXX use EDID name */
+   connector->name = "monitor";
+   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->master_fd < 0)
+      return NULL;
+
+   drm_connector = drmModeGetConnector(wsi->master_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 void
+wsi_display_fill_in_display_properties(struct wsi_device                *wsi_device,
+                                       struct wsi_display_connector     *connector,
+                                       VkDisplayPropertiesKHR           *properties)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode, *preferred_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 */
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->valid && display_mode->connector == connector && display_mode->preferred) {
+         preferred_mode = display_mode;
+         break;
+      }
+   }
+
+   if (preferred_mode) {
+      properties->physicalResolution.width = preferred_mode->hdisplay;
+      properties->physicalResolution.height = preferred_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];
+   struct wsi_display_connector *connector;
+   int                          c;
+   uint32_t                     connected;
+   uint32_t                     property_count_requested = *property_count;
+   drmModeResPtr                mode_res;
+
+   if (wsi->master_fd < 0)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   mode_res = drmModeGetResources(wsi->master_fd);
+
+   if (!mode_res)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   connected = 0;
+
+   /* Get current information */
+   for (c = 0; c < mode_res->count_connectors; c++) {
+      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)
+         connected++;
+   }
+
+   /* Fill in property information if requested */
+   if (properties != NULL) {
+      connected = 0;
+
+      for (c = 0; c < mode_res->count_connectors; c++) {
+         connector  = wsi_display_find_connector(wsi_device, mode_res->connectors[c]);
+
+         if (connector && connector->connected) {
+            if (connected < property_count_requested) {
+               wsi_display_fill_in_display_properties(wsi_device,
+                                                      connector,
+                                                      &properties[connected]);
+            }
+            connected++;
+         }
+      }
+   }
+
+   drmModeFreeResources(mode_res);
+
+   *property_count = connected;
+
+   if (connected > property_count_requested && properties != NULL)
+      return VK_INCOMPLETE;
+
+   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;
+   uint32_t                     property_count_requested = *property_count;
+   int                          c;
+
+   if (!properties)
+      property_count_requested = 0;
+
+   c = 0;
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
+      if (c < property_count_requested) {
+         if (connector && connector->active) {
+            properties[c].currentDisplay = wsi_display_connector_to_handle(connector);
+            properties[c].currentStackIndex = c;
+         } else {
+            properties[c].currentDisplay = NULL;
+            properties[c].currentStackIndex = 0;
+         }
+      }
+      c++;
+   }
+
+   *property_count = c;
+
+   if (c > property_count_requested && properties != NULL)
+      return VK_INCOMPLETE;
+
+   return VK_SUCCESS;
+}
+
+/*
+ * 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;
+   int                          c;
+
+
+   if (displays == NULL) {
+      *display_count = 1;
+      return VK_SUCCESS;
+   }
+
+   if (*display_count < 1)
+      return VK_INCOMPLETE;
+
+   c = 0;
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
+      if (c == plane_index) {
+         *displays = wsi_display_connector_to_handle(connector);
+         *display_count = 1;
+         return VK_SUCCESS;
+      }
+      c++;
+   }
+
+   *displays = 0;
+   *display_count = 0;
+
+   return VK_SUCCESS;
+}
+
+/*
+ * 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           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
+   int                          i;
+   struct wsi_display_mode      *display_mode;
+   uint32_t                     property_count_requested = *property_count;
+
+   i = 0;
+
+   if (properties == NULL)
+      property_count_requested = 0;
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->valid && display_mode->connector == connector) {
+         if (i < property_count_requested) {
+            properties[i].displayMode = wsi_display_mode_to_handle(display_mode);
+            properties[i].parameters.visibleRegion.width = display_mode->hdisplay;
+            properties[i].parameters.visibleRegion.height = display_mode->vdisplay;
+            properties[i].parameters.refreshRate = (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
+         }
+         i++;
+      }
+   }
+
+   *property_count = i;
+
+   if (i > property_count_requested && properties != NULL)
+      return VK_INCOMPLETE;
+
+   return VK_SUCCESS;
+
+}
+
+/*
+ * 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_alloc(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_INHERIT_BIT_KHR |
+                                    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 VkFormat available_surface_formats[] = {
+   VK_FORMAT_B8G8R8A8_SRGB,
+   VK_FORMAT_B8G8R8A8_UNORM,
+};
+
+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];
+         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];
+         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)
+{
+   if (present_modes == NULL) {
+      *present_mode_count = ARRAY_SIZE(available_present_modes);
+      return VK_SUCCESS;
+   }
+
+   *present_mode_count = MIN2(*present_mode_count, ARRAY_SIZE(available_present_modes));
+   typed_memcpy(present_modes, available_present_modes, *present_mode_count);
+
+   if (*present_mode_count < ARRAY_SIZE(available_present_modes))
+      return VK_INCOMPLETE;
+   return VK_SUCCESS;
+}
+
+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                     image_handle;
+
+   if (chain->base.use_prime_blit)
+      result = wsi_create_prime_image(&chain->base, create_info, &image->base);
+   else
+      result = wsi_create_native_image(&chain->base, create_info, &image->base);
+   if (result != VK_SUCCESS)
+      return result;
+
+   ret = drmPrimeFDToHandle(wsi->master_fd, image->base.fd, &image_handle);
+
+   close(image->base.fd);
+   image->base.fd = -1;
+
+   if (ret < 0)
+      goto fail_handle;
+
+   image->chain = chain;
+   image->state = wsi_image_idle;
+   image->fb_id = 0;
+
+   /* XXX extract depth and bpp from image somehow */
+   ret = drmModeAddFB(wsi->master_fd, create_info->imageExtent.width, create_info->imageExtent.height,
+                      24, 32, image->base.row_pitch, image_handle, &image->fb_id);
+
+   if (ret)
+      goto fail_fb;
+
+   return VK_SUCCESS;
+
+fail_fb:
+   /* fall through */
+
+fail_handle:
+   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;
+
+   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;
+
+   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);
+   (void) _wsi_display_queue_next(&(image->chain->base));
+}
+
+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->master_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->master_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;
+}
+
+/* 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;
+
+   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);
+   return result;
+}
+
+/*
+ * 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->master_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->master_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->master_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->master_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->master_fd);
+   if (!mode_res) {
+      result = VK_ERROR_INITIALIZATION_FAILED;
+      goto bail;
+   }
+
+   drm_connector = drmModeGetConnectorCurrent(wsi->master_fd, connector->id);
+   if (!drm_connector) {
+      result = VK_ERROR_INITIALIZATION_FAILED;
+      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->master_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->master_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->master_fd, connector->crtc_id, image->fb_id, 0, 0,
+                                 &connector->id, 1, &connector->current_drm_mode);
+
+            if (ret == 0) {
+               image->state = wsi_image_displaying;
+               wsi_display_idle_old_displaying(image);
+               connector->active = true;
+               return VK_SUCCESS;
+            }
+            break;
+         case EACCES:
+            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;
+
+   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);
+
+   pthread_mutex_unlock(&wsi->wait_mutex);
+
+   return result;
+}
+
+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_alloc(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->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)
+         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,
+                     VkPhysicalDevice physical_device,
+                     int device_fd)
+{
+   struct wsi_display *wsi;
+   VkResult result;
+
+   wsi = vk_alloc(alloc, sizeof(*wsi), 8,
+                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+   if (!wsi) {
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;
+      goto fail;
+   }
+   memset(wsi, '\0', sizeof (*wsi));
+
+   wsi->master_fd = -1;
+   if (drmGetNodeTypeFromFd(device_fd) == DRM_NODE_PRIMARY)
+      wsi->master_fd = device_fd;
+   wsi->render_fd = device_fd;
+
+   pthread_mutex_init(&wsi->wait_mutex, NULL);
+   wsi->physical_device = physical_device;
+   wsi->alloc = alloc;
+
+   LIST_INITHEAD(&wsi->display_modes);
+   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) {
+         vk_free(wsi->alloc, connector);
+      }
+
+      struct wsi_display_mode *mode, *mode_storage;
+      LIST_FOR_EACH_ENTRY_SAFE(mode, mode_storage, &wsi->display_modes, list) {
+         vk_free(wsi->alloc, mode);
+      }
+
+      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 503b2a015dc..d38d2efa116 100644
--- a/src/vulkan/wsi/wsi_common_private.h
+++ b/src/vulkan/wsi/wsi_common_private.h
@@ -135,6 +135,16 @@ 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,
+                     VkPhysicalDevice physical_device,
+                     int device_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.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 2/7] vulkan: Add EXT_direct_mode_display
  2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
  2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
@ 2018-02-10  4:45 ` Keith Packard
  2018-02-10  4:45 ` [PATCH 3/7] vulkan: Add EXT_acquire_xlib_display Keith Packard
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: dri-devel

Add support for the EXT_direct_mode_display extension. This just
provides the vkReleaseDisplayEXT function.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 src/amd/vulkan/radv_extensions.py   |  1 +
 src/amd/vulkan/radv_wsi_display.c   | 11 +++++++++++
 src/intel/vulkan/anv_extensions.py  |  1 +
 src/intel/vulkan/anv_wsi_display.c  | 11 +++++++++++
 src/vulkan/wsi/wsi_common_display.c | 17 +++++++++++++++++
 src/vulkan/wsi/wsi_common_display.h |  5 +++++
 6 files changed, 46 insertions(+)

diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index 24cab8cbb39..f784681ff57 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -82,6 +82,7 @@ EXTENSIONS = [
     Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
     Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
+    Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, '!ANDROID'),
     Extension('VK_EXT_debug_report',                      9, True),
     Extension('VK_EXT_discard_rectangles',                1, True),
diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
index b0a4db0344b..0051f5ac865 100644
--- a/src/amd/vulkan/radv_wsi_display.c
+++ b/src/amd/vulkan/radv_wsi_display.c
@@ -141,3 +141,14 @@ radv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instanc
 
    return wsi_create_display_surface(_instance, alloc, create_info, surface);
 }
+
+VkResult
+radv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
+                       VkDisplayKHR     display)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_release_display(physical_device,
+                              &pdevice->wsi_device,
+                              display);
+}
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 978a219e2b2..633e378e605 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -84,6 +84,7 @@ EXTENSIONS = [
     Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
     Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
+    Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, True),
     Extension('VK_EXT_debug_report',                      8, True),
     Extension('VK_EXT_external_memory_dma_buf',           1, True),
diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
index 9b00d7f02e4..e6f67f7dec9 100644
--- a/src/intel/vulkan/anv_wsi_display.c
+++ b/src/intel/vulkan/anv_wsi_display.c
@@ -127,3 +127,14 @@ anv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instance
 
    return wsi_create_display_surface(_instance, alloc, create_info, surface);
 }
+
+VkResult
+anv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
+                       VkDisplayKHR     display)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_release_display(physical_device,
+                              &pdevice->wsi_device,
+                              display);
+}
diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
index 2732b1dd721..5c123e6465e 100644
--- a/src/vulkan/wsi/wsi_common_display.c
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -1366,3 +1366,20 @@ wsi_display_finish_wsi(struct wsi_device *wsi_device,
       vk_free(alloc, wsi);
    }
 }
+
+/*
+ * Implement vkReleaseDisplay
+ */
+VkResult
+wsi_release_display(VkPhysicalDevice            physical_device,
+                    struct wsi_device           *wsi_device,
+                    VkDisplayKHR                display)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+
+   if (wsi->master_fd >= 0 && wsi->master_fd != wsi->render_fd) {
+      close(wsi->master_fd);
+      wsi->master_fd = -1;
+   }
+   return VK_SUCCESS;
+}
diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h
index b414a226293..5fbb6925e4a 100644
--- a/src/vulkan/wsi/wsi_common_display.h
+++ b/src/vulkan/wsi/wsi_common_display.h
@@ -69,4 +69,9 @@ wsi_create_display_surface(VkInstance instance,
                            const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
                            VkSurfaceKHR *pSurface);
 
+VkResult
+wsi_release_display(VkPhysicalDevice            physical_device,
+                    struct wsi_device           *wsi_device,
+                    VkDisplayKHR                display);
+
 #endif
-- 
2.15.1

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 3/7] vulkan: Add EXT_acquire_xlib_display
  2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
  2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
  2018-02-10  4:45 ` [PATCH 2/7] vulkan: Add EXT_direct_mode_display Keith Packard
@ 2018-02-10  4:45 ` Keith Packard
  2018-02-13  0:16   ` Dylan Baker
  2018-02-10  4:45 ` [PATCH 4/7] vulkan: Add VK_EXT_display_surface_counter [v4] Keith Packard
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel

This extension adds the ability to borrow an X RandR output for
temporary use directly by a Vulkan application. For DRM, we use the
Linux resource leasing mechanism.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 configure.ac                           |  25 ++
 meson.build                            |  17 ++
 meson_options.txt                      |   7 +
 src/amd/vulkan/Makefile.am             |   7 +
 src/amd/vulkan/meson.build             |   7 +
 src/amd/vulkan/radv_extensions.py      |  11 +-
 src/amd/vulkan/radv_wsi_display.c      |  30 +++
 src/intel/Makefile.vulkan.am           |   7 +
 src/intel/vulkan/anv_extensions.py     |   1 +
 src/intel/vulkan/anv_extensions_gen.py |  10 +-
 src/intel/vulkan/anv_wsi_display.c     |  30 +++
 src/intel/vulkan/meson.build           |   7 +
 src/vulkan/Makefile.am                 |   5 +
 src/vulkan/wsi/meson.build             |   7 +
 src/vulkan/wsi/wsi_common_display.c    | 472 +++++++++++++++++++++++++++++++++
 src/vulkan/wsi/wsi_common_display.h    |  17 ++
 16 files changed, 650 insertions(+), 10 deletions(-)

diff --git a/configure.ac b/configure.ac
index 46318365603..9effd15e8c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1547,6 +1547,7 @@ AM_CONDITIONAL(HAVE_APPLEDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = x
 AM_CONDITIONAL(HAVE_LMSENSORS, test "x$enable_lmsensors" = xyes )
 AM_CONDITIONAL(HAVE_GALLIUM_EXTRA_HUD, test "x$enable_gallium_extra_hud" = xyes )
 AM_CONDITIONAL(HAVE_WINDOWSDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = xwindows )
+AM_CONDITIONAL(HAVE_XLEASE, test "x$have_xlease" = xyes )
 
 AC_ARG_ENABLE([shared-glapi],
     [AS_HELP_STRING([--enable-shared-glapi],
@@ -1846,6 +1847,11 @@ if test x"$enable_dri3" = xyes; then
     PKG_CHECK_MODULES([XCB_DRI3], [$dri3_modules])
 fi
 
+if test x"$have_xlease" = xyes; then
+    randr_modules="x11-xcb xcb-randr"
+    PKG_CHECK_MODULES([XCB_RANDR], [$randr_modules])
+fi
+
 AM_CONDITIONAL(HAVE_PLATFORM_X11, echo "$platforms" | grep -q 'x11')
 AM_CONDITIONAL(HAVE_PLATFORM_WAYLAND, echo "$platforms" | grep -q 'wayland')
 AM_CONDITIONAL(HAVE_PLATFORM_DRM, echo "$platforms" | grep -q 'drm')
@@ -1853,6 +1859,25 @@ AM_CONDITIONAL(HAVE_PLATFORM_DISPLAY, echo "$platforms" | grep -q 'drm')
 AM_CONDITIONAL(HAVE_PLATFORM_SURFACELESS, echo "$platforms" | grep -q 'surfaceless')
 AM_CONDITIONAL(HAVE_PLATFORM_ANDROID, echo "$platforms" | grep -q 'android')
 
+AC_ARG_ENABLE(xlib-lease,
+    [AS_HELP_STRING([--enable-xlib-lease]
+                    [enable VK_acquire_xlib_display using X leases])],
+    [enable_xlib_lease=$enableval], [enable_xlib_lease=auto])
+case "x$enable_xlib_lease" in
+xyes)
+    ;;
+xno)
+    ;;
+*)
+    if echo "$platforms" | grep -q 'x11' && echo "$platforms" | grep -q 'drm';
+        enable_xlib_lease=yes
+    else
+        enable_xlib_lease=no
+    fi
+esac
+
+AM_CONDITIONAL(HAVE_XLIB_LEASE, test "x$enable_xlib_lease" = xyes)
+
 dnl
 dnl More DRI setup
 dnl
diff --git a/meson.build b/meson.build
index aeb7f5e2917..595b0f66cd7 100644
--- a/meson.build
+++ b/meson.build
@@ -262,6 +262,19 @@ if _platforms != ''
   egl_native_platform = _split[0]
 endif
 
+with_xlib_lease = get_option('xlib-lease')
+if with_xlib_lease == 'auto'
+  if with_platform_x11 and with_platform_display
+    with_xlib_lease = true
+  else
+    with_xlib_lease = false
+  endif
+elif with_xlib_lease == 'true'
+  with_xlib_lease = true
+else
+  with_xlib_lease = false
+endif
+
 with_glx = get_option('glx')
 if with_glx == 'auto'
   if with_dri
@@ -1151,6 +1164,7 @@ dep_xcb_present = []
 dep_xcb_sync = []
 dep_xcb_xfixes = []
 dep_xshmfence = []
+dep_xcb_xrandr = []
 if with_platform_x11
   if with_glx == 'xlib' or with_glx == 'gallium-xlib'
     dep_x11 = dependency('x11')
@@ -1190,6 +1204,9 @@ if with_platform_x11
   if with_egl
     dep_xcb_xfixes = dependency('xcb-xfixes')
   endif
+  if with_xlib_lease
+    dep_xcb_xrandr = dependency('xcb-randr', version : '>= 1.12')
+  endif
 endif
 
 if get_option('gallium-extra-hud')
diff --git a/meson_options.txt b/meson_options.txt
index 7fafe2deaac..d38c9aa6149 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -286,3 +286,10 @@ option(
   value : '',
   description : 'Comma delimited list of tools to build. choices : freedreno,glsl,intel,nir,nouveau or all'
 )
+option(
+  'xlib-lease',
+  type : 'combo',
+  value : 'auto',
+  choices : ['auto', 'true', 'false'],
+  description : 'Enable VK_EXT_acquire_xlib_display.'
+)
diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
index 061b8144b88..94ece06e99e 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -81,7 +81,14 @@ AM_CPPFLAGS += \
 	-DVK_USE_PLATFORM_DISPLAY_KHR
 
 VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
+endif
+
+if HAVE_XLIB_LEASE
+AM_CPPFLAGS += \
+	-DVK_USE_PLATFORM_XLIB_XRANDR_EXT \
+	$(XCB_RANDR_CFLAGS)
 
+VULKAN_LIB_DEPS += $(XCB_RANDR_LIBS)
 endif
 
 if HAVE_PLATFORM_X11
diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
index b7bb1075e7d..0b92a1763a1 100644
--- a/src/amd/vulkan/meson.build
+++ b/src/amd/vulkan/meson.build
@@ -119,6 +119,13 @@ if with_platform_display
   libradv_files += files('radv_wsi_display.c')
 endif
 
+if with_xlib_lease
+  radv_deps += dep_xcb_xrandr
+  radv_flags += [
+    '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
+  ]
+endif
+
 libvulkan_radeon = shared_library(
   'vulkan_radeon',
   [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index f784681ff57..2d804afed35 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -83,6 +83,7 @@ EXTENSIONS = [
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
     Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
+    Extension('VK_EXT_acquire_xlib_display',              1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
     Extension('VK_KHX_multiview',                         1, '!ANDROID'),
     Extension('VK_EXT_debug_report',                      9, True),
     Extension('VK_EXT_discard_rectangles',                1, True),
@@ -170,12 +171,12 @@ _TEMPLATE = Template(COPYRIGHT + """
 #include "vk_util.h"
 
 /* Convert the VK_USE_PLATFORM_* defines to booleans */
-%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
-#ifdef VK_USE_PLATFORM_${platform}_KHR
-#   undef VK_USE_PLATFORM_${platform}_KHR
-#   define VK_USE_PLATFORM_${platform}_KHR true
+%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']:
+#ifdef VK_USE_PLATFORM_${platform}
+#   undef VK_USE_PLATFORM_${platform}
+#   define VK_USE_PLATFORM_${platform} true
 #else
-#   define VK_USE_PLATFORM_${platform}_KHR false
+#   define VK_USE_PLATFORM_${platform} false
 #endif
 %endfor
 
diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
index 0051f5ac865..9b76ce623b0 100644
--- a/src/amd/vulkan/radv_wsi_display.c
+++ b/src/amd/vulkan/radv_wsi_display.c
@@ -152,3 +152,33 @@ radv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
                               &pdevice->wsi_device,
                               display);
 }
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+VkResult
+radv_AcquireXlibDisplayEXT(VkPhysicalDevice     physical_device,
+                           Display              *dpy,
+                           VkDisplayKHR         display)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_acquire_xlib_display(physical_device,
+                                   &pdevice->wsi_device,
+                                   dpy,
+                                   display);
+}
+
+VkResult
+radv_GetRandROutputDisplayEXT(VkPhysicalDevice  physical_device,
+                              Display           *dpy,
+                              RROutput          output,
+                              VkDisplayKHR      *display)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_get_randr_output_display(physical_device,
+                                       &pdevice->wsi_device,
+                                       dpy,
+                                       output,
+                                       display);
+}
+#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
index 7c428a799d7..0f0d3815097 100644
--- a/src/intel/Makefile.vulkan.am
+++ b/src/intel/Makefile.vulkan.am
@@ -194,6 +194,13 @@ VULKAN_CPPFLAGS += \
 VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
 endif
 
+if HAVE_XLIB_LEASE
+VULKAN_CPPFLAGS += \
+	-DVK_USE_PLATFORM_XLIB_XRANDR_EXT \
+	$(XCB_RANDR_CFLAGS)
+VULKAN_LIB_DEPS += $(XCB_RANDR_LIBS)
+endif
+
 noinst_LTLIBRARIES += vulkan/libvulkan_common.la
 vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
 vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS)
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 633e378e605..32a240acdcb 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -85,6 +85,7 @@ EXTENSIONS = [
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
     Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
+    Extension('VK_EXT_acquire_xlib_display',              1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
     Extension('VK_KHX_multiview',                         1, True),
     Extension('VK_EXT_debug_report',                      8, True),
     Extension('VK_EXT_external_memory_dma_buf',           1, True),
diff --git a/src/intel/vulkan/anv_extensions_gen.py b/src/intel/vulkan/anv_extensions_gen.py
index 84d07f9767a..025907aff72 100644
--- a/src/intel/vulkan/anv_extensions_gen.py
+++ b/src/intel/vulkan/anv_extensions_gen.py
@@ -113,12 +113,12 @@ _TEMPLATE_C = Template(COPYRIGHT + """
 #include "vk_util.h"
 
 /* Convert the VK_USE_PLATFORM_* defines to booleans */
-%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
-#ifdef VK_USE_PLATFORM_${platform}_KHR
-#   undef VK_USE_PLATFORM_${platform}_KHR
-#   define VK_USE_PLATFORM_${platform}_KHR true
+%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']:
+#ifdef VK_USE_PLATFORM_${platform}
+#   undef VK_USE_PLATFORM_${platform}
+#   define VK_USE_PLATFORM_${platform} true
 #else
-#   define VK_USE_PLATFORM_${platform}_KHR false
+#   define VK_USE_PLATFORM_${platform} false
 #endif
 %endfor
 
diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
index e6f67f7dec9..e87aed49f7d 100644
--- a/src/intel/vulkan/anv_wsi_display.c
+++ b/src/intel/vulkan/anv_wsi_display.c
@@ -138,3 +138,33 @@ anv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
                               &pdevice->wsi_device,
                               display);
 }
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+VkResult
+anv_AcquireXlibDisplayEXT(VkPhysicalDevice     physical_device,
+                           Display              *dpy,
+                           VkDisplayKHR         display)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_acquire_xlib_display(physical_device,
+                                   &pdevice->wsi_device,
+                                   dpy,
+                                   display);
+}
+
+VkResult
+anv_GetRandROutputDisplayEXT(VkPhysicalDevice  physical_device,
+                              Display           *dpy,
+                              RROutput          output,
+                              VkDisplayKHR      *display)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_get_randr_output_display(physical_device,
+                                       &pdevice->wsi_device,
+                                       dpy,
+                                       output,
+                                       display);
+}
+#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
index 2e2ab8f7ecd..d3ab5ac8a64 100644
--- a/src/intel/vulkan/meson.build
+++ b/src/intel/vulkan/meson.build
@@ -178,6 +178,13 @@ if with_platform_display
   libanv_files += files('anv_wsi_display.c')
 endif
 
+if with_xlib_lease
+  anv_deps += dep_xcb_xrandr
+  anv_flags += [
+    '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
+  ]
+endif
+
 libanv_common = static_library(
   'anv_common',
   [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h],
diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
index c33ac5758f7..e96ef68972c 100644
--- a/src/vulkan/Makefile.am
+++ b/src/vulkan/Makefile.am
@@ -64,6 +64,11 @@ AM_CPPFLAGS += \
 VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
 endif
 
+if HAVE_XLIB_LEASE
+AM_CPPFLAGS += \
+	-DVK_USE_PLATFORM_XLIB_XRANDR_EXT
+endif
+
 BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES)
 CLEANFILES = $(BUILT_SOURCES)
 
diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build
index 743631a6113..5e3d43a2748 100644
--- a/src/vulkan/wsi/meson.build
+++ b/src/vulkan/wsi/meson.build
@@ -67,6 +67,13 @@ if with_platform_display
   )
 endif
 
+if with_xlib_lease
+  vulkan_wsi_deps += dep_xcb_xrandr
+  vulkan_wsi_args += [
+    '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
+  ]
+endif
+
 libvulkan_wsi = static_library(
   'vulkan_wsi',
   files_vulkan_wsi,
diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
index 5c123e6465e..29d64b21aff 100644
--- a/src/vulkan/wsi/wsi_common_display.c
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -32,6 +32,10 @@
 #include <math.h>
 #include <xf86drm.h>
 #include <xf86drmMode.h>
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+#include <xcb/randr.h>
+#include <X11/Xlib-xcb.h>
+#endif
 #include "util/hash_table.h"
 #include "util/list.h"
 
@@ -73,6 +77,9 @@ typedef struct wsi_display_connector {
    bool                         active;
    wsi_display_mode             *current_mode;
    drmModeModeInfo              current_drm_mode;
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+   xcb_randr_output_t           output;
+#endif
 } wsi_display_connector;
 
 struct wsi_display {
@@ -1381,5 +1388,470 @@ wsi_release_display(VkPhysicalDevice            physical_device,
       close(wsi->master_fd);
       wsi->master_fd = -1;
    }
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+   wsi_display_connector_from_handle(display)->output = None;
+#endif
+
    return VK_SUCCESS;
 }
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+
+static struct wsi_display_connector *
+wsi_display_find_output(struct wsi_device               *wsi_device,
+                        RROutput                        output)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_connector *connector;
+
+   connector = NULL;
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
+      if (connector->output == output)
+         return connector;
+   }
+
+   return NULL;
+}
+
+/*
+ * Given a RandR output, find the associated kernel connector_id by
+ * looking at the CONNECTOR_ID property provided by the X server
+ */
+
+static uint32_t
+wsi_display_output_to_connector_id(xcb_connection_t     *connection,
+                                   xcb_atom_t           *connector_id_atom_p,
+                                   RROutput             output)
+{
+   uint32_t                     connector_id = 0;
+   xcb_atom_t                   connector_id_atom = *connector_id_atom_p;
+
+   if (connector_id_atom == 0) {
+   /* Go dig out the CONNECTOR_ID property */
+      xcb_intern_atom_cookie_t     ia_c = xcb_intern_atom(connection,
+                                                          true,
+                                                          12,
+                                                          "CONNECTOR_ID");
+      xcb_intern_atom_reply_t      *ia_r = xcb_intern_atom_reply(connection,
+                                                                 ia_c,
+                                                                 NULL);
+      if (ia_r) {
+         *connector_id_atom_p = connector_id_atom = ia_r->atom;
+         free(ia_r);
+      }
+   }
+
+   /* If there's an CONNECTOR_ID atom in the server, then there may be a CONNECTOR_ID property. Otherwise,
+    * there will not be and we don't even need to bother.
+    */
+   if (connector_id_atom) {
+
+      xcb_randr_query_version_cookie_t          qv_c = xcb_randr_query_version(connection, 1, 6);
+      xcb_randr_get_output_property_cookie_t    gop_c = xcb_randr_get_output_property(connection,
+                                                                                      output,
+                                                                                      connector_id_atom,
+                                                                                      0,
+                                                                                      0,
+                                                                                      0xffffffffUL,
+                                                                                      0,
+                                                                                      0);
+      xcb_randr_query_version_reply_t           *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL);
+      free(qv_r);
+      xcb_randr_get_output_property_reply_t     *gop_r = xcb_randr_get_output_property_reply(connection,
+                                                                                             gop_c,
+                                                                                             NULL);
+      if (gop_r) {
+         if (gop_r->num_items == 1 && gop_r->format == 32)
+            memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
+         free(gop_r);
+      }
+   }
+   return connector_id;
+}
+
+static bool
+wsi_display_check_randr_version(xcb_connection_t        *connection)
+{
+   xcb_randr_query_version_cookie_t     qv_c = xcb_randr_query_version(connection, 1, 6);
+   xcb_randr_query_version_reply_t      *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL);
+   bool                                 ret = false;
+
+   if (!qv_r)
+      return false;
+
+   /* Check for version 1.6 or newer */
+   ret = qv_r->major_version > 1 || (qv_r->major_version == 1 && qv_r->minor_version >= 6);
+
+   free(qv_r);
+   return ret;
+}
+
+/*
+ * Given a kernel connector id, find the associated RandR output using the
+ * CONNECTOR_ID property
+ */
+
+static xcb_randr_output_t
+wsi_display_connector_id_to_output(xcb_connection_t     *connection,
+                                   uint32_t             connector_id)
+{
+   if (!wsi_display_check_randr_version(connection))
+      return 0;
+
+   const xcb_setup_t                    *setup = xcb_get_setup(connection);
+
+   xcb_atom_t                           connector_id_atom = 0;
+   xcb_randr_output_t                   output = 0;
+
+   /* Search all of the screens for the provided output */
+   xcb_screen_iterator_t iter;
+   for (iter = xcb_setup_roots_iterator(setup); output == 0 && iter.rem; xcb_screen_next(&iter)) {
+
+      xcb_randr_get_screen_resources_cookie_t      gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root);
+      xcb_randr_get_screen_resources_reply_t       *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+      if (!gsr_r)
+         return 0;
+
+      xcb_randr_output_t        *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
+      int                       o;
+
+      for (o = 0; o < gsr_r->num_outputs; o++) {
+         if (wsi_display_output_to_connector_id(connection, &connector_id_atom, ro[o]) == connector_id) {
+            output = ro[o];
+            break;
+         }
+      }
+      free(gsr_r);
+   }
+   return output;
+}
+
+/*
+ * Given a RandR output, find out which screen it's associated with
+ */
+static xcb_window_t
+wsi_display_output_to_root(xcb_connection_t   *connection,
+                           xcb_randr_output_t output)
+{
+   if (!wsi_display_check_randr_version(connection))
+      return 0;
+
+   const xcb_setup_t                    *setup = xcb_get_setup(connection);
+   xcb_window_t                         root = 0;
+
+   /* Search all of the screens for the provided output */
+   xcb_screen_iterator_t iter;
+   for (iter = xcb_setup_roots_iterator(setup); root == 0 && iter.rem; xcb_screen_next(&iter)) {
+      xcb_randr_get_screen_resources_cookie_t      gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root);
+      xcb_randr_get_screen_resources_reply_t       *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+      if (!gsr_r)
+         return 0;
+
+      xcb_randr_output_t        *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
+      int                       o;
+
+      for (o = 0; o < gsr_r->num_outputs; o++) {
+         if (ro[o] == output) {
+            root = iter.data->root;
+            break;
+         }
+      }
+      free(gsr_r);
+   }
+   return root;
+}
+
+static bool
+wsi_display_mode_matches_x(struct wsi_display_mode      *wsi,
+                           xcb_randr_mode_info_t        *xcb)
+{
+   return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
+      wsi->hdisplay == xcb->width &&
+      wsi->hsync_start == xcb->hsync_start &&
+      wsi->hsync_end == xcb->hsync_end &&
+      wsi->htotal == xcb->htotal &&
+      wsi->hskew == xcb->hskew &&
+      wsi->vdisplay == xcb->height &&
+      wsi->vsync_start == xcb->vsync_start &&
+      wsi->vsync_end == xcb->vsync_end &&
+      wsi->vtotal == xcb->vtotal &&
+      wsi->flags == xcb->mode_flags;
+}
+
+static struct wsi_display_mode *
+wsi_display_find_x_mode(struct wsi_device                 *wsi_device,
+                        struct wsi_display_connector      *connector,
+                        xcb_randr_mode_info_t             *mode)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode;
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->connector == connector &&
+          wsi_display_mode_matches_x(display_mode, mode))
+         return display_mode;
+   }
+   return NULL;
+}
+
+static VkResult
+wsi_display_register_x_mode(struct wsi_device                   *wsi_device,
+                            struct wsi_display_connector        *connector,
+                            xcb_randr_mode_info_t               *x_mode,
+                            bool                                preferred)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode;
+
+   display_mode = wsi_display_find_x_mode(wsi_device, connector, x_mode);
+
+   if (display_mode) {
+      display_mode->valid = true;
+      return VK_SUCCESS;
+   }
+
+   display_mode = vk_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!display_mode)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   display_mode->connector = connector;
+   display_mode->valid = true;
+   display_mode->preferred = preferred;
+   display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
+   display_mode->hdisplay = x_mode->width;
+   display_mode->hsync_start = x_mode->hsync_start;
+   display_mode->hsync_end = x_mode->hsync_end;
+   display_mode->htotal = x_mode->htotal;
+   display_mode->hskew = x_mode->hskew;
+   display_mode->vdisplay = x_mode->height;
+   display_mode->vsync_start = x_mode->vsync_start;
+   display_mode->vsync_end = x_mode->vsync_end;
+   display_mode->vtotal = x_mode->vtotal;
+   display_mode->vscan = 0;
+   if (x_mode->mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN)
+      display_mode->vscan = 1;
+   display_mode->flags = x_mode->mode_flags;
+
+   LIST_ADDTAIL(&display_mode->list, &wsi->display_modes);
+   return VK_SUCCESS;
+}
+
+static struct wsi_display_connector *
+wsi_display_get_output(struct wsi_device        *wsi_device,
+                       xcb_connection_t         *connection,
+                       RROutput                 output)
+{
+   struct wsi_display                           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_connector                 *connector;
+   uint32_t                                     connector_id;
+   xcb_window_t                                 root;
+   xcb_randr_get_screen_resources_cookie_t      src;
+   xcb_randr_get_screen_resources_reply_t       *srr;
+   xcb_randr_get_output_info_cookie_t           oic;
+   xcb_randr_get_output_info_reply_t            *oir;
+   xcb_randr_mode_t                             *x_modes;
+   int                                          m;
+
+   root = wsi_display_output_to_root(connection, output);
+   if (!root)
+      return NULL;
+
+   src = xcb_randr_get_screen_resources(connection, root);
+   oic = xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
+   srr = xcb_randr_get_screen_resources_reply(connection, src, NULL);
+   oir = xcb_randr_get_output_info_reply(connection, oic, NULL);
+
+   /* See if we already have a connector for this output */
+   connector = wsi_display_find_output(wsi_device, output);
+
+   if (!connector) {
+      xcb_atom_t        connector_id_atom = 0;
+
+      /*
+       * Go get the kernel connector ID for this X output
+       */
+      connector_id = wsi_display_output_to_connector_id(connection, &connector_id_atom, output);
+
+      /* Any X server with lease support will have this atom */
+      if (!connector_id) {
+         free(oir);
+         free(srr);
+         return NULL;
+      }
+
+      if (!connector) {
+         /* See if we already have a connector for this id */
+         connector = wsi_display_find_connector(wsi_device, connector_id);
+
+         if (connector)
+            connector->output = output;
+      }
+   }
+
+   if (!connector) {
+      connector = wsi_display_alloc_connector(wsi, connector_id);
+      if (!connector) {
+         free(oir);
+         free(srr);
+         return NULL;
+      }
+      LIST_ADDTAIL(&connector->list, &wsi->connectors);
+      connector->output = output;
+   }
+
+   if (oir && srr) {
+      /* Get X modes and add them */
+
+      connector->connected = oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
+
+      wsi_display_invalidate_connector_modes(wsi_device, connector);
+
+      x_modes = xcb_randr_get_output_info_modes(oir);
+      for (m = 0; m < oir->num_modes; m++) {
+         xcb_randr_mode_info_iterator_t i = xcb_randr_get_screen_resources_modes_iterator(srr);
+         while (i.rem) {
+            xcb_randr_mode_info_t *mi = i.data;
+            if (mi->id == x_modes[m]) {
+               VkResult result = wsi_display_register_x_mode(wsi_device, connector, mi, m < oir->num_preferred);
+               if (result != VK_SUCCESS) {
+                  free(oir);
+                  free(srr);
+                  return NULL;
+               }
+               break;
+            }
+            xcb_randr_mode_info_next(&i);
+         }
+      }
+   }
+
+   free(oir);
+   free(srr);
+   return connector;
+}
+
+static xcb_randr_crtc_t
+wsi_display_find_crtc_for_output(xcb_connection_t       *connection,
+                                 xcb_window_t           root,
+                                 xcb_randr_output_t     output)
+{
+   xcb_randr_get_screen_resources_cookie_t      gsr_c = xcb_randr_get_screen_resources(connection, root);
+   xcb_randr_get_screen_resources_reply_t       *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+   if (!gsr_r)
+      return 0;
+
+   xcb_randr_crtc_t     *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
+   xcb_randr_crtc_t     idle_crtc = 0;
+   xcb_randr_crtc_t     active_crtc = 0;
+
+   /* Find either a crtc already connected to the desired output or idle */
+   int c;
+   for (c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
+      xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
+      xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
+      if (gci_r) {
+         if (gci_r->mode) {
+            int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
+            xcb_randr_output_t *outputs = xcb_randr_get_crtc_info_outputs(gci_r);
+            for (int o = 0; o < num_outputs; o++)
+               if (outputs[o] == output && num_outputs == 1) {
+                  active_crtc = rc[c];
+                  break;
+               }
+         } else if (idle_crtc == 0) {
+            int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
+            xcb_randr_output_t *possible = xcb_randr_get_crtc_info_possible(gci_r);
+            for (int p = 0; p < num_possible; p++)
+               if (possible[p] == output) {
+                  idle_crtc = rc[c];
+                  break;
+               }
+         }
+         free(gci_r);
+      }
+   }
+   free(gsr_r);
+
+   if (active_crtc)
+      return active_crtc;
+   return idle_crtc;
+}
+
+VkResult
+wsi_acquire_xlib_display(VkPhysicalDevice       physical_device,
+                         struct wsi_device      *wsi_device,
+                         Display                *dpy,
+                         VkDisplayKHR           display)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   xcb_connection_t             *connection = XGetXCBConnection(dpy);
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
+   xcb_window_t                 root;
+
+   if (!connector->output) {
+      connector->output = wsi_display_connector_id_to_output(connection, connector->id);
+
+      /* Check and see if we found the output */
+      if (!connector->output)
+         return VK_ERROR_OUT_OF_DATE_KHR;
+   }
+
+   root = wsi_display_output_to_root(connection, connector->output);
+   if (!root)
+      return VK_ERROR_OUT_OF_DATE_KHR;
+
+   xcb_randr_crtc_t                     crtc = wsi_display_find_crtc_for_output(connection,
+                                                                                root,
+                                                                                connector->output);
+
+   if (!crtc)
+      return VK_ERROR_OUT_OF_DATE_KHR;
+
+   xcb_randr_lease_t                    lease = xcb_generate_id(connection);
+   xcb_randr_create_lease_cookie_t      cl_c = xcb_randr_create_lease(connection,
+                                                                      root,
+                                                                      lease,
+                                                                      1,
+                                                                      1,
+                                                                      &crtc,
+                                                                      &connector->output);
+   xcb_randr_create_lease_reply_t       *cl_r = xcb_randr_create_lease_reply(connection, cl_c, NULL);
+   if (!cl_r)
+      return VK_ERROR_OUT_OF_DATE_KHR;
+
+   int fd = -1;
+   if (cl_r->nfd > 0) {
+      int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
+
+      fd = rcl_f[0];
+   }
+   free (cl_r);
+   if (fd < 0)
+      return VK_ERROR_OUT_OF_DATE_KHR;
+
+   wsi->master_fd = fd;
+
+   return VK_SUCCESS;
+}
+
+VkResult
+wsi_get_randr_output_display(VkPhysicalDevice   physical_device,
+                             struct wsi_device  *wsi_device,
+                             Display            *dpy,
+                             RROutput           output,
+                             VkDisplayKHR       *display)
+{
+   xcb_connection_t             *connection = XGetXCBConnection(dpy);
+   struct wsi_display_connector *connector = wsi_display_get_output(wsi_device, connection, output);
+
+   if (connector)
+      *display = wsi_display_connector_to_handle(connector);
+   else
+      *display = NULL;
+   return VK_SUCCESS;
+}
+
+#endif
diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h
index 5fbb6925e4a..1997c2a3c40 100644
--- a/src/vulkan/wsi/wsi_common_display.h
+++ b/src/vulkan/wsi/wsi_common_display.h
@@ -74,4 +74,21 @@ wsi_release_display(VkPhysicalDevice            physical_device,
                     struct wsi_device           *wsi_device,
                     VkDisplayKHR                display);
 
+
+#if VK_USE_PLATFORM_XLIB_XRANDR_EXT
+VkResult
+wsi_acquire_xlib_display(VkPhysicalDevice       physical_device,
+                         struct wsi_device      *wsi_device,
+                         Display                *dpy,
+                         VkDisplayKHR           display);
+
+VkResult
+wsi_get_randr_output_display(VkPhysicalDevice   physical_device,
+                             struct wsi_device  *wsi_device,
+                             Display            *dpy,
+                             RROutput           output,
+                             VkDisplayKHR       *display);
+
+#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
+
 #endif
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 4/7] vulkan: Add VK_EXT_display_surface_counter [v4]
  2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
                   ` (2 preceding siblings ...)
  2018-02-10  4:45 ` [PATCH 3/7] vulkan: Add EXT_acquire_xlib_display Keith Packard
@ 2018-02-10  4:45 ` Keith Packard
  2018-02-10  4:45 ` [PATCH 5/7] vulkan: add VK_EXT_display_control [v4] Keith Packard
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel

This extension is required to support EXT_display_control as it offers
a way to query whether the vblank counter is supported.

v2: Thanks to kisak

    Fix spelling of VkSurfaceCapabilities2EXT in wsi_common_wayland.c,
    it was using ext instead of EXT.

    Fix spelling of VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT

v3: Fix wayland WSI, regularize spelling

    Misspelled 'surface' in get_capabilities2ext
    Remove extra _ from get_capabilities_2ext in a couple of places

v4: Add anv support

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 src/amd/vulkan/radv_extensions.py   |  1 +
 src/amd/vulkan/radv_wsi.c           | 12 ++++++++++++
 src/intel/vulkan/anv_extensions.py  |  1 +
 src/intel/vulkan/anv_wsi.c          | 12 ++++++++++++
 src/vulkan/wsi/wsi_common.c         | 11 +++++++++++
 src/vulkan/wsi/wsi_common.h         |  5 +++++
 src/vulkan/wsi/wsi_common_display.c | 27 +++++++++++++++++++++++++++
 src/vulkan/wsi/wsi_common_private.h |  2 ++
 src/vulkan/wsi/wsi_common_wayland.c | 27 +++++++++++++++++++++++++++
 src/vulkan/wsi/wsi_common_x11.c     | 27 +++++++++++++++++++++++++++
 10 files changed, 125 insertions(+)

diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index 2d804afed35..3f315e074b5 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -84,6 +84,7 @@ EXTENSIONS = [
     Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_EXT_acquire_xlib_display',              1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
+    Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, '!ANDROID'),
     Extension('VK_EXT_debug_report',                      9, True),
     Extension('VK_EXT_discard_rectangles',                1, True),
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
index 5ec872a63d0..2d2a30ebbb1 100644
--- a/src/amd/vulkan/radv_wsi.c
+++ b/src/amd/vulkan/radv_wsi.c
@@ -103,6 +103,18 @@ VkResult radv_GetPhysicalDeviceSurfaceCapabilities2KHR(
 						    pSurfaceCapabilities);
 }
 
+VkResult radv_GetPhysicalDeviceSurfaceCapabilities2EXT(
+ 	VkPhysicalDevice                            physicalDevice,
+	VkSurfaceKHR                                surface,
+	VkSurfaceCapabilities2EXT*                  pSurfaceCapabilities)
+{
+	RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
+
+	return wsi_common_get_surface_capabilities2ext(&device->wsi_device,
+                                                       surface,
+                                                       pSurfaceCapabilities);
+}
+
 VkResult radv_GetPhysicalDeviceSurfaceFormatsKHR(
 	VkPhysicalDevice                            physicalDevice,
 	VkSurfaceKHR                                surface,
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 32a240acdcb..8265077d894 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -89,6 +89,7 @@ EXTENSIONS = [
     Extension('VK_KHX_multiview',                         1, True),
     Extension('VK_EXT_debug_report',                      8, True),
     Extension('VK_EXT_external_memory_dma_buf',           1, True),
+    Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
 ]
 
 class VkVersion:
diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
index f86d83589ea..52362adfb71 100644
--- a/src/intel/vulkan/anv_wsi.c
+++ b/src/intel/vulkan/anv_wsi.c
@@ -104,6 +104,18 @@ VkResult anv_GetPhysicalDeviceSurfaceCapabilities2KHR(
                                                pSurfaceCapabilities);
 }
 
+VkResult anv_GetPhysicalDeviceSurfaceCapabilities2EXT(
+ 	VkPhysicalDevice                            physicalDevice,
+	VkSurfaceKHR                                surface,
+	VkSurfaceCapabilities2EXT*                  pSurfaceCapabilities)
+{
+   ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
+
+   return wsi_common_get_surface_capabilities2ext(&device->wsi_device,
+                                                  surface,
+                                                  pSurfaceCapabilities);
+}
+
 VkResult anv_GetPhysicalDeviceSurfaceFormatsKHR(
     VkPhysicalDevice                            physicalDevice,
     VkSurfaceKHR                                surface,
diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c
index c0a285e5814..02abc9ef7fb 100644
--- a/src/vulkan/wsi/wsi_common.c
+++ b/src/vulkan/wsi/wsi_common.c
@@ -579,6 +579,17 @@ wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device,
                                    pSurfaceCapabilities);
 }
 
+VkResult
+wsi_common_get_surface_capabilities2ext(struct wsi_device *wsi_device,
+                                        VkSurfaceKHR _surface,
+                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities)
+{
+   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
+   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
+
+   return iface->get_capabilities2ext(surface, pSurfaceCapabilities);
+}
+
 VkResult
 wsi_common_get_surface_formats(struct wsi_device *wsi_device,
                                VkSurfaceKHR _surface,
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index 1cb6aaebca0..124d096170a 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -155,6 +155,11 @@ wsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
                                      uint32_t *pPresentModeCount,
                                      VkPresentModeKHR *pPresentModes);
 
+VkResult
+wsi_common_get_surface_capabilities2ext(struct wsi_device *wsi_device,
+                                        VkSurfaceKHR surface,
+                                        VkSurfaceCapabilities2EXT *pSurfaceCapabilities);
+
 VkResult
 wsi_common_get_images(VkSwapchainKHR _swapchain,
                       uint32_t *pSwapchainImageCount,
diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
index 29d64b21aff..e63700e2e65 100644
--- a/src/vulkan/wsi/wsi_common_display.c
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -655,6 +655,32 @@ wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
    return wsi_display_surface_get_capabilities(icd_surface, &caps->surfaceCapabilities);
 }
 
+static VkResult
+wsi_display_surface_get_capabilities2ext(VkIcdSurfaceBase *icd_surface,
+                                          VkSurfaceCapabilities2EXT *caps)
+{
+   VkSurfaceCapabilitiesKHR     khr_caps;
+   VkResult                     ret;
+
+   assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT);
+   ret = wsi_display_surface_get_capabilities(icd_surface, &khr_caps);
+   if (ret)
+      return ret;
+
+   caps->minImageCount = khr_caps.minImageCount;
+   caps->maxImageCount = khr_caps.maxImageCount;
+   caps->currentExtent = khr_caps.currentExtent;
+   caps->minImageExtent = khr_caps.minImageExtent;
+   caps->maxImageExtent = khr_caps.maxImageExtent;
+   caps->maxImageArrayLayers = khr_caps.maxImageArrayLayers;
+   caps->supportedTransforms = khr_caps.supportedTransforms;
+   caps->currentTransform = khr_caps.currentTransform;
+   caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha;
+   caps->supportedUsageFlags = khr_caps.supportedUsageFlags;
+   caps->supportedSurfaceCounters = 0;
+   return ret;
+}
+
 static const VkFormat available_surface_formats[] = {
    VK_FORMAT_B8G8R8A8_SRGB,
    VK_FORMAT_B8G8R8A8_UNORM,
@@ -1323,6 +1349,7 @@ wsi_display_init_wsi(struct wsi_device *wsi_device,
    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_capabilities2ext = wsi_display_surface_get_capabilities2ext;
    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;
diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h
index d38d2efa116..0d902846238 100644
--- a/src/vulkan/wsi/wsi_common_private.h
+++ b/src/vulkan/wsi/wsi_common_private.h
@@ -103,6 +103,8 @@ struct wsi_interface {
    VkResult (*get_capabilities2)(VkIcdSurfaceBase *surface,
                                  const void *info_next,
                                  VkSurfaceCapabilities2KHR* pSurfaceCapabilities);
+   VkResult (*get_capabilities2ext)(VkIcdSurfaceBase *surface,
+                                    VkSurfaceCapabilities2EXT* pSurfaceCapabilities);
    VkResult (*get_formats)(VkIcdSurfaceBase *surface,
                            struct wsi_device *wsi_device,
                            uint32_t* pSurfaceFormatCount,
diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c
index be7635bbf84..54b9449ab8c 100644
--- a/src/vulkan/wsi/wsi_common_wayland.c
+++ b/src/vulkan/wsi/wsi_common_wayland.c
@@ -457,6 +457,32 @@ wsi_wl_surface_get_capabilities2(VkIcdSurfaceBase *surface,
    return wsi_wl_surface_get_capabilities(surface, &caps->surfaceCapabilities);
 }
 
+static VkResult
+wsi_wl_surface_get_capabilities2ext(VkIcdSurfaceBase *surface,
+                                    VkSurfaceCapabilities2EXT* caps)
+{
+   VkSurfaceCapabilitiesKHR     khr_caps;
+   VkResult                     ret;
+
+   assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT);
+   ret = wsi_wl_surface_get_capabilities(surface, &khr_caps);
+   if (ret)
+      return ret;
+
+   caps->minImageCount = khr_caps.minImageCount;
+   caps->maxImageCount = khr_caps.maxImageCount;
+   caps->currentExtent = khr_caps.currentExtent;
+   caps->minImageExtent = khr_caps.minImageExtent;
+   caps->maxImageExtent = khr_caps.maxImageExtent;
+   caps->maxImageArrayLayers = khr_caps.maxImageArrayLayers;
+   caps->supportedTransforms = khr_caps.supportedTransforms;
+   caps->currentTransform = khr_caps.currentTransform;
+   caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha;
+   caps->supportedUsageFlags = khr_caps.supportedUsageFlags;
+   caps->supportedSurfaceCounters = 0;
+   return ret;
+}
+
 static VkResult
 wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface,
 			   struct wsi_device *wsi_device,
@@ -891,6 +917,7 @@ wsi_wl_init_wsi(struct wsi_device *wsi_device,
    wsi->base.get_support = wsi_wl_surface_get_support;
    wsi->base.get_capabilities = wsi_wl_surface_get_capabilities;
    wsi->base.get_capabilities2 = wsi_wl_surface_get_capabilities2;
+   wsi->base.get_capabilities2ext = wsi_wl_surface_get_capabilities2ext;
    wsi->base.get_formats = wsi_wl_surface_get_formats;
    wsi->base.get_formats2 = wsi_wl_surface_get_formats2;
    wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;
diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
index c29e0a2d30d..714523678d4 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -516,6 +516,32 @@ x11_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
    return x11_surface_get_capabilities(icd_surface, &caps->surfaceCapabilities);
 }
 
+static VkResult
+x11_surface_get_capabilities2ext(VkIcdSurfaceBase *icd_surface,
+                                 VkSurfaceCapabilities2EXT *caps)
+{
+   VkSurfaceCapabilitiesKHR     khr_caps;
+   VkResult                     ret;
+
+   assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT);
+   ret = x11_surface_get_capabilities(icd_surface, &khr_caps);
+   if (ret)
+      return ret;
+
+   caps->minImageCount = khr_caps.minImageCount;
+   caps->maxImageCount = khr_caps.maxImageCount;
+   caps->currentExtent = khr_caps.currentExtent;
+   caps->minImageExtent = khr_caps.minImageExtent;
+   caps->maxImageExtent = khr_caps.maxImageExtent;
+   caps->maxImageArrayLayers = khr_caps.maxImageArrayLayers;
+   caps->supportedTransforms = khr_caps.supportedTransforms;
+   caps->currentTransform = khr_caps.currentTransform;
+   caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha;
+   caps->supportedUsageFlags = khr_caps.supportedUsageFlags;
+   caps->supportedSurfaceCounters = 0;
+   return ret;
+}
+
 static VkResult
 x11_surface_get_formats(VkIcdSurfaceBase *surface,
                         struct wsi_device *wsi_device,
@@ -1207,6 +1233,7 @@ wsi_x11_init_wsi(struct wsi_device *wsi_device,
    wsi->base.get_support = x11_surface_get_support;
    wsi->base.get_capabilities = x11_surface_get_capabilities;
    wsi->base.get_capabilities2 = x11_surface_get_capabilities2;
+   wsi->base.get_capabilities2ext = x11_surface_get_capabilities2ext;
    wsi->base.get_formats = x11_surface_get_formats;
    wsi->base.get_formats2 = x11_surface_get_formats2;
    wsi->base.get_present_modes = x11_surface_get_present_modes;
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 5/7] vulkan: add VK_EXT_display_control [v4]
  2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
                   ` (3 preceding siblings ...)
  2018-02-10  4:45 ` [PATCH 4/7] vulkan: Add VK_EXT_display_surface_counter [v4] Keith Packard
@ 2018-02-10  4:45 ` Keith Packard
  2018-02-10  4:45 ` [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension Keith Packard
  2018-02-10  4:45 ` [PATCH 7/7] vulkan: Add VK_GOOGLE_display_timing extension (x11 and display backends) Keith Packard
  6 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel

This extension provides fences and frame count information to direct
display contexts. It uses new kernel ioctls to provide 64-bits of
vblank sequence and nanosecond resolution.

v2: Remove DRM_CRTC_SEQUENCE_FIRST_PIXEL_OUT flag. This has
    been removed from the proposed kernel API.

    Add NULL parameter to drmCrtcQueueSequence ioctl as we
    don't care what sequence the event was actually queued to.

v3: Adapt to pthread clock switch to MONOTONIC

v4: Add support for anv

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 src/amd/vulkan/radv_extensions.py   |   1 +
 src/amd/vulkan/radv_private.h       |  11 +-
 src/amd/vulkan/radv_wsi_display.c   | 109 ++++++++++++++
 src/intel/vulkan/anv_extensions.py  |   1 +
 src/intel/vulkan/anv_private.h      |   4 +
 src/intel/vulkan/anv_queue.c        |  59 +++++++-
 src/intel/vulkan/anv_wsi_display.c  | 103 +++++++++++++
 src/vulkan/wsi/wsi_common.h         |   9 ++
 src/vulkan/wsi/wsi_common_display.c | 286 +++++++++++++++++++++++++++++++++++-
 src/vulkan/wsi/wsi_common_display.h |  29 ++++
 10 files changed, 603 insertions(+), 9 deletions(-)

diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index 3f315e074b5..775d1ed4be6 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -85,6 +85,7 @@ EXTENSIONS = [
     Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_EXT_acquire_xlib_display',              1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
     Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
+    Extension('VK_EXT_display_control',                   1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, '!ANDROID'),
     Extension('VK_EXT_debug_report',                      9, True),
     Extension('VK_EXT_discard_rectangles',                1, True),
diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
index 1e3719bcc4f..2aee38f0159 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -1647,8 +1647,17 @@ void radv_initialise_cmask(struct radv_cmd_buffer *cmd_buffer,
 void radv_initialize_dcc(struct radv_cmd_buffer *cmd_buffer,
 			 struct radv_image *image, uint32_t value);
 
+enum radv_fence_type {
+        RADV_FENCE_TYPE_WINSYS = 0,
+        RADV_FENCE_TYPE_WSI = 1
+};
+
 struct radv_fence {
-	struct radeon_winsys_fence *fence;
+        enum radv_fence_type type;
+        union {
+                struct radeon_winsys_fence      *fence;
+                struct wsi_fence                *fence_wsi;
+        };
 	bool submitted;
 	bool signalled;
 
diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
index 9b76ce623b0..5dd66b34a1a 100644
--- a/src/amd/vulkan/radv_wsi_display.c
+++ b/src/amd/vulkan/radv_wsi_display.c
@@ -182,3 +182,112 @@ radv_GetRandROutputDisplayEXT(VkPhysicalDevice  physical_device,
                                        display);
 }
 #endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
+
+/* VK_EXT_display_control */
+
+VkResult
+radv_DisplayPowerControlEXT(VkDevice                    _device,
+                            VkDisplayKHR                display,
+                            const VkDisplayPowerInfoEXT *display_power_info)
+{
+   RADV_FROM_HANDLE(radv_device, device, _device);
+
+   return wsi_display_power_control(_device,
+                                    &device->physical_device->wsi_device,
+                                    display,
+                                    display_power_info);
+}
+
+VkResult
+radv_RegisterDeviceEventEXT(VkDevice                    _device,
+                            const VkDeviceEventInfoEXT  *device_event_info,
+                            const VkAllocationCallbacks *allocator,
+                            VkFence                     *_fence)
+{
+   RADV_FROM_HANDLE(radv_device, device, _device);
+   const VkAllocationCallbacks  *alloc;
+   struct radv_fence            *fence;
+   VkResult                     ret;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &device->instance->alloc;
+
+   fence = vk_alloc(alloc, sizeof (*fence), 8,
+                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!fence)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   fence->type = RADV_FENCE_TYPE_WSI;
+   fence->submitted = true;
+   fence->signalled = false;
+
+   ret = wsi_register_device_event(_device,
+                                   &device->physical_device->wsi_device,
+                                   device_event_info,
+                                   alloc,
+                                   &fence->fence_wsi);
+   if (ret == VK_SUCCESS)
+      *_fence = radv_fence_to_handle(fence);
+   else
+      vk_free(alloc, fence);
+   return ret;
+}
+
+VkResult
+radv_RegisterDisplayEventEXT(VkDevice                           _device,
+                             VkDisplayKHR                       display,
+                             const VkDisplayEventInfoEXT        *display_event_info,
+                             const VkAllocationCallbacks        *allocator,
+                             VkFence                            *_fence)
+{
+   RADV_FROM_HANDLE(radv_device, device, _device);
+
+   const VkAllocationCallbacks  *alloc;
+   struct radv_fence            *fence;
+   VkResult                     ret;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &device->instance->alloc;
+
+   fence = vk_alloc(alloc, sizeof (*fence), 8,
+                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!fence)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   fence->type = RADV_FENCE_TYPE_WSI;
+   fence->submitted = true;
+   fence->signalled = false;
+
+   ret = wsi_register_display_event(_device,
+                                    &device->physical_device->wsi_device,
+                                    display,
+                                    display_event_info,
+                                    alloc,
+                                    &(fence->fence_wsi));
+
+   if (ret == VK_SUCCESS)
+      *_fence = radv_fence_to_handle(fence);
+   else
+      vk_free(alloc, fence);
+   return ret;
+}
+
+VkResult
+radv_GetSwapchainCounterEXT(VkDevice                    _device,
+                            VkSwapchainKHR              swapchain,
+                            VkSurfaceCounterFlagBitsEXT flag_bits,
+                            uint64_t                    *value)
+{
+   RADV_FROM_HANDLE(radv_device, device, _device);
+
+   return wsi_get_swapchain_counter(_device,
+                                    &device->physical_device->wsi_device,
+                                    swapchain,
+                                    flag_bits,
+                                    value);
+}
+
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 8265077d894..f44598b305a 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -90,6 +90,7 @@ EXTENSIONS = [
     Extension('VK_EXT_debug_report',                      8, True),
     Extension('VK_EXT_external_memory_dma_buf',           1, True),
     Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
+    Extension('VK_EXT_display_control',                   1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
 ]
 
 class VkVersion:
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index d38dd9e4220..1d3e5fcd921 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -1941,6 +1941,7 @@ enum anv_fence_type {
    ANV_FENCE_TYPE_NONE = 0,
    ANV_FENCE_TYPE_BO,
    ANV_FENCE_TYPE_SYNCOBJ,
+   ANV_FENCE_TYPE_WSI,
 };
 
 enum anv_bo_fence_state {
@@ -1975,6 +1976,9 @@ struct anv_fence_impl {
 
       /** DRM syncobj handle for syncobj-based fences */
       uint32_t syncobj;
+
+      /** WSI fence */
+      struct wsi_fence *fence_wsi;
    };
 };
 
diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c
index c6b2e01c628..d0bfad742d7 100644
--- a/src/intel/vulkan/anv_queue.c
+++ b/src/intel/vulkan/anv_queue.c
@@ -320,6 +320,10 @@ anv_fence_impl_cleanup(struct anv_device *device,
    case ANV_FENCE_TYPE_SYNCOBJ:
       anv_gem_syncobj_destroy(device, impl->syncobj);
       return;
+
+   case ANV_FENCE_TYPE_WSI:
+      impl->fence_wsi->destroy(impl->fence_wsi);
+      return;
    }
 
    unreachable("Invalid fence type");
@@ -465,11 +469,32 @@ anv_wait_for_syncobj_fences(struct anv_device *device,
    uint32_t *syncobjs = vk_zalloc(&device->alloc,
                                   sizeof(*syncobjs) * fenceCount, 8,
                                   VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
+   uint32_t syncobjCount = 0;
    if (!syncobjs)
       return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
 
    for (uint32_t i = 0; i < fenceCount; i++) {
       ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
+
+      if (fence->permanent.type == ANV_FENCE_TYPE_WSI) {
+         struct anv_fence_impl *impl = &fence->permanent;
+         bool expired = impl->fence_wsi->wait(impl->fence_wsi, true, _timeout);
+
+         VkResult result;
+
+         if (!expired) {
+            result = VK_TIMEOUT;
+            goto done;
+         }
+         if (!waitAll) {
+            result = VK_SUCCESS;
+            goto done;
+         }
+         continue;
+      done:
+         vk_free(&device->alloc, syncobjs);
+         return result;
+      }
       assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
 
       struct anv_fence_impl *impl =
@@ -477,7 +502,7 @@ anv_wait_for_syncobj_fences(struct anv_device *device,
          &fence->temporary : &fence->permanent;
 
       assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
-      syncobjs[i] = impl->syncobj;
+      syncobjs[syncobjCount++] = impl->syncobj;
    }
 
    int64_t abs_timeout_ns = 0;
@@ -499,7 +524,7 @@ anv_wait_for_syncobj_fences(struct anv_device *device,
     */
    int ret;
    do {
-      ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
+      ret = anv_gem_syncobj_wait(device, syncobjs, syncobjCount,
                                  abs_timeout_ns, waitAll);
    } while (ret == -1 && errno == ETIME && gettime_ns() < abs_timeout_ns);
 
@@ -545,14 +570,33 @@ anv_wait_for_bo_fences(struct anv_device *device,
       for (uint32_t i = 0; i < fenceCount; i++) {
          ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
 
-         /* This function assumes that all fences are BO fences and that they
-          * have no temporary state.  Since BO fences will never be exported,
-          * this should be a safe assumption.
+         /* This function assumes that all fences have no temporary
+          * state.Since BO fences will never be exported, this should be a
+          * safe assumption.
           */
-         assert(fence->permanent.type == ANV_FENCE_TYPE_BO);
          assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
          struct anv_fence_impl *impl = &fence->permanent;
 
+         /* This function assumes that all fences are either BO fences or WSI
+          * fences
+          */
+
+         if (impl->type == ANV_FENCE_TYPE_WSI) {
+            bool expired = impl->fence_wsi->wait(impl->fence_wsi, true, timeout);
+
+            if (!expired) {
+               result = VK_TIMEOUT;
+               goto done;
+            }
+            if (!waitAll) {
+               result = VK_SUCCESS;
+               goto done;
+            }
+            continue;
+         }
+
+         assert(impl->type == ANV_FENCE_TYPE_BO);
+
          switch (impl->bo.state) {
          case ANV_BO_FENCE_STATE_RESET:
             /* This fence hasn't been submitted yet, we'll catch it the next
@@ -610,7 +654,8 @@ anv_wait_for_bo_fences(struct anv_device *device,
          uint32_t now_pending_fences = 0;
          for (uint32_t i = 0; i < fenceCount; i++) {
             ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
-            if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
+            if (fence->permanent.type == ANV_FENCE_TYPE_BO &&
+                fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
                now_pending_fences++;
          }
          assert(now_pending_fences <= pending_fences);
diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
index e87aed49f7d..32a948d76ca 100644
--- a/src/intel/vulkan/anv_wsi_display.c
+++ b/src/intel/vulkan/anv_wsi_display.c
@@ -168,3 +168,106 @@ anv_GetRandROutputDisplayEXT(VkPhysicalDevice  physical_device,
                                        display);
 }
 #endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
+
+/* VK_EXT_display_control */
+
+VkResult
+anv_DisplayPowerControlEXT(VkDevice                    _device,
+                            VkDisplayKHR                display,
+                            const VkDisplayPowerInfoEXT *display_power_info)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+
+   return wsi_display_power_control(_device,
+                                    &device->instance->physicalDevice.wsi_device,
+                                    display,
+                                    display_power_info);
+}
+
+VkResult
+anv_RegisterDeviceEventEXT(VkDevice                    _device,
+                            const VkDeviceEventInfoEXT  *device_event_info,
+                            const VkAllocationCallbacks *allocator,
+                            VkFence                     *_fence)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+   const VkAllocationCallbacks  *alloc;
+   struct anv_fence            *fence;
+   VkResult                     ret;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &device->instance->alloc;
+
+   fence = vk_alloc(alloc, sizeof (*fence), 8,
+                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!fence)
+      return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
+
+   fence->permanent.type = ANV_FENCE_TYPE_WSI;
+
+   ret = wsi_register_device_event(_device,
+                                   &device->instance->physicalDevice.wsi_device,
+                                   device_event_info,
+                                   alloc,
+                                   &fence->permanent.fence_wsi);
+   if (ret == VK_SUCCESS)
+      *_fence = anv_fence_to_handle(fence);
+   else
+      vk_free(alloc, fence);
+   return ret;
+}
+
+VkResult
+anv_RegisterDisplayEventEXT(VkDevice                           _device,
+                             VkDisplayKHR                       display,
+                             const VkDisplayEventInfoEXT        *display_event_info,
+                             const VkAllocationCallbacks        *allocator,
+                             VkFence                            *_fence)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+   const VkAllocationCallbacks  *alloc;
+   struct anv_fence            *fence;
+   VkResult                     ret;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &device->instance->alloc;
+
+   fence = vk_zalloc2(&device->alloc, allocator, sizeof (*fence), 8,
+                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!fence)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   fence->permanent.type = ANV_FENCE_TYPE_WSI;
+
+   ret = wsi_register_display_event(_device,
+                                    &device->instance->physicalDevice.wsi_device,
+                                    display,
+                                    display_event_info,
+                                    alloc,
+                                    &(fence->permanent.fence_wsi));
+
+   if (ret == VK_SUCCESS)
+      *_fence = anv_fence_to_handle(fence);
+   else
+      vk_free(alloc, fence);
+   return ret;
+}
+
+VkResult
+anv_GetSwapchainCounterEXT(VkDevice                    _device,
+                            VkSwapchainKHR              swapchain,
+                            VkSurfaceCounterFlagBitsEXT flag_bits,
+                            uint64_t                    *value)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+
+   return wsi_get_swapchain_counter(_device,
+                                    &device->instance->physicalDevice.wsi_device,
+                                    swapchain,
+                                    flag_bits,
+                                    value);
+}
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index 124d096170a..e504f4120ad 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -48,6 +48,15 @@ struct wsi_memory_allocate_info {
     bool implicit_sync;
 };
 
+struct wsi_fence {
+   VkDevice                     device;
+   const struct wsi_device      *wsi_device;
+   VkDisplayKHR                 display;
+   const VkAllocationCallbacks  *alloc;
+   bool                         (*wait)(struct wsi_fence *fence, bool absolute, uint64_t timeout);
+   void                         (*destroy)(struct wsi_fence *fence);
+};
+
 struct wsi_interface;
 
 #define VK_ICD_WSI_PLATFORM_MAX 6
diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
index e63700e2e65..c3608f13e54 100644
--- a/src/vulkan/wsi/wsi_common_display.c
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -77,6 +77,7 @@ typedef struct wsi_display_connector {
    bool                         active;
    wsi_display_mode             *current_mode;
    drmModeModeInfo              current_drm_mode;
+   uint32_t                     dpms_property;
 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
    xcb_randr_output_t           output;
 #endif
@@ -124,6 +125,15 @@ struct wsi_display_swapchain {
    struct wsi_display_image     images[0];
 };
 
+struct wsi_display_fence {
+   struct wsi_fence             base;
+   bool                         event_received;
+   bool                         destroyed;
+   uint64_t                     sequence;
+};
+
+static uint64_t fence_sequence;
+
 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
 
@@ -271,6 +281,7 @@ wsi_display_get_connector(struct wsi_device             *wsi_device,
    drmModeConnectorPtr          drm_connector;
    VkResult                     result;
    int                          m;
+   int                          p;
 
    if (wsi->master_fd < 0)
       return NULL;
@@ -292,6 +303,18 @@ wsi_display_get_connector(struct wsi_device             *wsi_device,
 
    connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED;
 
+   /* Look for a DPMS property */
+   for (p = 0; p < drm_connector->count_props; p++) {
+      drmModePropertyPtr prop = drmModeGetProperty(wsi->master_fd, drm_connector->props[p]);
+      if (!prop)
+         continue;
+      if (prop->flags & DRM_MODE_PROP_ENUM) {
+         if (!strcmp(prop->name, "DPMS"))
+            connector->dpms_property = drm_connector->props[p];
+      }
+      drmModeFreeProperty(prop);
+   }
+
    /* Mark all connector modes as invalid */
    wsi_display_invalidate_connector_modes(wsi_device, connector);
 
@@ -677,7 +700,7 @@ wsi_display_surface_get_capabilities2ext(VkIcdSurfaceBase *icd_surface,
    caps->currentTransform = khr_caps.currentTransform;
    caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha;
    caps->supportedUsageFlags = khr_caps.supportedUsageFlags;
-   caps->supportedSurfaceCounters = 0;
+   caps->supportedSurfaceCounters = VK_SURFACE_COUNTER_VBLANK_EXT;
    return ret;
 }
 
@@ -865,12 +888,20 @@ static void wsi_display_page_flip_handler(int fd, unsigned int frame,
    wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
 }
 
+static void wsi_display_vblank_handler(int fd, unsigned int frame,
+                                       unsigned int sec, unsigned int usec, void *data);
+
+static void wsi_display_sequence_handler(int fd, uint64_t frame,
+                                         uint64_t ns, uint64_t user_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
+   .vblank_handler = wsi_display_vblank_handler,
+   .sequence_handler = wsi_display_sequence_handler,
 };
 
 static void *
@@ -1117,6 +1148,135 @@ bail:
 
 }
 
+static bool
+wsi_display_fence_wait(struct wsi_fence *fence_wsi,
+                       bool absolute,
+                       uint64_t timeout)
+{
+   const struct wsi_device      *wsi_device = fence_wsi->wsi_device;
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_fence     *fence = (struct wsi_display_fence *) fence_wsi;
+   int                          ret = 0;
+   bool                         value;
+
+   if (!absolute)
+      timeout += wsi_get_current_monotonic();
+
+   wsi_display_debug("%9lu wait fence %lu %ld\n", pthread_self(), fence->sequence, (int64_t) (timeout - wsi_get_current_monotonic()));
+   wsi_display_debug_code(uint64_t start_ns = wsi_get_current_monotonic());
+   pthread_mutex_lock(&wsi->wait_mutex);
+   for (;;) {
+      if (fence->event_received) {
+         wsi_display_debug("%9lu fence %lu passed\n", pthread_self(), fence->sequence);
+         value = true;
+         break;
+      }
+
+      if (ret == ETIMEDOUT) {
+         wsi_display_debug("%9lu fence %lu timeout\n", pthread_self(), fence->sequence);
+         value = false;
+         break;
+      }
+
+      ret = wsi_display_wait_for_event(wsi, timeout);
+
+      if (ret && ret != ETIMEDOUT) {
+         wsi_display_debug("%9lu fence %lu error\n", pthread_self(), fence->sequence);
+         value = false;
+         break;
+      }
+   }
+   pthread_mutex_unlock(&wsi->wait_mutex);
+   wsi_display_debug("%9lu fence wait %f ms\n", pthread_self(), ((int64_t) (wsi_get_current_monotonic() - start_ns)) / 1.0e6);
+   return value;
+}
+
+static void
+wsi_display_fence_check_free(struct wsi_display_fence *fence)
+{
+   if (fence->event_received && fence->destroyed)
+      vk_free(fence->base.alloc, fence);
+}
+
+static void
+wsi_display_fence_destroy(struct wsi_fence *fence_wsi)
+{
+   struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
+
+   fence->destroyed = true;
+   wsi_display_fence_check_free(fence);
+}
+
+static struct wsi_display_fence *
+wsi_display_fence_alloc(VkDevice                        device,
+                        const struct wsi_device         *wsi_device,
+                        VkDisplayKHR                    display,
+                        const VkAllocationCallbacks     *allocator)
+{
+   struct wsi_display_fence *fence = vk_alloc(allocator, sizeof (*fence), 8,
+                                              VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+
+   if (!fence)
+      return NULL;
+
+   fence->base.device = device;
+   fence->base.display = display;
+   fence->base.wsi_device = wsi_device;
+   fence->base.alloc = allocator;
+   fence->base.wait = wsi_display_fence_wait;
+   fence->base.destroy = wsi_display_fence_destroy;
+   fence->event_received = false;
+   fence->destroyed = false;
+   fence->sequence = ++fence_sequence;
+   return fence;
+}
+
+static VkResult
+wsi_register_vblank_event(struct wsi_display_fence      *fence,
+                          const struct wsi_device       *wsi_device,
+                          VkDisplayKHR                  display,
+                          uint32_t                      flags,
+                          uint64_t                      frame_requested,
+                          uint64_t                      *frame_queued)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
+   int ret;
+
+   if (wsi->master_fd < 0)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   for (;;) {
+      ret = drmCrtcQueueSequence(wsi->master_fd, connector->crtc_id,
+                                 flags,
+                                 frame_requested,
+                                 frame_queued,
+                                 (uint64_t) fence);
+
+      if (!ret)
+         return VK_SUCCESS;
+
+      if (errno != ENOMEM) {
+         wsi_display_debug("queue vblank event %lu failed\n", fence->sequence);
+         struct timespec delay = {
+            .tv_sec = 0,
+            .tv_nsec = 100000000ull,
+         };
+         nanosleep(&delay, NULL);
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+      }
+
+      pthread_mutex_lock(&wsi->wait_mutex);
+      ret = wsi_display_wait_for_event(wsi, wsi_get_current_monotonic() + 100000000ull);
+      pthread_mutex_unlock(&wsi->wait_mutex);
+
+      if (ret) {
+         wsi_display_debug("vblank queue full, event wait failed\n");
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+      }
+   }
+}
+
 /*
  * Check to see if the kernel has no flip queued and if there's an image
  * waiting to be displayed.
@@ -1882,3 +2042,127 @@ wsi_get_randr_output_display(VkPhysicalDevice   physical_device,
 }
 
 #endif
+
+/* VK_EXT_display_control */
+VkResult
+wsi_display_power_control(VkDevice                      device,
+                          struct wsi_device             *wsi_device,
+                          VkDisplayKHR                  display,
+                          const VkDisplayPowerInfoEXT   *display_power_info)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
+   int                          mode;
+
+   if (wsi->master_fd < 0)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   switch (display_power_info->powerState) {
+   case VK_DISPLAY_POWER_STATE_OFF_EXT:
+      mode = DRM_MODE_DPMS_OFF;
+      break;
+   case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
+      mode = DRM_MODE_DPMS_SUSPEND;
+      break;
+   default:
+      mode = DRM_MODE_DPMS_ON;
+      break;
+   }
+   drmModeConnectorSetProperty(wsi->master_fd,
+                               connector->id,
+                               connector->dpms_property,
+                               mode);
+   return VK_SUCCESS;
+}
+
+VkResult
+wsi_register_device_event(VkDevice                      device,
+                          struct wsi_device             *wsi_device,
+                          const VkDeviceEventInfoEXT    *device_event_info,
+                          const VkAllocationCallbacks   *allocator,
+                          struct wsi_fence              **fence_p)
+{
+   return VK_ERROR_FEATURE_NOT_PRESENT;
+}
+
+VkResult
+wsi_register_display_event(VkDevice                     device,
+                           struct wsi_device            *wsi_device,
+                           VkDisplayKHR                 display,
+                           const VkDisplayEventInfoEXT  *display_event_info,
+                           const VkAllocationCallbacks  *allocator,
+                           struct wsi_fence             **fence_p)
+{
+   struct wsi_display_fence     *fence = NULL;
+   VkResult                     ret = VK_ERROR_FEATURE_NOT_PRESENT;
+
+   switch (display_event_info->displayEvent) {
+   case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
+
+      fence = wsi_display_fence_alloc(device, wsi_device, display, allocator);
+
+      if (!fence)
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+      ret = wsi_register_vblank_event(fence, wsi_device, display, DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
+
+      break;
+   default:
+      ret = VK_ERROR_FEATURE_NOT_PRESENT;
+   }
+
+   if (ret == VK_SUCCESS)
+      *fence_p = &fence->base;
+   else if (fence != NULL)
+      vk_free(allocator, fence);
+   return ret;
+}
+
+
+VkResult
+wsi_get_swapchain_counter(VkDevice                      device,
+                          struct wsi_device             *wsi_device,
+                          VkSwapchainKHR                _swapchain,
+                          VkSurfaceCounterFlagBitsEXT   flag_bits,
+                          uint64_t                      *value)
+{
+   struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_swapchain *swapchain = (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
+   struct wsi_display_connector *connector = wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
+   int ret;
+
+   if (wsi->master_fd < 0)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   if (!connector->active) {
+      *value = 0;
+      return VK_SUCCESS;
+   }
+
+   ret = drmCrtcGetSequence(wsi->master_fd, connector->crtc_id, value, NULL);
+   if (ret)
+      *value = 0;
+
+   return VK_SUCCESS;
+}
+
+static void wsi_display_vblank_handler(int fd, unsigned int frame,
+                                       unsigned int sec, unsigned int usec, void *data)
+{
+   struct wsi_display_fence     *fence = data;
+
+   wsi_display_debug("%9lu fence %lu received %d\n", pthread_self(), fence->sequence, frame);
+   fence->event_received = true;
+   wsi_display_fence_check_free(fence);
+}
+
+static void wsi_display_sequence_handler(int fd, uint64_t frame,
+                                         uint64_t ns, uint64_t user_data)
+{
+   struct wsi_display_fence     *fence = (struct wsi_display_fence *) (uintptr_t) user_data;
+
+   wsi_display_debug("%9lu fence %lu received %lu\n", pthread_self(), fence->sequence, frame);
+   fence->event_received = true;
+   wsi_display_fence_check_free(fence);
+}
+
diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h
index 1997c2a3c40..ec91ba471ae 100644
--- a/src/vulkan/wsi/wsi_common_display.h
+++ b/src/vulkan/wsi/wsi_common_display.h
@@ -91,4 +91,33 @@ wsi_get_randr_output_display(VkPhysicalDevice   physical_device,
 
 #endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
 
+/* VK_EXT_display_control */
+VkResult
+wsi_display_power_control(VkDevice                      device,
+                          struct wsi_device             *wsi_device,
+                          VkDisplayKHR                  display,
+                          const VkDisplayPowerInfoEXT   *display_power_info);
+
+VkResult
+wsi_register_device_event(VkDevice                      device,
+                          struct wsi_device             *wsi_device,
+                          const VkDeviceEventInfoEXT    *device_event_info,
+                          const VkAllocationCallbacks   *allocator,
+                          struct wsi_fence              **fence);
+
+VkResult
+wsi_register_display_event(VkDevice                     device,
+                           struct wsi_device            *wsi_device,
+                           VkDisplayKHR                 display,
+                           const VkDisplayEventInfoEXT  *display_event_info,
+                           const VkAllocationCallbacks  *allocator,
+                           struct wsi_fence             **fence);
+
+VkResult
+wsi_get_swapchain_counter(VkDevice                      device,
+                          struct wsi_device             *wsi_device,
+                          VkSwapchainKHR                swapchain,
+                          VkSurfaceCounterFlagBitsEXT   flag_bits,
+                          uint64_t                      *value);
+
 #endif
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension
  2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
                   ` (4 preceding siblings ...)
  2018-02-10  4:45 ` [PATCH 5/7] vulkan: add VK_EXT_display_control [v4] Keith Packard
@ 2018-02-10  4:45 ` Keith Packard
  2018-02-13  0:20   ` Dylan Baker
  2018-02-10  4:45 ` [PATCH 7/7] vulkan: Add VK_GOOGLE_display_timing extension (x11 and display backends) Keith Packard
  6 siblings, 1 reply; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel

This extension adds a single function to query the current GPU
timestamp, just like glGetInteger64v(GL_TIMESTAMP, &timestamp). This
function is needed to complete the implementation of
GOOGLE_display_timing, which needs to be able to coorelate GPU and CPU
timestamps.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 include/vulkan/vulkan.h                         |  6 ++++++
 src/Makefile.am                                 |  1 +
 src/amd/vulkan/Makefile.am                      |  3 +++
 src/amd/vulkan/meson.build                      |  8 ++++----
 src/amd/vulkan/radv_device.c                    |  8 ++++++++
 src/amd/vulkan/radv_extensions.py               |  1 +
 src/intel/Makefile.vulkan.am                    |  7 +++++++
 src/intel/vulkan/anv_extensions.py              |  1 +
 src/intel/vulkan/anv_gem.c                      | 13 +++++++++++++
 src/intel/vulkan/anv_private.h                  |  1 +
 src/intel/vulkan/genX_query.c                   | 15 +++++++++++++++
 src/intel/vulkan/meson.build                    | 12 ++++++------
 src/vulkan/meson.build                          |  1 +
 src/vulkan/registry/vk_mesa_query_timestamp.xml | 22 ++++++++++++++++++++++
 14 files changed, 89 insertions(+), 10 deletions(-)
 create mode 100644 src/vulkan/registry/vk_mesa_query_timestamp.xml

diff --git a/include/vulkan/vulkan.h b/include/vulkan/vulkan.h
index d3e2e246cf3..5523eb7586f 100644
--- a/include/vulkan/vulkan.h
+++ b/include/vulkan/vulkan.h
@@ -7025,6 +7025,12 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT(
     VkMemoryHostPointerPropertiesEXT*           pMemoryHostPointerProperties);
 #endif
 
+typedef VkResult (VKAPI_PTR *PFN_vkQueryCurrentTimestampMESA)(VkDevice device, uint64_t *timestamp);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkQueryCurrentTimestampMESA(
+    VkDevice                                    _device,
+    uint64_t                                    *timestamp);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 014ffaf3e29..74ff305d7c6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,6 +68,7 @@ endif
 
 EXTRA_DIST += vulkan/registry/vk.xml
 EXTRA_DIST += vulkan/registry/vk_android_native_buffer.xml
+EXTRA_DIST += vulkan/registry/vk_mesa_query_timestamp.xml
 
 if HAVE_AMD_DRIVERS
 SUBDIRS += amd
diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
index 94ece06e99e..0626fa2b3b3 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -129,12 +129,14 @@ libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES)
 
 vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
 vk_android_native_buffer_xml = $(top_srcdir)/src/vulkan/registry/vk_android_native_buffer.xml
+vk_mesa_query_timestamp_xml = $(top_srcdir)/src/vulkan/registry/vk_mesa_query_timestamps.xml
 
 radv_entrypoints.c: radv_entrypoints_gen.py radv_extensions.py $(vulkan_api_xml)
 	$(MKDIR_GEN)
 	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py \
 		--xml $(vulkan_api_xml) \
 		--xml $(vk_android_native_buffer_xml) \
+		--xml $(vk_mesa_query_timestamp_xml) \
 		--outdir $(builddir)
 radv_entrypoints.h: radv_entrypoints.c
 
@@ -144,6 +146,7 @@ radv_extensions.c: radv_extensions.py \
 	$(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_extensions.py \
 		--xml $(vulkan_api_xml) \
 		--xml $(vk_android_native_buffer_xml) \
+		--xml $(vk_mesa_query_timestamp_xml) \
 		--out $@
 
 vk_format_table.c: vk_format_table.py \
diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
index 0b92a1763a1..34f578476c0 100644
--- a/src/amd/vulkan/meson.build
+++ b/src/amd/vulkan/meson.build
@@ -20,10 +20,10 @@
 
 radv_entrypoints = custom_target(
   'radv_entrypoints.[ch]',
-  input : ['radv_entrypoints_gen.py', vk_api_xml],
+  input : ['radv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml],
   output : ['radv_entrypoints.h', 'radv_entrypoints.c'],
   command : [
-    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--outdir',
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@', '--outdir',
     meson.current_build_dir()
   ],
   depend_files : files('radv_extensions.py'),
@@ -31,10 +31,10 @@ radv_entrypoints = custom_target(
 
 radv_extensions_c = custom_target(
   'radv_extensions.c',
-  input : ['radv_extensions.py', vk_api_xml, vk_android_native_buffer_xml],
+  input : ['radv_extensions.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml],
   output : ['radv_extensions.c'],
   command : [
-    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--out', '@OUTPUT@',
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@', '--out', '@OUTPUT@',
   ],
 )
 
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index adf33eb35dc..6c13efba9e0 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -4084,3 +4084,11 @@ radv_DebugReportMessageEXT(VkInstance _instance,
 	vk_debug_report(&instance->debug_report_callbacks, flags, objectType,
 	                object, location, messageCode, pLayerPrefix, pMessage);
 }
+
+VkResult radv_QueryCurrentTimestampMESA(VkDevice _device, uint64_t *timestamp)
+{
+	RADV_FROM_HANDLE(radv_device, device, _device);
+
+	*timestamp = device->ws->query_value(device->ws, RADEON_TIMESTAMP);
+	return VK_SUCCESS;
+}
diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index 775d1ed4be6..fed198df412 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -95,6 +95,7 @@ EXTENSIONS = [
     Extension('VK_AMD_draw_indirect_count',               1, True),
     Extension('VK_AMD_rasterization_order',               1, 'device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2'),
     Extension('VK_AMD_shader_info',                       1, True),
+    Extension('VK_MESA_query_timestamp',                  1, True),
 ]
 
 class VkVersion:
diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
index 0f0d3815097..d7890022abe 100644
--- a/src/intel/Makefile.vulkan.am
+++ b/src/intel/Makefile.vulkan.am
@@ -24,36 +24,43 @@
 # out and we'll fail at `make dist'
 vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
 vk_android_native_buffer_xml = $(top_srcdir)/src/vulkan/registry/vk_android_native_buffer.xml
+vk_mesa_query_timestamp_xml = $(top_srcdir)/src/vulkan/registry/vk_mesa_query_timestamps.xml
 
 vulkan/anv_entrypoints.c: vulkan/anv_entrypoints_gen.py \
 			  vulkan/anv_extensions.py \
 			  $(vulkan_api_xml) \
+			  $(vk_mesa_query_timestamp_xml) \
 			  $(vk_android_native_buffer_xml)
 	$(MKDIR_GEN)
 	$(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_entrypoints_gen.py \
 		--xml $(vulkan_api_xml) \
 		--xml $(vk_android_native_buffer_xml) \
+		--xml $(vk_mesa_query_timestamp_xml) \
 		--outdir $(builddir)/vulkan
 vulkan/anv_entrypoints.h: vulkan/anv_entrypoints.c
 
 vulkan/anv_extensions.c: vulkan/anv_extensions_gen.py \
 			 vulkan/anv_extensions.py \
 			 $(vulkan_api_xml) \
+			 $(vk_mesa_query_timestamp_xml) \
 			 $(vk_android_native_buffer_xml)
 	$(MKDIR_GEN)
 	$(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_extensions_gen.py \
 		--xml $(vulkan_api_xml) \
 		--xml $(vk_android_native_buffer_xml) \
+		--xml $(vk_mesa_query_timestamp_xml) \
 		--out-c $@
 
 vulkan/anv_extensions.h: vulkan/anv_extensions_gen.py \
 			 vulkan/anv_extensions.py \
 			 $(vulkan_api_xml) \
+			 $(vk_mesa_query_timestamp_xml) \
 			 $(vk_android_native_buffer_xml)
 	$(MKDIR_GEN)
 	$(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_extensions_gen.py \
 		--xml $(vulkan_api_xml) \
 		--xml $(vk_android_native_buffer_xml) \
+		--xml $(vk_mesa_query_timestamp_xml) \
 		--out-h $@
 
 BUILT_SOURCES += $(VULKAN_GENERATED_FILES)
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index f44598b305a..dd4d5a1f970 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -91,6 +91,7 @@ EXTENSIONS = [
     Extension('VK_EXT_external_memory_dma_buf',           1, True),
     Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_EXT_display_control',                   1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
+    Extension('VK_MESA_query_timestamp',                  1, True),
 ]
 
 class VkVersion:
diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c
index 34c09891086..588b323d113 100644
--- a/src/intel/vulkan/anv_gem.c
+++ b/src/intel/vulkan/anv_gem.c
@@ -418,6 +418,19 @@ anv_gem_fd_to_handle(struct anv_device *device, int fd)
    return args.handle;
 }
 
+int
+anv_gem_reg_read(struct anv_device *device, uint32_t offset, uint64_t *result)
+{
+   struct drm_i915_reg_read args = {
+      .offset = offset
+   };
+
+   int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_REG_READ, &args);
+
+   *result = args.val;
+   return ret;
+}
+
 #ifndef SYNC_IOC_MAGIC
 /* duplicated from linux/sync_file.h to avoid build-time dependency
  * on new (v4.7) kernel headers.  Once distro's are mostly using
diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
index 1d3e5fcd921..337d8ca3f15 100644
--- a/src/intel/vulkan/anv_private.h
+++ b/src/intel/vulkan/anv_private.h
@@ -932,6 +932,7 @@ bool anv_gem_supports_48b_addresses(int fd);
 int anv_gem_gpu_get_reset_stats(struct anv_device *device,
                                 uint32_t *active, uint32_t *pending);
 int anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle);
+int anv_gem_reg_read(struct anv_device *device, uint32_t offset, uint64_t *result);
 uint32_t anv_gem_fd_to_handle(struct anv_device *device, int fd);
 int anv_gem_set_caching(struct anv_device *device, uint32_t gem_handle, uint32_t caching);
 int anv_gem_set_domain(struct anv_device *device, uint32_t gem_handle,
diff --git a/src/intel/vulkan/genX_query.c b/src/intel/vulkan/genX_query.c
index 4efcc57e475..d2de7e5f45e 100644
--- a/src/intel/vulkan/genX_query.c
+++ b/src/intel/vulkan/genX_query.c
@@ -546,6 +546,21 @@ void genX(CmdWriteTimestamp)(
    }
 }
 
+VkResult genX(QueryCurrentTimestampMESA)(
+   VkDevice                                     _device,
+   uint64_t                                     *timestamp)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+   int  ret;
+
+   /* XXX older kernels don't support this interface. */
+   ret = anv_gem_reg_read(device, TIMESTAMP | 1, timestamp);
+
+   if (ret != 0)
+      return VK_ERROR_DEVICE_LOST;
+   return VK_SUCCESS;
+}
+
 #if GEN_GEN > 7 || GEN_IS_HASWELL
 
 static uint32_t
diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
index d3ab5ac8a64..d4622ffdfdf 100644
--- a/src/intel/vulkan/meson.build
+++ b/src/intel/vulkan/meson.build
@@ -20,11 +20,11 @@
 
 anv_entrypoints = custom_target(
   'anv_entrypoints.[ch]',
-  input : ['anv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml,
+  input : ['anv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
            'anv_extensions.py'],
   output : ['anv_entrypoints.h', 'anv_entrypoints.c'],
   command : [
-    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
     '--outdir', meson.current_build_dir(),
   ],
   depend_files : files('anv_extensions.py'),
@@ -32,22 +32,22 @@ anv_entrypoints = custom_target(
 
 anv_extensions_c = custom_target(
   'anv_extensions.c',
-  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml,
+  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
            'anv_extensions.py'],
   output : 'anv_extensions.c',
   command : [
-    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
     '--out-c', '@OUTPUT@',
   ],
 )
 
 anv_extensions_h = custom_target(
   'anv_extensions.h',
-  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml,
+  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
            'anv_extensions.py'],
   output : 'anv_extensions.h',
   command : [
-    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
+    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
     '--out-h', '@OUTPUT@',
   ],
 )
diff --git a/src/vulkan/meson.build b/src/vulkan/meson.build
index 3908005b8a0..6ab0966b7c5 100644
--- a/src/vulkan/meson.build
+++ b/src/vulkan/meson.build
@@ -20,6 +20,7 @@
 
 vk_api_xml = files('registry/vk.xml')
 vk_android_native_buffer_xml = files('registry/vk_android_native_buffer.xml')
+vk_mesa_query_timestamp_xml = files('registry/vk_mesa_query_timestamp.xml')
 
 inc_vulkan_util = include_directories('util')
 inc_vulkan_wsi = include_directories('wsi')
diff --git a/src/vulkan/registry/vk_mesa_query_timestamp.xml b/src/vulkan/registry/vk_mesa_query_timestamp.xml
new file mode 100644
index 00000000000..7fd4d974872
--- /dev/null
+++ b/src/vulkan/registry/vk_mesa_query_timestamp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<registry>
+    <commands>
+        <command>
+            <proto><type>VkResult</type> <name>vkQueryCurrentTimestampMESA</name></proto>
+            <param><type>VkDevice</type> <name>device</name></param>
+            <param><type>uint64_t</type>* <name>pTimestamp</name></param>
+        </command>
+    </commands>
+    <extensions>
+        <extension name="VK_MESA_query_timestamp" number="200"
+		   type="device" author="MESA"
+		   contact="Keith Packard @keithp"
+		   supported="vulkan">
+            <require>
+                <enum value="1"                                         name="VK_MESA_QUERY_TIMESTAMP_SPEC_VERSION"/>
+                <enum value="&quot;VK_MESA_query_timestamp&quot;"       name="VK_MESA_QUERY_TIMESTAMP_NAME"/>
+                <command name="vkQueryCurrentTimestampMESA"/>
+            </require>
+        </extension>
+    </extensions>
+</registry>
-- 
2.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [PATCH 7/7] vulkan: Add VK_GOOGLE_display_timing extension (x11 and display backends)
  2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
                   ` (5 preceding siblings ...)
  2018-02-10  4:45 ` [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension Keith Packard
@ 2018-02-10  4:45 ` Keith Packard
  6 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-10  4:45 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel

This adds support for the VK_GOOGLE_display timing extension, which
provides two things:

 1) Detailed information about when frames are displayed, including
    slack time between GPU execution and display frame.

 2) Absolute time control over swapchain queue processing. This allows
    the application to request frames be displayed at specific
    absolute times, using the same timebase as that provided in vblank
    events.

Support for this extension has been implemented for the x11 and
display backends; adding support to other backends should be
reasonable straightforward for one familiar with those systems and
should not require any additional device-specific code.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 src/amd/vulkan/radv_extensions.py   |   1 +
 src/amd/vulkan/radv_wsi.c           |  32 +++++
 src/intel/vulkan/anv_extensions.py  |   1 +
 src/intel/vulkan/anv_wsi.c          |  29 ++++
 src/vulkan/wsi/wsi_common.c         | 254 +++++++++++++++++++++++++++++++++++-
 src/vulkan/wsi/wsi_common.h         |  24 ++++
 src/vulkan/wsi/wsi_common_display.c | 143 +++++++++++++++++++-
 src/vulkan/wsi/wsi_common_private.h |  35 +++++
 src/vulkan/wsi/wsi_common_x11.c     |  69 +++++++++-
 9 files changed, 577 insertions(+), 11 deletions(-)

diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index fed198df412..f38d6903a80 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -96,6 +96,7 @@ EXTENSIONS = [
     Extension('VK_AMD_rasterization_order',               1, 'device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2'),
     Extension('VK_AMD_shader_info',                       1, True),
     Extension('VK_MESA_query_timestamp',                  1, True),
+    Extension('VK_GOOGLE_display_timing',                 1, True),
 ]
 
 class VkVersion:
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
index 2d2a30ebbb1..48ff7107232 100644
--- a/src/amd/vulkan/radv_wsi.c
+++ b/src/amd/vulkan/radv_wsi.c
@@ -247,3 +247,35 @@ VkResult radv_QueuePresentKHR(
 					queue->queue_family_index,
 					pPresentInfo);
 }
+
+/* VK_GOOGLE_display_timing */
+VkResult
+radv_GetRefreshCycleDurationGOOGLE(
+	VkDevice                      _device,
+	VkSwapchainKHR                swapchain,
+	VkRefreshCycleDurationGOOGLE  *pDisplayTimingProperties)
+{
+	RADV_FROM_HANDLE(radv_device, device, _device);
+	struct radv_physical_device *pdevice = device->physical_device;
+
+	return wsi_common_get_refresh_cycle_duration(&pdevice->wsi_device,
+						     _device,
+						     swapchain,
+						     pDisplayTimingProperties);
+}
+
+VkResult
+radv_GetPastPresentationTimingGOOGLE(VkDevice                            _device,
+				     VkSwapchainKHR                      swapchain,
+				     uint32_t                            *pPresentationTimingCount,
+				     VkPastPresentationTimingGOOGLE      *pPresentationTimings)
+{
+	RADV_FROM_HANDLE(radv_device, device, _device);
+	struct radv_physical_device *pdevice = device->physical_device;
+
+	return wsi_common_get_past_presentation_timing(&pdevice->wsi_device,
+						       _device,
+						       swapchain,
+						       pPresentationTimingCount,
+						       pPresentationTimings);
+}
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index dd4d5a1f970..c45ef9ad09f 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -92,6 +92,7 @@ EXTENSIONS = [
     Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_EXT_display_control',                   1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_MESA_query_timestamp',                  1, True),
+    Extension('VK_GOOGLE_display_timing',                 1, True),
 ]
 
 class VkVersion:
diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
index 52362adfb71..7801a989e0d 100644
--- a/src/intel/vulkan/anv_wsi.c
+++ b/src/intel/vulkan/anv_wsi.c
@@ -239,3 +239,32 @@ VkResult anv_QueuePresentKHR(
                                    _queue, 0,
                                    pPresentInfo);
 }
+
+/* VK_GOOGLE_display_timing */
+VkResult
+anv_GetRefreshCycleDurationGOOGLE(VkDevice                      _device,
+                                  VkSwapchainKHR                swapchain,
+                                  VkRefreshCycleDurationGOOGLE  *pDisplayTimingProperties)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+
+   return wsi_common_get_refresh_cycle_duration(&device->instance->physicalDevice.wsi_device,
+                                                _device,
+                                                swapchain,
+                                                pDisplayTimingProperties);
+}
+
+VkResult
+anv_GetPastPresentationTimingGOOGLE(VkDevice                            _device,
+                                    VkSwapchainKHR                      swapchain,
+                                    uint32_t                            *pPresentationTimingCount,
+                                    VkPastPresentationTimingGOOGLE      *pPresentationTimings)
+{
+   ANV_FROM_HANDLE(anv_device, device, _device);
+
+   return wsi_common_get_past_presentation_timing(&device->instance->physicalDevice.wsi_device,
+                                                  _device,
+                                                  swapchain,
+                                                  pPresentationTimingCount,
+                                                  pPresentationTimings);
+}
diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c
index 02abc9ef7fb..c36e4ccdcbe 100644
--- a/src/vulkan/wsi/wsi_common.c
+++ b/src/vulkan/wsi/wsi_common.c
@@ -40,11 +40,16 @@ wsi_device_init(struct wsi_device *wsi,
    PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
    WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
    WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
+   WSI_GET_CB(GetPhysicalDeviceProperties);
 #undef WSI_GET_CB
 
    GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props);
    GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL);
 
+   VkPhysicalDeviceProperties properties;
+   GetPhysicalDeviceProperties(pdevice, &properties);
+   wsi->timestamp_period = properties.limits.timestampPeriod;
+
 #define WSI_GET_CB(func) \
    wsi->func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
    WSI_GET_CB(AllocateMemory);
@@ -53,14 +58,18 @@ wsi_device_init(struct wsi_device *wsi,
    WSI_GET_CB(BindImageMemory);
    WSI_GET_CB(BeginCommandBuffer);
    WSI_GET_CB(CmdCopyImageToBuffer);
+   WSI_GET_CB(CmdResetQueryPool);
+   WSI_GET_CB(CmdWriteTimestamp);
    WSI_GET_CB(CreateBuffer);
    WSI_GET_CB(CreateCommandPool);
    WSI_GET_CB(CreateFence);
    WSI_GET_CB(CreateImage);
+   WSI_GET_CB(CreateQueryPool);
    WSI_GET_CB(DestroyBuffer);
    WSI_GET_CB(DestroyCommandPool);
    WSI_GET_CB(DestroyFence);
    WSI_GET_CB(DestroyImage);
+   WSI_GET_CB(DestroyQueryPool);
    WSI_GET_CB(EndCommandBuffer);
    WSI_GET_CB(FreeMemory);
    WSI_GET_CB(FreeCommandBuffers);
@@ -68,9 +77,13 @@ wsi_device_init(struct wsi_device *wsi,
    WSI_GET_CB(GetImageMemoryRequirements);
    WSI_GET_CB(GetImageSubresourceLayout);
    WSI_GET_CB(GetMemoryFdKHR);
+   WSI_GET_CB(GetPhysicalDeviceProperties);
    WSI_GET_CB(GetPhysicalDeviceFormatProperties);
+   WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
+   WSI_GET_CB(GetQueryPoolResults);
    WSI_GET_CB(ResetFences);
    WSI_GET_CB(QueueSubmit);
+   WSI_GET_CB(QueryCurrentTimestampMESA);
    WSI_GET_CB(WaitForFences);
 #undef WSI_GET_CB
 
@@ -136,6 +149,8 @@ wsi_swapchain_init(const struct wsi_device *wsi,
    chain->device = device;
    chain->alloc = *pAllocator;
    chain->use_prime_blit = false;
+   chain->timing_insert = 0;
+   chain->timing_count = 0;
 
    chain->cmd_pools =
       vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8,
@@ -209,6 +224,60 @@ align_u32(uint32_t v, uint32_t a)
    return (v + a - 1) & ~(a - 1);
 }
 
+static VkResult
+wsi_image_init_timestamp(const struct wsi_swapchain *chain,
+                         struct wsi_image *image)
+{
+   const struct wsi_device *wsi = chain->wsi;
+   VkResult result;
+   /* Set up command buffer to get timestamp info */
+
+   result = wsi->CreateQueryPool(chain->device,
+                                 &(const VkQueryPoolCreateInfo) {
+                                    .sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
+                                       .queryType = VK_QUERY_TYPE_TIMESTAMP,
+                                       .queryCount = 1,
+                                       },
+                                 NULL,
+                                 &image->query_pool);
+
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   result = wsi->AllocateCommandBuffers(chain->device,
+                                        &(const VkCommandBufferAllocateInfo) {
+                                           .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+                                              .pNext = NULL,
+                                              .commandPool = chain->cmd_pools[0],
+                                              .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+                                              .commandBufferCount = 1,
+                                              },
+                                        &image->timestamp_buffer);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   wsi->BeginCommandBuffer(image->timestamp_buffer,
+                           &(VkCommandBufferBeginInfo) {
+                              .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+                                 .flags = 0
+                                 });
+
+   wsi->CmdResetQueryPool(image->timestamp_buffer,
+                          image->query_pool,
+                          0, 1);
+
+   wsi->CmdWriteTimestamp(image->timestamp_buffer,
+                          VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+                          image->query_pool,
+                          0);
+
+   wsi->EndCommandBuffer(image->timestamp_buffer);
+
+   return VK_SUCCESS;
+fail:
+   return result;
+}
+
 VkResult
 wsi_create_native_image(const struct wsi_swapchain *chain,
                         const VkSwapchainCreateInfoKHR *pCreateInfo,
@@ -303,6 +372,11 @@ wsi_create_native_image(const struct wsi_swapchain *chain,
    };
    int fd;
    result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
+   if (result != VK_SUCCESS)
+      goto fail;
+
+   result = wsi_image_init_timestamp(chain, image);
+
    if (result != VK_SUCCESS)
       goto fail;
 
@@ -497,6 +571,11 @@ wsi_create_prime_image(const struct wsi_swapchain *chain,
          goto fail;
    }
 
+   result = wsi_image_init_timestamp(chain, image);
+
+   if (result != VK_SUCCESS)
+      goto fail;
+
    const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
       .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
       .pNext = NULL,
@@ -695,6 +774,87 @@ wsi_common_acquire_next_image(const struct wsi_device *wsi,
                                         semaphore, pImageIndex);
 }
 
+static struct wsi_timing *
+wsi_get_timing(struct wsi_swapchain *chain, uint32_t i)
+{
+   uint32_t j = WSI_TIMING_HISTORY + chain->timing_insert - chain->timing_count + i;
+
+   if (j >= WSI_TIMING_HISTORY)
+      j -= WSI_TIMING_HISTORY;
+   return &chain->timing[j];
+}
+
+static struct wsi_timing *
+wsi_next_timing(struct wsi_swapchain *chain, int image_index)
+{
+   uint32_t j;
+   struct wsi_timing *timing;
+
+   j = chain->timing_insert;
+   ++chain->timing_insert;
+   if (chain->timing_insert >= WSI_TIMING_HISTORY)
+      chain->timing_insert = 0;
+   if (chain->timing_count < WSI_TIMING_HISTORY)
+      ++chain->timing_count;
+   timing = &chain->timing[j];
+   memset(timing, '\0', sizeof (*timing));
+   return timing;
+}
+
+void
+wsi_mark_timing(struct wsi_swapchain *swapchain,
+                struct wsi_image *image,
+                uint64_t ust,
+                uint64_t msc)
+{
+   const struct wsi_device *wsi = swapchain->wsi;
+   struct wsi_timing *timing = image->timing;
+   VkResult result;
+
+   if (!timing)
+      return;
+
+   swapchain->frame_msc = msc;
+   swapchain->frame_ust = ust;
+
+   uint64_t     render_timestamp;
+
+   result = wsi->GetQueryPoolResults(swapchain->device, image->query_pool,
+                                     0, 1, sizeof(render_timestamp), &render_timestamp,
+                                     sizeof (uint64_t),
+                                     VK_QUERY_RESULT_64_BIT|VK_QUERY_RESULT_WAIT_BIT);
+
+   if (result != VK_SUCCESS)
+      return;
+
+   uint64_t     current_gpu_timestamp;
+   result = wsi->QueryCurrentTimestampMESA(swapchain->device, &current_gpu_timestamp);
+   if (result != VK_SUCCESS)
+      return;
+   uint64_t     current_time = swapchain->get_current_time();
+
+   VkRefreshCycleDurationGOOGLE display_timings;
+   swapchain->get_refresh_cycle_duration(swapchain, &display_timings);
+
+   uint64_t     refresh_duration = display_timings.refreshDuration;
+
+   /* When did drawing complete (in nsec) */
+
+   uint64_t     render_time = current_time - (current_gpu_timestamp - render_timestamp) * wsi->timestamp_period;
+
+   if (render_time > ust)
+      render_time = ust;
+
+   uint64_t     render_frames = (ust - render_time) / refresh_duration;
+
+   uint64_t     earliest_time = ust - render_frames * refresh_duration;
+
+   timing->timing.actualPresentTime = ust;
+   timing->timing.earliestPresentTime = earliest_time;
+   timing->timing.presentMargin = earliest_time - render_time;
+   timing->complete = true;
+}
+
 VkResult
 wsi_common_queue_present(const struct wsi_device *wsi,
                          VkDevice device,
@@ -706,10 +866,13 @@ wsi_common_queue_present(const struct wsi_device *wsi,
 
    const VkPresentRegionsKHR *regions =
       vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
+   const VkPresentTimesInfoGOOGLE *present_times_info =
+      vk_find_struct_const(pPresentInfo->pNext, PRESENT_TIMES_INFO_GOOGLE);
 
    for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
       WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
       VkResult result;
+      struct wsi_timing *timing = NULL;
 
       if (swapchain->fences[0] == VK_NULL_HANDLE) {
          const VkFenceCreateInfo fence_info = {
@@ -726,9 +889,12 @@ wsi_common_queue_present(const struct wsi_device *wsi,
          wsi->ResetFences(device, 1, &swapchain->fences[0]);
       }
 
+      VkCommandBuffer submit_buffers[2];
       VkSubmitInfo submit_info = {
          .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
          .pNext = NULL,
+         .pCommandBuffers = submit_buffers,
+         .commandBufferCount = 0
       };
 
       VkPipelineStageFlags *stage_flags = NULL;
@@ -761,9 +927,44 @@ wsi_common_queue_present(const struct wsi_device *wsi,
           */
          struct wsi_image *image =
             swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]);
-         submit_info.commandBufferCount = 1;
-         submit_info.pCommandBuffers =
-            &image->prime.blit_cmd_buffers[queue_family_index];
+         submit_buffers[submit_info.commandBufferCount++] = 
+            image->prime.blit_cmd_buffers[queue_family_index];
+      }
+
+      /* Set up GOOGLE_display_timing bits */
+      if (present_times_info &&
+          present_times_info->pTimes != NULL &&
+          i < present_times_info->swapchainCount)
+      {
+         const VkPresentTimeGOOGLE *present_time = &present_times_info->pTimes[i];
+
+         struct wsi_image *image = swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]);
+
+         timing = wsi_next_timing(swapchain, pPresentInfo->pImageIndices[i]);
+         timing->timing.presentID = present_time->presentID;
+         timing->timing.desiredPresentTime = present_time->desiredPresentTime;
+         timing->target_msc = 0;
+         image->timing = timing;
+
+         if (present_time->desiredPresentTime != 0)
+         {
+            int64_t delta_nsec = (int64_t) (present_time->desiredPresentTime - swapchain->frame_ust);
+
+            /* Set the target msc only if it's no more than two seconds from
+             * now, and not stale
+             */
+            if (0 <= delta_nsec && delta_nsec <= 2000000000ul) {
+               VkRefreshCycleDurationGOOGLE refresh_timing;
+
+               swapchain->get_refresh_cycle_duration(swapchain, &refresh_timing);
+
+               int64_t refresh = (int64_t) refresh_timing.refreshDuration;
+               int64_t frames = (delta_nsec + refresh/2) / refresh;
+               timing->target_msc = swapchain->frame_msc + frames;
+            }
+         }
+
+         submit_buffers[submit_info.commandBufferCount++] = image->timestamp_buffer;
       }
 
       result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]);
@@ -801,3 +1002,50 @@ wsi_common_queue_present(const struct wsi_device *wsi,
 
    return final_result;
 }
+
+VkResult
+wsi_common_get_refresh_cycle_duration(const struct wsi_device *wsi,
+                                      VkDevice device_h,
+                                      VkSwapchainKHR _swapchain,
+                                      VkRefreshCycleDurationGOOGLE *pDisplayTimingProperties)
+{
+   WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
+
+   if (!swapchain->get_refresh_cycle_duration)
+      return VK_ERROR_EXTENSION_NOT_PRESENT;
+   return swapchain->get_refresh_cycle_duration(swapchain, pDisplayTimingProperties);
+}
+
+
+VkResult
+wsi_common_get_past_presentation_timing(const struct wsi_device *wsi,
+                                        VkDevice device_h,
+                                        VkSwapchainKHR _swapchain,
+                                        uint32_t *count,
+                                        VkPastPresentationTimingGOOGLE *timings)
+{
+   WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
+   uint32_t timing_count_requested = *count;
+   uint32_t timing_count_available = 0;
+   uint32_t t;
+
+   /* Count the number of completed entries, copy */
+   for (t = 0; t < swapchain->timing_count; t++) {
+      struct wsi_timing *timing = wsi_get_timing(swapchain, t);
+
+      if (timing->complete && !timing->consumed) {
+         if (timings && timing_count_available < timing_count_requested) {
+            timings[timing_count_available] = timing->timing;
+            timing->consumed = true;
+         }
+         timing_count_available++;
+      }
+   }
+
+   *count = timing_count_available;
+
+   if (timing_count_available > timing_count_requested && timings != NULL)
+      return VK_INCOMPLETE;
+
+   return VK_SUCCESS;
+}
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index e504f4120ad..47786810b66 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -64,6 +64,7 @@ struct wsi_interface;
 struct wsi_device {
    VkPhysicalDeviceMemoryProperties memory_props;
    uint32_t queue_family_count;
+   float timestamp_period;
 
 #define WSI_CB(cb) PFN_vk##cb cb
    WSI_CB(AllocateMemory);
@@ -72,14 +73,18 @@ struct wsi_device {
    WSI_CB(BindImageMemory);
    WSI_CB(BeginCommandBuffer);
    WSI_CB(CmdCopyImageToBuffer);
+   WSI_CB(CmdResetQueryPool);
+   WSI_CB(CmdWriteTimestamp);
    WSI_CB(CreateBuffer);
    WSI_CB(CreateCommandPool);
    WSI_CB(CreateFence);
    WSI_CB(CreateImage);
+   WSI_CB(CreateQueryPool);
    WSI_CB(DestroyBuffer);
    WSI_CB(DestroyCommandPool);
    WSI_CB(DestroyFence);
    WSI_CB(DestroyImage);
+   WSI_CB(DestroyQueryPool);
    WSI_CB(EndCommandBuffer);
    WSI_CB(FreeMemory);
    WSI_CB(FreeCommandBuffers);
@@ -87,9 +92,13 @@ struct wsi_device {
    WSI_CB(GetImageMemoryRequirements);
    WSI_CB(GetImageSubresourceLayout);
    WSI_CB(GetMemoryFdKHR);
+   WSI_CB(GetPhysicalDeviceProperties);
    WSI_CB(GetPhysicalDeviceFormatProperties);
+   WSI_CB(GetPhysicalDeviceQueueFamilyProperties);
+   WSI_CB(GetQueryPoolResults);
    WSI_CB(ResetFences);
    WSI_CB(QueueSubmit);
+   WSI_CB(QueryCurrentTimestampMESA);
    WSI_CB(WaitForFences);
 #undef WSI_CB
 
@@ -201,4 +210,19 @@ wsi_common_queue_present(const struct wsi_device *wsi,
                          int queue_family_index,
                          const VkPresentInfoKHR *pPresentInfo);
 
+/* VK_GOOGLE_display_timing */
+VkResult
+wsi_common_get_refresh_cycle_duration(const struct wsi_device *wsi,
+                                      VkDevice device_h,
+                                      VkSwapchainKHR swapchain,
+                                      VkRefreshCycleDurationGOOGLE *pDisplayTimingProperties);
+
+
+VkResult
+wsi_common_get_past_presentation_timing(const struct wsi_device *wsi,
+                                        VkDevice device_h,
+                                        VkSwapchainKHR swapchain,
+                                        uint32_t *pPresentationTimingCount,
+                                        VkPastPresentationTimingGOOGLE *pPresentationTimings);
+
 #endif
diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
index c3608f13e54..60bc6e8be00 100644
--- a/src/vulkan/wsi/wsi_common_display.c
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -75,6 +75,8 @@ typedef struct wsi_display_connector {
    char                         *name;
    bool                         connected;
    bool                         active;
+   uint64_t                     last_frame;
+   uint64_t                     last_nsec;
    wsi_display_mode             *current_mode;
    drmModeModeInfo              current_drm_mode;
    uint32_t                     dpms_property;
@@ -104,6 +106,7 @@ struct wsi_display {
 enum wsi_image_state {
    wsi_image_idle,
    wsi_image_drawing,
+   wsi_image_waiting,
    wsi_image_queued,
    wsi_image_flipping,
    wsi_image_displaying
@@ -113,6 +116,7 @@ struct wsi_display_image {
    struct wsi_image             base;
    struct wsi_display_swapchain *chain;
    enum wsi_image_state         state;
+   struct wsi_display_fence     *fence;
    uint32_t                     fb_id;
    uint64_t                     flip_sequence;
 };
@@ -122,6 +126,7 @@ struct wsi_display_swapchain {
    struct wsi_display           *wsi;
    VkIcdSurfaceDisplay          *surface;
    uint64_t                     flip_sequence;
+   const VkAllocationCallbacks  *allocator;
    struct wsi_display_image     images[0];
 };
 
@@ -130,6 +135,7 @@ struct wsi_display_fence {
    bool                         event_received;
    bool                         destroyed;
    uint64_t                     sequence;
+   struct wsi_display_image     *image;
 };
 
 static uint64_t fence_sequence;
@@ -799,6 +805,7 @@ wsi_display_image_init(VkDevice                         device_h,
 
    image->chain = chain;
    image->state = wsi_image_idle;
+   image->fence = NULL;
    image->fb_id = 0;
 
    /* XXX extract depth and bpp from image somehow */
@@ -866,6 +873,11 @@ wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
 static VkResult
 _wsi_display_queue_next(struct wsi_swapchain     *drv_chain);
 
+static uint64_t widen_32_to_64(uint32_t narrow, uint64_t near)
+{
+	return near + (int32_t) (narrow - near);
+}
+
 static void
 wsi_display_page_flip_handler2(int              fd,
                                unsigned int     frame,
@@ -875,11 +887,25 @@ wsi_display_page_flip_handler2(int              fd,
                                void             *data)
 {
    struct wsi_display_image     *image = data;
+   struct wsi_display_swapchain *chain = image->chain;
+   VkIcdSurfaceDisplay          *surface = chain->surface;
+   wsi_display_mode             *display_mode = wsi_display_mode_from_handle(surface->displayMode);
+   wsi_display_connector        *connector = display_mode->connector;
+   uint64_t                     frame64 = widen_32_to_64(frame, connector->last_frame);
+   uint64_t                     nsec = (uint64_t) sec * 1000000000 + (uint64_t) usec * 1000;
+
+   /* Don't let time go backwards because this function has lower resolution than ktime */
+   if (nsec < connector->last_nsec)
+      nsec = connector->last_nsec;
 
-   wsi_display_debug("image %ld displayed at %d\n", image - &(image->chain->images[0]), frame);
+   wsi_display_debug("image %ld displayed at %ld\n", image - &(image->chain->images[0]), frame64);
    image->state = wsi_image_displaying;
+   connector->last_frame = frame64;
+   connector->last_nsec = nsec;
+   wsi_mark_timing(&image->chain->base, &image->base,
+                   nsec, frame64);
    wsi_display_idle_old_displaying(image);
-   (void) _wsi_display_queue_next(&(image->chain->base));
+   (void) _wsi_display_queue_next(&(chain->base));
 }
 
 static void wsi_display_page_flip_handler(int fd, unsigned int frame,
@@ -1228,6 +1254,7 @@ wsi_display_fence_alloc(VkDevice                        device,
    fence->event_received = false;
    fence->destroyed = false;
    fence->sequence = ++fence_sequence;
+   fence->image = NULL;
    return fence;
 }
 
@@ -1323,6 +1350,12 @@ _wsi_display_queue_next(struct wsi_swapchain     *drv_chain)
       if (!image)
          return VK_SUCCESS;
 
+      if (image->fence) {
+         image->fence->image = NULL;
+         wsi_display_fence_destroy(&image->fence->base);
+         image->fence = NULL;
+      }
+
       if (connector->active) {
          ret = drmModePageFlip(wsi->master_fd, connector->crtc_id, image->fb_id,
                                DRM_MODE_PAGE_FLIP_EVENT, image);
@@ -1385,16 +1418,83 @@ wsi_display_queue_present(struct wsi_swapchain          *drv_chain,
 
    pthread_mutex_lock(&wsi->wait_mutex);
 
+   if (image->base.timing && image->base.timing->target_msc != 0) {
+      VkIcdSurfaceDisplay          *surface = chain->surface;
+      wsi_display_mode             *display_mode = wsi_display_mode_from_handle(surface->displayMode);
+      wsi_display_connector        *connector = display_mode->connector;
+
+      wsi_display_debug("delta frame %ld\n", image->base.timing->target_msc - connector->last_frame);
+      if (image->base.timing->target_msc > connector->last_frame) {
+         uint64_t frame_queued;
+         VkDisplayKHR display = wsi_display_connector_to_handle(connector);
+
+         wsi_display_debug_code(uint64_t current_frame, current_nsec;
+                                drmCrtcGetSequence(wsi->master_fd, connector->crtc_id, &current_frame, &current_nsec);
+                                wsi_display_debug("from current: %ld\n", image->base.timing->target_msc - current_frame));
+
+         image->fence = wsi_display_fence_alloc(chain->base.device, chain->base.wsi, display, &chain->base.alloc);
+
+         if (!image->fence) {
+            result = VK_ERROR_OUT_OF_HOST_MEMORY;
+            goto bail_unlock;
+         }
+
+         result = wsi_register_vblank_event(image->fence,
+                                            chain->base.wsi,
+                                            display,
+                                            0,
+                                            image->base.timing->target_msc - 1,
+                                            &frame_queued);
+
+         if (result != VK_SUCCESS)
+            goto bail_unlock;
+
+         /* Check and make sure we are queued for the right frame, otherwise just
+          * go queue an image
+          */
+         if (frame_queued <= image->base.timing->target_msc - 1) {
+            image->state = wsi_image_waiting;
+
+            /*
+             * Don't set the image member until we're going to wait for the
+             * event to arrive before flipping to the image. That way, if the
+             * register_vblank_event call happens to process the event, it
+             * won't actually do anything
+             */
+            image->fence->image = image;
+            wsi_display_start_wait_thread(wsi);
+            result = VK_SUCCESS;
+            goto bail_unlock;
+         }
+
+      }
+   }
+
+
    image->flip_sequence = ++chain->flip_sequence;
    image->state = wsi_image_queued;
 
    result = _wsi_display_queue_next(drv_chain);
 
+bail_unlock:
    pthread_mutex_unlock(&wsi->wait_mutex);
 
    return result;
 }
 
+static VkResult
+wsi_display_get_refresh_cycle_duration(struct wsi_swapchain *drv_chain,
+                                       VkRefreshCycleDurationGOOGLE *duration)
+{
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;
+   VkIcdSurfaceDisplay          *surface = chain->surface;
+   wsi_display_mode             *display_mode = wsi_display_mode_from_handle(surface->displayMode);
+   double                       refresh = wsi_display_mode_refresh(display_mode);
+
+   duration->refreshDuration = (uint64_t) (floor (1.0/refresh * 1e9 + 0.5));
+   return VK_SUCCESS;
+}
+
 static VkResult
 wsi_display_surface_create_swapchain(VkIcdSurfaceBase                   *icd_surface,
                                      VkDevice                           device,
@@ -1426,10 +1526,13 @@ wsi_display_surface_create_swapchain(VkIcdSurfaceBase                   *icd_sur
    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.get_refresh_cycle_duration = wsi_display_get_refresh_cycle_duration;
+   chain->base.get_current_time = wsi_get_current_monotonic;
    chain->base.present_mode = create_info->presentMode;
    chain->base.image_count = num_images;
 
    chain->wsi = wsi;
+   chain->allocator = allocator;
 
    chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
 
@@ -2130,6 +2233,7 @@ wsi_get_swapchain_counter(VkDevice                      device,
    struct wsi_display_swapchain *swapchain = (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
    struct wsi_display_connector *connector = wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
    int ret;
+   uint64_t nsec;
 
    if (wsi->master_fd < 0)
       return VK_ERROR_INITIALIZATION_FAILED;
@@ -2139,9 +2243,13 @@ wsi_get_swapchain_counter(VkDevice                      device,
       return VK_SUCCESS;
    }
 
-   ret = drmCrtcGetSequence(wsi->master_fd, connector->crtc_id, value, NULL);
+   ret = drmCrtcGetSequence(wsi->master_fd, connector->crtc_id, value, &nsec);
    if (ret)
       *value = 0;
+   else {
+      connector->last_frame = *value;
+      connector->last_nsec = nsec;
+   }
 
    return VK_SUCCESS;
 }
@@ -2150,19 +2258,44 @@ static void wsi_display_vblank_handler(int fd, unsigned int frame,
                                        unsigned int sec, unsigned int usec, void *data)
 {
    struct wsi_display_fence     *fence = data;
-
-   wsi_display_debug("%9lu fence %lu received %d\n", pthread_self(), fence->sequence, frame);
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(fence->base.display);
+   uint64_t frame64 = widen_32_to_64(frame, connector->last_frame);
+   uint64_t nsec = (uint64_t) sec * 1000000000 + (uint64_t) usec * 1000;
+   struct wsi_display_image *image = fence->image;
+
+   /* Don't let time go backwards because this function has lower resolution than ktime */
+   if (nsec < connector->last_nsec)
+      nsec = connector->last_nsec;
+
+   wsi_display_debug("%9lu fence %lu received %lu nsec %lu\n", pthread_self(), fence->sequence, frame64, nsec);
+   connector->last_nsec = nsec;
+   connector->last_frame = frame64;
    fence->event_received = true;
    wsi_display_fence_check_free(fence);
+   if (image) {
+      image->flip_sequence = ++image->chain->flip_sequence;
+      image->state = wsi_image_queued;
+      (void) _wsi_display_queue_next(&image->chain->base);
+   }
 }
 
 static void wsi_display_sequence_handler(int fd, uint64_t frame,
                                          uint64_t ns, uint64_t user_data)
 {
    struct wsi_display_fence     *fence = (struct wsi_display_fence *) (uintptr_t) user_data;
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(fence->base.display);
+   struct wsi_display_image *image = fence->image;
 
    wsi_display_debug("%9lu fence %lu received %lu\n", pthread_self(), fence->sequence, frame);
+   connector->last_nsec = ns;
+   connector->last_frame = frame;
    fence->event_received = true;
    wsi_display_fence_check_free(fence);
+   if (image) {
+      image->flip_sequence = ++image->chain->flip_sequence;
+      image->state = wsi_image_queued;
+      (void) _wsi_display_queue_next(&image->chain->base);
+   }
 }
 
+/* VK_GOOGLE_display_timing */
diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h
index 0d902846238..6f9d7323085 100644
--- a/src/vulkan/wsi/wsi_common_private.h
+++ b/src/vulkan/wsi/wsi_common_private.h
@@ -25,6 +25,13 @@
 
 #include "wsi_common.h"
 
+struct wsi_timing {
+   bool complete;
+   bool consumed;
+   uint64_t target_msc;
+   VkPastPresentationTimingGOOGLE timing;
+};
+
 struct wsi_image {
    VkImage image;
    VkDeviceMemory memory;
@@ -39,8 +46,16 @@ struct wsi_image {
    uint32_t offset;
    uint32_t row_pitch;
    int fd;
+
+   VkQueryPool query_pool;
+
+   VkCommandBuffer timestamp_buffer;
+
+   struct wsi_timing *timing;
 };
 
+#define WSI_TIMING_HISTORY      16
+
 struct wsi_swapchain {
    const struct wsi_device *wsi;
 
@@ -52,6 +67,16 @@ struct wsi_swapchain {
 
    bool use_prime_blit;
 
+   uint32_t timing_insert;
+   uint32_t timing_count;
+
+   struct wsi_timing timing[WSI_TIMING_HISTORY];
+
+   uint64_t frame_msc;
+   uint64_t frame_ust;
+
+   float timestamp_period;
+
    /* Command pools, one per queue family */
    VkCommandPool *cmd_pools;
 
@@ -65,6 +90,10 @@ struct wsi_swapchain {
    VkResult (*queue_present)(struct wsi_swapchain *swap_chain,
                              uint32_t image_index,
                              const VkPresentRegionKHR *damage);
+   VkResult (*get_refresh_cycle_duration)(struct wsi_swapchain *swap_chain,
+                                          VkRefreshCycleDurationGOOGLE *pDisplayTimingProperties);
+
+   uint64_t (*get_current_time)(void);
 };
 
 VkResult
@@ -91,6 +120,12 @@ wsi_destroy_image(const struct wsi_swapchain *chain,
                   struct wsi_image *image);
 
 
+void
+wsi_mark_timing(struct wsi_swapchain *swapchain,
+                struct wsi_image *image,
+                uint64_t ust,
+                uint64_t msc);
+
 struct wsi_interface {
    VkResult (*get_support)(VkIcdSurfaceBase *surface,
                            struct wsi_device *wsi_device,
diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
index 714523678d4..e0d9135da53 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -641,6 +641,7 @@ struct x11_image {
    bool                                      busy;
    struct xshmfence *                        shm_fence;
    uint32_t                                  sync_fence;
+   uint32_t                                  serial;
 };
 
 struct x11_swapchain {
@@ -657,6 +658,8 @@ struct x11_swapchain {
    uint64_t                                     send_sbc;
    uint64_t                                     last_present_msc;
    uint32_t                                     stamp;
+   uint64_t                                     last_present_nsec;
+   uint64_t                                     refresh_period;
 
    bool                                         threaded;
    VkResult                                     status;
@@ -706,8 +709,36 @@ x11_handle_dri3_present_event(struct x11_swapchain *chain,
 
    case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: {
       xcb_present_complete_notify_event_t *complete = (void *) event;
-      if (complete->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+      if (complete->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
+         uint64_t       frames = complete->msc - chain->last_present_msc;
+         uint64_t       present_nsec = complete->ust * 1000;
+
+         /*
+          * Well, this is about as good as we can do -- measure the refresh
+          * instead of asking for the current mode and using that. Turns out,
+          * for eDP panels, this works better anyways as they used the builtin
+          * fixed mode for everything
+          */
+         if (0 < frames && frames < 10 && present_nsec > chain->last_present_nsec) {
+
+            uint64_t refresh_period = (present_nsec - chain->last_present_nsec + frames / 2) / frames;
+
+            if (chain->refresh_period)
+               refresh_period = (3 * chain->refresh_period + refresh_period) >> 2;
+
+            chain->refresh_period = refresh_period;
+         }
+
          chain->last_present_msc = complete->msc;
+         chain->last_present_nsec = present_nsec;
+         for (unsigned i = 0; i < chain->base.image_count; i++) {
+            if (chain->images[i].serial == complete->serial) {
+               wsi_mark_timing(&chain->base, &chain->images[i].base,
+                               present_nsec, complete->msc);
+               break;
+            }
+         }
+      }
       break;
    }
 
@@ -823,7 +854,7 @@ x11_acquire_next_image_from_queue(struct x11_swapchain *chain,
 
 static VkResult
 x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
-                   uint32_t target_msc)
+                   uint64_t target_msc)
 {
    struct x11_image *image = &chain->images[image_index];
 
@@ -840,11 +871,12 @@ x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
    xshmfence_reset(image->shm_fence);
 
    ++chain->send_sbc;
+   image->serial = (uint32_t) chain->send_sbc;
    xcb_void_cookie_t cookie =
       xcb_present_pixmap(chain->conn,
                          chain->window,
                          image->pixmap,
-                         (uint32_t) chain->send_sbc,
+                         image->serial,
                          0,                                    /* valid */
                          0,                                    /* update */
                          0,                                    /* x_off */
@@ -894,6 +926,26 @@ x11_queue_present(struct wsi_swapchain *anv_chain,
    }
 }
 
+static uint64_t
+x11_refresh_duration(struct x11_swapchain *chain)
+{
+   /* Pick 60Hz if we don't know what it actually is yet */
+   if (!chain->refresh_period)
+      return (uint64_t) (1e9 / 59.98 + 0.5);
+
+   return chain->refresh_period;
+}
+
+static VkResult
+x11_get_refresh(struct wsi_swapchain *wsi_chain,
+                VkRefreshCycleDurationGOOGLE *timings)
+{
+   struct x11_swapchain *chain = (struct x11_swapchain *)wsi_chain;
+
+   timings->refreshDuration = x11_refresh_duration(chain);
+   return VK_SUCCESS;
+}
+
 static void *
 x11_manage_fifo_queues(void *state)
 {
@@ -910,6 +962,7 @@ x11_manage_fifo_queues(void *state)
        * other than the currently presented one.
        */
       uint32_t image_index;
+      struct x11_image *image;
       result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
       if (result != VK_SUCCESS) {
          goto fail;
@@ -918,6 +971,13 @@ x11_manage_fifo_queues(void *state)
       }
 
       uint64_t target_msc = chain->last_present_msc + 1;
+
+      image = &chain->images[image_index];
+
+      struct wsi_timing *timing = image->base.timing;
+      if (timing && timing->target_msc != 0 && timing->target_msc > target_msc)
+         target_msc = timing->target_msc;
+
       result = x11_present_to_x11(chain, image_index, target_msc);
       if (result != VK_SUCCESS)
          goto fail;
@@ -1098,7 +1158,9 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
    chain->base.get_wsi_image = x11_get_wsi_image;
    chain->base.acquire_next_image = x11_acquire_next_image;
    chain->base.queue_present = x11_queue_present;
+   chain->base.get_current_time = wsi_get_current_time;
    chain->base.present_mode = pCreateInfo->presentMode;
+   chain->base.get_refresh_cycle_duration = x11_get_refresh;
    chain->base.image_count = num_images;
    chain->conn = conn;
    chain->window = window;
@@ -1106,6 +1168,7 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
    chain->extent = pCreateInfo->imageExtent;
    chain->send_sbc = 0;
    chain->last_present_msc = 0;
+   chain->last_present_nsec = 0;
    chain->threaded = false;
    chain->status = VK_SUCCESS;
 
-- 
2.15.1


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
@ 2018-02-12 15:27   ` Eric Engestrom
  2018-02-12 22:16     ` Keith Packard
  2018-02-12 16:18   ` [Mesa-dev] " Emil Velikov
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 24+ messages in thread
From: Eric Engestrom @ 2018-02-12 15:27 UTC (permalink / raw)
  To: Keith Packard; +Cc: mesa-dev, dri-devel

On Friday, 2018-02-09 20:45:10 -0800, Keith Packard wrote:
> This adds support for the KHR_display extension to the anv and radv
> Vulkan drivers. The drivers now attempt to open the master DRM node
> when the KHR_display extension is requested so that the common winsys
> code can perform the necessary operations.
> 
> Signed-off-by: Keith Packard <keithp@keithp.com>
> ---
>  configure.ac                           |    1 +
>  meson.build                            |    4 +-
>  src/amd/vulkan/Makefile.am             |    8 +
>  src/amd/vulkan/Makefile.sources        |    3 +
>  src/amd/vulkan/meson.build             |    7 +
>  src/amd/vulkan/radv_device.c           |   28 +-
>  src/amd/vulkan/radv_extensions.py      |    7 +-
>  src/amd/vulkan/radv_private.h          |    2 +
>  src/amd/vulkan/radv_wsi.c              |    3 +-
>  src/amd/vulkan/radv_wsi_display.c      |  143 ++++
>  src/intel/Makefile.sources             |    3 +
>  src/intel/Makefile.vulkan.am           |    7 +
>  src/intel/vulkan/anv_device.c          |   18 +-
>  src/intel/vulkan/anv_extensions.py     |    1 +
>  src/intel/vulkan/anv_extensions_gen.py |    5 +-
>  src/intel/vulkan/anv_wsi.c             |    3 +-
>  src/intel/vulkan/anv_wsi_display.c     |  129 +++
>  src/intel/vulkan/meson.build           |    7 +
>  src/vulkan/Makefile.am                 |    7 +
>  src/vulkan/Makefile.sources            |    4 +
>  src/vulkan/wsi/meson.build             |   10 +
>  src/vulkan/wsi/wsi_common.c            |   19 +-
>  src/vulkan/wsi/wsi_common.h            |    5 +-
>  src/vulkan/wsi/wsi_common_display.c    | 1368 ++++++++++++++++++++++++++++++++
>  src/vulkan/wsi/wsi_common_display.h    |   72 ++
>  src/vulkan/wsi/wsi_common_private.h    |   10 +
>  26 files changed, 1858 insertions(+), 16 deletions(-)
>  create mode 100644 src/amd/vulkan/radv_wsi_display.c
>  create mode 100644 src/intel/vulkan/anv_wsi_display.c
>  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 8ed606c7694..46318365603 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1849,6 +1849,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')

copy/paste error: s/drm/display/

>  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 b39e2f8ab96..aeb7f5e2917 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'
>    else
> @@ -257,6 +258,7 @@ if _platforms != ''
>    with_platform_wayland = _split.contains('wayland')
>    with_platform_drm = _split.contains('drm')
>    with_platform_surfaceless = _split.contains('surfaceless')
> +  with_platform_display = _split.contains('display')
>    egl_native_platform = _split[0]
>  endif
>  
> diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
> index 61025968942..061b8144b88 100644
> --- a/src/amd/vulkan/Makefile.am
> +++ b/src/amd/vulkan/Makefile.am
> @@ -76,6 +76,14 @@ VULKAN_LIB_DEPS = \
>  	$(DLOPEN_LIBS) \
>  	-lm
>  
> +if HAVE_PLATFORM_DISPLAY
> +AM_CPPFLAGS += \
> +	-DVK_USE_PLATFORM_DISPLAY_KHR
> +
> +VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> +
> +endif
> +
>  if HAVE_PLATFORM_X11
>  AM_CPPFLAGS += \
>  	$(XCB_DRI3_CFLAGS) \
> diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources
> index a510d88d965..618a6cdaed0 100644
> --- a/src/amd/vulkan/Makefile.sources
> +++ b/src/amd/vulkan/Makefile.sources
> @@ -78,6 +78,9 @@ VULKAN_WSI_WAYLAND_FILES := \
>  VULKAN_WSI_X11_FILES := \
>  	radv_wsi_x11.c
>  
> +VULKAN_WSI_DISPLAY_FILES := \
> +	radv_wsi_display.c
> +
>  VULKAN_GENERATED_FILES := \
>  	radv_entrypoints.c \
>  	radv_entrypoints.h \
> diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
> index 0a7b7c0bf3c..b7bb1075e7d 100644
> --- a/src/amd/vulkan/meson.build
> +++ b/src/amd/vulkan/meson.build
> @@ -112,6 +112,13 @@ if with_platform_wayland
>    libradv_files += files('radv_wsi_wayland.c')
>  endif
>  
> +if with_platform_display
> +  radv_flags += [
> +    '-DVK_USE_PLATFORM_DISPLAY_KHR',
> +  ]

Nit: this can be a simple
  radv_flags += '-DVK_USE_PLATFORM_DISPLAY_KHR'

> +  libradv_files += files('radv_wsi_display.c')
> +endif
> +
>  libvulkan_radeon = shared_library(
>    'vulkan_radeon',
>    [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
> diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
> index 09bb382eeb8..adf33eb35dc 100644
> --- a/src/amd/vulkan/radv_device.c
> +++ b/src/amd/vulkan/radv_device.c
> @@ -191,9 +191,26 @@ radv_physical_device_init(struct radv_physical_device *device,
>  	const char *path = drm_device->nodes[DRM_NODE_RENDER];
>  	VkResult result;
>  	drmVersionPtr version;
> -	int fd;
> -
> -	fd = open(path, O_RDWR | O_CLOEXEC);
> +	int fd = -1;
> +
> +        if (instance->khr_display_requested) {
> +                fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC);
> +                if (fd >= 0) {
> +                        uint32_t accel_working = 0;
> +                        struct drm_amdgpu_info request = {
> +                                .return_pointer = (uintptr_t)&accel_working,
> +                                .return_size = sizeof(accel_working),
> +                                .query = AMDGPU_INFO_ACCEL_WORKING
> +                        };
> +
> +                        if (drmCommandWrite(fd, DRM_AMDGPU_INFO, &request, sizeof (struct drm_amdgpu_info)) < 0 || !accel_working) {
> +                                close(fd);
> +                                fd = -1;
> +                        }
> +                }
> +        }
> +        if (fd < 0)
> +                fd = open(path, O_RDWR | O_CLOEXEC);

Nit: src/amd/vulkan/ uses tabs for indent, you used spaces.

>  	if (fd < 0)
>  		return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
>  
> @@ -209,6 +226,7 @@ radv_physical_device_init(struct radv_physical_device *device,
>  		close(fd);
>  		return VK_ERROR_INCOMPATIBLE_DRIVER;
>  	}
> +
>  	drmFreeVersion(version);
>  
>  	device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
> @@ -387,6 +405,7 @@ VkResult radv_CreateInstance(
>  {
>  	struct radv_instance *instance;
>  	VkResult result;
> +        bool khr_display_requested = false;
>  
>  	assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
>  
> @@ -411,6 +430,8 @@ VkResult radv_CreateInstance(
>  	        const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i];
>  		if (!radv_instance_extension_supported(ext_name))
>  			return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT);
> +                if (strcmp(ext_name, VK_KHR_DISPLAY_EXTENSION_NAME) == 0)
> +                        khr_display_requested = true;
>  	}
>  
>  	instance = vk_zalloc2(&default_alloc, pAllocator, sizeof(*instance), 8,
> @@ -427,6 +448,7 @@ VkResult radv_CreateInstance(
>  
>  	instance->apiVersion = client_version;
>  	instance->physicalDeviceCount = -1;
> +        instance->khr_display_requested = khr_display_requested;
>  
>  	result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
>  	if (result != VK_SUCCESS) {
> diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
> index d761895d3a0..24cab8cbb39 100644
> --- a/src/amd/vulkan/radv_extensions.py
> +++ b/src/amd/vulkan/radv_extensions.py
> @@ -81,6 +81,7 @@ EXTENSIONS = [
>      Extension('VK_KHR_wayland_surface',                   6, 'VK_USE_PLATFORM_WAYLAND_KHR'),
>      Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
>      Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
> +    Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
>      Extension('VK_KHX_multiview',                         1, '!ANDROID'),
>      Extension('VK_EXT_debug_report',                      9, True),
>      Extension('VK_EXT_discard_rectangles',                1, True),
> @@ -168,7 +169,7 @@ _TEMPLATE = Template(COPYRIGHT + """
>  #include "vk_util.h"
>  
>  /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
> +%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
>  #ifdef VK_USE_PLATFORM_${platform}_KHR
>  #   undef VK_USE_PLATFORM_${platform}_KHR
>  #   define VK_USE_PLATFORM_${platform}_KHR true
> @@ -187,7 +188,9 @@ _TEMPLATE = Template(COPYRIGHT + """
>  
>  #define RADV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
>                           VK_USE_PLATFORM_XCB_KHR || \\
> -                         VK_USE_PLATFORM_XLIB_KHR)
> +                         VK_USE_PLATFORM_XLIB_KHR || \\
> +                         VK_USE_PLATFORM_DISPLAY_KHR)
> +
>  
>  bool
>  radv_instance_extension_supported(const char *name)
> diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
> index be9e8f43964..1e3719bcc4f 100644
> --- a/src/amd/vulkan/radv_private.h
> +++ b/src/amd/vulkan/radv_private.h
> @@ -75,6 +75,7 @@ typedef uint32_t xcb_window_t;
>  #include "radv_entrypoints.h"
>  
>  #include "wsi_common.h"
> +#include "wsi_common_display.h"
>  
>  #define ATI_VENDOR_ID 0x1002
>  
> @@ -300,6 +301,7 @@ struct radv_instance {
>  	uint64_t perftest_flags;
>  
>  	struct vk_debug_report_instance             debug_report_callbacks;
> +        bool                                        khr_display_requested;
>  };
>  
>  VkResult radv_init_wsi(struct radv_physical_device *physical_device);
> diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
> index e016e837102..5ec872a63d0 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->local_fd);
>  }
>  
>  void
> diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
> new file mode 100644
> index 00000000000..b0a4db0344b
> --- /dev/null
> +++ b/src/amd/vulkan/radv_wsi_display.c
> @@ -0,0 +1,143 @@
> +/*
> + * 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 <stdbool.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include "radv_private.h"
> +#include "radv_cs.h"
> +#include "util/disk_cache.h"
> +#include "util/strtod.h"
> +#include "vk_util.h"
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +#include <amdgpu.h>
> +#include <amdgpu_drm.h>
> +#include "winsys/amdgpu/radv_amdgpu_winsys_public.h"
> +#include "ac_llvm_util.h"
> +#include "vk_format.h"
> +#include "sid.h"
> +#include "util/debug.h"
> +#include "wsi_common_display.h"
> +
> +#define MM_PER_PIXEL     (1.0/96.0 * 25.4)

unused

> +
> +VkResult
> +radv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice             physical_device,
> +                                           uint32_t                     *property_count,
> +                                           VkDisplayPropertiesKHR       *properties)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_properties(physical_device,
> +                                                             &pdevice->wsi_device,
> +                                                             property_count,
> +                                                             properties);
> +}
> +
> +VkResult
> +radv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice                physical_device,
> +                                                uint32_t                        *property_count,
> +                                                VkDisplayPlanePropertiesKHR     *properties)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_plane_properties(physical_device,
> +                                                                   &pdevice->wsi_device,
> +                                                                   property_count,
> +                                                                   properties);
> +}
> +
> +VkResult
> +radv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice               physical_device,
> +                                         uint32_t                       plane_index,
> +                                         uint32_t                       *display_count,
> +                                         VkDisplayKHR                   *displays)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_plane_supported_displays(physical_device,
> +                                                           &pdevice->wsi_device,
> +                                                           plane_index,
> +                                                           display_count,
> +                                                           displays);
> +}
> +
> +
> +VkResult
> +radv_GetDisplayModePropertiesKHR(VkPhysicalDevice               physical_device,
> +                                 VkDisplayKHR                   display,
> +                                 uint32_t                       *property_count,
> +                                 VkDisplayModePropertiesKHR     *properties)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_mode_properties(physical_device,
> +                                                  &pdevice->wsi_device,
> +                                                  display,
> +                                                  property_count,
> +                                                  properties);
> +}
> +
> +VkResult
> +radv_CreateDisplayModeKHR(VkPhysicalDevice                      physical_device,
> +                          VkDisplayKHR                          display,
> +                          const VkDisplayModeCreateInfoKHR      *create_info,
> +                          const VkAllocationCallbacks           *allocator,
> +                          VkDisplayModeKHR                      *mode)
> +{
> +   return VK_ERROR_INITIALIZATION_FAILED;
> +}
> +
> +
> +VkResult
> +radv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice                    physical_device,
> +                                    VkDisplayModeKHR                    mode_khr,
> +                                    uint32_t                            plane_index,
> +                                    VkDisplayPlaneCapabilitiesKHR       *capabilities)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_get_display_plane_capabilities(physical_device,
> +                                             &pdevice->wsi_device,
> +                                             mode_khr,
> +                                             plane_index,
> +                                             capabilities);
> +}
> +
> +VkResult
> +radv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instance,
> +                                  const VkDisplaySurfaceCreateInfoKHR   *create_info,
> +                                  const VkAllocationCallbacks           *allocator,
> +                                  VkSurfaceKHR                          *surface)
> +{
> +   RADV_FROM_HANDLE(radv_instance, instance, _instance);
> +   const VkAllocationCallbacks *alloc;
> +
> +   if (allocator)
> +     alloc = allocator;
> +   else
> +     alloc = &instance->alloc;
> +
> +   return wsi_create_display_surface(_instance, alloc, create_info, surface);
> +}
> diff --git a/src/intel/Makefile.sources b/src/intel/Makefile.sources
> index 9595bf42582..6c142729d94 100644
> --- a/src/intel/Makefile.sources
> +++ b/src/intel/Makefile.sources
> @@ -240,6 +240,9 @@ VULKAN_WSI_WAYLAND_FILES := \
>  VULKAN_WSI_X11_FILES := \
>  	vulkan/anv_wsi_x11.c
>  
> +VULKAN_WSI_DISPLAY_FILES := \
> +	vulkan/anv_wsi_display.c
> +
>  VULKAN_GEM_FILES := \
>  	vulkan/anv_gem.c
>  
> diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
> index 23fa877e77d..7c428a799d7 100644
> --- a/src/intel/Makefile.vulkan.am
> +++ b/src/intel/Makefile.vulkan.am
> @@ -187,6 +187,13 @@ VULKAN_SOURCES += $(VULKAN_WSI_WAYLAND_FILES)
>  VULKAN_LIB_DEPS += $(WAYLAND_CLIENT_LIBS)
>  endif
>  
> +if HAVE_PLATFORM_DISPLAY
> +VULKAN_CPPFLAGS += \
> +	-DVK_USE_PLATFORM_DISPLAY_KHR
> +
> +VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> +endif
> +
>  noinst_LTLIBRARIES += vulkan/libvulkan_common.la
>  vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
>  vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS)
> diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
> index 86c1bdc1d51..9614907fda3 100644
> --- a/src/intel/vulkan/anv_device.c
> +++ b/src/intel/vulkan/anv_device.c
> @@ -277,14 +277,25 @@ anv_physical_device_init_uuids(struct anv_physical_device *device)
>  static VkResult
>  anv_physical_device_init(struct anv_physical_device *device,
>                           struct anv_instance *instance,
> -                         const char *path)
> +                         const char *primary_path,
> +                         const char *render_path)
>  {
>     VkResult result;
> -   int fd;
> +   int fd = -1;
> +   const char *path;
>  
>     brw_process_intel_debug_variable();
>  
> -   fd = open(path, O_RDWR | O_CLOEXEC);
> +   if (instance->enabled_extensions.KHR_display) {
> +      path = primary_path;
> +      fd = open(path, O_RDWR | O_CLOEXEC);
> +   }
> +
> +   if (fd < 0) {
> +      path = render_path;
> +      fd = open(path, O_RDWR | O_CLOEXEC);
> +   }
> +
>     if (fd < 0)
>        return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
>  
> @@ -652,6 +663,7 @@ anv_enumerate_devices(struct anv_instance *instance)
>  
>           result = anv_physical_device_init(&instance->physicalDevice,
>                          instance,
> +                        devices[i]->nodes[DRM_NODE_PRIMARY],
>                          devices[i]->nodes[DRM_NODE_RENDER]);
>           if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
>              break;
> diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
> index 581921e62a1..978a219e2b2 100644
> --- a/src/intel/vulkan/anv_extensions.py
> +++ b/src/intel/vulkan/anv_extensions.py
> @@ -83,6 +83,7 @@ EXTENSIONS = [
>      Extension('VK_KHR_wayland_surface',                   6, 'VK_USE_PLATFORM_WAYLAND_KHR'),
>      Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
>      Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
> +    Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
>      Extension('VK_KHX_multiview',                         1, True),
>      Extension('VK_EXT_debug_report',                      8, True),
>      Extension('VK_EXT_external_memory_dma_buf',           1, True),
> diff --git a/src/intel/vulkan/anv_extensions_gen.py b/src/intel/vulkan/anv_extensions_gen.py
> index 33827ecd015..84d07f9767a 100644
> --- a/src/intel/vulkan/anv_extensions_gen.py
> +++ b/src/intel/vulkan/anv_extensions_gen.py
> @@ -113,7 +113,7 @@ _TEMPLATE_C = Template(COPYRIGHT + """
>  #include "vk_util.h"
>  
>  /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
> +%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
>  #ifdef VK_USE_PLATFORM_${platform}_KHR
>  #   undef VK_USE_PLATFORM_${platform}_KHR
>  #   define VK_USE_PLATFORM_${platform}_KHR true
> @@ -132,7 +132,8 @@ _TEMPLATE_C = Template(COPYRIGHT + """
>  
>  #define ANV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
>                           VK_USE_PLATFORM_XCB_KHR || \\
> -                         VK_USE_PLATFORM_XLIB_KHR)
> +                         VK_USE_PLATFORM_XLIB_KHR || \\
> +                         VK_USE_PLATFORM_DISPLAY_KHR)
>  
>  const VkExtensionProperties anv_instance_extensions[ANV_INSTANCE_EXTENSION_COUNT] = {
>  %for ext in instance_extensions:
> diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
> index 6082c3dd093..f86d83589ea 100644
> --- a/src/intel/vulkan/anv_wsi.c
> +++ b/src/intel/vulkan/anv_wsi.c
> @@ -39,7 +39,8 @@ anv_init_wsi(struct anv_physical_device *physical_device)
>     return 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->local_fd);
>  }
>  
>  void
> diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
> new file mode 100644
> index 00000000000..9b00d7f02e4
> --- /dev/null
> +++ b/src/intel/vulkan/anv_wsi_display.c
> @@ -0,0 +1,129 @@
> +/*
> + * 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 "anv_private.h"
> +#include "wsi_common.h"
> +#include "vk_format_info.h"
> +#include "vk_util.h"
> +#include "wsi_common_display.h"
> +
> +#define MM_PER_PIXEL     (1.0/96.0 * 25.4)

unused

> +
> +VkResult
> +anv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice             physical_device,
> +                                           uint32_t                     *property_count,
> +                                           VkDisplayPropertiesKHR       *properties)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_properties(physical_device,
> +                                                             &pdevice->wsi_device,
> +                                                             property_count,
> +                                                             properties);
> +}
> +
> +VkResult
> +anv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice                physical_device,
> +                                                uint32_t                        *property_count,
> +                                                VkDisplayPlanePropertiesKHR     *properties)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_plane_properties(physical_device,
> +                                                                   &pdevice->wsi_device,
> +                                                                   property_count,
> +                                                                   properties);
> +}
> +
> +VkResult
> +anv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice               physical_device,
> +                                         uint32_t                       plane_index,
> +                                         uint32_t                       *display_count,
> +                                         VkDisplayKHR                   *displays)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_plane_supported_displays(physical_device,
> +                                                           &pdevice->wsi_device,
> +                                                           plane_index,
> +                                                           display_count,
> +                                                           displays);
> +}
> +
> +
> +VkResult
> +anv_GetDisplayModePropertiesKHR(VkPhysicalDevice               physical_device,
> +                                 VkDisplayKHR                   display,
> +                                 uint32_t                       *property_count,
> +                                 VkDisplayModePropertiesKHR     *properties)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_mode_properties(physical_device,
> +                                                  &pdevice->wsi_device,
> +                                                  display,
> +                                                  property_count,
> +                                                  properties);
> +}
> +
> +VkResult
> +anv_CreateDisplayModeKHR(VkPhysicalDevice                      physical_device,
> +                          VkDisplayKHR                          display,
> +                          const VkDisplayModeCreateInfoKHR      *create_info,
> +                          const VkAllocationCallbacks           *allocator,
> +                          VkDisplayModeKHR                      *mode)
> +{
> +   return VK_ERROR_INITIALIZATION_FAILED;
> +}
> +
> +
> +VkResult
> +anv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice                    physical_device,
> +                                    VkDisplayModeKHR                    mode_khr,
> +                                    uint32_t                            plane_index,
> +                                    VkDisplayPlaneCapabilitiesKHR       *capabilities)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_get_display_plane_capabilities(physical_device,
> +                                             &pdevice->wsi_device,
> +                                             mode_khr,
> +                                             plane_index,
> +                                             capabilities);
> +}
> +
> +VkResult
> +anv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instance,
> +                                  const VkDisplaySurfaceCreateInfoKHR   *create_info,
> +                                  const VkAllocationCallbacks           *allocator,
> +                                  VkSurfaceKHR                          *surface)
> +{
> +   ANV_FROM_HANDLE(anv_instance, instance, _instance);
> +   const VkAllocationCallbacks *alloc;
> +
> +   if (allocator)
> +     alloc = allocator;
> +   else
> +     alloc = &instance->alloc;
> +
> +   return wsi_create_display_surface(_instance, alloc, create_info, surface);
> +}
> diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
> index 69ec26e19b6..2e2ab8f7ecd 100644
> --- a/src/intel/vulkan/meson.build
> +++ b/src/intel/vulkan/meson.build
> @@ -171,6 +171,13 @@ if with_platform_wayland
>    libanv_files += files('anv_wsi_wayland.c')
>  endif
>  
> +if with_platform_display
> +  anv_flags += [
> +    '-DVK_USE_PLATFORM_DISPLAY_KHR',
> +  ]
> +  libanv_files += files('anv_wsi_display.c')
> +endif
> +
>  libanv_common = static_library(
>    'anv_common',
>    [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h],
> diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
> index 037436c1cd7..c33ac5758f7 100644
> --- a/src/vulkan/Makefile.am
> +++ b/src/vulkan/Makefile.am
> @@ -57,6 +57,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
> +
>  BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES)
>  CLEANFILES = $(BUILT_SOURCES)
>  
> diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources
> index a0a24ce7de8..3642c7662c4 100644
> --- a/src/vulkan/Makefile.sources
> +++ b/src/vulkan/Makefile.sources
> @@ -17,6 +17,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 bd0fd3cc53e..743631a6113 100644
> --- a/src/vulkan/wsi/meson.build
> +++ b/src/vulkan/wsi/meson.build
> @@ -57,6 +57,16 @@ if with_platform_wayland
>    ]
>  endif
>  
> +if with_platform_display
> +  vulkan_wsi_args += [
> +    '-DVK_USE_PLATFORM_DISPLAY_KHR',
> +  ]

Ditto:
  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 90ed07b7857..c0a285e5814 100644
> --- a/src/vulkan/wsi/wsi_common.c
> +++ b/src/vulkan/wsi/wsi_common.c
> @@ -29,7 +29,8 @@ VkResult
>  wsi_device_init(struct wsi_device *wsi,
>                  VkPhysicalDevice pdevice,
>                  WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
> -                const VkAllocationCallbacks *alloc)
> +                const VkAllocationCallbacks *alloc,
> +                int device_fd)
>  {
>     VkResult result;
>  
> @@ -89,6 +90,19 @@ wsi_device_init(struct wsi_device *wsi,
>     }
>  #endif
>  
> +#ifdef VK_USE_PLATFORM_DISPLAY_KHR
> +   result = wsi_display_init_wsi(wsi, alloc, pdevice, device_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;
>  }
>  
> @@ -96,6 +110,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 3e0d3be1c24..1cb6aaebca0 100644
> --- a/src/vulkan/wsi/wsi_common.h
> +++ b/src/vulkan/wsi/wsi_common.h
> @@ -50,7 +50,7 @@ struct wsi_memory_allocate_info {
>  
>  struct wsi_interface;
>  
> -#define VK_ICD_WSI_PLATFORM_MAX 5
> +#define VK_ICD_WSI_PLATFORM_MAX 6
>  
>  struct wsi_device {
>     VkPhysicalDeviceMemoryProperties memory_props;
> @@ -93,7 +93,8 @@ VkResult
>  wsi_device_init(struct wsi_device *wsi,
>                  VkPhysicalDevice pdevice,
>                  WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
> -                const VkAllocationCallbacks *alloc);
> +                const VkAllocationCallbacks *alloc,
> +                int device_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..2732b1dd721
> --- /dev/null
> +++ b/src/vulkan/wsi/wsi_common_display.c
> @@ -0,0 +1,1368 @@
> +/*
> + * 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 "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

`#if DEBUG` maybe?

> +#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
> +#define wsi_display_debug_code(...)     __VA_ARGS__

that 2nd one is unused

> +#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;
> +   wsi_display_mode             *current_mode;
> +   drmModeModeInfo              current_drm_mode;
> +} wsi_display_connector;
> +
> +struct wsi_display {
> +   struct wsi_interface         base;
> +
> +   const VkAllocationCallbacks  *alloc;
> +   VkPhysicalDevice             physical_device;
> +
> +   int                          master_fd;
> +   int                          render_fd;
> +
> +   pthread_mutex_t              wait_mutex;
> +   pthread_cond_t               wait_cond;
> +   pthread_t                    wait_thread;
> +
> +   struct list_head             connectors;
> +
> +   struct list_head             display_modes;
> +};
> +
> +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;
> +   uint64_t                     flip_sequence;
> +};
> +
> +struct wsi_display_swapchain {
> +   struct wsi_swapchain         base;
> +   struct wsi_display           *wsi;
> +   VkIcdSurfaceDisplay          *surface;
> +   uint64_t                     flip_sequence;
> +   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));
> +}
> +
> +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)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
> +      if (display_mode->connector == connector &&
> +          wsi_display_mode_matches_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           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list)
> +      if (display_mode->connector == connector)
> +         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];
> +   struct wsi_display_mode      *display_mode;
> +
> +   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_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
> +   if (!display_mode)
> +      return VK_ERROR_OUT_OF_HOST_MEMORY;
> +
> +   display_mode->connector = connector;
> +   display_mode->valid = true;
> +   display_mode->preferred = (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, &wsi->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_alloc(wsi->alloc, sizeof (struct wsi_display_connector), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
> +   memset(connector, '\0', sizeof (*connector));
> +   connector->id = connector_id;
> +   connector->wsi = wsi;
> +   connector->active = false;
> +   /* XXX use EDID name */
> +   connector->name = "monitor";
> +   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->master_fd < 0)
> +      return NULL;
> +
> +   drm_connector = drmModeGetConnector(wsi->master_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 void
> +wsi_display_fill_in_display_properties(struct wsi_device                *wsi_device,
> +                                       struct wsi_display_connector     *connector,
> +                                       VkDisplayPropertiesKHR           *properties)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode, *preferred_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 */
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
> +      if (display_mode->valid && display_mode->connector == connector && display_mode->preferred) {
> +         preferred_mode = display_mode;
> +         break;
> +      }
> +   }
> +
> +   if (preferred_mode) {
> +      properties->physicalResolution.width = preferred_mode->hdisplay;
> +      properties->physicalResolution.height = preferred_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];
> +   struct wsi_display_connector *connector;
> +   int                          c;
> +   uint32_t                     connected;
> +   uint32_t                     property_count_requested = *property_count;
> +   drmModeResPtr                mode_res;
> +
> +   if (wsi->master_fd < 0)
> +      return VK_ERROR_INITIALIZATION_FAILED;
> +
> +   mode_res = drmModeGetResources(wsi->master_fd);
> +
> +   if (!mode_res)
> +      return VK_ERROR_INITIALIZATION_FAILED;
> +
> +   connected = 0;
> +
> +   /* Get current information */
> +   for (c = 0; c < mode_res->count_connectors; c++) {
> +      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)
> +         connected++;
> +   }
> +
> +   /* Fill in property information if requested */
> +   if (properties != NULL) {
> +      connected = 0;
> +
> +      for (c = 0; c < mode_res->count_connectors; c++) {
> +         connector  = wsi_display_find_connector(wsi_device, mode_res->connectors[c]);
> +
> +         if (connector && connector->connected) {
> +            if (connected < property_count_requested) {
> +               wsi_display_fill_in_display_properties(wsi_device,
> +                                                      connector,
> +                                                      &properties[connected]);
> +            }
> +            connected++;
> +         }
> +      }
> +   }
> +
> +   drmModeFreeResources(mode_res);
> +
> +   *property_count = connected;
> +
> +   if (connected > property_count_requested && properties != NULL)
> +      return VK_INCOMPLETE;
> +
> +   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;
> +   uint32_t                     property_count_requested = *property_count;
> +   int                          c;
> +
> +   if (!properties)
> +      property_count_requested = 0;
> +
> +   c = 0;
> +   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
> +      if (c < property_count_requested) {
> +         if (connector && connector->active) {
> +            properties[c].currentDisplay = wsi_display_connector_to_handle(connector);
> +            properties[c].currentStackIndex = c;
> +         } else {
> +            properties[c].currentDisplay = NULL;
> +            properties[c].currentStackIndex = 0;
> +         }
> +      }
> +      c++;
> +   }
> +
> +   *property_count = c;
> +
> +   if (c > property_count_requested && properties != NULL)
> +      return VK_INCOMPLETE;
> +
> +   return VK_SUCCESS;
> +}
> +
> +/*
> + * 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;
> +   int                          c;
> +
> +
> +   if (displays == NULL) {
> +      *display_count = 1;
> +      return VK_SUCCESS;
> +   }
> +
> +   if (*display_count < 1)
> +      return VK_INCOMPLETE;
> +
> +   c = 0;
> +   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
> +      if (c == plane_index) {
> +         *displays = wsi_display_connector_to_handle(connector);
> +         *display_count = 1;
> +         return VK_SUCCESS;
> +      }
> +      c++;
> +   }
> +
> +   *displays = 0;
> +   *display_count = 0;
> +
> +   return VK_SUCCESS;
> +}
> +
> +/*
> + * 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           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
> +   int                          i;
> +   struct wsi_display_mode      *display_mode;
> +   uint32_t                     property_count_requested = *property_count;
> +
> +   i = 0;
> +
> +   if (properties == NULL)
> +      property_count_requested = 0;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
> +      if (display_mode->valid && display_mode->connector == connector) {
> +         if (i < property_count_requested) {
> +            properties[i].displayMode = wsi_display_mode_to_handle(display_mode);
> +            properties[i].parameters.visibleRegion.width = display_mode->hdisplay;
> +            properties[i].parameters.visibleRegion.height = display_mode->vdisplay;
> +            properties[i].parameters.refreshRate = (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
> +         }
> +         i++;
> +      }
> +   }
> +
> +   *property_count = i;
> +
> +   if (i > property_count_requested && properties != NULL)
> +      return VK_INCOMPLETE;
> +
> +   return VK_SUCCESS;
> +
> +}
> +
> +/*
> + * 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_alloc(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_INHERIT_BIT_KHR |
> +                                    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 VkFormat available_surface_formats[] = {
> +   VK_FORMAT_B8G8R8A8_SRGB,
> +   VK_FORMAT_B8G8R8A8_UNORM,
> +};
> +
> +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];
> +         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];
> +         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)
> +{
> +   if (present_modes == NULL) {
> +      *present_mode_count = ARRAY_SIZE(available_present_modes);
> +      return VK_SUCCESS;
> +   }
> +
> +   *present_mode_count = MIN2(*present_mode_count, ARRAY_SIZE(available_present_modes));
> +   typed_memcpy(present_modes, available_present_modes, *present_mode_count);
> +
> +   if (*present_mode_count < ARRAY_SIZE(available_present_modes))
> +      return VK_INCOMPLETE;
> +   return VK_SUCCESS;
> +}
> +
> +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                     image_handle;
> +
> +   if (chain->base.use_prime_blit)
> +      result = wsi_create_prime_image(&chain->base, create_info, &image->base);
> +   else
> +      result = wsi_create_native_image(&chain->base, create_info, &image->base);
> +   if (result != VK_SUCCESS)
> +      return result;
> +
> +   ret = drmPrimeFDToHandle(wsi->master_fd, image->base.fd, &image_handle);
> +
> +   close(image->base.fd);
> +   image->base.fd = -1;
> +
> +   if (ret < 0)
> +      goto fail_handle;
> +
> +   image->chain = chain;
> +   image->state = wsi_image_idle;
> +   image->fb_id = 0;
> +
> +   /* XXX extract depth and bpp from image somehow */
> +   ret = drmModeAddFB(wsi->master_fd, create_info->imageExtent.width, create_info->imageExtent.height,
> +                      24, 32, image->base.row_pitch, image_handle, &image->fb_id);
> +
> +   if (ret)
> +      goto fail_fb;
> +
> +   return VK_SUCCESS;
> +
> +fail_fb:
> +   /* fall through */
> +
> +fail_handle:
> +   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;
> +
> +   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;
> +
> +   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);
> +   (void) _wsi_display_queue_next(&(image->chain->base));
> +}
> +
> +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->master_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->master_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;
> +}
> +
> +/* 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;
> +
> +   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);
> +   return result;
> +}
> +
> +/*
> + * 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->master_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->master_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->master_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->master_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->master_fd);
> +   if (!mode_res) {
> +      result = VK_ERROR_INITIALIZATION_FAILED;
> +      goto bail;
> +   }
> +
> +   drm_connector = drmModeGetConnectorCurrent(wsi->master_fd, connector->id);
> +   if (!drm_connector) {
> +      result = VK_ERROR_INITIALIZATION_FAILED;
> +      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->master_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->master_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->master_fd, connector->crtc_id, image->fb_id, 0, 0,
> +                                 &connector->id, 1, &connector->current_drm_mode);
> +
> +            if (ret == 0) {
> +               image->state = wsi_image_displaying;
> +               wsi_display_idle_old_displaying(image);
> +               connector->active = true;
> +               return VK_SUCCESS;
> +            }
> +            break;
> +         case EACCES:
> +            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;
> +
> +   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);
> +
> +   pthread_mutex_unlock(&wsi->wait_mutex);
> +
> +   return result;
> +}
> +
> +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_alloc(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->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)
> +         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,
> +                     VkPhysicalDevice physical_device,
> +                     int device_fd)
> +{
> +   struct wsi_display *wsi;
> +   VkResult result;
> +
> +   wsi = vk_alloc(alloc, sizeof(*wsi), 8,
> +                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
> +   if (!wsi) {
> +      result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      goto fail;
> +   }
> +   memset(wsi, '\0', sizeof (*wsi));
> +
> +   wsi->master_fd = -1;
> +   if (drmGetNodeTypeFromFd(device_fd) == DRM_NODE_PRIMARY)
> +      wsi->master_fd = device_fd;
> +   wsi->render_fd = device_fd;
> +
> +   pthread_mutex_init(&wsi->wait_mutex, NULL);
> +   wsi->physical_device = physical_device;
> +   wsi->alloc = alloc;
> +
> +   LIST_INITHEAD(&wsi->display_modes);
> +   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) {

if (!wsi) return;
and carry on without the extra indent

I don't know enough for this to be an actual review though, but the rest
of this file looks reasonable to me :)

> +
> +      struct wsi_display_connector *connector, *connector_storage;
> +      LIST_FOR_EACH_ENTRY_SAFE(connector, connector_storage, &wsi->connectors, list) {
> +         vk_free(wsi->alloc, connector);
> +      }
> +
> +      struct wsi_display_mode *mode, *mode_storage;
> +      LIST_FOR_EACH_ENTRY_SAFE(mode, mode_storage, &wsi->display_modes, list) {
> +         vk_free(wsi->alloc, mode);
> +      }
> +
> +      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 503b2a015dc..d38d2efa116 100644
> --- a/src/vulkan/wsi/wsi_common_private.h
> +++ b/src/vulkan/wsi/wsi_common_private.h
> @@ -135,6 +135,16 @@ 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,
> +                     VkPhysicalDevice physical_device,
> +                     int device_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.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Mesa-dev] [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
  2018-02-12 15:27   ` Eric Engestrom
@ 2018-02-12 16:18   ` Emil Velikov
  2018-02-12 23:12     ` Keith Packard
  2018-02-14  1:10   ` Jason Ekstrand
  2018-03-29  6:59   ` Mao, David
  3 siblings, 1 reply; 24+ messages in thread
From: Emil Velikov @ 2018-02-12 16:18 UTC (permalink / raw)
  To: Keith Packard; +Cc: ML mesa-dev, ML dri-devel

Hi Keith,

A few top level comments:

 - using card/primary node and (missing) authentication
Current code opens the primary node when VK_KHR_display is available.
Thus running a platform=drm,x11,wayland build will fail, as the client
is not authenticated with the X/WL server.

 - reuse "drm" as a shorthand for the "display"
We've been using drm for egl/gbm, va/drm, etc, one less platform plus
no equivalent in either of egl/va/...

 - remove conditional compilation based on library version/features.
Eg. checks like the following should be avoided.
#if DRM_EVENT_CONTEXT_VERSION

 - use drmModeAddFB2 (or the withModifiers version even) over drmModeAddFB
Might help with the XXX just above it ;-)

 - the spec says we're at VK_KHR_display rev 21, while the code advertises rev1
    Extension('VK_KHR_display',                           1,
'VK_USE_PLATFORM_DISPLAY_KHR'),

 - there are plenty of unnecessary of headers #include(d)

 - we could simplify the ifdef spaghetti by making
wsi_*_{init,finish}_wsi empty stubs
Definitely something that can be done, independently of your work.

HTH
Emil
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-12 15:27   ` Eric Engestrom
@ 2018-02-12 22:16     ` Keith Packard
  0 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-12 22:16 UTC (permalink / raw)
  To: Eric Engestrom; +Cc: mesa-dev, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 1940 bytes --]

Eric Engestrom <eric.engestrom@imgtec.com> writes:

> copy/paste error: s/drm/display/

That's actually intentional -- any system which supports 'drm' can
support the display backend as it's based on that. Maybe it should use a
different test? (note that I haven't been using the autotools backend
recently, so it may not be great at this point. At least my current tree
builds?)

>> +if with_platform_display
>> +  radv_flags += [
>> +    '-DVK_USE_PLATFORM_DISPLAY_KHR',
>> +  ]
>
> Nit: this can be a simple
>   radv_flags += '-DVK_USE_PLATFORM_DISPLAY_KHR'
>
>> +if with_platform_display
>> +  vulkan_wsi_args += [
>> +    '-DVK_USE_PLATFORM_DISPLAY_KHR',
>> +  ]
>
> Ditto:
>   vulkan_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_KHR'


Oh, good point -- I'd split out the RANDR and DISPLAY bits but didn't
simplify the meson stuff.

> Nit: src/amd/vulkan/ uses tabs for indent, you used spaces.

Thanks; I'll reconfigure my environment so that it uses tabs in that
directory, and re-indent the changes.

>> +#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
>
> unused

Good catch; those got left in both anv and radv directories after some
refactoring.

>> +#if 0
>
> `#if DEBUG` maybe?

Could do; I could also just strip out the printf debugging, but when
you're doing timing-sensitive stuff at that level, printf debugging is
pretty useful.

>> +#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
>> +#define wsi_display_debug_code(...)     __VA_ARGS__
>
> that 2nd one is unused

It gets used in a later patch.

>> +   if (wsi) {
>
> if (!wsi) return;
> and carry on without the extra indent

Yeah, would probably look cleaner.

> I don't know enough for this to be an actual review though, but the rest
> of this file looks reasonable to me :)

Thanks for reviewing the basic formatting and structure though; I
totally missed the tabs/spaces issue.

-- 
-keith

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Mesa-dev] [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-12 16:18   ` [Mesa-dev] " Emil Velikov
@ 2018-02-12 23:12     ` Keith Packard
  0 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-12 23:12 UTC (permalink / raw)
  To: Emil Velikov; +Cc: ML mesa-dev, ML dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 3382 bytes --]

Emil Velikov <emil.l.velikov@gmail.com> writes:

> A few top level comments:

Thanks much for looking over this code. I realize it's a large amount of
change and hence more work to review.

>  - using card/primary node and (missing) authentication
> Current code opens the primary node when VK_KHR_display is available.
> Thus running a platform=drm,x11,wayland build will fail, as the client
> is not authenticated with the X/WL server.

this is really mostly there to make it easy to test the KHR_display
backend without needing any further code. I added this only recently for
this purpose. I'm not sure how we should be selecting for opening the
primary device; perhaps another extension that adds a block in the pNext
chain to look for?

I don't know if you saw the first version of this series, but I had
specified a new extension which provided the device FD from the
application, letting you pass in whatever you could open (including a
leased FD from X or a primary opened from the application). That seems
like it could use some design ideas so we can make this do what we
want.

One option would be to remove the primary device code from the drivers
once the leasing code is added so that the only way to use KHR_display
is by leasing resources from the window system?

The radv driver goes a bit further and checks with the kernel to see if
rendering will work. For anv, the ioctls necessary for drawing are
permitting on a non-authenticated node. Both drivers work fine for
direct and X as-is, but I'm not very happy with having a random app with
the primary device open as that seems like a mistake waiting to happen.

>  - reuse "drm" as a shorthand for the "display"
> We've been using drm for egl/gbm, va/drm, etc, one less platform plus
> no equivalent in either of egl/va/...

Yeah, anything that supports drm can support display. I'll review the
build process and try to simplify it further.

>  - remove conditional compilation based on library version/features.
> Eg. checks like the following should be avoided.
> #if DRM_EVENT_CONTEXT_VERSION

Should I just have the build depend on a recent enough version of the library?

>  - use drmModeAddFB2 (or the withModifiers version even) over drmModeAddFB
> Might help with the XXX just above it ;-)

It won't help with that -- I just need more information from the
driver. However, that information could come back as a format instead of
depth/bpp, which would mean using drmModeAddFB2 instead of
drmModeAddFB. Thanks for reminding me of this XXX.  wsi_create_*_image
gets a VkSwapchainCreateInfoKHR which has a VkFormat inside. Is that
sufficient to compute a fourcc format for AddFB2? I think I could
probably guess depth/bpp from it and be right most of the time?

>  - the spec says we're at VK_KHR_display rev 21, while the code advertises rev1
>     Extension('VK_KHR_display',                           1,
> 'VK_USE_PLATFORM_DISPLAY_KHR'),

Thanks. The version of the spec I've got (1.0.49) says it's already at
rev 23!

>  - there are plenty of unnecessary of headers #include(d)

As is often the case. I can go trim things down.

>  - we could simplify the ifdef spaghetti by making
> wsi_*_{init,finish}_wsi empty stubs
> Definitely something that can be done, independently of your work.

That would be lovely.

-- 
-keith

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 3/7] vulkan: Add EXT_acquire_xlib_display
  2018-02-10  4:45 ` [PATCH 3/7] vulkan: Add EXT_acquire_xlib_display Keith Packard
@ 2018-02-13  0:16   ` Dylan Baker
  0 siblings, 0 replies; 24+ messages in thread
From: Dylan Baker @ 2018-02-13  0:16 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 37076 bytes --]

Quoting Keith Packard (2018-02-09 20:45:12)
> This extension adds the ability to borrow an X RandR output for
> temporary use directly by a Vulkan application. For DRM, we use the
> Linux resource leasing mechanism.
> 
> Signed-off-by: Keith Packard <keithp@keithp.com>
> ---
>  configure.ac                           |  25 ++
>  meson.build                            |  17 ++
>  meson_options.txt                      |   7 +
>  src/amd/vulkan/Makefile.am             |   7 +
>  src/amd/vulkan/meson.build             |   7 +
>  src/amd/vulkan/radv_extensions.py      |  11 +-
>  src/amd/vulkan/radv_wsi_display.c      |  30 +++
>  src/intel/Makefile.vulkan.am           |   7 +
>  src/intel/vulkan/anv_extensions.py     |   1 +
>  src/intel/vulkan/anv_extensions_gen.py |  10 +-
>  src/intel/vulkan/anv_wsi_display.c     |  30 +++
>  src/intel/vulkan/meson.build           |   7 +
>  src/vulkan/Makefile.am                 |   5 +
>  src/vulkan/wsi/meson.build             |   7 +
>  src/vulkan/wsi/wsi_common_display.c    | 472 +++++++++++++++++++++++++++++++++
>  src/vulkan/wsi/wsi_common_display.h    |  17 ++
>  16 files changed, 650 insertions(+), 10 deletions(-)
> 
> diff --git a/configure.ac b/configure.ac
> index 46318365603..9effd15e8c5 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1547,6 +1547,7 @@ AM_CONDITIONAL(HAVE_APPLEDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = x
>  AM_CONDITIONAL(HAVE_LMSENSORS, test "x$enable_lmsensors" = xyes )
>  AM_CONDITIONAL(HAVE_GALLIUM_EXTRA_HUD, test "x$enable_gallium_extra_hud" = xyes )
>  AM_CONDITIONAL(HAVE_WINDOWSDRI, test "x$enable_dri" = xyes -a "x$dri_platform" = xwindows )
> +AM_CONDITIONAL(HAVE_XLEASE, test "x$have_xlease" = xyes )
>  
>  AC_ARG_ENABLE([shared-glapi],
>      [AS_HELP_STRING([--enable-shared-glapi],
> @@ -1846,6 +1847,11 @@ if test x"$enable_dri3" = xyes; then
>      PKG_CHECK_MODULES([XCB_DRI3], [$dri3_modules])
>  fi
>  
> +if test x"$have_xlease" = xyes; then
> +    randr_modules="x11-xcb xcb-randr"
> +    PKG_CHECK_MODULES([XCB_RANDR], [$randr_modules])
> +fi
> +
>  AM_CONDITIONAL(HAVE_PLATFORM_X11, echo "$platforms" | grep -q 'x11')
>  AM_CONDITIONAL(HAVE_PLATFORM_WAYLAND, echo "$platforms" | grep -q 'wayland')
>  AM_CONDITIONAL(HAVE_PLATFORM_DRM, echo "$platforms" | grep -q 'drm')
> @@ -1853,6 +1859,25 @@ AM_CONDITIONAL(HAVE_PLATFORM_DISPLAY, echo "$platforms" | grep -q 'drm')
>  AM_CONDITIONAL(HAVE_PLATFORM_SURFACELESS, echo "$platforms" | grep -q 'surfaceless')
>  AM_CONDITIONAL(HAVE_PLATFORM_ANDROID, echo "$platforms" | grep -q 'android')
>  
> +AC_ARG_ENABLE(xlib-lease,
> +    [AS_HELP_STRING([--enable-xlib-lease]
> +                    [enable VK_acquire_xlib_display using X leases])],
> +    [enable_xlib_lease=$enableval], [enable_xlib_lease=auto])
> +case "x$enable_xlib_lease" in
> +xyes)
> +    ;;
> +xno)
> +    ;;
> +*)
> +    if echo "$platforms" | grep -q 'x11' && echo "$platforms" | grep -q 'drm';
> +        enable_xlib_lease=yes
> +    else
> +        enable_xlib_lease=no
> +    fi
> +esac
> +
> +AM_CONDITIONAL(HAVE_XLIB_LEASE, test "x$enable_xlib_lease" = xyes)
> +
>  dnl
>  dnl More DRI setup
>  dnl
> diff --git a/meson.build b/meson.build
> index aeb7f5e2917..595b0f66cd7 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -262,6 +262,19 @@ if _platforms != ''
>    egl_native_platform = _split[0]
>  endif
>  
> +with_xlib_lease = get_option('xlib-lease')
> +if with_xlib_lease == 'auto'
> +  if with_platform_x11 and with_platform_display
> +    with_xlib_lease = true
> +  else
> +    with_xlib_lease = false
> +  endif

You could simplify this to
with_xlib_lease = with_platform_x11 and with_platform_display

> +elif with_xlib_lease == 'true'

We should probably error here if we don't have the correct platforms.

> +  with_xlib_lease = true
> +else
> +  with_xlib_lease = false
> +endif
> +
>  with_glx = get_option('glx')
>  if with_glx == 'auto'
>    if with_dri
> @@ -1151,6 +1164,7 @@ dep_xcb_present = []
>  dep_xcb_sync = []
>  dep_xcb_xfixes = []
>  dep_xshmfence = []
> +dep_xcb_xrandr = []
>  if with_platform_x11
>    if with_glx == 'xlib' or with_glx == 'gallium-xlib'
>      dep_x11 = dependency('x11')
> @@ -1190,6 +1204,9 @@ if with_platform_x11
>    if with_egl
>      dep_xcb_xfixes = dependency('xcb-xfixes')
>    endif
> +  if with_xlib_lease
> +    dep_xcb_xrandr = dependency('xcb-randr', version : '>= 1.12')
> +  endif
>  endif
>  
>  if get_option('gallium-extra-hud')
> diff --git a/meson_options.txt b/meson_options.txt
> index 7fafe2deaac..d38c9aa6149 100644
> --- a/meson_options.txt
> +++ b/meson_options.txt
> @@ -286,3 +286,10 @@ option(
>    value : '',
>    description : 'Comma delimited list of tools to build. choices : freedreno,glsl,intel,nir,nouveau or all'
>  )
> +option(
> +  'xlib-lease',
> +  type : 'combo',
> +  value : 'auto',
> +  choices : ['auto', 'true', 'false'],
> +  description : 'Enable VK_EXT_acquire_xlib_display.'
> +)
> diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
> index 061b8144b88..94ece06e99e 100644
> --- a/src/amd/vulkan/Makefile.am
> +++ b/src/amd/vulkan/Makefile.am
> @@ -81,7 +81,14 @@ AM_CPPFLAGS += \
>         -DVK_USE_PLATFORM_DISPLAY_KHR
>  
>  VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> +endif
> +
> +if HAVE_XLIB_LEASE
> +AM_CPPFLAGS += \
> +       -DVK_USE_PLATFORM_XLIB_XRANDR_EXT \
> +       $(XCB_RANDR_CFLAGS)
>  
> +VULKAN_LIB_DEPS += $(XCB_RANDR_LIBS)
>  endif
>  
>  if HAVE_PLATFORM_X11
> diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
> index b7bb1075e7d..0b92a1763a1 100644
> --- a/src/amd/vulkan/meson.build
> +++ b/src/amd/vulkan/meson.build
> @@ -119,6 +119,13 @@ if with_platform_display
>    libradv_files += files('radv_wsi_display.c')
>  endif
>  
> +if with_xlib_lease
> +  radv_deps += dep_xcb_xrandr

Since this is a stub when not building, we don't we just put his in the deps
unconditionally

> +  radv_flags += [
> +    '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
> +  ]

no [] needed here.

> +endif
> +
>  libvulkan_radeon = shared_library(
>    'vulkan_radeon',
>    [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
> diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
> index f784681ff57..2d804afed35 100644
> --- a/src/amd/vulkan/radv_extensions.py
> +++ b/src/amd/vulkan/radv_extensions.py
> @@ -83,6 +83,7 @@ EXTENSIONS = [
>      Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
>      Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
>      Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
> +    Extension('VK_EXT_acquire_xlib_display',              1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
>      Extension('VK_KHX_multiview',                         1, '!ANDROID'),
>      Extension('VK_EXT_debug_report',                      9, True),
>      Extension('VK_EXT_discard_rectangles',                1, True),
> @@ -170,12 +171,12 @@ _TEMPLATE = Template(COPYRIGHT + """
>  #include "vk_util.h"
>  
>  /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
> -#ifdef VK_USE_PLATFORM_${platform}_KHR
> -#   undef VK_USE_PLATFORM_${platform}_KHR
> -#   define VK_USE_PLATFORM_${platform}_KHR true
> +%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']:
> +#ifdef VK_USE_PLATFORM_${platform}
> +#   undef VK_USE_PLATFORM_${platform}
> +#   define VK_USE_PLATFORM_${platform} true
>  #else
> -#   define VK_USE_PLATFORM_${platform}_KHR false
> +#   define VK_USE_PLATFORM_${platform} false
>  #endif
>  %endfor
>  
> diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
> index 0051f5ac865..9b76ce623b0 100644
> --- a/src/amd/vulkan/radv_wsi_display.c
> +++ b/src/amd/vulkan/radv_wsi_display.c
> @@ -152,3 +152,33 @@ radv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
>                                &pdevice->wsi_device,
>                                display);
>  }
> +
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +VkResult
> +radv_AcquireXlibDisplayEXT(VkPhysicalDevice     physical_device,
> +                           Display              *dpy,
> +                           VkDisplayKHR         display)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_acquire_xlib_display(physical_device,
> +                                   &pdevice->wsi_device,
> +                                   dpy,
> +                                   display);
> +}
> +
> +VkResult
> +radv_GetRandROutputDisplayEXT(VkPhysicalDevice  physical_device,
> +                              Display           *dpy,
> +                              RROutput          output,
> +                              VkDisplayKHR      *display)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_get_randr_output_display(physical_device,
> +                                       &pdevice->wsi_device,
> +                                       dpy,
> +                                       output,
> +                                       display);
> +}
> +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
> diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
> index 7c428a799d7..0f0d3815097 100644
> --- a/src/intel/Makefile.vulkan.am
> +++ b/src/intel/Makefile.vulkan.am
> @@ -194,6 +194,13 @@ VULKAN_CPPFLAGS += \
>  VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
>  endif
>  
> +if HAVE_XLIB_LEASE
> +VULKAN_CPPFLAGS += \
> +       -DVK_USE_PLATFORM_XLIB_XRANDR_EXT \
> +       $(XCB_RANDR_CFLAGS)
> +VULKAN_LIB_DEPS += $(XCB_RANDR_LIBS)
> +endif
> +
>  noinst_LTLIBRARIES += vulkan/libvulkan_common.la
>  vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
>  vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS)
> diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
> index 633e378e605..32a240acdcb 100644
> --- a/src/intel/vulkan/anv_extensions.py
> +++ b/src/intel/vulkan/anv_extensions.py
> @@ -85,6 +85,7 @@ EXTENSIONS = [
>      Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
>      Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
>      Extension('VK_EXT_direct_mode_display',               1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
> +    Extension('VK_EXT_acquire_xlib_display',              1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'),
>      Extension('VK_KHX_multiview',                         1, True),
>      Extension('VK_EXT_debug_report',                      8, True),
>      Extension('VK_EXT_external_memory_dma_buf',           1, True),
> diff --git a/src/intel/vulkan/anv_extensions_gen.py b/src/intel/vulkan/anv_extensions_gen.py
> index 84d07f9767a..025907aff72 100644
> --- a/src/intel/vulkan/anv_extensions_gen.py
> +++ b/src/intel/vulkan/anv_extensions_gen.py
> @@ -113,12 +113,12 @@ _TEMPLATE_C = Template(COPYRIGHT + """
>  #include "vk_util.h"
>  
>  /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
> -#ifdef VK_USE_PLATFORM_${platform}_KHR
> -#   undef VK_USE_PLATFORM_${platform}_KHR
> -#   define VK_USE_PLATFORM_${platform}_KHR true
> +%for platform in ['ANDROID_KHR', 'WAYLAND_KHR', 'XCB_KHR', 'XLIB_KHR', 'DISPLAY_KHR', 'XLIB_XRANDR_EXT']:
> +#ifdef VK_USE_PLATFORM_${platform}
> +#   undef VK_USE_PLATFORM_${platform}
> +#   define VK_USE_PLATFORM_${platform} true
>  #else
> -#   define VK_USE_PLATFORM_${platform}_KHR false
> +#   define VK_USE_PLATFORM_${platform} false
>  #endif
>  %endfor
>  
> diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
> index e6f67f7dec9..e87aed49f7d 100644
> --- a/src/intel/vulkan/anv_wsi_display.c
> +++ b/src/intel/vulkan/anv_wsi_display.c
> @@ -138,3 +138,33 @@ anv_ReleaseDisplayEXT(VkPhysicalDevice physical_device,
>                                &pdevice->wsi_device,
>                                display);
>  }
> +
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +VkResult
> +anv_AcquireXlibDisplayEXT(VkPhysicalDevice     physical_device,
> +                           Display              *dpy,
> +                           VkDisplayKHR         display)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_acquire_xlib_display(physical_device,
> +                                   &pdevice->wsi_device,
> +                                   dpy,
> +                                   display);
> +}
> +
> +VkResult
> +anv_GetRandROutputDisplayEXT(VkPhysicalDevice  physical_device,
> +                              Display           *dpy,
> +                              RROutput          output,
> +                              VkDisplayKHR      *display)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_get_randr_output_display(physical_device,
> +                                       &pdevice->wsi_device,
> +                                       dpy,
> +                                       output,
> +                                       display);
> +}
> +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
> diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
> index 2e2ab8f7ecd..d3ab5ac8a64 100644
> --- a/src/intel/vulkan/meson.build
> +++ b/src/intel/vulkan/meson.build
> @@ -178,6 +178,13 @@ if with_platform_display
>    libanv_files += files('anv_wsi_display.c')
>  endif
>  
> +if with_xlib_lease
> +  anv_deps += dep_xcb_xrandr
> +  anv_flags += [
> +    '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
> +  ]
> +endif

Same here

> +
>  libanv_common = static_library(
>    'anv_common',
>    [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h],
> diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
> index c33ac5758f7..e96ef68972c 100644
> --- a/src/vulkan/Makefile.am
> +++ b/src/vulkan/Makefile.am
> @@ -64,6 +64,11 @@ AM_CPPFLAGS += \
>  VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
>  endif
>  
> +if HAVE_XLIB_LEASE
> +AM_CPPFLAGS += \
> +       -DVK_USE_PLATFORM_XLIB_XRANDR_EXT
> +endif
> +
>  BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES)
>  CLEANFILES = $(BUILT_SOURCES)
>  
> diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build
> index 743631a6113..5e3d43a2748 100644
> --- a/src/vulkan/wsi/meson.build
> +++ b/src/vulkan/wsi/meson.build
> @@ -67,6 +67,13 @@ if with_platform_display
>    )
>  endif
>  
> +if with_xlib_lease
> +  vulkan_wsi_deps += dep_xcb_xrandr
> +  vulkan_wsi_args += [
> +    '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT',
> +  ]
> +endif

ditto

> +
>  libvulkan_wsi = static_library(
>    'vulkan_wsi',
>    files_vulkan_wsi,
> diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
> index 5c123e6465e..29d64b21aff 100644
> --- a/src/vulkan/wsi/wsi_common_display.c
> +++ b/src/vulkan/wsi/wsi_common_display.c
> @@ -32,6 +32,10 @@
>  #include <math.h>
>  #include <xf86drm.h>
>  #include <xf86drmMode.h>
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +#include <xcb/randr.h>
> +#include <X11/Xlib-xcb.h>
> +#endif
>  #include "util/hash_table.h"
>  #include "util/list.h"
>  
> @@ -73,6 +77,9 @@ typedef struct wsi_display_connector {
>     bool                         active;
>     wsi_display_mode             *current_mode;
>     drmModeModeInfo              current_drm_mode;
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +   xcb_randr_output_t           output;
> +#endif
>  } wsi_display_connector;
>  
>  struct wsi_display {
> @@ -1381,5 +1388,470 @@ wsi_release_display(VkPhysicalDevice            physical_device,
>        close(wsi->master_fd);
>        wsi->master_fd = -1;
>     }
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +   wsi_display_connector_from_handle(display)->output = None;
> +#endif
> +
>     return VK_SUCCESS;
>  }
> +
> +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +
> +static struct wsi_display_connector *
> +wsi_display_find_output(struct wsi_device               *wsi_device,
> +                        RROutput                        output)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_connector *connector;
> +
> +   connector = NULL;
> +   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
> +      if (connector->output == output)
> +         return connector;
> +   }
> +
> +   return NULL;
> +}
> +
> +/*
> + * Given a RandR output, find the associated kernel connector_id by
> + * looking at the CONNECTOR_ID property provided by the X server
> + */
> +
> +static uint32_t
> +wsi_display_output_to_connector_id(xcb_connection_t     *connection,
> +                                   xcb_atom_t           *connector_id_atom_p,
> +                                   RROutput             output)
> +{
> +   uint32_t                     connector_id = 0;
> +   xcb_atom_t                   connector_id_atom = *connector_id_atom_p;
> +
> +   if (connector_id_atom == 0) {
> +   /* Go dig out the CONNECTOR_ID property */
> +      xcb_intern_atom_cookie_t     ia_c = xcb_intern_atom(connection,
> +                                                          true,
> +                                                          12,
> +                                                          "CONNECTOR_ID");
> +      xcb_intern_atom_reply_t      *ia_r = xcb_intern_atom_reply(connection,
> +                                                                 ia_c,
> +                                                                 NULL);
> +      if (ia_r) {
> +         *connector_id_atom_p = connector_id_atom = ia_r->atom;
> +         free(ia_r);
> +      }
> +   }
> +
> +   /* If there's an CONNECTOR_ID atom in the server, then there may be a CONNECTOR_ID property. Otherwise,
> +    * there will not be and we don't even need to bother.
> +    */
> +   if (connector_id_atom) {
> +
> +      xcb_randr_query_version_cookie_t          qv_c = xcb_randr_query_version(connection, 1, 6);
> +      xcb_randr_get_output_property_cookie_t    gop_c = xcb_randr_get_output_property(connection,
> +                                                                                      output,
> +                                                                                      connector_id_atom,
> +                                                                                      0,
> +                                                                                      0,
> +                                                                                      0xffffffffUL,
> +                                                                                      0,
> +                                                                                      0);
> +      xcb_randr_query_version_reply_t           *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL);
> +      free(qv_r);
> +      xcb_randr_get_output_property_reply_t     *gop_r = xcb_randr_get_output_property_reply(connection,
> +                                                                                             gop_c,
> +                                                                                             NULL);
> +      if (gop_r) {
> +         if (gop_r->num_items == 1 && gop_r->format == 32)
> +            memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
> +         free(gop_r);
> +      }
> +   }
> +   return connector_id;
> +}
> +
> +static bool
> +wsi_display_check_randr_version(xcb_connection_t        *connection)
> +{
> +   xcb_randr_query_version_cookie_t     qv_c = xcb_randr_query_version(connection, 1, 6);
> +   xcb_randr_query_version_reply_t      *qv_r = xcb_randr_query_version_reply(connection, qv_c, NULL);
> +   bool                                 ret = false;
> +
> +   if (!qv_r)
> +      return false;
> +
> +   /* Check for version 1.6 or newer */
> +   ret = qv_r->major_version > 1 || (qv_r->major_version == 1 && qv_r->minor_version >= 6);
> +
> +   free(qv_r);
> +   return ret;
> +}
> +
> +/*
> + * Given a kernel connector id, find the associated RandR output using the
> + * CONNECTOR_ID property
> + */
> +
> +static xcb_randr_output_t
> +wsi_display_connector_id_to_output(xcb_connection_t     *connection,
> +                                   uint32_t             connector_id)
> +{
> +   if (!wsi_display_check_randr_version(connection))
> +      return 0;
> +
> +   const xcb_setup_t                    *setup = xcb_get_setup(connection);
> +
> +   xcb_atom_t                           connector_id_atom = 0;
> +   xcb_randr_output_t                   output = 0;
> +
> +   /* Search all of the screens for the provided output */
> +   xcb_screen_iterator_t iter;
> +   for (iter = xcb_setup_roots_iterator(setup); output == 0 && iter.rem; xcb_screen_next(&iter)) {
> +
> +      xcb_randr_get_screen_resources_cookie_t      gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root);
> +      xcb_randr_get_screen_resources_reply_t       *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
> +
> +      if (!gsr_r)
> +         return 0;
> +
> +      xcb_randr_output_t        *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
> +      int                       o;
> +
> +      for (o = 0; o < gsr_r->num_outputs; o++) {
> +         if (wsi_display_output_to_connector_id(connection, &connector_id_atom, ro[o]) == connector_id) {
> +            output = ro[o];
> +            break;
> +         }
> +      }
> +      free(gsr_r);
> +   }
> +   return output;
> +}
> +
> +/*
> + * Given a RandR output, find out which screen it's associated with
> + */
> +static xcb_window_t
> +wsi_display_output_to_root(xcb_connection_t   *connection,
> +                           xcb_randr_output_t output)
> +{
> +   if (!wsi_display_check_randr_version(connection))
> +      return 0;
> +
> +   const xcb_setup_t                    *setup = xcb_get_setup(connection);
> +   xcb_window_t                         root = 0;
> +
> +   /* Search all of the screens for the provided output */
> +   xcb_screen_iterator_t iter;
> +   for (iter = xcb_setup_roots_iterator(setup); root == 0 && iter.rem; xcb_screen_next(&iter)) {
> +      xcb_randr_get_screen_resources_cookie_t      gsr_c = xcb_randr_get_screen_resources(connection, iter.data->root);
> +      xcb_randr_get_screen_resources_reply_t       *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
> +
> +      if (!gsr_r)
> +         return 0;
> +
> +      xcb_randr_output_t        *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
> +      int                       o;
> +
> +      for (o = 0; o < gsr_r->num_outputs; o++) {
> +         if (ro[o] == output) {
> +            root = iter.data->root;
> +            break;
> +         }
> +      }
> +      free(gsr_r);
> +   }
> +   return root;
> +}
> +
> +static bool
> +wsi_display_mode_matches_x(struct wsi_display_mode      *wsi,
> +                           xcb_randr_mode_info_t        *xcb)
> +{
> +   return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
> +      wsi->hdisplay == xcb->width &&
> +      wsi->hsync_start == xcb->hsync_start &&
> +      wsi->hsync_end == xcb->hsync_end &&
> +      wsi->htotal == xcb->htotal &&
> +      wsi->hskew == xcb->hskew &&
> +      wsi->vdisplay == xcb->height &&
> +      wsi->vsync_start == xcb->vsync_start &&
> +      wsi->vsync_end == xcb->vsync_end &&
> +      wsi->vtotal == xcb->vtotal &&
> +      wsi->flags == xcb->mode_flags;
> +}
> +
> +static struct wsi_display_mode *
> +wsi_display_find_x_mode(struct wsi_device                 *wsi_device,
> +                        struct wsi_display_connector      *connector,
> +                        xcb_randr_mode_info_t             *mode)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
> +      if (display_mode->connector == connector &&
> +          wsi_display_mode_matches_x(display_mode, mode))
> +         return display_mode;
> +   }
> +   return NULL;
> +}
> +
> +static VkResult
> +wsi_display_register_x_mode(struct wsi_device                   *wsi_device,
> +                            struct wsi_display_connector        *connector,
> +                            xcb_randr_mode_info_t               *x_mode,
> +                            bool                                preferred)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode;
> +
> +   display_mode = wsi_display_find_x_mode(wsi_device, connector, x_mode);
> +
> +   if (display_mode) {
> +      display_mode->valid = true;
> +      return VK_SUCCESS;
> +   }
> +
> +   display_mode = vk_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
> +   if (!display_mode)
> +      return VK_ERROR_OUT_OF_HOST_MEMORY;
> +
> +   display_mode->connector = connector;
> +   display_mode->valid = true;
> +   display_mode->preferred = preferred;
> +   display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
> +   display_mode->hdisplay = x_mode->width;
> +   display_mode->hsync_start = x_mode->hsync_start;
> +   display_mode->hsync_end = x_mode->hsync_end;
> +   display_mode->htotal = x_mode->htotal;
> +   display_mode->hskew = x_mode->hskew;
> +   display_mode->vdisplay = x_mode->height;
> +   display_mode->vsync_start = x_mode->vsync_start;
> +   display_mode->vsync_end = x_mode->vsync_end;
> +   display_mode->vtotal = x_mode->vtotal;
> +   display_mode->vscan = 0;
> +   if (x_mode->mode_flags & XCB_RANDR_MODE_FLAG_DOUBLE_SCAN)
> +      display_mode->vscan = 1;
> +   display_mode->flags = x_mode->mode_flags;
> +
> +   LIST_ADDTAIL(&display_mode->list, &wsi->display_modes);
> +   return VK_SUCCESS;
> +}
> +
> +static struct wsi_display_connector *
> +wsi_display_get_output(struct wsi_device        *wsi_device,
> +                       xcb_connection_t         *connection,
> +                       RROutput                 output)
> +{
> +   struct wsi_display                           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_connector                 *connector;
> +   uint32_t                                     connector_id;
> +   xcb_window_t                                 root;
> +   xcb_randr_get_screen_resources_cookie_t      src;
> +   xcb_randr_get_screen_resources_reply_t       *srr;
> +   xcb_randr_get_output_info_cookie_t           oic;
> +   xcb_randr_get_output_info_reply_t            *oir;
> +   xcb_randr_mode_t                             *x_modes;
> +   int                                          m;
> +
> +   root = wsi_display_output_to_root(connection, output);
> +   if (!root)
> +      return NULL;
> +
> +   src = xcb_randr_get_screen_resources(connection, root);
> +   oic = xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
> +   srr = xcb_randr_get_screen_resources_reply(connection, src, NULL);
> +   oir = xcb_randr_get_output_info_reply(connection, oic, NULL);
> +
> +   /* See if we already have a connector for this output */
> +   connector = wsi_display_find_output(wsi_device, output);
> +
> +   if (!connector) {
> +      xcb_atom_t        connector_id_atom = 0;
> +
> +      /*
> +       * Go get the kernel connector ID for this X output
> +       */
> +      connector_id = wsi_display_output_to_connector_id(connection, &connector_id_atom, output);
> +
> +      /* Any X server with lease support will have this atom */
> +      if (!connector_id) {
> +         free(oir);
> +         free(srr);
> +         return NULL;
> +      }
> +
> +      if (!connector) {
> +         /* See if we already have a connector for this id */
> +         connector = wsi_display_find_connector(wsi_device, connector_id);
> +
> +         if (connector)
> +            connector->output = output;
> +      }
> +   }
> +
> +   if (!connector) {
> +      connector = wsi_display_alloc_connector(wsi, connector_id);
> +      if (!connector) {
> +         free(oir);
> +         free(srr);
> +         return NULL;
> +      }
> +      LIST_ADDTAIL(&connector->list, &wsi->connectors);
> +      connector->output = output;
> +   }
> +
> +   if (oir && srr) {
> +      /* Get X modes and add them */
> +
> +      connector->connected = oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
> +
> +      wsi_display_invalidate_connector_modes(wsi_device, connector);
> +
> +      x_modes = xcb_randr_get_output_info_modes(oir);
> +      for (m = 0; m < oir->num_modes; m++) {
> +         xcb_randr_mode_info_iterator_t i = xcb_randr_get_screen_resources_modes_iterator(srr);
> +         while (i.rem) {
> +            xcb_randr_mode_info_t *mi = i.data;
> +            if (mi->id == x_modes[m]) {
> +               VkResult result = wsi_display_register_x_mode(wsi_device, connector, mi, m < oir->num_preferred);
> +               if (result != VK_SUCCESS) {
> +                  free(oir);
> +                  free(srr);
> +                  return NULL;
> +               }
> +               break;
> +            }
> +            xcb_randr_mode_info_next(&i);
> +         }
> +      }
> +   }
> +
> +   free(oir);
> +   free(srr);
> +   return connector;
> +}
> +
> +static xcb_randr_crtc_t
> +wsi_display_find_crtc_for_output(xcb_connection_t       *connection,
> +                                 xcb_window_t           root,
> +                                 xcb_randr_output_t     output)
> +{
> +   xcb_randr_get_screen_resources_cookie_t      gsr_c = xcb_randr_get_screen_resources(connection, root);
> +   xcb_randr_get_screen_resources_reply_t       *gsr_r = xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
> +
> +   if (!gsr_r)
> +      return 0;
> +
> +   xcb_randr_crtc_t     *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
> +   xcb_randr_crtc_t     idle_crtc = 0;
> +   xcb_randr_crtc_t     active_crtc = 0;
> +
> +   /* Find either a crtc already connected to the desired output or idle */
> +   int c;
> +   for (c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
> +      xcb_randr_get_crtc_info_cookie_t gci_c = xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
> +      xcb_randr_get_crtc_info_reply_t *gci_r = xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
> +      if (gci_r) {
> +         if (gci_r->mode) {
> +            int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
> +            xcb_randr_output_t *outputs = xcb_randr_get_crtc_info_outputs(gci_r);
> +            for (int o = 0; o < num_outputs; o++)
> +               if (outputs[o] == output && num_outputs == 1) {
> +                  active_crtc = rc[c];
> +                  break;
> +               }
> +         } else if (idle_crtc == 0) {
> +            int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
> +            xcb_randr_output_t *possible = xcb_randr_get_crtc_info_possible(gci_r);
> +            for (int p = 0; p < num_possible; p++)
> +               if (possible[p] == output) {
> +                  idle_crtc = rc[c];
> +                  break;
> +               }
> +         }
> +         free(gci_r);
> +      }
> +   }
> +   free(gsr_r);
> +
> +   if (active_crtc)
> +      return active_crtc;
> +   return idle_crtc;
> +}
> +
> +VkResult
> +wsi_acquire_xlib_display(VkPhysicalDevice       physical_device,
> +                         struct wsi_device      *wsi_device,
> +                         Display                *dpy,
> +                         VkDisplayKHR           display)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   xcb_connection_t             *connection = XGetXCBConnection(dpy);
> +   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
> +   xcb_window_t                 root;
> +
> +   if (!connector->output) {
> +      connector->output = wsi_display_connector_id_to_output(connection, connector->id);
> +
> +      /* Check and see if we found the output */
> +      if (!connector->output)
> +         return VK_ERROR_OUT_OF_DATE_KHR;
> +   }
> +
> +   root = wsi_display_output_to_root(connection, connector->output);
> +   if (!root)
> +      return VK_ERROR_OUT_OF_DATE_KHR;
> +
> +   xcb_randr_crtc_t                     crtc = wsi_display_find_crtc_for_output(connection,
> +                                                                                root,
> +                                                                                connector->output);
> +
> +   if (!crtc)
> +      return VK_ERROR_OUT_OF_DATE_KHR;
> +
> +   xcb_randr_lease_t                    lease = xcb_generate_id(connection);
> +   xcb_randr_create_lease_cookie_t      cl_c = xcb_randr_create_lease(connection,
> +                                                                      root,
> +                                                                      lease,
> +                                                                      1,
> +                                                                      1,
> +                                                                      &crtc,
> +                                                                      &connector->output);
> +   xcb_randr_create_lease_reply_t       *cl_r = xcb_randr_create_lease_reply(connection, cl_c, NULL);
> +   if (!cl_r)
> +      return VK_ERROR_OUT_OF_DATE_KHR;
> +
> +   int fd = -1;
> +   if (cl_r->nfd > 0) {
> +      int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
> +
> +      fd = rcl_f[0];
> +   }
> +   free (cl_r);
> +   if (fd < 0)
> +      return VK_ERROR_OUT_OF_DATE_KHR;
> +
> +   wsi->master_fd = fd;
> +
> +   return VK_SUCCESS;
> +}
> +
> +VkResult
> +wsi_get_randr_output_display(VkPhysicalDevice   physical_device,
> +                             struct wsi_device  *wsi_device,
> +                             Display            *dpy,
> +                             RROutput           output,
> +                             VkDisplayKHR       *display)
> +{
> +   xcb_connection_t             *connection = XGetXCBConnection(dpy);
> +   struct wsi_display_connector *connector = wsi_display_get_output(wsi_device, connection, output);
> +
> +   if (connector)
> +      *display = wsi_display_connector_to_handle(connector);
> +   else
> +      *display = NULL;
> +   return VK_SUCCESS;
> +}
> +
> +#endif
> diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h
> index 5fbb6925e4a..1997c2a3c40 100644
> --- a/src/vulkan/wsi/wsi_common_display.h
> +++ b/src/vulkan/wsi/wsi_common_display.h
> @@ -74,4 +74,21 @@ wsi_release_display(VkPhysicalDevice            physical_device,
>                      struct wsi_device           *wsi_device,
>                      VkDisplayKHR                display);
>  
> +
> +#if VK_USE_PLATFORM_XLIB_XRANDR_EXT
> +VkResult
> +wsi_acquire_xlib_display(VkPhysicalDevice       physical_device,
> +                         struct wsi_device      *wsi_device,
> +                         Display                *dpy,
> +                         VkDisplayKHR           display);
> +
> +VkResult
> +wsi_get_randr_output_display(VkPhysicalDevice   physical_device,
> +                             struct wsi_device  *wsi_device,
> +                             Display            *dpy,
> +                             RROutput           output,
> +                             VkDisplayKHR       *display);
> +
> +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
> +
>  #endif
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

[-- Attachment #1.2: signature --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

-----BEGIN PGP SIGNATURE-----

iHUEABYKAB0WIQRxxLdWILx1cItL2yVMlfqrPrBz7AUCWoIuRwAKCRBMlfqrPrBz
7OZ0AQCpW8ne6OudEIcVgSW24rk9JmVqb2nGai0IJNj/eEZm2wD/aGYxrE0NI7po
vTokXm3wQQLoGuunP2794H14TmZQtwA=
=/9Bi
-----END PGP SIGNATURE-----

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension
  2018-02-10  4:45 ` [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension Keith Packard
@ 2018-02-13  0:20   ` Dylan Baker
  2018-02-13 10:49     ` [Mesa-dev] " Lionel Landwerlin
  0 siblings, 1 reply; 24+ messages in thread
From: Dylan Baker @ 2018-02-13  0:20 UTC (permalink / raw)
  To: mesa-dev; +Cc: Keith Packard, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 16324 bytes --]

Quoting Keith Packard (2018-02-09 20:45:15)
> This extension adds a single function to query the current GPU
> timestamp, just like glGetInteger64v(GL_TIMESTAMP, &timestamp). This
> function is needed to complete the implementation of
> GOOGLE_display_timing, which needs to be able to coorelate GPU and CPU
> timestamps.
> 
> Signed-off-by: Keith Packard <keithp@keithp.com>
> ---
>  include/vulkan/vulkan.h                         |  6 ++++++
>  src/Makefile.am                                 |  1 +
>  src/amd/vulkan/Makefile.am                      |  3 +++
>  src/amd/vulkan/meson.build                      |  8 ++++----
>  src/amd/vulkan/radv_device.c                    |  8 ++++++++
>  src/amd/vulkan/radv_extensions.py               |  1 +
>  src/intel/Makefile.vulkan.am                    |  7 +++++++
>  src/intel/vulkan/anv_extensions.py              |  1 +
>  src/intel/vulkan/anv_gem.c                      | 13 +++++++++++++
>  src/intel/vulkan/anv_private.h                  |  1 +
>  src/intel/vulkan/genX_query.c                   | 15 +++++++++++++++
>  src/intel/vulkan/meson.build                    | 12 ++++++------
>  src/vulkan/meson.build                          |  1 +
>  src/vulkan/registry/vk_mesa_query_timestamp.xml | 22 ++++++++++++++++++++++
>  14 files changed, 89 insertions(+), 10 deletions(-)
>  create mode 100644 src/vulkan/registry/vk_mesa_query_timestamp.xml
> 
> diff --git a/include/vulkan/vulkan.h b/include/vulkan/vulkan.h
> index d3e2e246cf3..5523eb7586f 100644
> --- a/include/vulkan/vulkan.h
> +++ b/include/vulkan/vulkan.h
> @@ -7025,6 +7025,12 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT(
>      VkMemoryHostPointerPropertiesEXT*           pMemoryHostPointerProperties);
>  #endif
>  
> +typedef VkResult (VKAPI_PTR *PFN_vkQueryCurrentTimestampMESA)(VkDevice device, uint64_t *timestamp);
> +
> +VKAPI_ATTR VkResult VKAPI_CALL vkQueryCurrentTimestampMESA(
> +    VkDevice                                    _device,
> +    uint64_t                                    *timestamp);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 014ffaf3e29..74ff305d7c6 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -68,6 +68,7 @@ endif
>  
>  EXTRA_DIST += vulkan/registry/vk.xml
>  EXTRA_DIST += vulkan/registry/vk_android_native_buffer.xml
> +EXTRA_DIST += vulkan/registry/vk_mesa_query_timestamp.xml
>  
>  if HAVE_AMD_DRIVERS
>  SUBDIRS += amd
> diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
> index 94ece06e99e..0626fa2b3b3 100644
> --- a/src/amd/vulkan/Makefile.am
> +++ b/src/amd/vulkan/Makefile.am
> @@ -129,12 +129,14 @@ libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES)
>  
>  vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
>  vk_android_native_buffer_xml = $(top_srcdir)/src/vulkan/registry/vk_android_native_buffer.xml
> +vk_mesa_query_timestamp_xml = $(top_srcdir)/src/vulkan/registry/vk_mesa_query_timestamps.xml
>  
>  radv_entrypoints.c: radv_entrypoints_gen.py radv_extensions.py $(vulkan_api_xml)
>         $(MKDIR_GEN)
>         $(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py \
>                 --xml $(vulkan_api_xml) \
>                 --xml $(vk_android_native_buffer_xml) \
> +               --xml $(vk_mesa_query_timestamp_xml) \
>                 --outdir $(builddir)
>  radv_entrypoints.h: radv_entrypoints.c
>  
> @@ -144,6 +146,7 @@ radv_extensions.c: radv_extensions.py \
>         $(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_extensions.py \
>                 --xml $(vulkan_api_xml) \
>                 --xml $(vk_android_native_buffer_xml) \
> +               --xml $(vk_mesa_query_timestamp_xml) \
>                 --out $@
>  
>  vk_format_table.c: vk_format_table.py \
> diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
> index 0b92a1763a1..34f578476c0 100644
> --- a/src/amd/vulkan/meson.build
> +++ b/src/amd/vulkan/meson.build
> @@ -20,10 +20,10 @@
>  
>  radv_entrypoints = custom_target(
>    'radv_entrypoints.[ch]',
> -  input : ['radv_entrypoints_gen.py', vk_api_xml],
> +  input : ['radv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml],

some of these lines look a little long, 
input : [
    'radv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml,
    vk_mesa_query_timestamp_xml,
],

>    output : ['radv_entrypoints.h', 'radv_entrypoints.c'],
>    command : [
> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--outdir',
> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@', '--outdir',
>      meson.current_build_dir()
>    ],
>    depend_files : files('radv_extensions.py'),
> @@ -31,10 +31,10 @@ radv_entrypoints = custom_target(
>  
>  radv_extensions_c = custom_target(
>    'radv_extensions.c',
> -  input : ['radv_extensions.py', vk_api_xml, vk_android_native_buffer_xml],
> +  input : ['radv_extensions.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml],
>    output : ['radv_extensions.c'],
>    command : [
> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--out', '@OUTPUT@',
> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@', '--out', '@OUTPUT@',
>    ],
>  )
>  
> diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
> index adf33eb35dc..6c13efba9e0 100644
> --- a/src/amd/vulkan/radv_device.c
> +++ b/src/amd/vulkan/radv_device.c
> @@ -4084,3 +4084,11 @@ radv_DebugReportMessageEXT(VkInstance _instance,
>         vk_debug_report(&instance->debug_report_callbacks, flags, objectType,
>                         object, location, messageCode, pLayerPrefix, pMessage);
>  }
> +
> +VkResult radv_QueryCurrentTimestampMESA(VkDevice _device, uint64_t *timestamp)
> +{
> +       RADV_FROM_HANDLE(radv_device, device, _device);
> +
> +       *timestamp = device->ws->query_value(device->ws, RADEON_TIMESTAMP);
> +       return VK_SUCCESS;
> +}
> diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
> index 775d1ed4be6..fed198df412 100644
> --- a/src/amd/vulkan/radv_extensions.py
> +++ b/src/amd/vulkan/radv_extensions.py
> @@ -95,6 +95,7 @@ EXTENSIONS = [
>      Extension('VK_AMD_draw_indirect_count',               1, True),
>      Extension('VK_AMD_rasterization_order',               1, 'device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2'),
>      Extension('VK_AMD_shader_info',                       1, True),
> +    Extension('VK_MESA_query_timestamp',                  1, True),
>  ]
>  
>  class VkVersion:
> diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
> index 0f0d3815097..d7890022abe 100644
> --- a/src/intel/Makefile.vulkan.am
> +++ b/src/intel/Makefile.vulkan.am
> @@ -24,36 +24,43 @@
>  # out and we'll fail at `make dist'
>  vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
>  vk_android_native_buffer_xml = $(top_srcdir)/src/vulkan/registry/vk_android_native_buffer.xml
> +vk_mesa_query_timestamp_xml = $(top_srcdir)/src/vulkan/registry/vk_mesa_query_timestamps.xml
>  
>  vulkan/anv_entrypoints.c: vulkan/anv_entrypoints_gen.py \
>                           vulkan/anv_extensions.py \
>                           $(vulkan_api_xml) \
> +                         $(vk_mesa_query_timestamp_xml) \
>                           $(vk_android_native_buffer_xml)
>         $(MKDIR_GEN)
>         $(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_entrypoints_gen.py \
>                 --xml $(vulkan_api_xml) \
>                 --xml $(vk_android_native_buffer_xml) \
> +               --xml $(vk_mesa_query_timestamp_xml) \
>                 --outdir $(builddir)/vulkan
>  vulkan/anv_entrypoints.h: vulkan/anv_entrypoints.c
>  
>  vulkan/anv_extensions.c: vulkan/anv_extensions_gen.py \
>                          vulkan/anv_extensions.py \
>                          $(vulkan_api_xml) \
> +                        $(vk_mesa_query_timestamp_xml) \
>                          $(vk_android_native_buffer_xml)
>         $(MKDIR_GEN)
>         $(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_extensions_gen.py \
>                 --xml $(vulkan_api_xml) \
>                 --xml $(vk_android_native_buffer_xml) \
> +               --xml $(vk_mesa_query_timestamp_xml) \
>                 --out-c $@
>  
>  vulkan/anv_extensions.h: vulkan/anv_extensions_gen.py \
>                          vulkan/anv_extensions.py \
>                          $(vulkan_api_xml) \
> +                        $(vk_mesa_query_timestamp_xml) \
>                          $(vk_android_native_buffer_xml)
>         $(MKDIR_GEN)
>         $(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_extensions_gen.py \
>                 --xml $(vulkan_api_xml) \
>                 --xml $(vk_android_native_buffer_xml) \
> +               --xml $(vk_mesa_query_timestamp_xml) \
>                 --out-h $@
>  
>  BUILT_SOURCES += $(VULKAN_GENERATED_FILES)
> diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
> index f44598b305a..dd4d5a1f970 100644
> --- a/src/intel/vulkan/anv_extensions.py
> +++ b/src/intel/vulkan/anv_extensions.py
> @@ -91,6 +91,7 @@ EXTENSIONS = [
>      Extension('VK_EXT_external_memory_dma_buf',           1, True),
>      Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
>      Extension('VK_EXT_display_control',                   1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
> +    Extension('VK_MESA_query_timestamp',                  1, True),
>  ]
>  
>  class VkVersion:
> diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c
> index 34c09891086..588b323d113 100644
> --- a/src/intel/vulkan/anv_gem.c
> +++ b/src/intel/vulkan/anv_gem.c
> @@ -418,6 +418,19 @@ anv_gem_fd_to_handle(struct anv_device *device, int fd)
>     return args.handle;
>  }
>  
> +int
> +anv_gem_reg_read(struct anv_device *device, uint32_t offset, uint64_t *result)
> +{
> +   struct drm_i915_reg_read args = {
> +      .offset = offset
> +   };
> +
> +   int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_REG_READ, &args);
> +
> +   *result = args.val;
> +   return ret;
> +}
> +
>  #ifndef SYNC_IOC_MAGIC
>  /* duplicated from linux/sync_file.h to avoid build-time dependency
>   * on new (v4.7) kernel headers.  Once distro's are mostly using
> diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
> index 1d3e5fcd921..337d8ca3f15 100644
> --- a/src/intel/vulkan/anv_private.h
> +++ b/src/intel/vulkan/anv_private.h
> @@ -932,6 +932,7 @@ bool anv_gem_supports_48b_addresses(int fd);
>  int anv_gem_gpu_get_reset_stats(struct anv_device *device,
>                                  uint32_t *active, uint32_t *pending);
>  int anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle);
> +int anv_gem_reg_read(struct anv_device *device, uint32_t offset, uint64_t *result);
>  uint32_t anv_gem_fd_to_handle(struct anv_device *device, int fd);
>  int anv_gem_set_caching(struct anv_device *device, uint32_t gem_handle, uint32_t caching);
>  int anv_gem_set_domain(struct anv_device *device, uint32_t gem_handle,
> diff --git a/src/intel/vulkan/genX_query.c b/src/intel/vulkan/genX_query.c
> index 4efcc57e475..d2de7e5f45e 100644
> --- a/src/intel/vulkan/genX_query.c
> +++ b/src/intel/vulkan/genX_query.c
> @@ -546,6 +546,21 @@ void genX(CmdWriteTimestamp)(
>     }
>  }
>  
> +VkResult genX(QueryCurrentTimestampMESA)(
> +   VkDevice                                     _device,
> +   uint64_t                                     *timestamp)
> +{
> +   ANV_FROM_HANDLE(anv_device, device, _device);
> +   int  ret;
> +
> +   /* XXX older kernels don't support this interface. */
> +   ret = anv_gem_reg_read(device, TIMESTAMP | 1, timestamp);
> +
> +   if (ret != 0)
> +      return VK_ERROR_DEVICE_LOST;
> +   return VK_SUCCESS;
> +}
> +
>  #if GEN_GEN > 7 || GEN_IS_HASWELL
>  
>  static uint32_t
> diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
> index d3ab5ac8a64..d4622ffdfdf 100644
> --- a/src/intel/vulkan/meson.build
> +++ b/src/intel/vulkan/meson.build
> @@ -20,11 +20,11 @@
>  
>  anv_entrypoints = custom_target(
>    'anv_entrypoints.[ch]',
> -  input : ['anv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml,
> +  input : ['anv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
>             'anv_extensions.py'],

Same with this, could you also fix my bad indentation here?

>    output : ['anv_entrypoints.h', 'anv_entrypoints.c'],
>    command : [
> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
>      '--outdir', meson.current_build_dir(),
>    ],
>    depend_files : files('anv_extensions.py'),
> @@ -32,22 +32,22 @@ anv_entrypoints = custom_target(
>  
>  anv_extensions_c = custom_target(
>    'anv_extensions.c',
> -  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml,
> +  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
>             'anv_extensions.py'],
>    output : 'anv_extensions.c',
>    command : [
> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
>      '--out-c', '@OUTPUT@',
>    ],
>  )
>  
>  anv_extensions_h = custom_target(
>    'anv_extensions.h',
> -  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml,
> +  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
>             'anv_extensions.py'],
>    output : 'anv_extensions.h',
>    command : [
> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
>      '--out-h', '@OUTPUT@',
>    ],
>  )
> diff --git a/src/vulkan/meson.build b/src/vulkan/meson.build
> index 3908005b8a0..6ab0966b7c5 100644
> --- a/src/vulkan/meson.build
> +++ b/src/vulkan/meson.build
> @@ -20,6 +20,7 @@
>  
>  vk_api_xml = files('registry/vk.xml')
>  vk_android_native_buffer_xml = files('registry/vk_android_native_buffer.xml')
> +vk_mesa_query_timestamp_xml = files('registry/vk_mesa_query_timestamp.xml')
>  
>  inc_vulkan_util = include_directories('util')
>  inc_vulkan_wsi = include_directories('wsi')
> diff --git a/src/vulkan/registry/vk_mesa_query_timestamp.xml b/src/vulkan/registry/vk_mesa_query_timestamp.xml
> new file mode 100644
> index 00000000000..7fd4d974872
> --- /dev/null
> +++ b/src/vulkan/registry/vk_mesa_query_timestamp.xml
> @@ -0,0 +1,22 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<registry>
> +    <commands>
> +        <command>
> +            <proto><type>VkResult</type> <name>vkQueryCurrentTimestampMESA</name></proto>
> +            <param><type>VkDevice</type> <name>device</name></param>
> +            <param><type>uint64_t</type>* <name>pTimestamp</name></param>
> +        </command>
> +    </commands>
> +    <extensions>
> +        <extension name="VK_MESA_query_timestamp" number="200"
> +                  type="device" author="MESA"
> +                  contact="Keith Packard @keithp"
> +                  supported="vulkan">
> +            <require>
> +                <enum value="1"                                         name="VK_MESA_QUERY_TIMESTAMP_SPEC_VERSION"/>
> +                <enum value="&quot;VK_MESA_query_timestamp&quot;"       name="VK_MESA_QUERY_TIMESTAMP_NAME"/>
> +                <command name="vkQueryCurrentTimestampMESA"/>
> +            </require>
> +        </extension>
> +    </extensions>
> +</registry>
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

[-- Attachment #1.2: signature --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

-----BEGIN PGP SIGNATURE-----

iHUEABYKAB0WIQRxxLdWILx1cItL2yVMlfqrPrBz7AUCWoIvWgAKCRBMlfqrPrBz
7OMSAQDWwgOywD0E+t5hGM5p6WJmQs4TUBNY5dIMbjuzuFQGeAD+Mg68z1brt4FH
ULuJSdjy8GJHjHxSr9yqo6nddbeehw8=
=cO/s
-----END PGP SIGNATURE-----

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [Mesa-dev] [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension
  2018-02-13  0:20   ` Dylan Baker
@ 2018-02-13 10:49     ` Lionel Landwerlin
  2018-02-13 21:11       ` Keith Packard
  0 siblings, 1 reply; 24+ messages in thread
From: Lionel Landwerlin @ 2018-02-13 10:49 UTC (permalink / raw)
  To: Dylan Baker, Keith Packard, mesa-dev; +Cc: dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 17160 bytes --]

On 13/02/18 00:20, Dylan Baker wrote:
> Quoting Keith Packard (2018-02-09 20:45:15)
>> This extension adds a single function to query the current GPU
>> timestamp, just like glGetInteger64v(GL_TIMESTAMP, &timestamp). This
>> function is needed to complete the implementation of
>> GOOGLE_display_timing, which needs to be able to coorelate GPU and CPU
>> timestamps.

I'm assuming the correlation is done outside the vulkan driver? With a 
clock_gettime() maybe?

If that's the case, I'm afraid this will be highly inaccurate.
The kernel might execute other tasks when the ioctl() happens and that 
might introduce (in my experience) a few milliseconds of delay.

I think if you want to do something like that, this has to be 
implemented in the kernel, making sure you disable interruptions while 
doing the correlation.

>>
>> Signed-off-by: Keith Packard <keithp@keithp.com>
>> ---
>>   include/vulkan/vulkan.h                         |  6 ++++++
>>   src/Makefile.am                                 |  1 +
>>   src/amd/vulkan/Makefile.am                      |  3 +++
>>   src/amd/vulkan/meson.build                      |  8 ++++----
>>   src/amd/vulkan/radv_device.c                    |  8 ++++++++
>>   src/amd/vulkan/radv_extensions.py               |  1 +
>>   src/intel/Makefile.vulkan.am                    |  7 +++++++
>>   src/intel/vulkan/anv_extensions.py              |  1 +
>>   src/intel/vulkan/anv_gem.c                      | 13 +++++++++++++
>>   src/intel/vulkan/anv_private.h                  |  1 +
>>   src/intel/vulkan/genX_query.c                   | 15 +++++++++++++++
>>   src/intel/vulkan/meson.build                    | 12 ++++++------
>>   src/vulkan/meson.build                          |  1 +
>>   src/vulkan/registry/vk_mesa_query_timestamp.xml | 22 ++++++++++++++++++++++
>>   14 files changed, 89 insertions(+), 10 deletions(-)
>>   create mode 100644 src/vulkan/registry/vk_mesa_query_timestamp.xml
>>
>> diff --git a/include/vulkan/vulkan.h b/include/vulkan/vulkan.h
>> index d3e2e246cf3..5523eb7586f 100644
>> --- a/include/vulkan/vulkan.h
>> +++ b/include/vulkan/vulkan.h
>> @@ -7025,6 +7025,12 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryHostPointerPropertiesEXT(
>>       VkMemoryHostPointerPropertiesEXT*           pMemoryHostPointerProperties);
>>   #endif
>>   
>> +typedef VkResult (VKAPI_PTR *PFN_vkQueryCurrentTimestampMESA)(VkDevice device, uint64_t *timestamp);
>> +
>> +VKAPI_ATTR VkResult VKAPI_CALL vkQueryCurrentTimestampMESA(
>> +    VkDevice                                    _device,
>> +    uint64_t                                    *timestamp);
>> +
>>   #ifdef __cplusplus
>>   }
>>   #endif
>> diff --git a/src/Makefile.am b/src/Makefile.am
>> index 014ffaf3e29..74ff305d7c6 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -68,6 +68,7 @@ endif
>>   
>>   EXTRA_DIST += vulkan/registry/vk.xml
>>   EXTRA_DIST += vulkan/registry/vk_android_native_buffer.xml
>> +EXTRA_DIST += vulkan/registry/vk_mesa_query_timestamp.xml
>>   
>>   if HAVE_AMD_DRIVERS
>>   SUBDIRS += amd
>> diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
>> index 94ece06e99e..0626fa2b3b3 100644
>> --- a/src/amd/vulkan/Makefile.am
>> +++ b/src/amd/vulkan/Makefile.am
>> @@ -129,12 +129,14 @@ libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES)
>>   
>>   vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
>>   vk_android_native_buffer_xml = $(top_srcdir)/src/vulkan/registry/vk_android_native_buffer.xml
>> +vk_mesa_query_timestamp_xml = $(top_srcdir)/src/vulkan/registry/vk_mesa_query_timestamps.xml
>>   
>>   radv_entrypoints.c: radv_entrypoints_gen.py radv_extensions.py $(vulkan_api_xml)
>>          $(MKDIR_GEN)
>>          $(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py \
>>                  --xml $(vulkan_api_xml) \
>>                  --xml $(vk_android_native_buffer_xml) \
>> +               --xml $(vk_mesa_query_timestamp_xml) \
>>                  --outdir $(builddir)
>>   radv_entrypoints.h: radv_entrypoints.c
>>   
>> @@ -144,6 +146,7 @@ radv_extensions.c: radv_extensions.py \
>>          $(AM_V_GEN)$(PYTHON2) $(srcdir)/radv_extensions.py \
>>                  --xml $(vulkan_api_xml) \
>>                  --xml $(vk_android_native_buffer_xml) \
>> +               --xml $(vk_mesa_query_timestamp_xml) \
>>                  --out $@
>>   
>>   vk_format_table.c: vk_format_table.py \
>> diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
>> index 0b92a1763a1..34f578476c0 100644
>> --- a/src/amd/vulkan/meson.build
>> +++ b/src/amd/vulkan/meson.build
>> @@ -20,10 +20,10 @@
>>   
>>   radv_entrypoints = custom_target(
>>     'radv_entrypoints.[ch]',
>> -  input : ['radv_entrypoints_gen.py', vk_api_xml],
>> +  input : ['radv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml],
> some of these lines look a little long,
> input : [
>      'radv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml,
>      vk_mesa_query_timestamp_xml,
> ],
>
>>     output : ['radv_entrypoints.h', 'radv_entrypoints.c'],
>>     command : [
>> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--outdir',
>> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@', '--outdir',
>>       meson.current_build_dir()
>>     ],
>>     depend_files : files('radv_extensions.py'),
>> @@ -31,10 +31,10 @@ radv_entrypoints = custom_target(
>>   
>>   radv_extensions_c = custom_target(
>>     'radv_extensions.c',
>> -  input : ['radv_extensions.py', vk_api_xml, vk_android_native_buffer_xml],
>> +  input : ['radv_extensions.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml],
>>     output : ['radv_extensions.c'],
>>     command : [
>> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--out', '@OUTPUT@',
>> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@', '--out', '@OUTPUT@',
>>     ],
>>   )
>>   
>> diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
>> index adf33eb35dc..6c13efba9e0 100644
>> --- a/src/amd/vulkan/radv_device.c
>> +++ b/src/amd/vulkan/radv_device.c
>> @@ -4084,3 +4084,11 @@ radv_DebugReportMessageEXT(VkInstance _instance,
>>          vk_debug_report(&instance->debug_report_callbacks, flags, objectType,
>>                          object, location, messageCode, pLayerPrefix, pMessage);
>>   }
>> +
>> +VkResult radv_QueryCurrentTimestampMESA(VkDevice _device, uint64_t *timestamp)
>> +{
>> +       RADV_FROM_HANDLE(radv_device, device, _device);
>> +
>> +       *timestamp = device->ws->query_value(device->ws, RADEON_TIMESTAMP);
>> +       return VK_SUCCESS;
>> +}
>> diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
>> index 775d1ed4be6..fed198df412 100644
>> --- a/src/amd/vulkan/radv_extensions.py
>> +++ b/src/amd/vulkan/radv_extensions.py
>> @@ -95,6 +95,7 @@ EXTENSIONS = [
>>       Extension('VK_AMD_draw_indirect_count',               1, True),
>>       Extension('VK_AMD_rasterization_order',               1, 'device->rad_info.chip_class >= VI && device->rad_info.max_se >= 2'),
>>       Extension('VK_AMD_shader_info',                       1, True),
>> +    Extension('VK_MESA_query_timestamp',                  1, True),
>>   ]
>>   
>>   class VkVersion:
>> diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
>> index 0f0d3815097..d7890022abe 100644
>> --- a/src/intel/Makefile.vulkan.am
>> +++ b/src/intel/Makefile.vulkan.am
>> @@ -24,36 +24,43 @@
>>   # out and we'll fail at `make dist'
>>   vulkan_api_xml = $(top_srcdir)/src/vulkan/registry/vk.xml
>>   vk_android_native_buffer_xml = $(top_srcdir)/src/vulkan/registry/vk_android_native_buffer.xml
>> +vk_mesa_query_timestamp_xml = $(top_srcdir)/src/vulkan/registry/vk_mesa_query_timestamps.xml
>>   
>>   vulkan/anv_entrypoints.c: vulkan/anv_entrypoints_gen.py \
>>                            vulkan/anv_extensions.py \
>>                            $(vulkan_api_xml) \
>> +                         $(vk_mesa_query_timestamp_xml) \
>>                            $(vk_android_native_buffer_xml)
>>          $(MKDIR_GEN)
>>          $(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_entrypoints_gen.py \
>>                  --xml $(vulkan_api_xml) \
>>                  --xml $(vk_android_native_buffer_xml) \
>> +               --xml $(vk_mesa_query_timestamp_xml) \
>>                  --outdir $(builddir)/vulkan
>>   vulkan/anv_entrypoints.h: vulkan/anv_entrypoints.c
>>   
>>   vulkan/anv_extensions.c: vulkan/anv_extensions_gen.py \
>>                           vulkan/anv_extensions.py \
>>                           $(vulkan_api_xml) \
>> +                        $(vk_mesa_query_timestamp_xml) \
>>                           $(vk_android_native_buffer_xml)
>>          $(MKDIR_GEN)
>>          $(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_extensions_gen.py \
>>                  --xml $(vulkan_api_xml) \
>>                  --xml $(vk_android_native_buffer_xml) \
>> +               --xml $(vk_mesa_query_timestamp_xml) \
>>                  --out-c $@
>>   
>>   vulkan/anv_extensions.h: vulkan/anv_extensions_gen.py \
>>                           vulkan/anv_extensions.py \
>>                           $(vulkan_api_xml) \
>> +                        $(vk_mesa_query_timestamp_xml) \
>>                           $(vk_android_native_buffer_xml)
>>          $(MKDIR_GEN)
>>          $(AM_V_GEN)$(PYTHON2) $(srcdir)/vulkan/anv_extensions_gen.py \
>>                  --xml $(vulkan_api_xml) \
>>                  --xml $(vk_android_native_buffer_xml) \
>> +               --xml $(vk_mesa_query_timestamp_xml) \
>>                  --out-h $@
>>   
>>   BUILT_SOURCES += $(VULKAN_GENERATED_FILES)
>> diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
>> index f44598b305a..dd4d5a1f970 100644
>> --- a/src/intel/vulkan/anv_extensions.py
>> +++ b/src/intel/vulkan/anv_extensions.py
>> @@ -91,6 +91,7 @@ EXTENSIONS = [
>>       Extension('VK_EXT_external_memory_dma_buf',           1, True),
>>       Extension('VK_EXT_display_surface_counter',           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
>>       Extension('VK_EXT_display_control',                   1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
>> +    Extension('VK_MESA_query_timestamp',                  1, True),
>>   ]
>>   
>>   class VkVersion:
>> diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c
>> index 34c09891086..588b323d113 100644
>> --- a/src/intel/vulkan/anv_gem.c
>> +++ b/src/intel/vulkan/anv_gem.c
>> @@ -418,6 +418,19 @@ anv_gem_fd_to_handle(struct anv_device *device, int fd)
>>      return args.handle;
>>   }
>>   
>> +int
>> +anv_gem_reg_read(struct anv_device *device, uint32_t offset, uint64_t *result)
>> +{
>> +   struct drm_i915_reg_read args = {
>> +      .offset = offset
>> +   };
>> +
>> +   int ret = anv_ioctl(device->fd, DRM_IOCTL_I915_REG_READ, &args);
>> +
>> +   *result = args.val;
>> +   return ret;
>> +}
>> +
>>   #ifndef SYNC_IOC_MAGIC
>>   /* duplicated from linux/sync_file.h to avoid build-time dependency
>>    * on new (v4.7) kernel headers.  Once distro's are mostly using
>> diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h
>> index 1d3e5fcd921..337d8ca3f15 100644
>> --- a/src/intel/vulkan/anv_private.h
>> +++ b/src/intel/vulkan/anv_private.h
>> @@ -932,6 +932,7 @@ bool anv_gem_supports_48b_addresses(int fd);
>>   int anv_gem_gpu_get_reset_stats(struct anv_device *device,
>>                                   uint32_t *active, uint32_t *pending);
>>   int anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle);
>> +int anv_gem_reg_read(struct anv_device *device, uint32_t offset, uint64_t *result);
>>   uint32_t anv_gem_fd_to_handle(struct anv_device *device, int fd);
>>   int anv_gem_set_caching(struct anv_device *device, uint32_t gem_handle, uint32_t caching);
>>   int anv_gem_set_domain(struct anv_device *device, uint32_t gem_handle,
>> diff --git a/src/intel/vulkan/genX_query.c b/src/intel/vulkan/genX_query.c
>> index 4efcc57e475..d2de7e5f45e 100644
>> --- a/src/intel/vulkan/genX_query.c
>> +++ b/src/intel/vulkan/genX_query.c
>> @@ -546,6 +546,21 @@ void genX(CmdWriteTimestamp)(
>>      }
>>   }
>>   
>> +VkResult genX(QueryCurrentTimestampMESA)(
>> +   VkDevice                                     _device,
>> +   uint64_t                                     *timestamp)
>> +{
>> +   ANV_FROM_HANDLE(anv_device, device, _device);
>> +   int  ret;
>> +
>> +   /* XXX older kernels don't support this interface. */
>> +   ret = anv_gem_reg_read(device, TIMESTAMP | 1, timestamp);
>> +
>> +   if (ret != 0)
>> +      return VK_ERROR_DEVICE_LOST;
>> +   return VK_SUCCESS;
>> +}
>> +
>>   #if GEN_GEN > 7 || GEN_IS_HASWELL
>>   
>>   static uint32_t
>> diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
>> index d3ab5ac8a64..d4622ffdfdf 100644
>> --- a/src/intel/vulkan/meson.build
>> +++ b/src/intel/vulkan/meson.build
>> @@ -20,11 +20,11 @@
>>   
>>   anv_entrypoints = custom_target(
>>     'anv_entrypoints.[ch]',
>> -  input : ['anv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml,
>> +  input : ['anv_entrypoints_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
>>              'anv_extensions.py'],
> Same with this, could you also fix my bad indentation here?
>
>>     output : ['anv_entrypoints.h', 'anv_entrypoints.c'],
>>     command : [
>> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
>> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
>>       '--outdir', meson.current_build_dir(),
>>     ],
>>     depend_files : files('anv_extensions.py'),
>> @@ -32,22 +32,22 @@ anv_entrypoints = custom_target(
>>   
>>   anv_extensions_c = custom_target(
>>     'anv_extensions.c',
>> -  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml,
>> +  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
>>              'anv_extensions.py'],
>>     output : 'anv_extensions.c',
>>     command : [
>> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
>> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
>>       '--out-c', '@OUTPUT@',
>>     ],
>>   )
>>   
>>   anv_extensions_h = custom_target(
>>     'anv_extensions.h',
>> -  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml,
>> +  input : ['anv_extensions_gen.py', vk_api_xml, vk_android_native_buffer_xml, vk_mesa_query_timestamp_xml,
>>              'anv_extensions.py'],
>>     output : 'anv_extensions.h',
>>     command : [
>> -    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@',
>> +    prog_python2, '@INPUT0@', '--xml', '@INPUT1@', '--xml', '@INPUT2@', '--xml', '@INPUT3@',
>>       '--out-h', '@OUTPUT@',
>>     ],
>>   )
>> diff --git a/src/vulkan/meson.build b/src/vulkan/meson.build
>> index 3908005b8a0..6ab0966b7c5 100644
>> --- a/src/vulkan/meson.build
>> +++ b/src/vulkan/meson.build
>> @@ -20,6 +20,7 @@
>>   
>>   vk_api_xml = files('registry/vk.xml')
>>   vk_android_native_buffer_xml = files('registry/vk_android_native_buffer.xml')
>> +vk_mesa_query_timestamp_xml = files('registry/vk_mesa_query_timestamp.xml')
>>   
>>   inc_vulkan_util = include_directories('util')
>>   inc_vulkan_wsi = include_directories('wsi')
>> diff --git a/src/vulkan/registry/vk_mesa_query_timestamp.xml b/src/vulkan/registry/vk_mesa_query_timestamp.xml
>> new file mode 100644
>> index 00000000000..7fd4d974872
>> --- /dev/null
>> +++ b/src/vulkan/registry/vk_mesa_query_timestamp.xml
>> @@ -0,0 +1,22 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<registry>
>> +    <commands>
>> +        <command>
>> +            <proto><type>VkResult</type> <name>vkQueryCurrentTimestampMESA</name></proto>
>> +            <param><type>VkDevice</type> <name>device</name></param>
>> +            <param><type>uint64_t</type>* <name>pTimestamp</name></param>
>> +        </command>
>> +    </commands>
>> +    <extensions>
>> +        <extension name="VK_MESA_query_timestamp" number="200"
>> +                  type="device" author="MESA"
>> +                  contact="Keith Packard @keithp"
>> +                  supported="vulkan">
>> +            <require>
>> +                <enum value="1"                                         name="VK_MESA_QUERY_TIMESTAMP_SPEC_VERSION"/>
>> +                <enum value="&quot;VK_MESA_query_timestamp&quot;"       name="VK_MESA_QUERY_TIMESTAMP_NAME"/>
>> +                <command name="vkQueryCurrentTimestampMESA"/>
>> +            </require>
>> +        </extension>
>> +    </extensions>
>> +</registry>
>> -- 
>> 2.15.1
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
>>
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/mesa-dev



[-- Attachment #1.2: Type: text/html, Size: 17672 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension
  2018-02-13 10:49     ` [Mesa-dev] " Lionel Landwerlin
@ 2018-02-13 21:11       ` Keith Packard
  0 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-02-13 21:11 UTC (permalink / raw)
  To: Lionel Landwerlin, Dylan Baker, mesa-dev; +Cc: dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 1021 bytes --]

Lionel Landwerlin <lionel.g.landwerlin@intel.com> writes:

> I'm assuming the correlation is done outside the vulkan driver? With a 
> clock_gettime() maybe?
>
> If that's the case, I'm afraid this will be highly inaccurate.
> The kernel might execute other tasks when the ioctl() happens and that 
> might introduce (in my experience) a few milliseconds of delay.

Yes, I agree. The trouble is that the window system layer works in one
time base while the rendering layer works in the other, so there's no
one driver which has access to both values, at least in Mesa.

> I think if you want to do something like that, this has to be 
> implemented in the kernel, making sure you disable interruptions while 
> doing the correlation.

That was my thinking originally, until I realized that there wasn't a
single place which knew of the two clocks.

Suggestions are welcome; I just don't know how the rendering driver is
supposed to know what timebase the window system is running in?

-- 
-keith

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 157 bytes --]

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
  2018-02-12 15:27   ` Eric Engestrom
  2018-02-12 16:18   ` [Mesa-dev] " Emil Velikov
@ 2018-02-14  1:10   ` Jason Ekstrand
  2018-02-15 17:46     ` Keith Packard
  2018-03-29  6:59   ` Mao, David
  3 siblings, 1 reply; 24+ messages in thread
From: Jason Ekstrand @ 2018-02-14  1:10 UTC (permalink / raw)
  To: Keith Packard; +Cc: ML mesa-dev, Maling list - DRI developers


[-- Attachment #1.1: Type: text/plain, Size: 94579 bytes --]

On Fri, Feb 9, 2018 at 8:45 PM, Keith Packard <keithp@keithp.com> wrote:

> This adds support for the KHR_display extension to the anv and radv
> Vulkan drivers. The drivers now attempt to open the master DRM node
> when the KHR_display extension is requested so that the common winsys
> code can perform the necessary operations.
>
> Signed-off-by: Keith Packard <keithp@keithp.com>
> ---
>  configure.ac                           |    1 +
>  meson.build                            |    4 +-
>  src/amd/vulkan/Makefile.am             |    8 +
>  src/amd/vulkan/Makefile.sources        |    3 +
>  src/amd/vulkan/meson.build             |    7 +
>  src/amd/vulkan/radv_device.c           |   28 +-
>  src/amd/vulkan/radv_extensions.py      |    7 +-
>  src/amd/vulkan/radv_private.h          |    2 +
>  src/amd/vulkan/radv_wsi.c              |    3 +-
>  src/amd/vulkan/radv_wsi_display.c      |  143 ++++
>  src/intel/Makefile.sources             |    3 +
>  src/intel/Makefile.vulkan.am           |    7 +
>  src/intel/vulkan/anv_device.c          |   18 +-
>  src/intel/vulkan/anv_extensions.py     |    1 +
>  src/intel/vulkan/anv_extensions_gen.py |    5 +-
>  src/intel/vulkan/anv_wsi.c             |    3 +-
>  src/intel/vulkan/anv_wsi_display.c     |  129 +++
>  src/intel/vulkan/meson.build           |    7 +
>  src/vulkan/Makefile.am                 |    7 +
>  src/vulkan/Makefile.sources            |    4 +
>  src/vulkan/wsi/meson.build             |   10 +
>  src/vulkan/wsi/wsi_common.c            |   19 +-
>  src/vulkan/wsi/wsi_common.h            |    5 +-
>  src/vulkan/wsi/wsi_common_display.c    | 1368
> ++++++++++++++++++++++++++++++++
>  src/vulkan/wsi/wsi_common_display.h    |   72 ++
>  src/vulkan/wsi/wsi_common_private.h    |   10 +
>  26 files changed, 1858 insertions(+), 16 deletions(-)
>  create mode 100644 src/amd/vulkan/radv_wsi_display.c
>  create mode 100644 src/intel/vulkan/anv_wsi_display.c
>  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 8ed606c7694..46318365603 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1849,6 +1849,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 b39e2f8ab96..aeb7f5e2917 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'
>    else
> @@ -257,6 +258,7 @@ if _platforms != ''
>    with_platform_wayland = _split.contains('wayland')
>    with_platform_drm = _split.contains('drm')
>    with_platform_surfaceless = _split.contains('surfaceless')
> +  with_platform_display = _split.contains('display')
>    egl_native_platform = _split[0]
>  endif
>
> diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
> index 61025968942..061b8144b88 100644
> --- a/src/amd/vulkan/Makefile.am
> +++ b/src/amd/vulkan/Makefile.am
> @@ -76,6 +76,14 @@ VULKAN_LIB_DEPS = \
>         $(DLOPEN_LIBS) \
>         -lm
>
> +if HAVE_PLATFORM_DISPLAY
> +AM_CPPFLAGS += \
> +       -DVK_USE_PLATFORM_DISPLAY_KHR
> +
> +VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> +
> +endif
> +
>  if HAVE_PLATFORM_X11
>  AM_CPPFLAGS += \
>         $(XCB_DRI3_CFLAGS) \
> diff --git a/src/amd/vulkan/Makefile.sources
> b/src/amd/vulkan/Makefile.sources
> index a510d88d965..618a6cdaed0 100644
> --- a/src/amd/vulkan/Makefile.sources
> +++ b/src/amd/vulkan/Makefile.sources
> @@ -78,6 +78,9 @@ VULKAN_WSI_WAYLAND_FILES := \
>  VULKAN_WSI_X11_FILES := \
>         radv_wsi_x11.c
>
> +VULKAN_WSI_DISPLAY_FILES := \
> +       radv_wsi_display.c
> +
>  VULKAN_GENERATED_FILES := \
>         radv_entrypoints.c \
>         radv_entrypoints.h \
> diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
> index 0a7b7c0bf3c..b7bb1075e7d 100644
> --- a/src/amd/vulkan/meson.build
> +++ b/src/amd/vulkan/meson.build
> @@ -112,6 +112,13 @@ if with_platform_wayland
>    libradv_files += files('radv_wsi_wayland.c')
>  endif
>
> +if with_platform_display
> +  radv_flags += [
> +    '-DVK_USE_PLATFORM_DISPLAY_KHR',
> +  ]
> +  libradv_files += files('radv_wsi_display.c')
> +endif
> +
>  libvulkan_radeon = shared_library(
>    'vulkan_radeon',
>    [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
> diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
> index 09bb382eeb8..adf33eb35dc 100644
> --- a/src/amd/vulkan/radv_device.c
> +++ b/src/amd/vulkan/radv_device.c
> @@ -191,9 +191,26 @@ radv_physical_device_init(struct
> radv_physical_device *device,
>         const char *path = drm_device->nodes[DRM_NODE_RENDER];
>         VkResult result;
>         drmVersionPtr version;
> -       int fd;
> -
> -       fd = open(path, O_RDWR | O_CLOEXEC);
> +       int fd = -1;
> +
> +        if (instance->khr_display_requested) {
> +                fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR |
> O_CLOEXEC);
> +                if (fd >= 0) {
> +                        uint32_t accel_working = 0;
> +                        struct drm_amdgpu_info request = {
> +                                .return_pointer =
> (uintptr_t)&accel_working,
> +                                .return_size = sizeof(accel_working),
> +                                .query = AMDGPU_INFO_ACCEL_WORKING
> +                        };
> +
> +                        if (drmCommandWrite(fd, DRM_AMDGPU_INFO,
> &request, sizeof (struct drm_amdgpu_info)) < 0 || !accel_working) {
> +                                close(fd);
> +                                fd = -1;
> +                        }
> +                }
> +        }
> +        if (fd < 0)
> +                fd = open(path, O_RDWR | O_CLOEXEC);
>         if (fd < 0)
>                 return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
>
> @@ -209,6 +226,7 @@ radv_physical_device_init(struct radv_physical_device
> *device,
>                 close(fd);
>                 return VK_ERROR_INCOMPATIBLE_DRIVER;
>         }
> +
>         drmFreeVersion(version);
>
>         device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
> @@ -387,6 +405,7 @@ VkResult radv_CreateInstance(
>  {
>         struct radv_instance *instance;
>         VkResult result;
> +        bool khr_display_requested = false;
>
>         assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CRE
> ATE_INFO);
>
> @@ -411,6 +430,8 @@ VkResult radv_CreateInstance(
>                 const char *ext_name = pCreateInfo->ppEnabledExtensio
> nNames[i];
>                 if (!radv_instance_extension_supported(ext_name))
>                         return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT);
> +                if (strcmp(ext_name, VK_KHR_DISPLAY_EXTENSION_NAME) == 0)
> +                        khr_display_requested = true;
>         }
>
>         instance = vk_zalloc2(&default_alloc, pAllocator,
> sizeof(*instance), 8,
> @@ -427,6 +448,7 @@ VkResult radv_CreateInstance(
>
>         instance->apiVersion = client_version;
>         instance->physicalDeviceCount = -1;
> +        instance->khr_display_requested = khr_display_requested;
>
>         result = vk_debug_report_instance_init(
> &instance->debug_report_callbacks);
>         if (result != VK_SUCCESS) {
> diff --git a/src/amd/vulkan/radv_extensions.py
> b/src/amd/vulkan/radv_extensions.py
> index d761895d3a0..24cab8cbb39 100644
> --- a/src/amd/vulkan/radv_extensions.py
> +++ b/src/amd/vulkan/radv_extensions.py
> @@ -81,6 +81,7 @@ EXTENSIONS = [
>      Extension('VK_KHR_wayland_surface',                   6,
> 'VK_USE_PLATFORM_WAYLAND_KHR'),
>      Extension('VK_KHR_xcb_surface',                       6,
> 'VK_USE_PLATFORM_XCB_KHR'),
>      Extension('VK_KHR_xlib_surface',                      6,
> 'VK_USE_PLATFORM_XLIB_KHR'),
> +    Extension('VK_KHR_display',                           1,
> 'VK_USE_PLATFORM_DISPLAY_KHR'),
>      Extension('VK_KHX_multiview',                         1, '!ANDROID'),
>      Extension('VK_EXT_debug_report',                      9, True),
>      Extension('VK_EXT_discard_rectangles',                1, True),
> @@ -168,7 +169,7 @@ _TEMPLATE = Template(COPYRIGHT + """
>  #include "vk_util.h"
>
>  /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
> +%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
>  #ifdef VK_USE_PLATFORM_${platform}_KHR
>  #   undef VK_USE_PLATFORM_${platform}_KHR
>  #   define VK_USE_PLATFORM_${platform}_KHR true
> @@ -187,7 +188,9 @@ _TEMPLATE = Template(COPYRIGHT + """
>
>  #define RADV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
>                           VK_USE_PLATFORM_XCB_KHR || \\
> -                         VK_USE_PLATFORM_XLIB_KHR)
> +                         VK_USE_PLATFORM_XLIB_KHR || \\
> +                         VK_USE_PLATFORM_DISPLAY_KHR)
> +
>
>  bool
>  radv_instance_extension_supported(const char *name)
> diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
> index be9e8f43964..1e3719bcc4f 100644
> --- a/src/amd/vulkan/radv_private.h
> +++ b/src/amd/vulkan/radv_private.h
> @@ -75,6 +75,7 @@ typedef uint32_t xcb_window_t;
>  #include "radv_entrypoints.h"
>
>  #include "wsi_common.h"
> +#include "wsi_common_display.h"
>
>  #define ATI_VENDOR_ID 0x1002
>
> @@ -300,6 +301,7 @@ struct radv_instance {
>         uint64_t perftest_flags;
>
>         struct vk_debug_report_instance             debug_report_callbacks;
> +        bool                                        khr_display_requested;
>  };
>
>  VkResult radv_init_wsi(struct radv_physical_device *physical_device);
> diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
> index e016e837102..5ec872a63d0 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_handl
> e(physical_device),
>                                radv_wsi_proc_addr,
> -                              &physical_device->instance->alloc);
> +                              &physical_device->instance->alloc,
> +                               physical_device->local_fd);
>  }
>
>  void
> diff --git a/src/amd/vulkan/radv_wsi_display.c
> b/src/amd/vulkan/radv_wsi_display.c
> new file mode 100644
> index 00000000000..b0a4db0344b
> --- /dev/null
> +++ b/src/amd/vulkan/radv_wsi_display.c
> @@ -0,0 +1,143 @@
> +/*
> + * 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 <stdbool.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include "radv_private.h"
> +#include "radv_cs.h"
> +#include "util/disk_cache.h"
> +#include "util/strtod.h"
> +#include "vk_util.h"
> +#include <xf86drm.h>
> +#include <xf86drmMode.h>
> +#include <amdgpu.h>
> +#include <amdgpu_drm.h>
> +#include "winsys/amdgpu/radv_amdgpu_winsys_public.h"
> +#include "ac_llvm_util.h"
> +#include "vk_format.h"
> +#include "sid.h"
> +#include "util/debug.h"
> +#include "wsi_common_display.h"
> +
> +#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
> +
> +VkResult
> +radv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice
>  physical_device,
> +                                           uint32_t
>  *property_count,
> +                                           VkDisplayPropertiesKHR
>  *properties)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_properties(physical_
> device,
> +
>  &pdevice->wsi_device,
> +
>  property_count,
> +                                                             properties);
> +}
> +
> +VkResult
> +radv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice
>         physical_device,
> +                                                uint32_t
>       *property_count,
> +
> VkDisplayPlanePropertiesKHR     *properties)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_plane_properties(
> physical_device,
> +
>  &pdevice->wsi_device,
> +
>  property_count,
> +
>  properties);
> +}
> +
> +VkResult
> +radv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice
>  physical_device,
> +                                         uint32_t
>  plane_index,
> +                                         uint32_t
>  *display_count,
> +                                         VkDisplayKHR
>  *displays)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_plane_supported_displays(physical_de
> vice,
> +
>  &pdevice->wsi_device,
> +                                                           plane_index,
> +                                                           display_count,
> +                                                           displays);
> +}
> +
> +
> +VkResult
> +radv_GetDisplayModePropertiesKHR(VkPhysicalDevice
>  physical_device,
> +                                 VkDisplayKHR                   display,
> +                                 uint32_t
>  *property_count,
> +                                 VkDisplayModePropertiesKHR
>  *properties)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_mode_properties(physical_device,
> +                                                  &pdevice->wsi_device,
> +                                                  display,
> +                                                  property_count,
> +                                                  properties);
> +}
> +
> +VkResult
> +radv_CreateDisplayModeKHR(VkPhysicalDevice
> physical_device,
> +                          VkDisplayKHR                          display,
> +                          const VkDisplayModeCreateInfoKHR
> *create_info,
> +                          const VkAllocationCallbacks
>  *allocator,
> +                          VkDisplayModeKHR                      *mode)
> +{
> +   return VK_ERROR_INITIALIZATION_FAILED;
> +}
> +
> +
> +VkResult
> +radv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice
> physical_device,
> +                                    VkDisplayModeKHR
> mode_khr,
> +                                    uint32_t
> plane_index,
> +                                    VkDisplayPlaneCapabilitiesKHR
>  *capabilities)
> +{
> +   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
> +
> +   return wsi_get_display_plane_capabilities(physical_device,
> +                                             &pdevice->wsi_device,
> +                                             mode_khr,
> +                                             plane_index,
> +                                             capabilities);
> +}
> +
> +VkResult
> +radv_CreateDisplayPlaneSurfaceKHR(VkInstance
> _instance,
> +                                  const VkDisplaySurfaceCreateInfoKHR
>  *create_info,
> +                                  const VkAllocationCallbacks
>  *allocator,
> +                                  VkSurfaceKHR
> *surface)
> +{
> +   RADV_FROM_HANDLE(radv_instance, instance, _instance);
> +   const VkAllocationCallbacks *alloc;
> +
> +   if (allocator)
> +     alloc = allocator;
> +   else
> +     alloc = &instance->alloc;
> +
> +   return wsi_create_display_surface(_instance, alloc, create_info,
> surface);
> +}
> diff --git a/src/intel/Makefile.sources b/src/intel/Makefile.sources
> index 9595bf42582..6c142729d94 100644
> --- a/src/intel/Makefile.sources
> +++ b/src/intel/Makefile.sources
> @@ -240,6 +240,9 @@ VULKAN_WSI_WAYLAND_FILES := \
>  VULKAN_WSI_X11_FILES := \
>         vulkan/anv_wsi_x11.c
>
> +VULKAN_WSI_DISPLAY_FILES := \
> +       vulkan/anv_wsi_display.c
> +
>  VULKAN_GEM_FILES := \
>         vulkan/anv_gem.c
>
> diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
> index 23fa877e77d..7c428a799d7 100644
> --- a/src/intel/Makefile.vulkan.am
> +++ b/src/intel/Makefile.vulkan.am
> @@ -187,6 +187,13 @@ VULKAN_SOURCES += $(VULKAN_WSI_WAYLAND_FILES)
>  VULKAN_LIB_DEPS += $(WAYLAND_CLIENT_LIBS)
>  endif
>
> +if HAVE_PLATFORM_DISPLAY
> +VULKAN_CPPFLAGS += \
> +       -DVK_USE_PLATFORM_DISPLAY_KHR
> +
> +VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
> +endif
> +
>  noinst_LTLIBRARIES += vulkan/libvulkan_common.la
>  vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
>  vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS)
> diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
> index 86c1bdc1d51..9614907fda3 100644
> --- a/src/intel/vulkan/anv_device.c
> +++ b/src/intel/vulkan/anv_device.c
> @@ -277,14 +277,25 @@ anv_physical_device_init_uuids(struct
> anv_physical_device *device)
>  static VkResult
>  anv_physical_device_init(struct anv_physical_device *device,
>                           struct anv_instance *instance,
> -                         const char *path)
> +                         const char *primary_path,
> +                         const char *render_path)
>  {
>     VkResult result;
> -   int fd;
> +   int fd = -1;
> +   const char *path;
>
>     brw_process_intel_debug_variable();
>
> -   fd = open(path, O_RDWR | O_CLOEXEC);
> +   if (instance->enabled_extensions.KHR_display) {
> +      path = primary_path;
> +      fd = open(path, O_RDWR | O_CLOEXEC);
> +   }
> +
> +   if (fd < 0) {
> +      path = render_path;
> +      fd = open(path, O_RDWR | O_CLOEXEC);
> +   }
>

It seems a little odd to me to default to opening the master node and then
fall back to the render node if it doesn't work.  I suppose that's probably
ok so long as we ensure that vkGetPhysicalDeviceDisplayPropertiesKHR
returns no displays if we're on the render node.

We could always go back to the DRM fd extension idea but I'm not coming up
with something nice and clean in the 60 seconds I've thought about it.

+
>     if (fd < 0)
>        return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
>
> @@ -652,6 +663,7 @@ anv_enumerate_devices(struct anv_instance *instance)
>
>           result = anv_physical_device_init(&instance->physicalDevice,
>                          instance,
> +                        devices[i]->nodes[DRM_NODE_PRIMARY],
>                          devices[i]->nodes[DRM_NODE_RENDER]);
>           if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
>              break;
> diff --git a/src/intel/vulkan/anv_extensions.py
> b/src/intel/vulkan/anv_extensions.py
> index 581921e62a1..978a219e2b2 100644
> --- a/src/intel/vulkan/anv_extensions.py
> +++ b/src/intel/vulkan/anv_extensions.py
> @@ -83,6 +83,7 @@ EXTENSIONS = [
>      Extension('VK_KHR_wayland_surface',                   6,
> 'VK_USE_PLATFORM_WAYLAND_KHR'),
>      Extension('VK_KHR_xcb_surface',                       6,
> 'VK_USE_PLATFORM_XCB_KHR'),
>      Extension('VK_KHR_xlib_surface',                      6,
> 'VK_USE_PLATFORM_XLIB_KHR'),
> +    Extension('VK_KHR_display',                           1,
> 'VK_USE_PLATFORM_DISPLAY_KHR'),
>      Extension('VK_KHX_multiview',                         1, True),
>      Extension('VK_EXT_debug_report',                      8, True),
>      Extension('VK_EXT_external_memory_dma_buf',           1, True),
> diff --git a/src/intel/vulkan/anv_extensions_gen.py
> b/src/intel/vulkan/anv_extensions_gen.py
> index 33827ecd015..84d07f9767a 100644
> --- a/src/intel/vulkan/anv_extensions_gen.py
> +++ b/src/intel/vulkan/anv_extensions_gen.py
> @@ -113,7 +113,7 @@ _TEMPLATE_C = Template(COPYRIGHT + """
>  #include "vk_util.h"
>
>  /* Convert the VK_USE_PLATFORM_* defines to booleans */
> -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
> +%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
>  #ifdef VK_USE_PLATFORM_${platform}_KHR
>  #   undef VK_USE_PLATFORM_${platform}_KHR
>  #   define VK_USE_PLATFORM_${platform}_KHR true
> @@ -132,7 +132,8 @@ _TEMPLATE_C = Template(COPYRIGHT + """
>
>  #define ANV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
>                           VK_USE_PLATFORM_XCB_KHR || \\
> -                         VK_USE_PLATFORM_XLIB_KHR)
> +                         VK_USE_PLATFORM_XLIB_KHR || \\
> +                         VK_USE_PLATFORM_DISPLAY_KHR)
>
>  const VkExtensionProperties anv_instance_extensions[ANV_INSTANCE_EXTENSION_COUNT]
> = {
>  %for ext in instance_extensions:
> diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
> index 6082c3dd093..f86d83589ea 100644
> --- a/src/intel/vulkan/anv_wsi.c
> +++ b/src/intel/vulkan/anv_wsi.c
> @@ -39,7 +39,8 @@ anv_init_wsi(struct anv_physical_device *physical_device)
>     return 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->local_fd);
>  }
>
>  void
> diff --git a/src/intel/vulkan/anv_wsi_display.c
> b/src/intel/vulkan/anv_wsi_display.c
> new file mode 100644
> index 00000000000..9b00d7f02e4
> --- /dev/null
> +++ b/src/intel/vulkan/anv_wsi_display.c
> @@ -0,0 +1,129 @@
> +/*
> + * 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 "anv_private.h"
> +#include "wsi_common.h"
> +#include "vk_format_info.h"
> +#include "vk_util.h"
> +#include "wsi_common_display.h"
> +
> +#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
> +
> +VkResult
> +anv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice
>  physical_device,
> +                                           uint32_t
>  *property_count,
> +                                           VkDisplayPropertiesKHR
>  *properties)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_properties(physical_
> device,
> +
>  &pdevice->wsi_device,
> +
>  property_count,
> +                                                             properties);
> +}
> +
> +VkResult
> +anv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice
>       physical_device,
> +                                                uint32_t
>       *property_count,
> +
> VkDisplayPlanePropertiesKHR     *properties)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_physical_device_display_plane_properties(
> physical_device,
> +
>  &pdevice->wsi_device,
> +
>  property_count,
> +
>  properties);
> +}
> +
> +VkResult
> +anv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice
>  physical_device,
> +                                         uint32_t
>  plane_index,
> +                                         uint32_t
>  *display_count,
> +                                         VkDisplayKHR
>  *displays)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_plane_supported_displays(physical_de
> vice,
> +
>  &pdevice->wsi_device,
> +                                                           plane_index,
> +                                                           display_count,
> +                                                           displays);
> +}
> +
> +
> +VkResult
> +anv_GetDisplayModePropertiesKHR(VkPhysicalDevice
>  physical_device,
> +                                 VkDisplayKHR                   display,
> +                                 uint32_t
>  *property_count,
> +                                 VkDisplayModePropertiesKHR
>  *properties)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_display_get_display_mode_properties(physical_device,
> +                                                  &pdevice->wsi_device,
> +                                                  display,
> +                                                  property_count,
> +                                                  properties);
> +}
> +
> +VkResult
> +anv_CreateDisplayModeKHR(VkPhysicalDevice
> physical_device,
> +                          VkDisplayKHR                          display,
> +                          const VkDisplayModeCreateInfoKHR
> *create_info,
> +                          const VkAllocationCallbacks
>  *allocator,
> +                          VkDisplayModeKHR                      *mode)
> +{
> +   return VK_ERROR_INITIALIZATION_FAILED;
> +}
> +
> +
> +VkResult
> +anv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice
> physical_device,
> +                                    VkDisplayModeKHR
> mode_khr,
> +                                    uint32_t
> plane_index,
> +                                    VkDisplayPlaneCapabilitiesKHR
>  *capabilities)
> +{
> +   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
> +
> +   return wsi_get_display_plane_capabilities(physical_device,
> +                                             &pdevice->wsi_device,
> +                                             mode_khr,
> +                                             plane_index,
> +                                             capabilities);
> +}
> +
> +VkResult
> +anv_CreateDisplayPlaneSurfaceKHR(VkInstance
> _instance,
> +                                  const VkDisplaySurfaceCreateInfoKHR
>  *create_info,
> +                                  const VkAllocationCallbacks
>  *allocator,
> +                                  VkSurfaceKHR
> *surface)
> +{
> +   ANV_FROM_HANDLE(anv_instance, instance, _instance);
> +   const VkAllocationCallbacks *alloc;
> +
> +   if (allocator)
> +     alloc = allocator;
> +   else
> +     alloc = &instance->alloc;
> +
> +   return wsi_create_display_surface(_instance, alloc, create_info,
> surface);
> +}
> diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
> index 69ec26e19b6..2e2ab8f7ecd 100644
> --- a/src/intel/vulkan/meson.build
> +++ b/src/intel/vulkan/meson.build
> @@ -171,6 +171,13 @@ if with_platform_wayland
>    libanv_files += files('anv_wsi_wayland.c')
>  endif
>
> +if with_platform_display
> +  anv_flags += [
> +    '-DVK_USE_PLATFORM_DISPLAY_KHR',
> +  ]
> +  libanv_files += files('anv_wsi_display.c')
> +endif
> +
>  libanv_common = static_library(
>    'anv_common',
>    [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h],
> diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
> index 037436c1cd7..c33ac5758f7 100644
> --- a/src/vulkan/Makefile.am
> +++ b/src/vulkan/Makefile.am
> @@ -57,6 +57,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
> +
>  BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES)
>  CLEANFILES = $(BUILT_SOURCES)
>
> diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources
> index a0a24ce7de8..3642c7662c4 100644
> --- a/src/vulkan/Makefile.sources
> +++ b/src/vulkan/Makefile.sources
> @@ -17,6 +17,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 bd0fd3cc53e..743631a6113 100644
> --- a/src/vulkan/wsi/meson.build
> +++ b/src/vulkan/wsi/meson.build
> @@ -57,6 +57,16 @@ 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 90ed07b7857..c0a285e5814 100644
> --- a/src/vulkan/wsi/wsi_common.c
> +++ b/src/vulkan/wsi/wsi_common.c
> @@ -29,7 +29,8 @@ VkResult
>  wsi_device_init(struct wsi_device *wsi,
>                  VkPhysicalDevice pdevice,
>                  WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
> -                const VkAllocationCallbacks *alloc)
> +                const VkAllocationCallbacks *alloc,
> +                int device_fd)
>  {
>     VkResult result;
>
> @@ -89,6 +90,19 @@ wsi_device_init(struct wsi_device *wsi,
>     }
>  #endif
>
> +#ifdef VK_USE_PLATFORM_DISPLAY_KHR
> +   result = wsi_display_init_wsi(wsi, alloc, pdevice, device_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
>

Not your problem but we really need a better clean-up path....


> +
>     return VK_SUCCESS;
>  }
>
> @@ -96,6 +110,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 3e0d3be1c24..1cb6aaebca0 100644
> --- a/src/vulkan/wsi/wsi_common.h
> +++ b/src/vulkan/wsi/wsi_common.h
> @@ -50,7 +50,7 @@ struct wsi_memory_allocate_info {
>
>  struct wsi_interface;
>
> -#define VK_ICD_WSI_PLATFORM_MAX 5
> +#define VK_ICD_WSI_PLATFORM_MAX 6
>
>  struct wsi_device {
>     VkPhysicalDeviceMemoryProperties memory_props;
> @@ -93,7 +93,8 @@ VkResult
>  wsi_device_init(struct wsi_device *wsi,
>                  VkPhysicalDevice pdevice,
>                  WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
> -                const VkAllocationCallbacks *alloc);
> +                const VkAllocationCallbacks *alloc,
> +                int device_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..2732b1dd721
> --- /dev/null
> +++ b/src/vulkan/wsi/wsi_common_display.c
> @@ -0,0 +1,1368 @@
> +/*
> + * 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 "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;
>

Would it make anything easier if we just storred the DRM struct here?  "No"
is a perfectly valid answer.


> +} 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;
> +   wsi_display_mode             *current_mode;
> +   drmModeModeInfo              current_drm_mode;
> +} wsi_display_connector;
> +
> +struct wsi_display {
> +   struct wsi_interface         base;
> +
> +   const VkAllocationCallbacks  *alloc;
> +   VkPhysicalDevice             physical_device;
> +
> +   int                          master_fd;
> +   int                          render_fd;
> +
> +   pthread_mutex_t              wait_mutex;
> +   pthread_cond_t               wait_cond;
> +   pthread_t                    wait_thread;
> +
> +   struct list_head             connectors;
> +
> +   struct list_head             display_modes;
> +};
> +
> +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;
> +   uint64_t                     flip_sequence;
> +};
> +
> +struct wsi_display_swapchain {
> +   struct wsi_swapchain         base;
> +   struct wsi_display           *wsi;
> +   VkIcdSurfaceDisplay          *surface;
> +   uint64_t                     flip_sequence;
> +   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));
> +}
> +
> +static uint64_t wsi_get_current_monotonic(void)
> +{
> +   struct timespec tv;
> +
> +   clock_gettime(CLOCK_MONOTONIC, &tv);
> +   return tv.tv_nsec + tv.tv_sec*1000000000ull;
> +}
>

This should probably gone in a helper one day.  Meh.


> +
> +static struct wsi_display_mode *
> +wsi_display_find_drm_mode(struct wsi_device                 *wsi_device,
> +                          struct wsi_display_connector      *connector,
> +                          drmModeModeInfoPtr                mode)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
> +      if (display_mode->connector == connector &&
> +          wsi_display_mode_matches_drm(display_mode, mode))
>

Any particular reason why the list of modes is global and not in the
connector?  It seems like it would be a tiny bit more efficient and
convenient to put the list in the connector.


> +         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           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list)
> +      if (display_mode->connector == connector)
> +         display_mode->valid = false;
>

Please use braces for loops containing more than one line.


> +}
> +
> +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];
> +   struct wsi_display_mode      *display_mode;
> +
> +   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_alloc(wsi->alloc, sizeof (struct wsi_display_mode),
> 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
>

Since we're allocating these in a physical device query, we need to use the
INSTANCE scope.  the OBJECT scope is intended for vkCreate functions to
allocated data that will live no longer than the associated vkDestroy
function.


> +   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, &wsi->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_alloc(wsi->alloc, sizeof (struct
> wsi_display_connector), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
>

VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE


> +   memset(connector, '\0', sizeof (*connector));
>

Just use vk_zalloc().


> +   connector->id = connector_id;
> +   connector->wsi = wsi;
> +   connector->active = false;
> +   /* XXX use EDID name */
> +   connector->name = "monitor";
> +   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->master_fd < 0)
> +      return NULL;
> +
> +   drm_connector = drmModeGetConnector(wsi->master_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)
>

Hooray for obviously false fixed constants!

I know the answer to this will be "EDIDs lie, never trust them!" but can we
get the real value somehow?  As someone who has a 13" laptop with a
3200x1800 display, I know that number isn't always right. :-)


> +
> +static void
> +wsi_display_fill_in_display_properties(struct wsi_device
> *wsi_device,
> +                                       struct wsi_display_connector
>  *connector,
> +                                       VkDisplayPropertiesKHR
>  *properties)
> +{
> +   struct wsi_display           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_mode      *display_mode, *preferred_mode = NULL;;
>

double-;;


> +
> +   properties->display = wsi_display_connector_to_handle(connector);
> +   properties->displayName = connector->name;
> +
> +   /* Find the preferred mode and assume that's the physical resolution */
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
> +      if (display_mode->valid && display_mode->connector == connector &&
> display_mode->preferred) {
> +         preferred_mode = display_mode;
> +         break;
> +      }
> +   }
> +
> +   if (preferred_mode) {
> +      properties->physicalResolution.width = preferred_mode->hdisplay;
> +      properties->physicalResolution.height = preferred_mode->vdisplay;
> +   } else {
> +      properties->physicalResolution.width = 1024;
> +      properties->physicalResolution.height = 768;
>

>From the Vulkan spec:

    Note:
    For devices which have no natural value to return here, implementations
*should* return the maximum resolution supported.

We should walk the list and pick the biggest one.


> +   }
> +
> +   /* 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);
>

See question about MM_PER_PIXEL above


> +
> +   properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_
> BIT_KHR;
>

I know i915 can do better at least in some cases.  Is there a practical way
to expose this?  If not, I'm fine with just exposing IDENTITY.


> +   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];
> +   struct wsi_display_connector *connector;
> +   int                          c;
> +   uint32_t                     connected;
> +   uint32_t                     property_count_requested =
> *property_count;
> +   drmModeResPtr                mode_res;
> +
> +   if (wsi->master_fd < 0)
> +      return VK_ERROR_INITIALIZATION_FAILED;
> +
> +   mode_res = drmModeGetResources(wsi->master_fd);
> +
> +   if (!mode_res)
> +      return VK_ERROR_INITIALIZATION_FAILED;
>

This error is not allowed for this function.  We should just write 0 to
property_count and return VK_SUCCESS.  Maybe add some asserts for debug
builds if you really think this shouldn't ever happen.


> +
> +   connected = 0;
> +
> +   /* Get current information */
> +   for (c = 0; c < mode_res->count_connectors; c++) {
> +      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)
> +         connected++;
> +   }
> +
> +   /* Fill in property information if requested */
> +   if (properties != NULL) {
> +      connected = 0;
> +
> +      for (c = 0; c < mode_res->count_connectors; c++) {
> +         connector  = wsi_display_find_connector(wsi_device,
> mode_res->connectors[c]);
> +
> +         if (connector && connector->connected) {
> +            if (connected < property_count_requested) {
> +               wsi_display_fill_in_display_properties(wsi_device,
> +                                                      connector,
> +
> &properties[connected]);
> +            }
> +            connected++;
> +         }
> +      }
> +   }
>

This could be made a lot easier with vk_outarray:

VK_OUTARRAY_MAKE(conn, properties, property_count);

for (int c = 0; c < mode_res->count_connectors; c++) {
   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);

It's a bit magic but a lot less typing and you don't have to think about
all the details of whether or not you've gotten the return value right.


> +
> +   drmModeFreeResources(mode_res);
> +
> +   *property_count = connected;
> +
> +   if (connected > property_count_requested && properties != NULL)
> +      return VK_INCOMPLETE;
> +
> +   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;
> +   uint32_t                     property_count_requested =
> *property_count;
> +   int                          c;
> +
> +   if (!properties)
> +      property_count_requested = 0;
> +
> +   c = 0;
> +   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
> +      if (c < property_count_requested) {
> +         if (connector && connector->active) {
> +            properties[c].currentDisplay = wsi_display_connector_to_handl
> e(connector);
> +            properties[c].currentStackIndex = c;
> +         } else {
> +            properties[c].currentDisplay = NULL;
> +            properties[c].currentStackIndex = 0;
>

It's not entirely clear what the stack index for a disabled plane should
be.  I guess 0 is as good as anything.


> +         }
> +      }
> +      c++;
> +   }
> +
> +   *property_count = c;
> +
> +   if (c > property_count_requested && properties != NULL)
> +      return VK_INCOMPLETE;
>

Again, vk_outarray is your friend.


> +
> +   return VK_SUCCESS;
> +}
> +
> +/*
> + * 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;
> +   int                          c;
> +
> +
> +   if (displays == NULL) {
> +      *display_count = 1;
>

This isn't correct.  The loop below could turn up no displays.  Again,
vk_outarray is your friend.


> +      return VK_SUCCESS;
> +   }
> +
> +   if (*display_count < 1)
> +      return VK_INCOMPLETE;
> +
> +   c = 0;
> +   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
> +      if (c == plane_index) {
> +         *displays = wsi_display_connector_to_handle(connector);
> +         *display_count = 1;
> +         return VK_SUCCESS;
> +      }
> +      c++;
> +   }
> +
> +   *displays = 0;
> +   *display_count = 0;
>

One of these is wrong.  Either you have zero displays or you have one
display and it's VK_NULL_HANDLE.


> +
> +   return VK_SUCCESS;
> +}
> +
> +/*
> + * 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           *wsi = (struct wsi_display *)
> wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
> +   struct wsi_display_connector *connector =
> wsi_display_connector_from_handle(display);
> +   int                          i;
> +   struct wsi_display_mode      *display_mode;
> +   uint32_t                     property_count_requested =
> *property_count;
> +
> +   i = 0;
> +
> +   if (properties == NULL)
> +      property_count_requested = 0;
> +
> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
> +      if (display_mode->valid && display_mode->connector == connector) {
> +         if (i < property_count_requested) {
> +            properties[i].displayMode = wsi_display_mode_to_handle(dis
> play_mode);
> +            properties[i].parameters.visibleRegion.width =
> display_mode->hdisplay;
> +            properties[i].parameters.visibleRegion.height =
> display_mode->vdisplay;
> +            properties[i].parameters.refreshRate = (uint32_t)
> (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
> +         }
> +         i++;
> +      }
> +   }
> +
> +   *property_count = i;
> +
> +   if (i > property_count_requested && properties != NULL)
> +      return VK_INCOMPLETE;
>

Yeah, I sound like a broken record now.  vk_outarray.  I think this one is
actually correct, so you could leave it alone if you wanted.


> +
> +   return VK_SUCCESS;
> +
> +}
> +
> +/*
> + * 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(m
> ode_khr);
> +
> +   /* XXX use actual values */
>

That would be good.  I don't know enough about KMS to know where you'd get
those.


> +   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_alloc(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;
>

As I commented above, I think we want this to be conditional on whether or
not you actually got a master FD.


> +   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(s
> urface->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_INHERIT_BIT_KHR |
> +                                    VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR);
>

I don't think INHERIT is really appropreate here.  I don't think it's
practical to set the transparency using KMS without doing it as part of the
modeset.  Since it really has to be insde the WSI code, we just want
OPAQUE_BIT for now.


> +
> +   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 VkFormat available_surface_formats[] = {
> +   VK_FORMAT_B8G8R8A8_SRGB,
> +   VK_FORMAT_B8G8R8A8_UNORM,
> +};
>
+
> +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];
> +         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];
> +         f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
> +      }
> +   }
> +
> +   return vk_outarray_status(&out);
> +}
>

=======================================================================

I'm done reviewing for the day.  I'll try to resume tomorrow.  If you'd
like me to continue on the new patches, I can do that.


> +
> +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)
> +{
> +   if (present_modes == NULL) {
> +      *present_mode_count = ARRAY_SIZE(available_present_modes);
> +      return VK_SUCCESS;
> +   }
> +
> +   *present_mode_count = MIN2(*present_mode_count,
> ARRAY_SIZE(available_present_modes));
> +   typed_memcpy(present_modes, available_present_modes,
> *present_mode_count);
> +
> +   if (*present_mode_count < ARRAY_SIZE(available_present_modes))
> +      return VK_INCOMPLETE;
> +   return VK_SUCCESS;
> +}
> +
> +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                     image_handle;
> +
> +   if (chain->base.use_prime_blit)
> +      result = wsi_create_prime_image(&chain->base, create_info,
> &image->base);
> +   else
> +      result = wsi_create_native_image(&chain->base, create_info,
> &image->base);
> +   if (result != VK_SUCCESS)
> +      return result;
> +
> +   ret = drmPrimeFDToHandle(wsi->master_fd, image->base.fd,
> &image_handle);
> +
> +   close(image->base.fd);
> +   image->base.fd = -1;
> +
> +   if (ret < 0)
> +      goto fail_handle;
> +
> +   image->chain = chain;
> +   image->state = wsi_image_idle;
> +   image->fb_id = 0;
> +
> +   /* XXX extract depth and bpp from image somehow */
> +   ret = drmModeAddFB(wsi->master_fd, create_info->imageExtent.width,
> create_info->imageExtent.height,
> +                      24, 32, image->base.row_pitch, image_handle,
> &image->fb_id);
> +
> +   if (ret)
> +      goto fail_fb;
> +
> +   return VK_SUCCESS;
> +
> +fail_fb:
> +   /* fall through */
> +
> +fail_handle:
> +   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;
> +
> +   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;
> +
> +   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);
> +   (void) _wsi_display_queue_next(&(image->chain->base));
> +}
> +
> +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->master_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->master_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;
> +}
> +
> +/* 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;
> +
> +   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);
> +   return result;
> +}
> +
> +/*
> + * 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->master_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->master_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->master_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->master_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->master_fd);
> +   if (!mode_res) {
> +      result = VK_ERROR_INITIALIZATION_FAILED;
> +      goto bail;
> +   }
> +
> +   drm_connector = drmModeGetConnectorCurrent(wsi->master_fd,
> connector->id);
> +   if (!drm_connector) {
> +      result = VK_ERROR_INITIALIZATION_FAILED;
> +      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->master_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->master_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->master_fd, connector->crtc_id,
> image->fb_id, 0, 0,
> +                                 &connector->id, 1,
> &connector->current_drm_mode);
> +
> +            if (ret == 0) {
> +               image->state = wsi_image_displaying;
> +               wsi_display_idle_old_displaying(image);
> +               connector->active = true;
> +               return VK_SUCCESS;
> +            }
> +            break;
> +         case EACCES:
> +            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;
> +
> +   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);
> +
> +   pthread_mutex_unlock(&wsi->wait_mutex);
> +
> +   return result;
> +}
> +
> +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_CR
> EATE_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_alloc(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->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)
> +         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,
> +                     VkPhysicalDevice physical_device,
> +                     int device_fd)
> +{
> +   struct wsi_display *wsi;
> +   VkResult result;
> +
> +   wsi = vk_alloc(alloc, sizeof(*wsi), 8,
> +                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
> +   if (!wsi) {
> +      result = VK_ERROR_OUT_OF_HOST_MEMORY;
> +      goto fail;
> +   }
> +   memset(wsi, '\0', sizeof (*wsi));
> +
> +   wsi->master_fd = -1;
> +   if (drmGetNodeTypeFromFd(device_fd) == DRM_NODE_PRIMARY)
> +      wsi->master_fd = device_fd;
> +   wsi->render_fd = device_fd;
> +
> +   pthread_mutex_init(&wsi->wait_mutex, NULL);
> +   wsi->physical_device = physical_device;
> +   wsi->alloc = alloc;
> +
> +   LIST_INITHEAD(&wsi->display_modes);
> +   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) {
> +         vk_free(wsi->alloc, connector);
> +      }
> +
> +      struct wsi_display_mode *mode, *mode_storage;
> +      LIST_FOR_EACH_ENTRY_SAFE(mode, mode_storage, &wsi->display_modes,
> list) {
> +         vk_free(wsi->alloc, mode);
> +      }
> +
> +      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 503b2a015dc..d38d2efa116 100644
> --- a/src/vulkan/wsi/wsi_common_private.h
> +++ b/src/vulkan/wsi/wsi_common_private.h
> @@ -135,6 +135,16 @@ 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,
> +                     VkPhysicalDevice physical_device,
> +                     int device_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.15.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>

[-- Attachment #1.2: Type: text/html, Size: 122128 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-14  1:10   ` Jason Ekstrand
@ 2018-02-15 17:46     ` Keith Packard
  2018-02-23 23:00       ` Jason Ekstrand
  0 siblings, 1 reply; 24+ messages in thread
From: Keith Packard @ 2018-02-15 17:46 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: ML mesa-dev, Maling list - DRI developers


[-- Attachment #1.1: Type: text/plain, Size: 8805 bytes --]

Jason Ekstrand <jason@jlekstrand.net> writes:

> It seems a little odd to me to default to opening the master node and then
> fall back to the render node if it doesn't work.  I suppose that's probably
> ok so long as we ensure that vkGetPhysicalDeviceDisplayPropertiesKHR
> returns no displays if we're on the render node.
>
> We could always go back to the DRM fd extension idea but I'm not coming up
> with something nice and clean in the 60 seconds I've thought about it.

As I said in the last comments about this section, Dave Airlie and I
added this code only recently so that we could test this extension
without also needing the kernel and X leasing changes.

I think we should decide how to enable this functionality "for real",
and I have two easy options:

 1) Use my KEITHP_kms_display extension (presumably renamed MESA), which
    exposes a way to pass the DRM fd from the application into the
    driver. This makes it possible for the application to get the FD
    through any mechanism at all (including RandR or the new Wayland
    extension) and leave that out of the Vulkan code entirely.

 2) Add a new extension which passes a new data structure that directs
    the driver to open either the Render or Primary nodes.

When this is done, we can switch from the current code which tries to
open the Primary node whenever the KHR_display extension is requested.

> Would it make anything easier if we just storred the DRM struct here?  "No"
> is a perfectly valid answer.

Nope -- once we add the acquire_xlib extension, we get modes through
either X or DRM, depending on whether we're pre-lease or post-lease.

> Any particular reason why the list of modes is global and not in the
> connector?  It seems like it would be a tiny bit more efficient and
> convenient to put the list in the connector.

I think you're right. I have some vague memory of a lifetime issue with
connectors, but can't think of what it might be, even after reviewing
the relevant parts of the Vulkan spec. I've gone ahead and changed it;
seems to work fine.

>> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list)
>> +      if (display_mode->connector == connector)
>> +         display_mode->valid = false;
>>
>
> Please use braces for loops containing more than one line.

Well, that was easy to fix -- the condition is now gone :-)

> Since we're allocating these in a physical device query, we need to use the
> INSTANCE scope.  the OBJECT scope is intended for vkCreate functions to
> allocated data that will live no longer than the associated vkDestroy
> function.

Thanks! The whole Vulkan memory model remains a mystery to me.

I've changed allocation of wsi_display_mode and wsi_display_connector to
use SCOPE_INSTANCE. VkIceSurfaceDisplay, wsi_display_fence and
wsi_display_swapchain remain using SCOPE_OBJECT.

I've also changed *all* instances of vk_alloc to use
vk_zalloc. These are all small data structures allocated only during
application startup, so I think the benefit of known memory contents is
worth the cost of memset.

> Hooray for obviously false fixed constants!
>
> I know the answer to this will be "EDIDs lie, never trust them!" but can we
> get the real value somehow?  As someone who has a 13" laptop with a
> 3200x1800 display, I know that number isn't always right. :-)

Yes, we could dig the real value out of the EDID, but we'd have to parse
the entire EDID to manage that. I don't want to stick an EDID parser
directly in Mesa, so I'm kinda waiting for someone to create a separate
EDID parsing library that the X server, Mesa and others can share. Until
then, I'd prefer to just lie here.

> double-;;

Thx. I remember seeing this while reviewing patches and forgot all about
it...

> From the Vulkan spec:
>
>     Note:
>     For devices which have no natural value to return here, implementations
> *should* return the maximum resolution supported.
>
> We should walk the list and pick the biggest one.

I did this intentionally -- most monitors have a preferred resolution,
which is their native pixel size. And, we want to tell applications to
use that size, even if the monitor offers a larger (presumabl scaled)
resolution in their mode list.

> See question about MM_PER_PIXEL above

Yeah, see response about not boiling the EDID ocean above ;-)

> I know i915 can do better at least in some cases.  Is there a practical way
> to expose this?  If not, I'm fine with just exposing IDENTITY.

I'm not seeing this exposed through the common DRM mode interfaces
yet. We should probably consider adding this to the kernel and then
adding it here.

> This error is not allowed for this function.  We should just write 0 to
> property_count and return VK_SUCCESS.  Maybe add some asserts for debug
> builds if you really think this shouldn't ever happen.

I bet it will happen if you VT switch away and then try this function.

I've added this at the end of the function:

        bail:
           *property_count = 0;
           return VK_SUCCESS;

> This could be made a lot easier with vk_outarray:
...
> Again, vk_outarray is your friend.
...
> This isn't correct.  The loop below could turn up no displays.  Again,
> vk_outarray is your friend.
...
> Yeah, I sound like a broken record now.  vk_outarray.  I think this one is
> actually correct, so you could leave it alone if you wanted.

I've replaced all of the array returns with vk_outarray; I'm afraid I
found a bunch of open-coded versions of this and didn't stumble on
vk_outarray until too late. Thanks!

>> +   /* XXX use actual values */
>>
>
> That would be good.  I don't know enough about KMS to know where you'd get
> those.

I think the real values will only be useful once we add multi-plane
support to this code. At this point, with only a single plane, I'm not
sure it's interesting to be able to pan it around? So, these values are
'safe', and sufficient to display a single plane covering the full
screen. When we want more, we can go actually hook up multi-plane
support, which will require more work in the window system extensions to
allow applications to request the desired number of planes.

>> +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;
>>
>
> As I commented above, I think we want this to be conditional on whether or
> not you actually got a master FD.

With just KHR_display, you can't get here without already having needed
a master FD -- you need a VkSurfaceKHR, and you create one of those
using vkCreateDisplayPlaneSurfaceKHR, which requires a plane and a mode;
a mode comes from vkGetDisplayModePropertiesKHR or
vkCreateDisplayModeKHR, both of which requires a VkDisplayKHR. A
VkDisplayKHR comes from vkGetPhysicalDeviceDisplayPropertiesKHR, which
fails if you don't have a master FD.

Once we have AcquireXlibDisplay, then you will be able to create display
surfaces before you have a master FD as you can create modes using X
resources. And, you can't actually tell if you will be able to get a
master FD until you try...

>> +   caps->supportedCompositeAlpha = (VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
>> +                                    VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR);
>>
>
> I don't think INHERIT is really appropreate here.  I don't think it's
> practical to set the transparency using KMS without doing it as part of the
> modeset.  Since it really has to be insde the WSI code, we just want
> OPAQUE_BIT for now.

Yeah, another area which really needs to wait until we figure out what
we want for multi-plane support. If you only have one plane, you don't
exactly have any alpha compositing.

>  I'm done reviewing for the day.  I'll try to resume tomorrow.  If you'd
>  like me to continue on the new patches, I can do that.

Thanks so much for your review so far; getting rid of the open-coded
property queries is really valuable, along with using vk_zalloc
everywhere.

The "new" patches are exactly the same code changes, just split into
core/anv/radv bits to make Dave Airlie happy. Feel free to either
continue with the old patches or to switch over. I've pushed out a
series of tiny patches which address each of the review comments above
separately if you want to check those over. I'll merge them into the
main patch series at some point.

-- 
-keith

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-15 17:46     ` Keith Packard
@ 2018-02-23 23:00       ` Jason Ekstrand
  2018-02-23 23:43         ` Keith Packard
  0 siblings, 1 reply; 24+ messages in thread
From: Jason Ekstrand @ 2018-02-23 23:00 UTC (permalink / raw)
  To: Keith Packard; +Cc: ML mesa-dev, Maling list - DRI developers


[-- Attachment #1.1: Type: text/plain, Size: 10105 bytes --]

On Thu, Feb 15, 2018 at 9:46 AM, Keith Packard <keithp@keithp.com> wrote:

> Jason Ekstrand <jason@jlekstrand.net> writes:
>
> > It seems a little odd to me to default to opening the master node and
> then
> > fall back to the render node if it doesn't work.  I suppose that's
> probably
> > ok so long as we ensure that vkGetPhysicalDeviceDisplayPropertiesKHR
> > returns no displays if we're on the render node.
> >
> > We could always go back to the DRM fd extension idea but I'm not coming
> up
> > with something nice and clean in the 60 seconds I've thought about it.
>
> As I said in the last comments about this section, Dave Airlie and I
> added this code only recently so that we could test this extension
> without also needing the kernel and X leasing changes.
>
> I think we should decide how to enable this functionality "for real",
> and I have two easy options:
>
>  1) Use my KEITHP_kms_display extension (presumably renamed MESA), which
>     exposes a way to pass the DRM fd from the application into the
>     driver. This makes it possible for the application to get the FD
>     through any mechanism at all (including RandR or the new Wayland
>     extension) and leave that out of the Vulkan code entirely.
>
>  2) Add a new extension which passes a new data structure that directs
>     the driver to open either the Render or Primary nodes.
>
> When this is done, we can switch from the current code which tries to
> open the Primary node whenever the KHR_display extension is requested.
>

I think I like option 1.  If the client knows the difference between render
and primary for 2, then they are most likely already opening the master
node themselves or at least have access to the FD.

For an application that just wants to draw some stuff on the screen and is
ok with letting Vulkan fully handle KMS for it, the current code may be a
fine solution.

Sorry, I'm just not feeling all that opinionated about this at the moment.
:-)


> > Would it make anything easier if we just storred the DRM struct here?
> "No"
> > is a perfectly valid answer.
>
> Nope -- once we add the acquire_xlib extension, we get modes through
> either X or DRM, depending on whether we're pre-lease or post-lease.
>

Sounds good.


> > Any particular reason why the list of modes is global and not in the
> > connector?  It seems like it would be a tiny bit more efficient and
> > convenient to put the list in the connector.
>
> I think you're right. I have some vague memory of a lifetime issue with
> connectors, but can't think of what it might be, even after reviewing
> the relevant parts of the Vulkan spec. I've gone ahead and changed it;
> seems to work fine.
>
> >> +   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list)
> >> +      if (display_mode->connector == connector)
> >> +         display_mode->valid = false;
> >>
> >
> > Please use braces for loops containing more than one line.
>
> Well, that was easy to fix -- the condition is now gone :-)
>

Even better!


> > Since we're allocating these in a physical device query, we need to use
> the
> > INSTANCE scope.  the OBJECT scope is intended for vkCreate functions to
> > allocated data that will live no longer than the associated vkDestroy
> > function.
>
> Thanks! The whole Vulkan memory model remains a mystery to me.
>
> I've changed allocation of wsi_display_mode and wsi_display_connector to
> use SCOPE_INSTANCE. VkIceSurfaceDisplay, wsi_display_fence and
> wsi_display_swapchain remain using SCOPE_OBJECT.
>

That sounds correct to me.


> I've also changed *all* instances of vk_alloc to use
> vk_zalloc. These are all small data structures allocated only during
> application startup, so I think the benefit of known memory contents is
> worth the cost of memset.
>
> > Hooray for obviously false fixed constants!
> >
> > I know the answer to this will be "EDIDs lie, never trust them!" but can
> we
> > get the real value somehow?  As someone who has a 13" laptop with a
> > 3200x1800 display, I know that number isn't always right. :-)
>
> Yes, we could dig the real value out of the EDID, but we'd have to parse
> the entire EDID to manage that. I don't want to stick an EDID parser
> directly in Mesa, so I'm kinda waiting for someone to create a separate
> EDID parsing library that the X server, Mesa and others can share. Until
> then, I'd prefer to just lie here.
>

Clearly, we need systemd-edidd. :-)


> > double-;;
>
> Thx. I remember seeing this while reviewing patches and forgot all about
> it...
>
> > From the Vulkan spec:
> >
> >     Note:
> >     For devices which have no natural value to return here,
> implementations
> > *should* return the maximum resolution supported.
> >
> > We should walk the list and pick the biggest one.
>
> I did this intentionally -- most monitors have a preferred resolution,
> which is their native pixel size. And, we want to tell applications to
> use that size, even if the monitor offers a larger (presumabl scaled)
> resolution in their mode list.
>

Yes, *if* it has a preferred resolution, we should return that one.  If it
doesn't, we should walk the list and return the largest instead of just
defaulting to 1024x768.  At least that's what the spec seems to say to me.


> > See question about MM_PER_PIXEL above
>
> Yeah, see response about not boiling the EDID ocean above ;-)
>
> > I know i915 can do better at least in some cases.  Is there a practical
> way
> > to expose this?  If not, I'm fine with just exposing IDENTITY.
>
> I'm not seeing this exposed through the common DRM mode interfaces
> yet. We should probably consider adding this to the kernel and then
> adding it here.
>

That's fine.


> > This error is not allowed for this function.  We should just write 0 to
> > property_count and return VK_SUCCESS.  Maybe add some asserts for debug
> > builds if you really think this shouldn't ever happen.
>
> I bet it will happen if you VT switch away and then try this function.
>
> I've added this at the end of the function:
>
>         bail:
>            *property_count = 0;
>            return VK_SUCCESS;
>

Sounds good.


> > This could be made a lot easier with vk_outarray:
> ...
> > Again, vk_outarray is your friend.
> ...
> > This isn't correct.  The loop below could turn up no displays.  Again,
> > vk_outarray is your friend.
> ...
> > Yeah, I sound like a broken record now.  vk_outarray.  I think this one
> is
> > actually correct, so you could leave it alone if you wanted.
>
> I've replaced all of the array returns with vk_outarray; I'm afraid I
> found a bunch of open-coded versions of this and didn't stumble on
> vk_outarray until too late. Thanks!
>

You're welcome.  I'm so glad Chad made that little helper.  50-75% of the
open-coded versions were wrong.


> >> +   /* XXX use actual values */
> >>
> >
> > That would be good.  I don't know enough about KMS to know where you'd
> get
> > those.
>
> I think the real values will only be useful once we add multi-plane
> support to this code. At this point, with only a single plane, I'm not
> sure it's interesting to be able to pan it around? So, these values are
> 'safe', and sufficient to display a single plane covering the full
> screen. When we want more, we can go actually hook up multi-plane
> support, which will require more work in the window system extensions to
> allow applications to request the desired number of planes.
>

Sounds good to me.


> >> +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;
> >>
> >
> > As I commented above, I think we want this to be conditional on whether
> or
> > not you actually got a master FD.
>
> With just KHR_display, you can't get here without already having needed
> a master FD -- you need a VkSurfaceKHR, and you create one of those
> using vkCreateDisplayPlaneSurfaceKHR, which requires a plane and a mode;
> a mode comes from vkGetDisplayModePropertiesKHR or
> vkCreateDisplayModeKHR, both of which requires a VkDisplayKHR. A
> VkDisplayKHR comes from vkGetPhysicalDeviceDisplayPropertiesKHR, which
> fails if you don't have a master FD.
>

Right.  That makes sense.


> Once we have AcquireXlibDisplay, then you will be able to create display
> surfaces before you have a master FD as you can create modes using X
> resources. And, you can't actually tell if you will be able to get a
> master FD until you try...
>

Yeah


> >> +   caps->supportedCompositeAlpha = (VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
> |
> >> +                                    VK_COMPOSITE_ALPHA_OPAQUE_BIT_
> KHR);
> >>
> >
> > I don't think INHERIT is really appropreate here.  I don't think it's
> > practical to set the transparency using KMS without doing it as part of
> the
> > modeset.  Since it really has to be insde the WSI code, we just want
> > OPAQUE_BIT for now.
>
> Yeah, another area which really needs to wait until we figure out what
> we want for multi-plane support. If you only have one plane, you don't
> exactly have any alpha compositing.
>

Yup.  Let's just drop INHERIT and only advertise OPAQUE.


> >  I'm done reviewing for the day.  I'll try to resume tomorrow.  If you'd
> >  like me to continue on the new patches, I can do that.
>
> Thanks so much for your review so far; getting rid of the open-coded
> property queries is really valuable, along with using vk_zalloc
> everywhere.
>
> The "new" patches are exactly the same code changes, just split into
> core/anv/radv bits to make Dave Airlie happy. Feel free to either
> continue with the old patches or to switch over. I've pushed out a
> series of tiny patches which address each of the review comments above
> separately if you want to check those over. I'll merge them into the
> main patch series at some point.
>
> --
> -keith
>

[-- Attachment #1.2: Type: text/html, Size: 14480 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-23 23:00       ` Jason Ekstrand
@ 2018-02-23 23:43         ` Keith Packard
  2018-02-24  0:51           ` Jason Ekstrand
  0 siblings, 1 reply; 24+ messages in thread
From: Keith Packard @ 2018-02-23 23:43 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: ML mesa-dev, Maling list - DRI developers


[-- Attachment #1.1: Type: text/plain, Size: 2085 bytes --]

Jason Ekstrand <jason@jlekstrand.net> writes:

> I think I like option 1 (KEITHP_kms_display).  If the client knows the
> difference between render and primary for 2, then they are most likely
> already opening the master node themselves or at least have access to
> the FD.

Ok, I'll work on cleaning up that extension and renaming it. I have no
idea how to get new words into the Vulkan spec, but it would be good to
have that done too.

I guess the question is whether I should bother to leave the current
try-to-open-primary kludge in place. In good news, under X, both radv
and anv "fail" to use the primary device as another master is already
running, so at least we aren't running with a primary FD open?

> Sorry, I'm just not feeling all that opinionated about this at the moment.
> :-)

No more than I; either way is fine with me, if you're happy to use
something like the existing code I've got, that's even nicer.

> Clearly, we need systemd-edidd. :-)

A library would be nice; we have the edid data everywhere, we just don't
have it in a useful form except inside the X server and kernel.

> Yes, *if* it has a preferred resolution, we should return that one.  If it
> doesn't, we should walk the list and return the largest instead of just
> defaulting to 1024x768.  At least that's what the spec seems to say to
> me.

Oh. I totally missed that part. Yeah, that's just wrong. I've just
pushed a patch that finds the largest mode when there isn't a preferred
one. Oddly, I have no devices here which don't specify a preferred mode,
so it will be somewhat difficult to test...

> Yup.  Let's just drop INHERIT and only advertise OPAQUE.

Done.

I've updated my drm-lease branch with all of these changes merged into
the existing patches (and so noted), plus the new patch described above
which looks for the largest mode when no preferred mode is specified.

Thanks again for all of your careful review; while we haven't changed
any significant semantics, we have found a bunch of outright bugs in the
code.

-- 
-keith

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-23 23:43         ` Keith Packard
@ 2018-02-24  0:51           ` Jason Ekstrand
  2018-03-12 23:02             ` Keith Packard
  0 siblings, 1 reply; 24+ messages in thread
From: Jason Ekstrand @ 2018-02-24  0:51 UTC (permalink / raw)
  To: Keith Packard; +Cc: ML mesa-dev, Maling list - DRI developers


[-- Attachment #1.1: Type: text/plain, Size: 2924 bytes --]

On Fri, Feb 23, 2018 at 3:43 PM, Keith Packard <keithp@keithp.com> wrote:

> Jason Ekstrand <jason@jlekstrand.net> writes:
>
> > I think I like option 1 (KEITHP_kms_display).  If the client knows the
> > difference between render and primary for 2, then they are most likely
> > already opening the master node themselves or at least have access to
> > the FD.
>
> Ok, I'll work on cleaning up that extension and renaming it. I have no
> idea how to get new words into the Vulkan spec, but it would be good to
> have that done too.
>

Once we're sure that's what we want, create an MR against the spec that
just adds enough to the XML to reserve your extension number.  That will
get merged almost immediately.  Then make a second one with the actual
extension text and we'll iterate on that either in Khronos gitlab or, if
you prefer, you can send it as a patch to mesa-dev and then make a Khrons
MR once it's baked.


> I guess the question is whether I should bother to leave the current
> try-to-open-primary kludge in place. In good news, under X, both radv
> and anv "fail" to use the primary device as another master is already
> running, so at least we aren't running with a primary FD open?
>

See also my comments about GEM handle ownership.


> > Sorry, I'm just not feeling all that opinionated about this at the
> moment.
> > :-)
>
> No more than I; either way is fine with me, if you're happy to use
> something like the existing code I've got, that's even nicer.
>
> > Clearly, we need systemd-edidd. :-)
>
> A library would be nice; we have the edid data everywhere, we just don't
> have it in a useful form except inside the X server and kernel.
>

Yeah, in the scary new world of Wayland compositors, having an edid library
would be a very good thing.  No sense in having everyone fail to handle it
properly themselves.


> > Yes, *if* it has a preferred resolution, we should return that one.  If
> it
> > doesn't, we should walk the list and return the largest instead of just
> > defaulting to 1024x768.  At least that's what the spec seems to say to
> > me.
>
> Oh. I totally missed that part. Yeah, that's just wrong. I've just
> pushed a patch that finds the largest mode when there isn't a preferred
> one. Oddly, I have no devices here which don't specify a preferred mode,
> so it will be somewhat difficult to test...
>
> > Yup.  Let's just drop INHERIT and only advertise OPAQUE.
>
> Done.
>
> I've updated my drm-lease branch with all of these changes merged into
> the existing patches (and so noted), plus the new patch described above
> which looks for the largest mode when no preferred mode is specified.
>
> Thanks again for all of your careful review; while we haven't changed
> any significant semantics, we have found a bunch of outright bugs in the
> code.
>

Glad to help. :-)  I figure I should learn something about KMS one day and
reviewing this is as good an opportunity as any.

[-- Attachment #1.2: Type: text/html, Size: 4235 bytes --]

[-- Attachment #2: Type: text/plain, Size: 157 bytes --]

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-24  0:51           ` Jason Ekstrand
@ 2018-03-12 23:02             ` Keith Packard
  0 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-03-12 23:02 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: ML mesa-dev, Maling list - DRI developers


[-- Attachment #1.1: Type: text/plain, Size: 974 bytes --]

Jason Ekstrand <jason@jlekstrand.net> writes:

> On Fri, Feb 23, 2018 at 3:43 PM, Keith Packard <keithp@keithp.com> wrote:
>
> Once we're sure that's what we want, create an MR against the spec that
> just adds enough to the XML to reserve your extension number.  That will
> get merged almost immediately.  Then make a second one with the actual
> extension text and we'll iterate on that either in Khronos gitlab or, if
> you prefer, you can send it as a patch to mesa-dev and then make a Khrons
> MR once it's baked.

I just wrote up the full extension description for both extensions I
need (the one for passing a KMS fd to the driver, and the second to get
the GPU timestamp for doing GOOGLE_display_timing):

        https://github.com/keith-packard/Vulkan-Docs

> See also my comments about GEM handle ownership.

Yeah, I think I've got that all cleaned up now -- the code no longer
shares the same file for rendering and display.

-- 
-keith

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
                     ` (2 preceding siblings ...)
  2018-02-14  1:10   ` Jason Ekstrand
@ 2018-03-29  6:59   ` Mao, David
  2018-03-29 15:05     ` Keith Packard
  3 siblings, 1 reply; 24+ messages in thread
From: Mao, David @ 2018-03-29  6:59 UTC (permalink / raw)
  To: Keith Packard, mesa-dev; +Cc: dri-devel

Hi Keith,
If I read the patch correctly, the plane has been interpreted as the same as connector, and the stackIndex is the index of connector of current device.
Is it by intentional?
If the hardware don't have underlay/overlay supported, is it better to always report plane 0 rather than pretend to have multiple plane?

Thanks.
Best Regards,
David

-----Original Message-----
From: dri-devel [mailto:dri-devel-bounces@lists.freedesktop.org] On Behalf Of Keith Packard
Sent: Saturday, February 10, 2018 12:45 PM
To: mesa-dev@lists.freedesktop.org
Cc: Keith Packard <keithp@keithp.com>; dri-devel@lists.freedesktop.org
Subject: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM

This adds support for the KHR_display extension to the anv and radv
Vulkan drivers. The drivers now attempt to open the master DRM node
when the KHR_display extension is requested so that the common winsys
code can perform the necessary operations.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 configure.ac                           |    1 +
 meson.build                            |    4 +-
 src/amd/vulkan/Makefile.am             |    8 +
 src/amd/vulkan/Makefile.sources        |    3 +
 src/amd/vulkan/meson.build             |    7 +
 src/amd/vulkan/radv_device.c           |   28 +-
 src/amd/vulkan/radv_extensions.py      |    7 +-
 src/amd/vulkan/radv_private.h          |    2 +
 src/amd/vulkan/radv_wsi.c              |    3 +-
 src/amd/vulkan/radv_wsi_display.c      |  143 ++++
 src/intel/Makefile.sources             |    3 +
 src/intel/Makefile.vulkan.am           |    7 +
 src/intel/vulkan/anv_device.c          |   18 +-
 src/intel/vulkan/anv_extensions.py     |    1 +
 src/intel/vulkan/anv_extensions_gen.py |    5 +-
 src/intel/vulkan/anv_wsi.c             |    3 +-
 src/intel/vulkan/anv_wsi_display.c     |  129 +++
 src/intel/vulkan/meson.build           |    7 +
 src/vulkan/Makefile.am                 |    7 +
 src/vulkan/Makefile.sources            |    4 +
 src/vulkan/wsi/meson.build             |   10 +
 src/vulkan/wsi/wsi_common.c            |   19 +-
 src/vulkan/wsi/wsi_common.h            |    5 +-
 src/vulkan/wsi/wsi_common_display.c    | 1368 ++++++++++++++++++++++++++++++++
 src/vulkan/wsi/wsi_common_display.h    |   72 ++
 src/vulkan/wsi/wsi_common_private.h    |   10 +
 26 files changed, 1858 insertions(+), 16 deletions(-)
 create mode 100644 src/amd/vulkan/radv_wsi_display.c
 create mode 100644 src/intel/vulkan/anv_wsi_display.c
 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 8ed606c7694..46318365603 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1849,6 +1849,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 b39e2f8ab96..aeb7f5e2917 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'
   else
@@ -257,6 +258,7 @@ if _platforms != ''
   with_platform_wayland = _split.contains('wayland')
   with_platform_drm = _split.contains('drm')
   with_platform_surfaceless = _split.contains('surfaceless')
+  with_platform_display = _split.contains('display')
   egl_native_platform = _split[0]
 endif
 
diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
index 61025968942..061b8144b88 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -76,6 +76,14 @@ VULKAN_LIB_DEPS = \
 	$(DLOPEN_LIBS) \
 	-lm
 
+if HAVE_PLATFORM_DISPLAY
+AM_CPPFLAGS += \
+	-DVK_USE_PLATFORM_DISPLAY_KHR
+
+VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
+
+endif
+
 if HAVE_PLATFORM_X11
 AM_CPPFLAGS += \
 	$(XCB_DRI3_CFLAGS) \
diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources
index a510d88d965..618a6cdaed0 100644
--- a/src/amd/vulkan/Makefile.sources
+++ b/src/amd/vulkan/Makefile.sources
@@ -78,6 +78,9 @@ VULKAN_WSI_WAYLAND_FILES := \
 VULKAN_WSI_X11_FILES := \
 	radv_wsi_x11.c
 
+VULKAN_WSI_DISPLAY_FILES := \
+	radv_wsi_display.c
+
 VULKAN_GENERATED_FILES := \
 	radv_entrypoints.c \
 	radv_entrypoints.h \
diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build
index 0a7b7c0bf3c..b7bb1075e7d 100644
--- a/src/amd/vulkan/meson.build
+++ b/src/amd/vulkan/meson.build
@@ -112,6 +112,13 @@ if with_platform_wayland
   libradv_files += files('radv_wsi_wayland.c')
 endif
 
+if with_platform_display
+  radv_flags += [
+    '-DVK_USE_PLATFORM_DISPLAY_KHR',
+  ]
+  libradv_files += files('radv_wsi_display.c')
+endif
+
 libvulkan_radeon = shared_library(
   'vulkan_radeon',
   [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c],
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index 09bb382eeb8..adf33eb35dc 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -191,9 +191,26 @@ radv_physical_device_init(struct radv_physical_device *device,
 	const char *path = drm_device->nodes[DRM_NODE_RENDER];
 	VkResult result;
 	drmVersionPtr version;
-	int fd;
-
-	fd = open(path, O_RDWR | O_CLOEXEC);
+	int fd = -1;
+
+        if (instance->khr_display_requested) {
+                fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC);
+                if (fd >= 0) {
+                        uint32_t accel_working = 0;
+                        struct drm_amdgpu_info request = {
+                                .return_pointer = (uintptr_t)&accel_working,
+                                .return_size = sizeof(accel_working),
+                                .query = AMDGPU_INFO_ACCEL_WORKING
+                        };
+
+                        if (drmCommandWrite(fd, DRM_AMDGPU_INFO, &request, sizeof (struct drm_amdgpu_info)) < 0 || !accel_working) {
+                                close(fd);
+                                fd = -1;
+                        }
+                }
+        }
+        if (fd < 0)
+                fd = open(path, O_RDWR | O_CLOEXEC);
 	if (fd < 0)
 		return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
 
@@ -209,6 +226,7 @@ radv_physical_device_init(struct radv_physical_device *device,
 		close(fd);
 		return VK_ERROR_INCOMPATIBLE_DRIVER;
 	}
+
 	drmFreeVersion(version);
 
 	device->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
@@ -387,6 +405,7 @@ VkResult radv_CreateInstance(
 {
 	struct radv_instance *instance;
 	VkResult result;
+        bool khr_display_requested = false;
 
 	assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO);
 
@@ -411,6 +430,8 @@ VkResult radv_CreateInstance(
 	        const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i];
 		if (!radv_instance_extension_supported(ext_name))
 			return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT);
+                if (strcmp(ext_name, VK_KHR_DISPLAY_EXTENSION_NAME) == 0)
+                        khr_display_requested = true;
 	}
 
 	instance = vk_zalloc2(&default_alloc, pAllocator, sizeof(*instance), 8,
@@ -427,6 +448,7 @@ VkResult radv_CreateInstance(
 
 	instance->apiVersion = client_version;
 	instance->physicalDeviceCount = -1;
+        instance->khr_display_requested = khr_display_requested;
 
 	result = vk_debug_report_instance_init(&instance->debug_report_callbacks);
 	if (result != VK_SUCCESS) {
diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py
index d761895d3a0..24cab8cbb39 100644
--- a/src/amd/vulkan/radv_extensions.py
+++ b/src/amd/vulkan/radv_extensions.py
@@ -81,6 +81,7 @@ EXTENSIONS = [
     Extension('VK_KHR_wayland_surface',                   6, 'VK_USE_PLATFORM_WAYLAND_KHR'),
     Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
+    Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, '!ANDROID'),
     Extension('VK_EXT_debug_report',                      9, True),
     Extension('VK_EXT_discard_rectangles',                1, True),
@@ -168,7 +169,7 @@ _TEMPLATE = Template(COPYRIGHT + """
 #include "vk_util.h"
 
 /* Convert the VK_USE_PLATFORM_* defines to booleans */
-%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
+%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
 #ifdef VK_USE_PLATFORM_${platform}_KHR
 #   undef VK_USE_PLATFORM_${platform}_KHR
 #   define VK_USE_PLATFORM_${platform}_KHR true
@@ -187,7 +188,9 @@ _TEMPLATE = Template(COPYRIGHT + """
 
 #define RADV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
                          VK_USE_PLATFORM_XCB_KHR || \\
-                         VK_USE_PLATFORM_XLIB_KHR)
+                         VK_USE_PLATFORM_XLIB_KHR || \\
+                         VK_USE_PLATFORM_DISPLAY_KHR)
+
 
 bool
 radv_instance_extension_supported(const char *name)
diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
index be9e8f43964..1e3719bcc4f 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -75,6 +75,7 @@ typedef uint32_t xcb_window_t;
 #include "radv_entrypoints.h"
 
 #include "wsi_common.h"
+#include "wsi_common_display.h"
 
 #define ATI_VENDOR_ID 0x1002
 
@@ -300,6 +301,7 @@ struct radv_instance {
 	uint64_t perftest_flags;
 
 	struct vk_debug_report_instance             debug_report_callbacks;
+        bool                                        khr_display_requested;
 };
 
 VkResult radv_init_wsi(struct radv_physical_device *physical_device);
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
index e016e837102..5ec872a63d0 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->local_fd);
 }
 
 void
diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
new file mode 100644
index 00000000000..b0a4db0344b
--- /dev/null
+++ b/src/amd/vulkan/radv_wsi_display.c
@@ -0,0 +1,143 @@
+/*
+ * 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 <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "radv_private.h"
+#include "radv_cs.h"
+#include "util/disk_cache.h"
+#include "util/strtod.h"
+#include "vk_util.h"
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <amdgpu.h>
+#include <amdgpu_drm.h>
+#include "winsys/amdgpu/radv_amdgpu_winsys_public.h"
+#include "ac_llvm_util.h"
+#include "vk_format.h"
+#include "sid.h"
+#include "util/debug.h"
+#include "wsi_common_display.h"
+
+#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
+
+VkResult
+radv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice             physical_device,
+                                           uint32_t                     *property_count,
+                                           VkDisplayPropertiesKHR       *properties)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_properties(physical_device,
+                                                             &pdevice->wsi_device,
+                                                             property_count,
+                                                             properties);
+}
+
+VkResult
+radv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice                physical_device,
+                                                uint32_t                        *property_count,
+                                                VkDisplayPlanePropertiesKHR     *properties)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_plane_properties(physical_device,
+                                                                   &pdevice->wsi_device,
+                                                                   property_count,
+                                                                   properties);
+}
+
+VkResult
+radv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice               physical_device,
+                                         uint32_t                       plane_index,
+                                         uint32_t                       *display_count,
+                                         VkDisplayKHR                   *displays)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_plane_supported_displays(physical_device,
+                                                           &pdevice->wsi_device,
+                                                           plane_index,
+                                                           display_count,
+                                                           displays);
+}
+
+
+VkResult
+radv_GetDisplayModePropertiesKHR(VkPhysicalDevice               physical_device,
+                                 VkDisplayKHR                   display,
+                                 uint32_t                       *property_count,
+                                 VkDisplayModePropertiesKHR     *properties)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_mode_properties(physical_device,
+                                                  &pdevice->wsi_device,
+                                                  display,
+                                                  property_count,
+                                                  properties);
+}
+
+VkResult
+radv_CreateDisplayModeKHR(VkPhysicalDevice                      physical_device,
+                          VkDisplayKHR                          display,
+                          const VkDisplayModeCreateInfoKHR      *create_info,
+                          const VkAllocationCallbacks           *allocator,
+                          VkDisplayModeKHR                      *mode)
+{
+   return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+
+VkResult
+radv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice                    physical_device,
+                                    VkDisplayModeKHR                    mode_khr,
+                                    uint32_t                            plane_index,
+                                    VkDisplayPlaneCapabilitiesKHR       *capabilities)
+{
+   RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device);
+
+   return wsi_get_display_plane_capabilities(physical_device,
+                                             &pdevice->wsi_device,
+                                             mode_khr,
+                                             plane_index,
+                                             capabilities);
+}
+
+VkResult
+radv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instance,
+                                  const VkDisplaySurfaceCreateInfoKHR   *create_info,
+                                  const VkAllocationCallbacks           *allocator,
+                                  VkSurfaceKHR                          *surface)
+{
+   RADV_FROM_HANDLE(radv_instance, instance, _instance);
+   const VkAllocationCallbacks *alloc;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &instance->alloc;
+
+   return wsi_create_display_surface(_instance, alloc, create_info, surface);
+}
diff --git a/src/intel/Makefile.sources b/src/intel/Makefile.sources
index 9595bf42582..6c142729d94 100644
--- a/src/intel/Makefile.sources
+++ b/src/intel/Makefile.sources
@@ -240,6 +240,9 @@ VULKAN_WSI_WAYLAND_FILES := \
 VULKAN_WSI_X11_FILES := \
 	vulkan/anv_wsi_x11.c
 
+VULKAN_WSI_DISPLAY_FILES := \
+	vulkan/anv_wsi_display.c
+
 VULKAN_GEM_FILES := \
 	vulkan/anv_gem.c
 
diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am
index 23fa877e77d..7c428a799d7 100644
--- a/src/intel/Makefile.vulkan.am
+++ b/src/intel/Makefile.vulkan.am
@@ -187,6 +187,13 @@ VULKAN_SOURCES += $(VULKAN_WSI_WAYLAND_FILES)
 VULKAN_LIB_DEPS += $(WAYLAND_CLIENT_LIBS)
 endif
 
+if HAVE_PLATFORM_DISPLAY
+VULKAN_CPPFLAGS += \
+	-DVK_USE_PLATFORM_DISPLAY_KHR
+
+VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
+endif
+
 noinst_LTLIBRARIES += vulkan/libvulkan_common.la
 vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
 vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS)
diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c
index 86c1bdc1d51..9614907fda3 100644
--- a/src/intel/vulkan/anv_device.c
+++ b/src/intel/vulkan/anv_device.c
@@ -277,14 +277,25 @@ anv_physical_device_init_uuids(struct anv_physical_device *device)
 static VkResult
 anv_physical_device_init(struct anv_physical_device *device,
                          struct anv_instance *instance,
-                         const char *path)
+                         const char *primary_path,
+                         const char *render_path)
 {
    VkResult result;
-   int fd;
+   int fd = -1;
+   const char *path;
 
    brw_process_intel_debug_variable();
 
-   fd = open(path, O_RDWR | O_CLOEXEC);
+   if (instance->enabled_extensions.KHR_display) {
+      path = primary_path;
+      fd = open(path, O_RDWR | O_CLOEXEC);
+   }
+
+   if (fd < 0) {
+      path = render_path;
+      fd = open(path, O_RDWR | O_CLOEXEC);
+   }
+
    if (fd < 0)
       return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER);
 
@@ -652,6 +663,7 @@ anv_enumerate_devices(struct anv_instance *instance)
 
          result = anv_physical_device_init(&instance->physicalDevice,
                         instance,
+                        devices[i]->nodes[DRM_NODE_PRIMARY],
                         devices[i]->nodes[DRM_NODE_RENDER]);
          if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
             break;
diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py
index 581921e62a1..978a219e2b2 100644
--- a/src/intel/vulkan/anv_extensions.py
+++ b/src/intel/vulkan/anv_extensions.py
@@ -83,6 +83,7 @@ EXTENSIONS = [
     Extension('VK_KHR_wayland_surface',                   6, 'VK_USE_PLATFORM_WAYLAND_KHR'),
     Extension('VK_KHR_xcb_surface',                       6, 'VK_USE_PLATFORM_XCB_KHR'),
     Extension('VK_KHR_xlib_surface',                      6, 'VK_USE_PLATFORM_XLIB_KHR'),
+    Extension('VK_KHR_display',                           1, 'VK_USE_PLATFORM_DISPLAY_KHR'),
     Extension('VK_KHX_multiview',                         1, True),
     Extension('VK_EXT_debug_report',                      8, True),
     Extension('VK_EXT_external_memory_dma_buf',           1, True),
diff --git a/src/intel/vulkan/anv_extensions_gen.py b/src/intel/vulkan/anv_extensions_gen.py
index 33827ecd015..84d07f9767a 100644
--- a/src/intel/vulkan/anv_extensions_gen.py
+++ b/src/intel/vulkan/anv_extensions_gen.py
@@ -113,7 +113,7 @@ _TEMPLATE_C = Template(COPYRIGHT + """
 #include "vk_util.h"
 
 /* Convert the VK_USE_PLATFORM_* defines to booleans */
-%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']:
+%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']:
 #ifdef VK_USE_PLATFORM_${platform}_KHR
 #   undef VK_USE_PLATFORM_${platform}_KHR
 #   define VK_USE_PLATFORM_${platform}_KHR true
@@ -132,7 +132,8 @@ _TEMPLATE_C = Template(COPYRIGHT + """
 
 #define ANV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\
                          VK_USE_PLATFORM_XCB_KHR || \\
-                         VK_USE_PLATFORM_XLIB_KHR)
+                         VK_USE_PLATFORM_XLIB_KHR || \\
+                         VK_USE_PLATFORM_DISPLAY_KHR)
 
 const VkExtensionProperties anv_instance_extensions[ANV_INSTANCE_EXTENSION_COUNT] = {
 %for ext in instance_extensions:
diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
index 6082c3dd093..f86d83589ea 100644
--- a/src/intel/vulkan/anv_wsi.c
+++ b/src/intel/vulkan/anv_wsi.c
@@ -39,7 +39,8 @@ anv_init_wsi(struct anv_physical_device *physical_device)
    return 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->local_fd);
 }
 
 void
diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c
new file mode 100644
index 00000000000..9b00d7f02e4
--- /dev/null
+++ b/src/intel/vulkan/anv_wsi_display.c
@@ -0,0 +1,129 @@
+/*
+ * 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 "anv_private.h"
+#include "wsi_common.h"
+#include "vk_format_info.h"
+#include "vk_util.h"
+#include "wsi_common_display.h"
+
+#define MM_PER_PIXEL     (1.0/96.0 * 25.4)
+
+VkResult
+anv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice             physical_device,
+                                           uint32_t                     *property_count,
+                                           VkDisplayPropertiesKHR       *properties)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_properties(physical_device,
+                                                             &pdevice->wsi_device,
+                                                             property_count,
+                                                             properties);
+}
+
+VkResult
+anv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice                physical_device,
+                                                uint32_t                        *property_count,
+                                                VkDisplayPlanePropertiesKHR     *properties)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_physical_device_display_plane_properties(physical_device,
+                                                                   &pdevice->wsi_device,
+                                                                   property_count,
+                                                                   properties);
+}
+
+VkResult
+anv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice               physical_device,
+                                         uint32_t                       plane_index,
+                                         uint32_t                       *display_count,
+                                         VkDisplayKHR                   *displays)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_plane_supported_displays(physical_device,
+                                                           &pdevice->wsi_device,
+                                                           plane_index,
+                                                           display_count,
+                                                           displays);
+}
+
+
+VkResult
+anv_GetDisplayModePropertiesKHR(VkPhysicalDevice               physical_device,
+                                 VkDisplayKHR                   display,
+                                 uint32_t                       *property_count,
+                                 VkDisplayModePropertiesKHR     *properties)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_display_get_display_mode_properties(physical_device,
+                                                  &pdevice->wsi_device,
+                                                  display,
+                                                  property_count,
+                                                  properties);
+}
+
+VkResult
+anv_CreateDisplayModeKHR(VkPhysicalDevice                      physical_device,
+                          VkDisplayKHR                          display,
+                          const VkDisplayModeCreateInfoKHR      *create_info,
+                          const VkAllocationCallbacks           *allocator,
+                          VkDisplayModeKHR                      *mode)
+{
+   return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+
+VkResult
+anv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice                    physical_device,
+                                    VkDisplayModeKHR                    mode_khr,
+                                    uint32_t                            plane_index,
+                                    VkDisplayPlaneCapabilitiesKHR       *capabilities)
+{
+   ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device);
+
+   return wsi_get_display_plane_capabilities(physical_device,
+                                             &pdevice->wsi_device,
+                                             mode_khr,
+                                             plane_index,
+                                             capabilities);
+}
+
+VkResult
+anv_CreateDisplayPlaneSurfaceKHR(VkInstance                            _instance,
+                                  const VkDisplaySurfaceCreateInfoKHR   *create_info,
+                                  const VkAllocationCallbacks           *allocator,
+                                  VkSurfaceKHR                          *surface)
+{
+   ANV_FROM_HANDLE(anv_instance, instance, _instance);
+   const VkAllocationCallbacks *alloc;
+
+   if (allocator)
+     alloc = allocator;
+   else
+     alloc = &instance->alloc;
+
+   return wsi_create_display_surface(_instance, alloc, create_info, surface);
+}
diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build
index 69ec26e19b6..2e2ab8f7ecd 100644
--- a/src/intel/vulkan/meson.build
+++ b/src/intel/vulkan/meson.build
@@ -171,6 +171,13 @@ if with_platform_wayland
   libanv_files += files('anv_wsi_wayland.c')
 endif
 
+if with_platform_display
+  anv_flags += [
+    '-DVK_USE_PLATFORM_DISPLAY_KHR',
+  ]
+  libanv_files += files('anv_wsi_display.c')
+endif
+
 libanv_common = static_library(
   'anv_common',
   [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h],
diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
index 037436c1cd7..c33ac5758f7 100644
--- a/src/vulkan/Makefile.am
+++ b/src/vulkan/Makefile.am
@@ -57,6 +57,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
+
 BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES)
 CLEANFILES = $(BUILT_SOURCES)
 
diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources
index a0a24ce7de8..3642c7662c4 100644
--- a/src/vulkan/Makefile.sources
+++ b/src/vulkan/Makefile.sources
@@ -17,6 +17,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 bd0fd3cc53e..743631a6113 100644
--- a/src/vulkan/wsi/meson.build
+++ b/src/vulkan/wsi/meson.build
@@ -57,6 +57,16 @@ 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 90ed07b7857..c0a285e5814 100644
--- a/src/vulkan/wsi/wsi_common.c
+++ b/src/vulkan/wsi/wsi_common.c
@@ -29,7 +29,8 @@ VkResult
 wsi_device_init(struct wsi_device *wsi,
                 VkPhysicalDevice pdevice,
                 WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
-                const VkAllocationCallbacks *alloc)
+                const VkAllocationCallbacks *alloc,
+                int device_fd)
 {
    VkResult result;
 
@@ -89,6 +90,19 @@ wsi_device_init(struct wsi_device *wsi,
    }
 #endif
 
+#ifdef VK_USE_PLATFORM_DISPLAY_KHR
+   result = wsi_display_init_wsi(wsi, alloc, pdevice, device_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;
 }
 
@@ -96,6 +110,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 3e0d3be1c24..1cb6aaebca0 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -50,7 +50,7 @@ struct wsi_memory_allocate_info {
 
 struct wsi_interface;
 
-#define VK_ICD_WSI_PLATFORM_MAX 5
+#define VK_ICD_WSI_PLATFORM_MAX 6
 
 struct wsi_device {
    VkPhysicalDeviceMemoryProperties memory_props;
@@ -93,7 +93,8 @@ VkResult
 wsi_device_init(struct wsi_device *wsi,
                 VkPhysicalDevice pdevice,
                 WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
-                const VkAllocationCallbacks *alloc);
+                const VkAllocationCallbacks *alloc,
+                int device_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..2732b1dd721
--- /dev/null
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -0,0 +1,1368 @@
+/*
+ * 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 "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;
+   wsi_display_mode             *current_mode;
+   drmModeModeInfo              current_drm_mode;
+} wsi_display_connector;
+
+struct wsi_display {
+   struct wsi_interface         base;
+
+   const VkAllocationCallbacks  *alloc;
+   VkPhysicalDevice             physical_device;
+
+   int                          master_fd;
+   int                          render_fd;
+
+   pthread_mutex_t              wait_mutex;
+   pthread_cond_t               wait_cond;
+   pthread_t                    wait_thread;
+
+   struct list_head             connectors;
+
+   struct list_head             display_modes;
+};
+
+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;
+   uint64_t                     flip_sequence;
+};
+
+struct wsi_display_swapchain {
+   struct wsi_swapchain         base;
+   struct wsi_display           *wsi;
+   VkIcdSurfaceDisplay          *surface;
+   uint64_t                     flip_sequence;
+   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));
+}
+
+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)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode;
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->connector == connector &&
+          wsi_display_mode_matches_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           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode;
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list)
+      if (display_mode->connector == connector)
+         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];
+   struct wsi_display_mode      *display_mode;
+
+   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_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   if (!display_mode)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   display_mode->connector = connector;
+   display_mode->valid = true;
+   display_mode->preferred = (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, &wsi->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_alloc(wsi->alloc, sizeof (struct wsi_display_connector), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+   memset(connector, '\0', sizeof (*connector));
+   connector->id = connector_id;
+   connector->wsi = wsi;
+   connector->active = false;
+   /* XXX use EDID name */
+   connector->name = "monitor";
+   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->master_fd < 0)
+      return NULL;
+
+   drm_connector = drmModeGetConnector(wsi->master_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 void
+wsi_display_fill_in_display_properties(struct wsi_device                *wsi_device,
+                                       struct wsi_display_connector     *connector,
+                                       VkDisplayPropertiesKHR           *properties)
+{
+   struct wsi_display           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_mode      *display_mode, *preferred_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 */
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->valid && display_mode->connector == connector && display_mode->preferred) {
+         preferred_mode = display_mode;
+         break;
+      }
+   }
+
+   if (preferred_mode) {
+      properties->physicalResolution.width = preferred_mode->hdisplay;
+      properties->physicalResolution.height = preferred_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];
+   struct wsi_display_connector *connector;
+   int                          c;
+   uint32_t                     connected;
+   uint32_t                     property_count_requested = *property_count;
+   drmModeResPtr                mode_res;
+
+   if (wsi->master_fd < 0)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   mode_res = drmModeGetResources(wsi->master_fd);
+
+   if (!mode_res)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   connected = 0;
+
+   /* Get current information */
+   for (c = 0; c < mode_res->count_connectors; c++) {
+      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)
+         connected++;
+   }
+
+   /* Fill in property information if requested */
+   if (properties != NULL) {
+      connected = 0;
+
+      for (c = 0; c < mode_res->count_connectors; c++) {
+         connector  = wsi_display_find_connector(wsi_device, mode_res->connectors[c]);
+
+         if (connector && connector->connected) {
+            if (connected < property_count_requested) {
+               wsi_display_fill_in_display_properties(wsi_device,
+                                                      connector,
+                                                      &properties[connected]);
+            }
+            connected++;
+         }
+      }
+   }
+
+   drmModeFreeResources(mode_res);
+
+   *property_count = connected;
+
+   if (connected > property_count_requested && properties != NULL)
+      return VK_INCOMPLETE;
+
+   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;
+   uint32_t                     property_count_requested = *property_count;
+   int                          c;
+
+   if (!properties)
+      property_count_requested = 0;
+
+   c = 0;
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
+      if (c < property_count_requested) {
+         if (connector && connector->active) {
+            properties[c].currentDisplay = wsi_display_connector_to_handle(connector);
+            properties[c].currentStackIndex = c;
+         } else {
+            properties[c].currentDisplay = NULL;
+            properties[c].currentStackIndex = 0;
+         }
+      }
+      c++;
+   }
+
+   *property_count = c;
+
+   if (c > property_count_requested && properties != NULL)
+      return VK_INCOMPLETE;
+
+   return VK_SUCCESS;
+}
+
+/*
+ * 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;
+   int                          c;
+
+
+   if (displays == NULL) {
+      *display_count = 1;
+      return VK_SUCCESS;
+   }
+
+   if (*display_count < 1)
+      return VK_INCOMPLETE;
+
+   c = 0;
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
+      if (c == plane_index) {
+         *displays = wsi_display_connector_to_handle(connector);
+         *display_count = 1;
+         return VK_SUCCESS;
+      }
+      c++;
+   }
+
+   *displays = 0;
+   *display_count = 0;
+
+   return VK_SUCCESS;
+}
+
+/*
+ * 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           *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
+   int                          i;
+   struct wsi_display_mode      *display_mode;
+   uint32_t                     property_count_requested = *property_count;
+
+   i = 0;
+
+   if (properties == NULL)
+      property_count_requested = 0;
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->valid && display_mode->connector == connector) {
+         if (i < property_count_requested) {
+            properties[i].displayMode = wsi_display_mode_to_handle(display_mode);
+            properties[i].parameters.visibleRegion.width = display_mode->hdisplay;
+            properties[i].parameters.visibleRegion.height = display_mode->vdisplay;
+            properties[i].parameters.refreshRate = (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
+         }
+         i++;
+      }
+   }
+
+   *property_count = i;
+
+   if (i > property_count_requested && properties != NULL)
+      return VK_INCOMPLETE;
+
+   return VK_SUCCESS;
+
+}
+
+/*
+ * 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_alloc(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_INHERIT_BIT_KHR |
+                                    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 VkFormat available_surface_formats[] = {
+   VK_FORMAT_B8G8R8A8_SRGB,
+   VK_FORMAT_B8G8R8A8_UNORM,
+};
+
+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];
+         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];
+         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)
+{
+   if (present_modes == NULL) {
+      *present_mode_count = ARRAY_SIZE(available_present_modes);
+      return VK_SUCCESS;
+   }
+
+   *present_mode_count = MIN2(*present_mode_count, ARRAY_SIZE(available_present_modes));
+   typed_memcpy(present_modes, available_present_modes, *present_mode_count);
+
+   if (*present_mode_count < ARRAY_SIZE(available_present_modes))
+      return VK_INCOMPLETE;
+   return VK_SUCCESS;
+}
+
+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                     image_handle;
+
+   if (chain->base.use_prime_blit)
+      result = wsi_create_prime_image(&chain->base, create_info, &image->base);
+   else
+      result = wsi_create_native_image(&chain->base, create_info, &image->base);
+   if (result != VK_SUCCESS)
+      return result;
+
+   ret = drmPrimeFDToHandle(wsi->master_fd, image->base.fd, &image_handle);
+
+   close(image->base.fd);
+   image->base.fd = -1;
+
+   if (ret < 0)
+      goto fail_handle;
+
+   image->chain = chain;
+   image->state = wsi_image_idle;
+   image->fb_id = 0;
+
+   /* XXX extract depth and bpp from image somehow */
+   ret = drmModeAddFB(wsi->master_fd, create_info->imageExtent.width, create_info->imageExtent.height,
+                      24, 32, image->base.row_pitch, image_handle, &image->fb_id);
+
+   if (ret)
+      goto fail_fb;
+
+   return VK_SUCCESS;
+
+fail_fb:
+   /* fall through */
+
+fail_handle:
+   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;
+
+   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;
+
+   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);
+   (void) _wsi_display_queue_next(&(image->chain->base));
+}
+
+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->master_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->master_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;
+}
+
+/* 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;
+
+   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);
+   return result;
+}
+
+/*
+ * 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->master_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->master_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->master_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->master_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->master_fd);
+   if (!mode_res) {
+      result = VK_ERROR_INITIALIZATION_FAILED;
+      goto bail;
+   }
+
+   drm_connector = drmModeGetConnectorCurrent(wsi->master_fd, connector->id);
+   if (!drm_connector) {
+      result = VK_ERROR_INITIALIZATION_FAILED;
+      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->master_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->master_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->master_fd, connector->crtc_id, image->fb_id, 0, 0,
+                                 &connector->id, 1, &connector->current_drm_mode);
+
+            if (ret == 0) {
+               image->state = wsi_image_displaying;
+               wsi_display_idle_old_displaying(image);
+               connector->active = true;
+               return VK_SUCCESS;
+            }
+            break;
+         case EACCES:
+            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;
+
+   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);
+
+   pthread_mutex_unlock(&wsi->wait_mutex);
+
+   return result;
+}
+
+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_alloc(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->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)
+         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,
+                     VkPhysicalDevice physical_device,
+                     int device_fd)
+{
+   struct wsi_display *wsi;
+   VkResult result;
+
+   wsi = vk_alloc(alloc, sizeof(*wsi), 8,
+                   VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+   if (!wsi) {
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;
+      goto fail;
+   }
+   memset(wsi, '\0', sizeof (*wsi));
+
+   wsi->master_fd = -1;
+   if (drmGetNodeTypeFromFd(device_fd) == DRM_NODE_PRIMARY)
+      wsi->master_fd = device_fd;
+   wsi->render_fd = device_fd;
+
+   pthread_mutex_init(&wsi->wait_mutex, NULL);
+   wsi->physical_device = physical_device;
+   wsi->alloc = alloc;
+
+   LIST_INITHEAD(&wsi->display_modes);
+   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) {
+         vk_free(wsi->alloc, connector);
+      }
+
+      struct wsi_display_mode *mode, *mode_storage;
+      LIST_FOR_EACH_ENTRY_SAFE(mode, mode_storage, &wsi->display_modes, list) {
+         vk_free(wsi->alloc, mode);
+      }
+
+      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 503b2a015dc..d38d2efa116 100644
--- a/src/vulkan/wsi/wsi_common_private.h
+++ b/src/vulkan/wsi/wsi_common_private.h
@@ -135,6 +135,16 @@ 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,
+                     VkPhysicalDevice physical_device,
+                     int device_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.15.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* RE: [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM
  2018-03-29  6:59   ` Mao, David
@ 2018-03-29 15:05     ` Keith Packard
  0 siblings, 0 replies; 24+ messages in thread
From: Keith Packard @ 2018-03-29 15:05 UTC (permalink / raw)
  To: Mao, David, mesa-dev; +Cc: dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 592 bytes --]

"Mao, David" <David.Mao@amd.com> writes:

> Hi Keith,
> If I read the patch correctly, the plane has been interpreted as the same as connector, and the stackIndex is the index of connector of current device.
> Is it by intentional?
> If the hardware don't have underlay/overlay supported, is it better to
> always report plane 0 rather than pretend to have multiple plane?

Yes, you're right. I must have mis-read the specification when writing
this function. Thanks for catching this. I've merged this fix into the
patch and re-pushed it to my drm-lease-v2 branch.

-- 
-keith

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2018-03-29 15:05 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
2018-02-12 15:27   ` Eric Engestrom
2018-02-12 22:16     ` Keith Packard
2018-02-12 16:18   ` [Mesa-dev] " Emil Velikov
2018-02-12 23:12     ` Keith Packard
2018-02-14  1:10   ` Jason Ekstrand
2018-02-15 17:46     ` Keith Packard
2018-02-23 23:00       ` Jason Ekstrand
2018-02-23 23:43         ` Keith Packard
2018-02-24  0:51           ` Jason Ekstrand
2018-03-12 23:02             ` Keith Packard
2018-03-29  6:59   ` Mao, David
2018-03-29 15:05     ` Keith Packard
2018-02-10  4:45 ` [PATCH 2/7] vulkan: Add EXT_direct_mode_display Keith Packard
2018-02-10  4:45 ` [PATCH 3/7] vulkan: Add EXT_acquire_xlib_display Keith Packard
2018-02-13  0:16   ` Dylan Baker
2018-02-10  4:45 ` [PATCH 4/7] vulkan: Add VK_EXT_display_surface_counter [v4] Keith Packard
2018-02-10  4:45 ` [PATCH 5/7] vulkan: add VK_EXT_display_control [v4] Keith Packard
2018-02-10  4:45 ` [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension Keith Packard
2018-02-13  0:20   ` Dylan Baker
2018-02-13 10:49     ` [Mesa-dev] " Lionel Landwerlin
2018-02-13 21:11       ` Keith Packard
2018-02-10  4:45 ` [PATCH 7/7] vulkan: Add VK_GOOGLE_display_timing extension (x11 and display backends) Keith Packard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.