All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/1] Adding VK_KHR_display to mesa based on KMS
@ 2017-05-31 22:41 "Keith Packard"
  0 siblings, 0 replies; only message in thread
From: "Keith Packard" @ 2017-05-31 22:41 UTC (permalink / raw)
  To: dri-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 2473 bytes --]


As part of my adventures to implement 'DRM leases', it turns out to be
easiest to just implement 'real' VK_KHR_display in mesa now, rather than
a pile of ugly kludges. Because DRM leases just provide a DRM master
fd with limited resource access, mesa doesn't have to care whether you
provide a 'real' master or a lease.

That means all of the mesa code is separate from DRM leases, and can
also be used to run applications directly on bare hardware.

The implementation of the KHR_display extension lives pretty much
entirely within the common vulkan code in
src/vulkan/wsi/wsi_common_display.c

The driver functions in radv simply call those functions, which means
this should be 'trivial' to enable in the anv driver, but I haven't done
that work.

To get the master FD into the driver, I've created a new extension,
VK_KEITHP_kms_display which provides a DRM master file descriptor that
the driver uses in place of creating it's own render node file
descriptor. There's a bit of a dance involved in making sure we use the
right driver; that could probably be improved.

There are a few bits of unimplemented functionality within the
KHR_display implementation:

 1) I don't dig the monitor name out of EDID. I'm thinking this
    should be done by the kernel and exposed as a property. It already
    has the code for this...

 2) plane and surface capabilities are 'faked'. These expose the range
    of source surface sizes and positions which can be used; obviously
    the hardware can do a lot more than display an image at full size.

 3) Planes in general. I'm exposing only a single plane per connector at
    this point. Obviously we'd want more.

 4) bpp/depth. For now, I'm assuming depth 24, 32bpp. I think I just
    need a driver hook to get this out of the image; I sure don't want
    to try and parse the format.

I haven't rebased this in a while; it's a few revs back on master. I'm
looking for general feedback and comments about the plan at this point;
this is the second implementation of the code, I'm entirely willing to
do at least one more to make it 'right'.

git://people.freedesktop.org/~keithp/mesa.git   khr_display

There are also some simple changes in the vulkan looader (replicated in
the relevant files in mesa) needed to gain access to the
VK_KEITHP_kms_display extension (thanks, Vulkan, for not exposing vendor
instance extensions by default)

git://people.freedesktop.org/~keithp/Vulkan-LoaderAndValidationLayers.git drm-leases


