[Mesa-dev] [PATCH 1/3] radv: Add VK_KHR_display, VK_KEITHP_kms_display and VK_EXT_direct_mode_display [v2]
Keith Packard
keithp at keithp.com
Wed Aug 2 10:12:39 UTC 2017
Implements VK_KHR_display and VK_EXT_direct_mode_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 at keithp.com>
---
configure.ac | 3 +-
include/vulkan/vulkan.h | 1 +
include/vulkan/vulkan_keithp.h | 40 +
src/Makefile.am | 7 +
src/amd/vulkan/Makefile.am | 10 +
src/amd/vulkan/Makefile.sources | 3 +
src/amd/vulkan/radv_device.c | 73 +-
src/amd/vulkan/radv_entrypoints_gen.py | 3 +
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 | 155 +++
src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c | 18 +
src/intel/vulkan/anv_wsi.c | 2 +-
src/vulkan/Makefile.am | 7 +
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 | 1255 +++++++++++++++++++++++++
src/vulkan/wsi/wsi_common_display.h | 77 ++
src/vulkan/wsi/wsi_common_wayland.c | 2 +-
src/vulkan/wsi/wsi_common_x11.c | 4 +-
22 files changed, 1728 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 6302aa2b0c8..d95b915b984 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,7 @@ AC_SUBST([OPENCL_VERSION])
# in the first entry.
LIBDRM_REQUIRED=2.4.75
LIBDRM_RADEON_REQUIRED=2.4.71
-LIBDRM_AMDGPU_REQUIRED=2.4.82
+LIBDRM_AMDGPU_REQUIRED=2.4.83
LIBDRM_INTEL_REQUIRED=2.4.75
LIBDRM_NVVIEUX_REQUIRED=2.4.66
LIBDRM_NOUVEAU_REQUIRED=2.4.66
@@ -1752,6 +1752,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/include/vulkan/vulkan.h b/include/vulkan/vulkan.h
index 16434fefbe6..943ff7c82b5 100644
--- a/include/vulkan/vulkan.h
+++ b/include/vulkan/vulkan.h
@@ -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 00000000000..acf59fa4e13
--- /dev/null
+++ b/include/vulkan/vulkan_keithp.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2017 Keith Packard <keithp at 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 5aee6b01417..1a0f32c9f25 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,6 +74,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 3350f545403..3a6ada825b5 100644
--- a/src/amd/vulkan/Makefile.am
+++ b/src/amd/vulkan/Makefile.am
@@ -76,6 +76,16 @@ VULKAN_LIB_DEPS = \
$(DLOPEN_LIBS) \
-lm
+if HAVE_PLATFORM_DISPLAY
+AM_CPPFLAGS += \
+ -DVK_USE_PLATFORM_DISPLAY_KHR \
+ -DVK_USE_PLATFORM_KMS_KEITHP \
+ -DVK_USE_PLATFORM_XLIB_XRANDR_EXT
+
+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 d3e0c81e9a3..1119e908d19 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 19f1e105779..da8e7a89f66 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -1,6 +1,7 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
+ * Copyright © 2017 Keith Packard
*
* based in part on anv driver which is:
* Copyright © 2015 Intel Corporation
@@ -106,6 +107,22 @@ static const VkExtensionProperties instance_extensions[] = {
.extensionName = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
.specVersion = 1,
},
+#ifdef VK_USE_PLATFORM_DISPLAY_KHR
+ {
+ .extensionName = VK_KHR_DISPLAY_EXTENSION_NAME,
+ .specVersion = VK_KHR_DISPLAY_SPEC_VERSION
+ },
+ {
+ .extensionName = VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME,
+ .specVersion = 1,
+ },
+#endif
+#ifdef VK_USE_PLATFORM_KMS_KEITHP
+ {
+ .extensionName = VK_KEITHP_KMS_DISPLAY_EXTENSION_NAME,
+ .specVersion = 1,
+ },
+#endif
};
static const VkExtensionProperties common_device_extensions[] = {
@@ -263,6 +280,12 @@ get_chip_name(enum radeon_family family)
}
}
+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,
@@ -271,9 +294,24 @@ 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;
+ 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))
+ {
+ fd = dup(instance->master_fd);
+ } else {
+ return VK_ERROR_INCOMPATIBLE_DRIVER;
+ }
+ }
+
+ if (fd < 0)
+ fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0)
return VK_ERROR_INCOMPATIBLE_DRIVER;
@@ -469,6 +507,20 @@ VkResult radv_CreateInstance(
instance->perftest_flags = parse_debug_string(getenv("RADV_PERFTEST"),
radv_perftest_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;
+ instance->master_fd = vk_kms->fd;
+ break;
+ default:
+ break;
+ }
+ }
+
*pInstance = radv_instance_to_handle(instance);
return VK_SUCCESS;
@@ -2222,6 +2274,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 9634f76fcd6..48125da2e76 100644
--- a/src/amd/vulkan/radv_entrypoints_gen.py
+++ b/src/amd/vulkan/radv_entrypoints_gen.py
@@ -57,6 +57,9 @@ SUPPORTED_EXTENSIONS = [
'VK_KHR_external_semaphore_capabilities',
'VK_KHR_external_semaphore',
'VK_KHR_external_semaphore_fd',
+ 'VK_KEITHP_kms_display',
+ 'VK_KHR_display',
+ 'VK_EXT_direct_mode_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 25afd497da0..27e1e6d6ed7 100644
--- a/src/amd/vulkan/radv_private.h
+++ b/src/amd/vulkan/radv_private.h
@@ -69,11 +69,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
@@ -287,6 +289,8 @@ struct radv_instance {
int physicalDeviceCount;
struct radv_physical_device physicalDevices[RADV_MAX_DRM_DEVICES];
+ int master_fd;
+
uint64_t debug_flags;
uint64_t perftest_flags;
};
@@ -924,6 +928,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 215ef0bfc15..a68671fa152 100644
--- a/src/amd/vulkan/radv_radeon_winsys.h
+++ b/src/amd/vulkan/radv_radeon_winsys.h
@@ -172,6 +172,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 adc43111122..6b58f51cbd8 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, physical_device->local_fd,
+ &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 00000000000..26fb4bee803
--- /dev/null
+++ b/src/amd/vulkan/radv_wsi_display.c
@@ -0,0 +1,155 @@
+/*
+ * 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 "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_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);
+}
+
+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 5c374a238d6..e56113cb5dc 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) {
@@ -507,6 +524,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 9369f26a8fa..991a98fa206 100644
--- a/src/intel/vulkan/anv_wsi.c
+++ b/src/intel/vulkan/anv_wsi.c
@@ -178,7 +178,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 c897a07d6a8..693b93e0c11 100644
--- a/src/vulkan/Makefile.am
+++ b/src/vulkan/Makefile.am
@@ -48,6 +48,13 @@ AM_CPPFLAGS += \
VULKAN_WSI_SOURCES += $(VULKAN_WSI_X11_FILES)
endif
+if HAVE_PLATFORM_DISPLAY
+AM_CPPFLAGS += \
+ -DVK_USE_PLATFORM_DISPLAY
+
+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 2cf7218e926..c7bde8cc1aa 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_FILES := \
util/vk_alloc.h \
util/vk_util.c \
diff --git a/src/vulkan/registry/vk.xml b/src/vulkan/registry/vk.xml
index a3e142f7bad..bbf33c817e0 100644
--- a/src/vulkan/registry/vk.xml
+++ b/src/vulkan/registry/vk.xml
@@ -61,6 +61,7 @@ private version is maintained in the 1.0 branch of the member gitlab server.
<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 -->
@@ -1547,6 +1548,16 @@ private version is maintained in the 1.0 branch of the member gitlab server.
<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 -->
@@ -5456,6 +5467,13 @@ private version is maintained in the 1.0 branch of the member gitlab server.
<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=""VK_KEITHP_kms_display"" 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 8166b7dd344..9ce3b071122 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,
@@ -112,7 +113,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];
@@ -170,5 +171,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 master_fd, int render_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 00000000000..1ec0004be91
--- /dev/null
+++ b/src/vulkan/wsi/wsi_common_display.c
@@ -0,0 +1,1255 @@
+/*
+ * 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 "wsi_common.h"
+#include "wsi_common_queue.h"
+#include "wsi_common_display.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;
+ 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;
+ uint32_t edid_length;
+ uint8_t *edid;
+} wsi_display_connector;
+
+struct wsi_display {
+ struct wsi_interface base;
+
+ const VkAllocationCallbacks *alloc;
+ VkPhysicalDevice physical_device;
+
+ const struct wsi_callbacks *cbs;
+
+ int master_fd;
+
+ pthread_mutex_t wait_mutex;
+ pthread_cond_t wait_cond;
+ pthread_t wait_thread;
+
+ struct list_head connectors;
+
+ struct list_head display_modes;
+
+ drmModeResPtr mode_res;
+};
+
+enum wsi_image_state {
+ wsi_image_idle = 0,
+ wsi_image_drawing = 1,
+ wsi_image_flipping = 2,
+ wsi_image_displaying = 3
+};
+
+struct wsi_display_image {
+ struct wsi_display_swapchain *chain;
+ VkImage image;
+ VkImage linear_image;
+ VkDeviceMemory memory;
+ VkDeviceMemory linear_memory;
+ enum wsi_image_state state;
+ 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;
+ struct wsi_display *wsi;
+ 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)
+
+static bool
+same_mode(drmModeModeInfoPtr a,
+ drmModeModeInfoPtr b)
+{
+ return memcmp(a, b, sizeof (drmModeModeInfo)) == 0;
+}
+
+static uint64_t wsi_get_current_realtime(void)
+{
+ struct timespec tv;
+
+ clock_gettime(CLOCK_REALTIME, &tv);
+ return tv.tv_nsec + tv.tv_sec*1000000000ull;
+}
+
+static int
+wsi_display_wait_for_event(struct wsi_display *wsi,
+ uint64_t timeout_ns);
+
+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;
+ drmModeConnectorPtr drm_connector;
+ int drm_fd = wsi->master_fd;
+ int p, m;
+ VkResult result;
+
+ drm_connector = drmModeGetConnector(drm_fd, connector_id);
+ if (!drm_connector)
+ return NULL;
+
+ 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 = drm_connector;
+
+ /* Look for an EDID property */
+ for (p = 0; p < connector->connector->count_props; p++) {
+ drmModePropertyPtr prop = drmModeGetProperty(drm_fd, drm_connector->props[p]);
+ if (!prop)
+ continue;
+ if (prop->flags & DRM_MODE_PROP_BLOB) {
+ if (!strcmp(prop->name, "EDID")) {
+ drmModePropertyBlobPtr edid_blob = drmModeGetPropertyBlob(drm_fd,
+ drm_connector->prop_values[p]);
+ if (edid_blob) {
+ uint8_t *edid = vk_alloc(wsi->alloc, edid_blob->length, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ if (edid) {
+ memcpy(edid, edid_blob->data, edid_blob->length);
+ if (connector->edid)
+ vk_free(wsi->alloc, connector->edid);
+ connector->edid_length = edid_blob->length;
+ connector->edid = edid;
+ }
+ }
+ /* XXX dig name out of EDID data */
+ }
+ }
+ drmModeFreeProperty(prop);
+ }
+
+ /* XXX use EDID name */
+ connector->name = "monitor";
+
+ /* Register modes */
+ for (m = 0; m < drm_connector->count_modes; m++) {
+ result = wsi_display_register_mode(wsi_device,
+ connector,
+ &drm_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 drm_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(drm_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_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];
+
+ 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);
+
+ if (!wsi->master_is_render && wsi->master_fd >= 0)
+ close(wsi->master_fd);
+ 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;
+ struct wsi_display *wsi = chain->wsi;
+ VkResult result;
+ uint32_t row_pitch;
+ uint32_t offset;
+ uint32_t handle;
+ uint32_t size;
+ int ret;
+
+ memset(image, '\0', sizeof (*image));
+ image->chain = chain;
+ 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(wsi->master_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_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 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;
+ image->sec = sec;
+ image->usec = usec;
+ wsi_display_idle_old_displaying(image);
+}
+
+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_wait_for_event(struct wsi_display *wsi,
+ uint64_t timeout_ns)
+{
+ int ret;
+
+ if (!wsi->wait_thread) {
+ ret = pthread_create(&wsi->wait_thread, NULL, wsi_display_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;
+
+ if (timeout != 0 && timeout != UINT64_MAX)
+ timeout += wsi_get_current_realtime();
+
+ 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;
+ return VK_SUCCESS;
+ }
+ wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
+ }
+
+ if (ret == ETIMEDOUT)
+ return VK_TIMEOUT;
+
+ ret = wsi_display_wait_for_event(wsi, timeout);
+
+ if (ret && ret != ETIMEDOUT)
+ return VK_ERROR_OUT_OF_DATE_KHR;
+ }
+}
+
+/*
+ * Check whether there are any other connectors driven by this crtc
+ */
+static bool
+wsi_display_crtc_solo(struct wsi_display *wsi,
+ drmModeConnectorPtr connector,
+ uint32_t crtc_id)
+{
+ drmModeResPtr mode_res = wsi->mode_res;
+ int drm_fd = wsi->master_fd;
+ 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(drm_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(drm_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;
+}
+
+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;
+ int drm_fd = wsi->master_fd;
+ uint32_t crtc_id;
+
+ if (!mode_res)
+ return 0;
+
+ /* See what CRTC is currently driving this connector */
+ if (connector->connector && connector->connector->encoder_id) {
+ drmModeEncoderPtr encoder = drmModeGetEncoder(drm_fd, connector->connector->encoder_id);
+ if (encoder) {
+ crtc_id = encoder->crtc_id;
+ drmModeFreeEncoder(encoder);
+ if (crtc_id) {
+ if (wsi_display_crtc_solo(wsi, connector->connector, crtc_id))
+ return crtc_id;
+ }
+ }
+ }
+ crtc_id = 0;
+ for (c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
+ drmModeCrtcPtr crtc = drmModeGetCrtc(drm_fd, mode_res->crtcs[c]);
+ if (crtc && crtc->buffer_id == 0)
+ crtc_id = crtc->crtc_id;
+ drmModeFreeCrtc(crtc);
+ }
+ return crtc_id;
+}
+
+static void
+wsi_display_wait_flip_idle(struct wsi_swapchain *drv_chain)
+{
+ struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain;
+ struct wsi_display *wsi = chain->wsi;
+ int ret;
+ uint64_t timeout = 0;
+
+ wsi_display_debug("%9lu wait flip idle\n", pthread_self());
+
+ wsi_display_debug_code(uint64_t start_ns = wsi_get_current_realtime());
+ pthread_mutex_lock(&wsi->wait_mutex);
+ for (;;) {
+ bool busy = false;
+ for (uint32_t i = 0; i < chain->base.image_count; i++)
+ if (chain->images[i].state == wsi_image_flipping) {
+ wsi_display_debug("image %d flipping\n", i);
+ busy = true;
+ break;
+ }
+ if (!busy)
+ break;
+
+ /* wait for at most 100ms; a flip shouldn't take that long... */
+ if (!timeout)
+ timeout = wsi_get_current_realtime() + 100000000ull;
+
+ ret = wsi_display_wait_for_event(wsi, timeout);
+
+ if (ret != 0) {
+ wsi_display_debug("wait for flip idle failed %d %s\n", ret, strerror(ret));
+ break;
+ }
+ }
+
+ wsi_display_debug("%9lu wait flip idle %f ms\n", pthread_self(), ((int64_t) (wsi_get_current_realtime() - start_ns)) / 1.0e6);
+ pthread_mutex_unlock(&wsi->wait_mutex);
+}
+
+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];
+ 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;
+ }
+
+ assert(image->state == wsi_image_drawing);
+ wsi_display_debug("present %d\n", image_index);
+ for (;;) {
+ if (connector->active) {
+ wsi_display_wait_flip_idle(drv_chain);
+ 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:
+
+ /* XXX allow setting of position */
+ mode_info = wsi_display_find_mode_info(connector, mode);
+ if (!mode_info) {
+ image->state = wsi_image_idle;
+ return VK_ERROR_OUT_OF_DATE_KHR;
+ }
+
+ ret = drmModeSetCrtc(wsi->master_fd, connector->crtc_id, image->fb_id, 0, 0,
+ &connector->id, 1, mode_info);
+
+ 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_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)
+{
+ 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, 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->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 master_fd,
+ int render_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;
+ pthread_mutex_init(&wsi->wait_mutex, NULL);
+ wsi->physical_device = physical_device;
+ wsi->alloc = alloc;
+ wsi->cbs = cbs;
+
+ LIST_INITHEAD(&wsi->display_modes);
+ LIST_INITHEAD(&wsi->connectors);
+
+ pthread_mutex_init(&wsi->wait_mutex, NULL);
+ pthread_cond_init(&wsi->wait_cond, NULL);
+
+ 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 00000000000..173c019c4bd
--- /dev/null
+++ b/src/vulkan/wsi/wsi_common_display.h
@@ -0,0 +1,77 @@
+/*
+ * 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))); \
+})
+
+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_release_display(VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ VkDisplayKHR display);
+
+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 dd283a12111..f30c6e01ff2 100644
--- a/src/vulkan/wsi/wsi_common_wayland.c
+++ b/src/vulkan/wsi/wsi_common_wayland.c
@@ -708,7 +708,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 ecdaf914344..6ecfd3ee510 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -975,7 +975,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
&size,
&offset,
&row_pitch,
- &fd);
+ &fd, NULL);
if (result != VK_SUCCESS)
return result;
@@ -990,7 +990,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
More information about the mesa-dev
mailing list