[-- Attachment #1.1.2: 0001-Add-VK_KHR_display-and-VK_KEITHP_kms_display-to-radv.patch --]
[-- Type: text/x-diff, Size: 76515 bytes --]

From 06088071af2a396ce58b0490ceb228e3aa079a09 Mon Sep 17 00:00:00 2001
From: Keith Packard <keithp@keithp.com>
Date: Wed, 17 May 2017 23:02:33 -0700
Subject: [PATCH] Add VK_KHR_display and VK_KEITHP_kms_display to radv vulkan
 driver [v2]

Implements VK_KHR_display using DRM/KMS.

Expose ability to get to that using VK_KEITHP_kms_display, which
allows the application to provide a master fd to the library which it
uses instead of opening its own.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 configure.ac                                  |    1 +
 include/vulkan/vulkan.h                       |    3 +-
 include/vulkan/vulkan_keithp.h                |   40 +
 src/Makefile.am                               |    7 +
 src/amd/vulkan/Makefile.am                    |    9 +
 src/amd/vulkan/Makefile.sources               |    3 +
 src/amd/vulkan/radv_device.c                  |   71 +-
 src/amd/vulkan/radv_entrypoints_gen.py        |    2 +
 src/amd/vulkan/radv_private.h                 |    7 +
 src/amd/vulkan/radv_radeon_winsys.h           |    4 +
 src/amd/vulkan/radv_wsi.c                     |   37 +-
 src/amd/vulkan/radv_wsi_display.c             |  144 ++++
 src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c |   18 +
 src/intel/vulkan/anv_wsi.c                    |    2 +-
 src/vulkan/Makefile.am                        |    9 +
 src/vulkan/Makefile.sources                   |    4 +
 src/vulkan/registry/vk.xml                    |   18 +
 src/vulkan/wsi/wsi_common.h                   |   12 +-
 src/vulkan/wsi/wsi_common_display.c           | 1063 +++++++++++++++++++++++++
 src/vulkan/wsi/wsi_common_display.h           |   80 ++
 src/vulkan/wsi/wsi_common_wayland.c           |    2 +-
 src/vulkan/wsi/wsi_common_x11.c               |    4 +-
 22 files changed, 1526 insertions(+), 14 deletions(-)
 create mode 100644 include/vulkan/vulkan_keithp.h
 create mode 100644 src/amd/vulkan/radv_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 df3eb6b29a..4712efcd5e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2238,6 +2238,7 @@ fi
 
 AM_CONDITIONAL(HAVE_PLATFORM_X11, echo "$egl_platforms" | grep -q 'x11')
 AM_CONDITIONAL(HAVE_PLATFORM_WAYLAND, echo "$egl_platforms" | grep -q 'wayland')
+AM_CONDITIONAL(HAVE_PLATFORM_DISPLAY, echo "$egl_platforms" | grep -q 'drm')
 AM_CONDITIONAL(HAVE_EGL_PLATFORM_DRM, echo "$egl_platforms" | grep -q 'drm')
 AM_CONDITIONAL(HAVE_EGL_PLATFORM_SURFACELESS, echo "$egl_platforms" | grep -q 'surfaceless')
 AM_CONDITIONAL(HAVE_EGL_PLATFORM_ANDROID, echo "$egl_platforms" | grep -q 'android')
diff --git a/include/vulkan/vulkan.h b/include/vulkan/vulkan.h
index ef0c246780..8b5be61e29 100644
--- a/include/vulkan/vulkan.h
+++ b/include/vulkan/vulkan.h
@@ -43,7 +43,7 @@ extern "C" {
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 46
+#define VK_HEADER_VERSION 48
 
 
 #define VK_NULL_HANDLE 0
@@ -214,6 +214,7 @@ typedef enum VkStructureType {
     VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
     VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
     VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
+    VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP = 1000010000,
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
     VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000,
     VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
diff --git a/include/vulkan/vulkan_keithp.h b/include/vulkan/vulkan_keithp.h
new file mode 100644
index 0000000000..acf59fa4e1
--- /dev/null
+++ b/include/vulkan/vulkan_keithp.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2017 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _VULKAN_KEITHP_H_
+#define _VULKAN_KEITHP_H_
+
+#include "vulkan.h"
+#include <xf86drmMode.h>
+#include <xf86drm.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+typedef struct VkKmsDisplayInfoKEITHP {
+	VkStructureType         sType;	/* VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP */
+	const void*             pNext;
+	int                     fd;
+} VkKmsDisplayInfoKEITHP;
+
+#define VK_KEITHP_KMS_DISPLAY_SPEC_VERSION      1
+#define VK_KEITHP_KMS_DISPLAY_EXTENSION_NAME    "VK_KEITHP_kms_display"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _VULKAN_KEITHP_H_ */
diff --git a/src/Makefile.am b/src/Makefile.am
index aa5f8aaf7d..6fcd8b9d24 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,6 +85,13 @@ SUBDIRS += vulkan
 endif
 EXTRA_DIST += vulkan/registry/vk.xml
 
+EXTRA_DIST += include/vulkan/vulkan_keithp.h
+
+vulkan_includedir = $(includedir)/vulkan
+
+vulkan_include_HEADERS = \
+	$(top_srcdir)/include/vulkan/vulkan_keithp.h
+
 if HAVE_AMD_DRIVERS
 SUBDIRS += amd
 endif
diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am
index fbd9f5a030..cf1f5219b9 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -61,6 +61,15 @@ VULKAN_SOURCES = \
 
 VULKAN_LIB_DEPS =
 
+if HAVE_PLATFORM_DISPLAY
+AM_CPPFLAGS += \
+	-DVK_USE_PLATFORM_DISPLAY_KHR \
+	-DVK_USE_PLATFORM_KMS_KEITHP
+
+VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
+
+VULKAN_LIB_DEPS += $(LIBDRM_LIBS)
+endif
 
 if HAVE_PLATFORM_X11
 AM_CPPFLAGS += \
diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources
index d3e0c81e9a..1119e908d1 100644
--- a/src/amd/vulkan/Makefile.sources
+++ b/src/amd/vulkan/Makefile.sources
@@ -72,6 +72,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/radv_device.c b/src/amd/vulkan/radv_device.c
index 921b8e48f5..1a30992d48 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -88,6 +88,18 @@ static const VkExtensionProperties instance_extensions[] = {
 		.extensionName = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
 		.specVersion = 1,
 	},
+        {
+                .extensionName = VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME,
+                .specVersion = VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION
+        },
+        {
+                .extensionName = VK_KHR_DISPLAY_EXTENSION_NAME,
+                .specVersion = VK_KHR_DISPLAY_SPEC_VERSION
+        },
+        {
+                .extensionName = VK_KEITHP_KMS_DISPLAY_EXTENSION_NAME,
+                .specVersion = 1,
+        }
 };
 
 static const VkExtensionProperties common_device_extensions[] = {
@@ -187,6 +199,12 @@ is_extension_enabled(const VkExtensionProperties *extensions,
 	return false;
 }
 
+static bool
+is_same_device(dev_t a, dev_t b)
+{
+        return major(a) == major(b) && (minor(a) & 0x3f) == (minor(b) & 0x3f);
+}
+
 static VkResult
 radv_physical_device_init(struct radv_physical_device *device,
 			  struct radv_instance *instance,
@@ -194,9 +212,26 @@ radv_physical_device_init(struct radv_physical_device *device,
 {
 	VkResult result;
 	drmVersionPtr version;
-	int fd;
-
-	fd = open(path, O_RDWR | O_CLOEXEC);
+	int fd = -1;
+        struct stat     stat_info, stat_path;
+
+        if (instance->master_fd >= 0) {
+                if (fstat(instance->master_fd, &stat_info) >= 0 &&
+                    stat(path, &stat_path) >= 0 &&
+                    S_ISCHR(stat_info.st_mode) &&
+                    S_ISCHR(stat_path.st_mode) &&
+                    is_same_device(stat_info.st_rdev, stat_path.st_rdev))
+                {
+                        printf("matched physical device to provided device info\n");
+                        fd = dup(instance->master_fd);
+                } else {
+                        printf("no match for provided device info\n");
+                        return VK_ERROR_INCOMPATIBLE_DRIVER;
+                }
+        }
+
+        if (fd < 0)
+                fd = open(path, O_RDWR | O_CLOEXEC);
 	if (fd < 0)
 		return VK_ERROR_INCOMPATIBLE_DRIVER;
 
@@ -366,6 +401,21 @@ VkResult radv_CreateInstance(
 	instance->debug_flags = parse_debug_string(getenv("RADV_DEBUG"),
 						   radv_debug_options);
 
+        instance->master_fd = -1;
+
+	vk_foreach_struct(ext, pCreateInfo->pNext) {
+                VkKmsDisplayInfoKEITHP *vk_kms;
+                switch (ext->sType) {
+                case VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP:
+                        vk_kms = (void *) ext;
+                        fprintf(stderr, "Found kms display info keithp struct fd %d\n", vk_kms->fd);
+                        instance->master_fd = vk_kms->fd;
+                        break;
+                default:
+                        break;
+                }
+        }
+
 	*pInstance = radv_instance_to_handle(instance);
 
 	return VK_SUCCESS;
@@ -2004,6 +2054,21 @@ bool radv_get_memory_fd(struct radv_device *device,
 					 pFD);
 }
 
+bool radv_get_memory_handle(struct radv_device *device,
+                            struct radv_device_memory *memory,
+                            uint32_t *pHandle)
+{
+	struct radeon_bo_metadata metadata;
+
+	if (memory->image) {
+		radv_init_metadata(device, memory->image, &metadata);
+		device->ws->buffer_set_metadata(memory->bo, &metadata);
+	}
+
+	return device->ws->buffer_get_handle(device->ws, memory->bo,
+                                             pHandle);
+}
+
 VkResult radv_AllocateMemory(
 	VkDevice                                    _device,
 	const VkMemoryAllocateInfo*                 pAllocateInfo,
diff --git a/src/amd/vulkan/radv_entrypoints_gen.py b/src/amd/vulkan/radv_entrypoints_gen.py
index 3474c789ea..e8e24b8da7 100644
--- a/src/amd/vulkan/radv_entrypoints_gen.py
+++ b/src/amd/vulkan/radv_entrypoints_gen.py
@@ -42,6 +42,8 @@ supported_extensions = [
    'VK_KHR_wayland_surface',
    'VK_KHR_xcb_surface',
    'VK_KHR_xlib_surface',
+   'VK_KEITHP_kms_display',
+   'VK_KHR_display'
 ]
 
 # We generate a static hash table for entry point lookup
diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h
index 088d24a706..7a2e1442d7 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -67,11 +67,13 @@ typedef uint32_t xcb_window_t;
 
 #include <vulkan/vulkan.h>
 #include <vulkan/vulkan_intel.h>
+#include <vulkan/vulkan_keithp.h>
 #include <vulkan/vk_icd.h>
 
 #include "radv_entrypoints.h"
 
 #include "wsi_common.h"
+#include "wsi_common_display.h"
 
 #define MAX_VBS         32
 #define MAX_VERTEX_ATTRIBS 32
@@ -281,6 +283,8 @@ struct radv_instance {
 	int                                         physicalDeviceCount;
 	struct radv_physical_device                 physicalDevices[RADV_MAX_DRM_DEVICES];
 
+        int                                         master_fd;
+
 	uint64_t debug_flags;
 };
 
@@ -894,6 +898,9 @@ void radv_cmd_buffer_trace_emit(struct radv_cmd_buffer *cmd_buffer);
 bool radv_get_memory_fd(struct radv_device *device,
 			struct radv_device_memory *memory,
 			int *pFD);
+bool radv_get_memory_handle(struct radv_device *device,
+                            struct radv_device_memory *memory,
+                            uint32_t *pHandle);
 /*
  * Takes x,y,z as exact numbers of invocations, instead of blocks.
  *
diff --git a/src/amd/vulkan/radv_radeon_winsys.h b/src/amd/vulkan/radv_radeon_winsys.h
index 84b1d73780..cc7bca73bc 100644
--- a/src/amd/vulkan/radv_radeon_winsys.h
+++ b/src/amd/vulkan/radv_radeon_winsys.h
@@ -283,6 +283,10 @@ struct radeon_winsys {
 			      struct radeon_winsys_bo *bo,
 			      int *fd);
 
+	bool (*buffer_get_handle)(struct radeon_winsys *ws,
+                                  struct radeon_winsys_bo *bo,
+                                  uint32_t *handle);
+
 	void (*buffer_unmap)(struct radeon_winsys_bo *bo);
 
 	uint64_t (*buffer_get_va)(struct radeon_winsys_bo *bo);
diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c
index 3a8617fd8f..85efb2c279 100644
--- a/src/amd/vulkan/radv_wsi.c
+++ b/src/amd/vulkan/radv_wsi.c
@@ -57,6 +57,23 @@ radv_init_wsi(struct radv_physical_device *physical_device)
 	}
 #endif
 
+#ifdef VK_USE_PLATFORM_DISPLAY_KHR
+        result = wsi_display_init_wsi(&physical_device->wsi_device,
+                                      &physical_device->instance->alloc,
+                                      radv_physical_device_to_handle(physical_device),
+                                      physical_device->instance->master_fd >= 0 ? physical_device->local_fd : -1,
+                                      &wsi_cbs);
+        if (result != VK_SUCCESS) {
+#ifdef VK_USE_PLATFORM_XCB_KHR
+           wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
+#endif
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+           wsi_wayland_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
+#endif
+           return result;
+        }
+#endif
+
 	return VK_SUCCESS;
 }
 
@@ -69,6 +86,9 @@ radv_finish_wsi(struct radv_physical_device *physical_device)
 #ifdef VK_USE_PLATFORM_XCB_KHR
 	wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
 #endif
+#ifdef VK_USE_PLATFORM_DISPLAY_KHR
+        wsi_display_finish_wsi(&physical_device->wsi_device, &physical_device->instance->alloc);
+#endif
 }
 
 void radv_DestroySurfaceKHR(
@@ -147,7 +167,7 @@ radv_wsi_image_create(VkDevice device_h,
 		      VkDeviceMemory *memory_p,
 		      uint32_t *size,
 		      uint32_t *offset,
-		      uint32_t *row_pitch, int *fd_p)
+		      uint32_t *row_pitch, int *fd_p, uint32_t *handle_p)
 {
 	VkResult result = VK_SUCCESS;
 	struct radeon_surf *surface;
@@ -213,9 +233,18 @@ radv_wsi_image_create(VkDevice device_h,
 	if (!needs_linear_copy || (needs_linear_copy && linear)) {
 		RADV_FROM_HANDLE(radv_device, device, device_h);
 		RADV_FROM_HANDLE(radv_device_memory, memory, memory_h);
-		if (!radv_get_memory_fd(device, memory, &fd))
-			goto fail_alloc_memory;
-		*fd_p = fd;
+
+                if (fd_p) {
+                   if (!radv_get_memory_fd(device, memory, &fd))
+                      goto fail_alloc_memory;
+                   *fd_p = fd;
+                }
+                if (handle_p) {
+                   uint32_t     handle;
+                   if (!radv_get_memory_handle(device, memory, &handle))
+                      goto fail_alloc_memory;
+                   *handle_p = handle;
+                }
 	}
 
 	surface = &image->surface;
diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c
new file mode 100644
index 0000000000..7113b78593
--- /dev/null
+++ b/src/amd/vulkan/radv_wsi_display.c
@@ -0,0 +1,144 @@
+/*
+ * 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 "util/vk_util.h"
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <amdgpu.h>
+#include <amdgpu_drm.h>
+#include "amdgpu_id.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/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c
index 7b679450cb..eeae79cb76 100644
--- a/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c
+++ b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c
@@ -445,6 +445,23 @@ radv_amdgpu_winsys_get_fd(struct radeon_winsys *_ws,
 	return true;
 }
 
+static bool
+radv_amdgpu_winsys_get_handle(struct radeon_winsys *_ws,
+                              struct radeon_winsys_bo *_bo,
+                              uint32_t *handle)
+{
+	struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
+	enum amdgpu_bo_handle_type type = amdgpu_bo_handle_type_kms;
+	int r;
+
+	r = amdgpu_bo_export(bo->bo, type, handle);
+	if (r)
+		return false;
+
+        bo->is_shared = true;
+	return true;
+}
+
 static unsigned radv_eg_tile_split_rev(unsigned eg_tile_split)
 {
 	switch (eg_tile_split) {
@@ -503,6 +520,7 @@ void radv_amdgpu_bo_init_functions(struct radv_amdgpu_winsys *ws)
 	ws->base.buffer_unmap = radv_amdgpu_winsys_bo_unmap;
 	ws->base.buffer_from_fd = radv_amdgpu_winsys_bo_from_fd;
 	ws->base.buffer_get_fd = radv_amdgpu_winsys_get_fd;
+        ws->base.buffer_get_handle = radv_amdgpu_winsys_get_handle;
 	ws->base.buffer_set_metadata = radv_amdgpu_winsys_bo_set_metadata;
 	ws->base.buffer_virtual_bind = radv_amdgpu_winsys_bo_virtual_bind;
 }
diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c
index 2ab37c30b7..d274493599 100644
--- a/src/intel/vulkan/anv_wsi.c
+++ b/src/intel/vulkan/anv_wsi.c
@@ -151,7 +151,7 @@ anv_wsi_image_create(VkDevice device_h,
                      VkDeviceMemory *memory_p,
                      uint32_t *size,
                      uint32_t *offset,
-                     uint32_t *row_pitch, int *fd_p)
+                     uint32_t *row_pitch, int *fd_p, uint32_t *handle_p)
 {
    struct anv_device *device = anv_device_from_handle(device_h);
    VkImage image_h;
diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am
index bd66901255..d7b654d266 100644
--- a/src/vulkan/Makefile.am
+++ b/src/vulkan/Makefile.am
@@ -48,6 +48,15 @@ VULKAN_WSI_SOURCES += $(VULKAN_WSI_X11_FILES)
 VULKAN_LIB_DEPS += $(XCB_DRI3_LIBS) -lX11-xcb
 endif
 
+if HAVE_PLATFORM_DISPLAY
+AM_CPPFLAGS += \
+	-DVK_USE_PLATFORM_DISPLAY
+
+VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES)
+
+VULKAN_LIB_DEPS += $(LIBDRM_LIBS)
+endif
+
 BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES)
 CLEANFILES = $(BUILT_SOURCES)
 
diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources
index 63f4ac1162..109aa83e6b 100644
--- a/src/vulkan/Makefile.sources
+++ b/src/vulkan/Makefile.sources
@@ -15,6 +15,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_GENERATED_FILES := \
 	util/vk_enum_to_str.c \
 	util/vk_enum_to_str.h
diff --git a/src/vulkan/registry/vk.xml b/src/vulkan/registry/vk.xml
index b233108a36..d9c01f6e52 100644
--- a/src/vulkan/registry/vk.xml
+++ b/src/vulkan/registry/vk.xml
@@ -67,6 +67,7 @@ maintained in the master branch of the Khronos Vulkan GitHub project.
         <tag name="KHR"         author="Khronos"                       contact="Tom Olson @tom.olson"/>
         <tag name="EXT"         author="Multivendor"                   contact="Jon Leech @oddhack"/>
         <tag name="MESA"        author="Mesa open source project"      contact="Chad Versace @chadversary, Daniel Stone @fooishbar, David Airlie @airlied, Jason Ekstrand @jekstrand"/>
+        <tag name="KEITHP"      author="keithp.com"                    contact="keithp @keithp.com"/>
     </tags>
 
     <!-- SECTION: Vulkan type definitions -->
@@ -1538,6 +1539,16 @@ maintained in the master branch of the Khronos Vulkan GitHub project.
             <member noautovalidity="true"><type>xcb_connection_t</type>*                <name>connection</name></member>
             <member><type>xcb_window_t</type>                     <name>window</name></member>
         </type>
+	<type catagory="struct" name="VkKmsDisplayInfoKEITHP">
+	  <member values="VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP"><type>VkStructureType</type> <name>sType</name></member>
+	  <member><type>VkStructureType</type>			  <name>sType</name></member>
+	  <member>const<type>void</type>*			  <name>pNext</name></member>
+	  <member><type>int</type>                                <name>fd</name></member>
+	  <member><type>uint32_t</type>                           <name>crtc_id</name></member>
+	  <member><type>uint32_t</type>*                          <name>connector_ids</name></member>
+	  <member><type>int</type>                                <name>connector_count</name></member>
+	  <member><type>drmModeModeInfoPtr</type>                 <name>mode</name></member>
+	</type>
         <type category="struct" name="VkSurfaceFormatKHR" returnedonly="true">
             <member><type>VkFormat</type>                         <name>format</name></member>                   <!-- Supported pair of rendering format -->
             <member><type>VkColorSpaceKHR</type>                  <name>colorSpace</name></member>               <!-- and color space for the surface -->
@@ -5117,6 +5128,13 @@ maintained in the master branch of the Khronos Vulkan GitHub project.
                 <command name="vkGetPhysicalDeviceXcbPresentationSupportKHR"/>
             </require>
         </extension>
+        <extension name="VK_KEITHP_kms_display" number="1" type="instance" requires="VK_KHR_surface" protect="VK_USE_PLATFORM_KMS_KEITHP" supported="vulkan">
+            <require>
+                <enum value="1"                                         name="VK_KEITHP_KMS_DISPLAY_SPEC_VERSION"/>
+                <enum value="&quot;VK_KEITHP_kms_display&quot;"         name="VK_KEITHP_KMS_DISPLAY_EXTENSION_NAME"/>
+                <enum offset="0" extends="VkStructureType"              name="VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP"/>
+            </require>
+        </extension>
         <extension name="VK_KHR_wayland_surface" number="7" type="instance" requires="VK_KHR_surface" protect="VK_USE_PLATFORM_WAYLAND_KHR" supported="vulkan">
             <require>
                 <enum value="6"                                         name="VK_KHR_WAYLAND_SURFACE_SPEC_VERSION"/>
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index 5e77518c09..ccf91ecac9 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -42,7 +42,8 @@ struct wsi_image_fns {
                                 uint32_t *size_p,
                                 uint32_t *offset_p,
                                 uint32_t *row_pitch_p,
-                                int *fd_p);
+                                int *fd_p,
+                                uint32_t *handle_p);
    void (*free_wsi_image)(VkDevice device,
                           const VkAllocationCallbacks *pAllocator,
                           VkImage image_h,
@@ -104,7 +105,7 @@ struct wsi_interface {
                                 struct wsi_swapchain **swapchain);
 };
 
-#define VK_ICD_WSI_PLATFORM_MAX 5
+#define VK_ICD_WSI_PLATFORM_MAX 6
 
 struct wsi_device {
     struct wsi_interface *                  wsi[VK_ICD_WSI_PLATFORM_MAX];
@@ -162,5 +163,12 @@ VkResult wsi_wl_init_wsi(struct wsi_device *wsi_device,
 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 fd,
+                              const struct wsi_callbacks *cbs);
+void wsi_display_finish_wsi(struct wsi_device *wsi_device,
+                            const VkAllocationCallbacks *alloc);
 
 #endif
diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c
new file mode 100644
index 0000000000..9336b2ae67
--- /dev/null
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -0,0 +1,1063 @@
+/*
+ * 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 <xf86drm.h>
+#include <xf86drmMode.h>
+#include "util/hash_table.h"
+#include "util/list.h"
+
+#include "wsi_common.h"
+#include "wsi_common_queue.h"
+#include "wsi_common_display.h"
+
+/* 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;
+   drmModeModeInfo              mode;
+} 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                         active;
+   drmModeConnectorPtr          connector;
+   drmModePropertyBlobPtr       edid_blob;
+} wsi_display_connector;
+
+struct wsi_display {
+   struct wsi_interface         base;
+
+   const VkAllocationCallbacks  *alloc;
+   VkPhysicalDevice             physical_device;
+
+   const struct wsi_callbacks   *cbs;
+
+   int                          master_fd;
+
+   struct list_head             connectors;
+
+   struct list_head             display_modes;
+
+   drmModeResPtr                mode_res;
+};
+
+struct wsi_display_image {
+   struct wsi_display_swapchain *chain;
+   VkImage                      image;
+   VkImage                      linear_image;
+   VkDeviceMemory               memory;
+   VkDeviceMemory               linear_memory;
+   bool                         busy;
+   unsigned int                 frame;
+   unsigned int                 sec;
+   unsigned int                 usec;
+   uint32_t                     bo_handle;
+   uint32_t                     fb_id;
+};
+
+struct wsi_display_swapchain {
+   struct wsi_swapchain         base;
+   int                          fd;
+   VkIcdSurfaceDisplay          *surface;
+   struct wsi_display_image     images[0];
+};
+
+ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
+ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
+
+VkResult
+wsi_display_set_master_fd(VkInstance                    instance,
+                          struct wsi_device             *wsi_device,
+                          int                           master_fd)
+{
+   struct wsi_display   *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+
+   wsi->master_fd = master_fd;
+
+   return VK_SUCCESS;
+}
+
+static bool
+same_mode(drmModeModeInfoPtr    a,
+          drmModeModeInfoPtr    b)
+{
+   return memcmp(a, b, sizeof (drmModeModeInfo)) == 0;
+}
+
+static struct wsi_display_mode *
+wsi_display_find_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];
+   size_t                       len;
+   struct wsi_display_mode      *display_mode;
+
+   /* clear name bytes beyond string len */
+   len = strnlen(mode->name, sizeof(mode->name));
+   memset(mode->name + len, '\0', sizeof(mode->name) - len);
+
+   LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) {
+      if (display_mode->connector == connector &&
+          same_mode(&display_mode->mode, mode))
+         return display_mode;
+   }
+   return NULL;
+}
+
+static drmModeModeInfoPtr
+wsi_display_find_mode_info(struct wsi_display_connector *connector,
+                           struct wsi_display_mode      *display_mode)
+{
+   int                          m;
+
+   for (m = 0; m < connector->connector->count_modes; m++) {
+      if (same_mode(&connector->connector->modes[m], &display_mode->mode))
+         return &connector->connector->modes[m];
+   }
+   return NULL;
+}
+
+static VkResult
+wsi_display_register_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;
+
+   display_mode = wsi_display_find_mode(wsi_device, connector, mode);
+
+   if (display_mode)
+      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->mode = *mode;
+
+   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_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;
+   int                          master_fd = wsi->master_fd;
+   int                          p, m;
+   VkResult                     result;
+
+
+   connector = wsi_display_find_connector(wsi_device, connector_id);
+
+   if (!connector) {
+      connector = vk_alloc(wsi->alloc, sizeof *connector, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+      if (!connector)
+         return NULL;
+      memset(connector, '\0', sizeof (*connector));
+      connector->id = connector_id;
+      connector->wsi = wsi;
+      connector->active = false;
+      LIST_ADDTAIL(&connector->list, &wsi->connectors);
+   }
+
+   if (connector->connector)
+      drmModeFreeConnector(connector->connector);
+
+   connector->connector = drmModeGetConnector(master_fd, connector->id);
+
+   if (!connector->connector)
+      return NULL;
+
+   /* Look for an EDID property */
+   for (p = 0; p < connector->connector->count_props; p++) {
+      drmModePropertyPtr prop = drmModeGetProperty(master_fd, connector->connector->props[p]);
+      if (prop && (prop->flags & DRM_MODE_PROP_BLOB)) {
+         if (!strcmp(prop->name, "EDID")) {
+            if (connector->edid_blob)
+               drmModeFreePropertyBlob(connector->edid_blob);
+            connector->edid_blob = drmModeGetPropertyBlob(master_fd,
+                                                       connector->connector->prop_values[p]);
+            /* XXX dig name out of EDID data */
+         }
+      }
+   }
+
+   /* XXX use EDID name */
+   connector->name = "monitor";
+
+   /* Register modes */
+   for (m = 0; m < connector->connector->count_modes; m++) {
+      result = wsi_display_register_mode(wsi_device,
+                                         connector,
+                                         &connector->connector->modes[m]);
+      if (result != VK_SUCCESS)
+         return NULL;
+   }
+
+   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)
+{
+   int                          m;
+   drmModeModeInfoPtr           preferred_mode;
+
+   properties->display = wsi_display_connector_to_handle(connector);
+   properties->displayName = connector->name;
+
+   /* Find the preferred mode and assume that's the physical resolution */
+   if (connector->connector->count_modes > 0) {
+      preferred_mode = &connector->connector->modes[0];
+      for (m = 0; m < connector->connector->count_modes; m++)
+         if (connector->connector->modes[m].type & DRM_MODE_TYPE_PREFERRED) {
+            preferred_mode = &connector->connector->modes[m];
+            break;
+         }
+
+      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
+ */
+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];
+   int                          master_fd = wsi->master_fd;
+   struct wsi_display_connector *connector;
+   int                          c;
+   uint32_t                     connected = 0;
+
+   if (wsi->mode_res)
+      drmModeFreeResources(wsi->mode_res);
+
+   wsi->mode_res = drmModeGetResources(master_fd);
+
+   if (!wsi->mode_res)
+      return VK_ERROR_INITIALIZATION_FAILED;
+
+   connected = 0;
+
+   /* Erase saved connector information */
+   LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) {
+      if (connector->connector) {
+         drmModeFreeConnector(connector->connector);
+         connector->connector = NULL;
+      }
+   }
+
+   /* Get current information */
+   for (c = 0; c < wsi->mode_res->count_connectors; c++) {
+      connector = wsi_display_get_connector(wsi_device, wsi->mode_res->connectors[c]);
+
+      if (!connector)
+         return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+      if (connector->connector->connection != DRM_MODE_DISCONNECTED)
+         connected++;
+   }
+
+   /* Asking only for count, return that */
+   if (properties == NULL) {
+      *property_count = connected;
+      return VK_SUCCESS;
+   }
+
+   connected = 0;
+
+   for (c = 0; c < wsi->mode_res->count_connectors; c++) {
+      connector  = wsi_display_find_connector(wsi_device, wsi->mode_res->connectors[c]);
+      if (connector && connector->connector->connection != DRM_MODE_DISCONNECTED) {
+         if (connected < *property_count) {
+
+            wsi_display_fill_in_display_properties(wsi_device,
+                                                   connector,
+                                                   &properties[connected]);
+         }
+         connected++;
+      }
+   }
+
+   *property_count = connected;
+
+   if (connected <= *property_count)
+      return VK_SUCCESS;
+
+   return VK_INCOMPLETE;
+}
+
+/*
+ * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR
+ */
+
+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;
+   int                          c;
+
+   if (!properties) {
+      *property_count = wsi->mode_res->count_connectors;
+      return VK_SUCCESS;
+   }
+
+   for (c = 0; c < wsi->mode_res->count_connectors; c++) {
+      connector = wsi_display_find_connector(wsi_device, wsi->mode_res->connectors[c]);
+      if (c < *property_count) {
+         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;
+         }
+      }
+   }
+
+   if (c <= *property_count)
+      return VK_SUCCESS;
+
+   return VK_INCOMPLETE;
+}
+
+/*
+ * Implement vkGetDisplayPlaneSupportedDisplaysKHR
+ */
+
+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;
+
+   if (displays == NULL) {
+      *display_count = 1;
+      return VK_SUCCESS;
+   }
+
+   if (*display_count < 1)
+      return VK_INCOMPLETE;
+
+   if (plane_index >= wsi->mode_res->count_connectors)
+      return VK_ERROR_OUT_OF_DATE_KHR;
+
+   connector = wsi_display_find_connector(wsi_device, wsi->mode_res->connectors[plane_index]);
+
+   if (connector) {
+      *displays = wsi_display_connector_to_handle(connector);
+      *display_count = 1;
+   } else {
+      *display_count = 0;
+   }
+
+   return VK_SUCCESS;
+}
+
+/*
+ * Implement vkGetDisplayModePropertiesKHR
+ */
+
+VkResult
+wsi_display_get_display_mode_properties(VkPhysicalDevice               physical_device,
+                                        struct wsi_device              *wsi_device,
+                                        VkDisplayKHR                   display,
+                                        uint32_t                       *property_count,
+                                        VkDisplayModePropertiesKHR     *properties)
+{
+   struct wsi_display_connector *connector = wsi_display_connector_from_handle(display);
+   int                          m, i;
+   struct wsi_display_mode      *display_mode;
+
+   if (properties == NULL) {
+      *property_count = connector->connector->count_modes;
+      return VK_SUCCESS;
+   }
+
+   i = 0;
+   for (m = 0; m < connector->connector->count_modes; m++) {
+      display_mode = wsi_display_find_mode(wsi_device, connector, &connector->connector->modes[m]);
+      if (display_mode) {
+         if (i < *property_count) {
+            properties[i].displayMode = wsi_display_mode_to_handle(display_mode);
+            properties[i].parameters.visibleRegion.width = display_mode->mode.hdisplay;
+            properties[i].parameters.visibleRegion.height = display_mode->mode.vdisplay;
+            properties[i].parameters.refreshRate = display_mode->mode.vrefresh;
+         }
+         i++;
+      }
+   }
+
+   if (i <= *property_count)
+      return VK_SUCCESS;
+
+   return VK_INCOMPLETE;
+}
+
+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->mode.hdisplay;
+   capabilities->minSrcExtent.height = mode->mode.vdisplay;
+   capabilities->maxSrcExtent.width = mode->mode.hdisplay;
+   capabilities->maxSrcExtent.height = mode->mode.vdisplay;
+   capabilities->minDstPosition.x = 0;
+   capabilities->minDstPosition.y = 0;
+   capabilities->maxDstPosition.x = 0;
+   capabilities->maxDstPosition.y = 0;
+   capabilities->minDstExtent.width = mode->mode.hdisplay;
+   capabilities->minDstExtent.height = mode->mode.vdisplay;
+   capabilities->maxDstExtent.width = mode->mode.hdisplay;
+   capabilities->maxDstExtent.height = mode->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,
+                                bool can_handle_different_gpu,
+                                VkBool32* pSupported)
+{
+   struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+
+   *pSupported = wsi->master_fd >= 0;
+
+   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->mode.hdisplay;
+   caps->currentExtent.height = mode->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 const VkSurfaceFormatKHR available_surface_formats[] = {
+   { .format = VK_FORMAT_B8G8R8A8_SRGB, },
+   { .format = 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)
+{
+   if (surface_formats == NULL) {
+      *surface_format_count = ARRAY_SIZE(available_surface_formats);
+      return VK_SUCCESS;
+   }
+
+   *surface_format_count = MIN2(*surface_format_count, ARRAY_SIZE(available_surface_formats));
+   typed_memcpy(surface_formats, available_surface_formats, *surface_format_count);
+
+   return *surface_format_count < ARRAY_SIZE(available_surface_formats) ?
+      VK_INCOMPLETE : VK_SUCCESS;
+}
+
+static const VkPresentModeKHR available_present_modes[] = {
+   VK_PRESENT_MODE_IMMEDIATE_KHR,
+   VK_PRESENT_MODE_MAILBOX_KHR,
+   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;
+   VkResult                     result;
+   uint32_t                     row_pitch;
+   uint32_t                     offset;
+   uint32_t                     handle;
+   uint32_t                     size;
+   int                          ret;
+
+   result = chain->base.image_fns->create_wsi_image(device_h,
+                                                    create_info,
+                                                    allocator,
+                                                    chain->base.needs_linear_copy,
+                                                    false,
+                                                    &image->image,
+                                                    &image->memory,
+                                                    &size,
+                                                    &offset,
+                                                    &row_pitch,
+                                                    NULL,
+                                                    &handle);
+
+   if (result != VK_SUCCESS)
+      return result;
+
+   if (chain->base.needs_linear_copy) {
+      result = chain->base.image_fns->create_wsi_image(device_h,
+                                                       create_info,
+                                                       allocator,
+                                                       chain->base.needs_linear_copy,
+                                                       true,
+                                                       &image->linear_image,
+                                                       &image->linear_memory,
+                                                       &size,
+                                                       &offset,
+                                                       &row_pitch,
+                                                       NULL,
+                                                       &handle);
+
+      if (result != VK_SUCCESS) {
+         goto fail_linear;
+      }
+   }
+
+   image->bo_handle = handle;
+
+   /* XXX extract depth and bpp from image somehow */
+   ret = drmModeAddFB(chain->fd, create_info->imageExtent.width, create_info->imageExtent.height,
+                      24, 32, row_pitch, handle, &image->fb_id);
+
+   if (ret) {
+      result = VK_ERROR_OUT_OF_HOST_MEMORY;
+      goto fail_fb;
+   }
+
+   return VK_SUCCESS;
+
+fail_fb:
+
+   if (chain->base.needs_linear_copy)
+         chain->base.image_fns->free_wsi_image(device_h, allocator,
+                                               image->linear_image, image->linear_memory);
+
+fail_linear:
+
+   chain->base.image_fns->free_wsi_image(device_h, allocator,
+                                         image->image, image->memory);
+
+   return result;
+}
+
+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;
+
+   if (chain->base.needs_linear_copy) {
+      chain->base.image_fns->free_wsi_image(chain->base.device, allocator,
+                                            image->linear_image, image->linear_memory);
+   }
+   chain->base.image_fns->free_wsi_image(chain->base.device, allocator,
+                                        image->image, image->memory);
+}
+
+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 VkResult
+wsi_display_get_images(struct wsi_swapchain     *drv_chain,
+                       uint32_t                 *count,
+                       VkImage                  *images)
+{
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;
+   uint32_t                     ret_count;
+   VkResult                     result;
+
+   if (images == NULL) {
+      *count = chain->base.image_count;
+      return VK_SUCCESS;
+   }
+
+   result = VK_SUCCESS;
+   ret_count = chain->base.image_count;
+   if (chain->base.image_count > *count) {
+     ret_count = *count;
+     result = VK_INCOMPLETE;
+   }
+
+   for (uint32_t i = 0; i < ret_count; i++)
+      images[i] = chain->images[i].image;
+
+   return result;
+}
+
+static void
+wsi_display_get_image_and_linear(struct wsi_swapchain   *drv_chain,
+                                 int                    image_index,
+                                 VkImage                *image,
+                                 VkImage                *linear_image)
+{
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)drv_chain;
+   *image = chain->images[image_index].image;
+   *linear_image = chain->images[image_index].linear_image;
+}
+
+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;
+
+   /* XXX Deal with multiple CRTCs */
+   image->busy = false;
+   image->sec = sec;
+   image->usec = usec;
+}
+
+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 uint64_t wsi_get_current_time(void)
+{
+   uint64_t current_time;
+   struct timespec tv;
+
+   clock_gettime(CLOCK_MONOTONIC, &tv);
+   current_time = tv.tv_nsec + tv.tv_sec*1000000000ull;
+   return current_time;
+}
+
+static int
+wsi_display_wait_for_event(struct wsi_swapchain         *drv_chain,
+                           uint64_t                     timeout_ns)
+{
+   struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)drv_chain;
+   int                          ret_poll;
+   int                          timeout_ms;
+   struct pollfd                pollfd;
+   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
+   };
+
+   if (timeout_ns == UINT64_MAX)
+      timeout_ms = -1;
+   else
+      timeout_ms = timeout_ns / (1000 * 1000);
+
+   pollfd.fd = chain->fd;
+   pollfd.events = POLLIN;
+
+   ret_poll = poll(&pollfd, 1, timeout_ms);
+   (void) drmHandleEvent(chain->fd, &event_context);
+   return ret_poll;
+}
+
+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;
+   uint64_t                     abs_timeout;
+   int64_t                      timeout_remaining;
+   int                          ret = 1;
+
+   if (timeout != 0 && timeout != UINT64_MAX)
+      abs_timeout = wsi_get_current_time() + timeout;
+
+   for (;;) {
+      for (uint32_t i = 0; i < chain->base.image_count; i++) {
+         if (!chain->images[i].busy) {
+            *image_index = i;
+            chain->images[i].busy = true;
+            return VK_SUCCESS;
+         }
+      }
+
+      if (ret == 0)
+         return VK_TIMEOUT;
+      if (ret < 0)
+         return VK_ERROR_OUT_OF_DATE_KHR;
+
+      ret = wsi_display_wait_for_event(drv_chain, timeout);
+
+      if (ret < 0)
+         return VK_ERROR_OUT_OF_DATE_KHR;
+
+      if (timeout != 0 && timeout != UINT64_MAX) {
+         timeout_remaining = abs_timeout - wsi_get_current_time();
+         if (timeout_remaining < 0)
+            timeout_remaining = 0;
+         timeout = timeout_remaining;
+      }
+   }
+}
+
+static uint32_t
+wsi_display_select_crtc(struct wsi_display_connector    *connector)
+{
+   struct wsi_display   *wsi = connector->wsi;
+   int                  c;
+   drmModeResPtr        mode_res = wsi->mode_res;
+   drmModeCrtcPtr       crtc;
+   uint32_t             crtc_id;
+
+   if (!mode_res)
+      return 0;
+
+   crtc_id = 0;
+   for (c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
+      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_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_image     *image = &chain->images[image_index];
+   VkIcdSurfaceDisplay          *surface = chain->surface;
+   wsi_display_mode             *mode = wsi_display_mode_from_handle(surface->displayMode);
+   wsi_display_connector        *connector = mode->connector;
+   drmModeModeInfoPtr           mode_info;
+   int                          ret;
+
+   if (!connector->crtc_id) {
+      connector->crtc_id = wsi_display_select_crtc(connector);
+      if (!connector->crtc_id)
+         return VK_ERROR_OUT_OF_DATE_KHR;
+   }
+
+   for (;;) {
+      ret = drmModePageFlip(chain->fd, connector->crtc_id, image->fb_id,
+                            DRM_MODE_PAGE_FLIP_EVENT, image);
+      if (ret == 0) {
+         image->busy = true;
+         connector->active = true;
+         return VK_SUCCESS;
+      }
+
+      if (ret) {
+         switch(-ret) {
+         case EINVAL:
+
+            /* XXX allow setting of position */
+            mode_info = wsi_display_find_mode_info(connector, mode);
+            if (!mode_info)
+               return VK_ERROR_OUT_OF_DATE_KHR;
+
+            ret = drmModeSetCrtc(chain->fd, connector->crtc_id, image->fb_id, 0, 0,
+                                 &connector->id, 1, mode_info);
+
+            if (ret == 0) {
+               image->busy = true;
+               connector->active = true;
+               return VK_SUCCESS;
+            }
+            break;
+         case EACCES:
+            usleep(1000 * 1000);
+            break;
+         default:
+            return VK_ERROR_OUT_OF_DATE_KHR;
+         }
+      }
+   }
+}
+
+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,
+                                     const struct wsi_image_fns         *image_fns,
+                                     struct wsi_swapchain               **swapchain_out)
+{
+   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, 0,
+                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+
+   if (chain == NULL)
+      return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+   chain->base.device = device;
+   chain->base.destroy = wsi_display_swapchain_destroy;
+   chain->base.get_images = wsi_display_get_images;
+   chain->base.get_image_and_linear = wsi_display_get_image_and_linear;
+   chain->base.acquire_next_image = wsi_display_acquire_next_image;
+   chain->base.queue_present = wsi_display_queue_present;
+   chain->base.image_fns = image_fns;
+   chain->base.present_mode = create_info->presentMode;
+   chain->base.image_count = num_images;
+
+   chain->base.needs_linear_copy = false;
+
+   chain->fd = local_fd;
+
+   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 master_fd,
+                     const struct wsi_callbacks *cbs)
+{
+   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 = master_fd;
+   wsi->physical_device = physical_device;
+   wsi->alloc = alloc;
+   wsi->cbs = cbs;
+
+   LIST_INITHEAD(&wsi->display_modes);
+   LIST_INITHEAD(&wsi->connectors);
+
+   wsi->base.get_support = wsi_display_surface_get_support;
+   wsi->base.get_capabilities = wsi_display_surface_get_capabilities;
+   wsi->base.get_formats = wsi_display_surface_get_formats;
+   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:
+   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) {
+      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 0000000000..7c3db48758
--- /dev/null
+++ b/src/vulkan/wsi/wsi_common_display.h
@@ -0,0 +1,80 @@
+/*
+ * 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 <vulkan/vulkan_keithp.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))); \
+})
+
+VkBool32
+wsi_display_get_presentation_support(struct wsi_device *wsi_device);
+
+VkResult
+wsi_display_set_master_fd(VkInstance                    instance,
+                          struct wsi_device             *wsi_device,
+                          int                           master_fd);
+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_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c
index 5613283d9d..bba389faec 100644
--- a/src/vulkan/wsi/wsi_common_wayland.c
+++ b/src/vulkan/wsi/wsi_common_wayland.c
@@ -659,7 +659,7 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain,
                                                     &size,
                                                     &offset,
                                                     &row_pitch,
-                                                    &fd);
+                                                    &fd, NULL);
    if (result != VK_SUCCESS)
       return result;
 
diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
index c399aae5af..c8659ee9c5 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -944,7 +944,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
                                                     &size,
                                                     &offset,
                                                     &row_pitch,
-                                                    &fd);
+                                                    &fd, NULL);
    if (result != VK_SUCCESS)
       return result;
 
@@ -959,7 +959,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
                                                        &size,
                                                        &offset,
                                                        &row_pitch,
-                                                       &fd);
+                                                       &fd, NULL);
       if (result != VK_SUCCESS) {
          chain->base.image_fns->free_wsi_image(device_h, pAllocator,
                                                image->image, image->memory);
-- 
2.11.0


[-- Attachment #1.1.3: Type: text/plain, Size: 15 bytes --]


-- 
-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 related	[flat|nested] only message in thread

only message in thread, other threads:[~2017-05-31 22:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-05-31 22:41 [PATCH 1/1] Adding VK_KHR_display to mesa based on KMS "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.