From mboxrd@z Thu Jan 1 00:00:00 1970 From: keithp@keithp.com ("Keith Packard") Subject: [PATCH 1/1] Adding VK_KHR_display to mesa based on KMS Date: Wed, 31 May 2017 15:41:04 -0700 Message-ID: <86r2z43b0f.fsf@hiro.keithp.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1909497287==" Return-path: Received: from elaine.keithp.com (home.keithp.com [63.227.221.253]) by gabe.freedesktop.org (Postfix) with ESMTP id 0247C6E1FC for ; Wed, 31 May 2017 22:41:07 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by elaine.keithp.com (Postfix) with ESMTP id E6E1A3F204C8 for ; Wed, 31 May 2017 15:41:06 -0700 (PDT) Received: from elaine.keithp.com ([127.0.0.1]) by localhost (elaine.keithp.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id lXLqvje2p_Gf for ; Wed, 31 May 2017 15:41:04 -0700 (PDT) Received: from hiro.keithp.com (hiro.keithp.com [10.0.0.36]) by elaine.keithp.com (Postfix) with ESMTPSA id 28FFA3F201D9 for ; Wed, 31 May 2017 15:41:04 -0700 (PDT) List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: dri-devel@lists.freedesktop.orgdri-devel@lists.freedesktop.org List-Id: dri-devel@lists.freedesktop.org --===============1909497287== Content-Type: multipart/signed; boundary="==-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" --==-=-= Content-Type: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: text/plain 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 --=-=-= Content-Type: text/x-diff; charset=utf-8 Content-Disposition: inline; filename=0001-Add-VK_KHR_display-and-VK_KEITHP_kms_display-to-radv.patch Content-Transfer-Encoding: quoted-printable From=2006088071af2a396ce58b0490ceb228e3aa079a09 Mon Sep 17 00:00:00 2001 From: Keith Packard 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 =2D-- 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 =2D-- a/configure.ac +++ b/configure.ac @@ -2238,6 +2238,7 @@ fi =20 AM_CONDITIONAL(HAVE_PLATFORM_X11, echo "$egl_platforms" | grep -q 'x11') AM_CONDITIONAL(HAVE_PLATFORM_WAYLAND, echo "$egl_platforms" | grep -q 'way= land') +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 =2D-- 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 =2D#define VK_HEADER_VERSION 46 +#define VK_HEADER_VERSION 48 =20 =20 #define VK_NULL_HANDLE 0 @@ -214,6 +214,7 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR =3D 1000007000, VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR =3D 1000008000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR =3D 1000009000, + VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP =3D 1000010000, VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT =3D 1000011000, VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD= =3D 1000018000, VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT =3D 1000022000, diff --git a/include/vulkan/vulkan_keithp.h b/include/vulkan/vulkan_keithp.h new file mode 100644 index 0000000000..acf59fa4e1 =2D-- /dev/null +++ b/include/vulkan/vulkan_keithp.h @@ -0,0 +1,40 @@ +/* + * Copyright =C2=A9 2017 Keith Packard + * + * 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 +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +typedef struct VkKmsDisplayInfoKEITHP { + VkStructureType sType; /* VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEIT= HP */ + 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 =2D-- a/src/Makefile.am +++ b/src/Makefile.am @@ -85,6 +85,13 @@ SUBDIRS +=3D vulkan endif EXTRA_DIST +=3D vulkan/registry/vk.xml =20 +EXTRA_DIST +=3D include/vulkan/vulkan_keithp.h + +vulkan_includedir =3D $(includedir)/vulkan + +vulkan_include_HEADERS =3D \ + $(top_srcdir)/include/vulkan/vulkan_keithp.h + if HAVE_AMD_DRIVERS SUBDIRS +=3D amd endif diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am index fbd9f5a030..cf1f5219b9 100644 =2D-- a/src/amd/vulkan/Makefile.am +++ b/src/amd/vulkan/Makefile.am @@ -61,6 +61,15 @@ VULKAN_SOURCES =3D \ =20 VULKAN_LIB_DEPS =3D =20 +if HAVE_PLATFORM_DISPLAY +AM_CPPFLAGS +=3D \ + -DVK_USE_PLATFORM_DISPLAY_KHR \ + -DVK_USE_PLATFORM_KMS_KEITHP + +VULKAN_SOURCES +=3D $(VULKAN_WSI_DISPLAY_FILES) + +VULKAN_LIB_DEPS +=3D $(LIBDRM_LIBS) +endif =20 if HAVE_PLATFORM_X11 AM_CPPFLAGS +=3D \ diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sour= ces index d3e0c81e9a..1119e908d1 100644 =2D-- a/src/amd/vulkan/Makefile.sources +++ b/src/amd/vulkan/Makefile.sources @@ -72,6 +72,9 @@ VULKAN_WSI_WAYLAND_FILES :=3D \ VULKAN_WSI_X11_FILES :=3D \ radv_wsi_x11.c =20 +VULKAN_WSI_DISPLAY_FILES :=3D \ + radv_wsi_display.c + VULKAN_GENERATED_FILES :=3D \ 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 =2D-- a/src/amd/vulkan/radv_device.c +++ b/src/amd/vulkan/radv_device.c @@ -88,6 +88,18 @@ static const VkExtensionProperties instance_extensions[]= =3D { .extensionName =3D VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAM= E, .specVersion =3D 1, }, + { + .extensionName =3D VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NA= ME, + .specVersion =3D VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION + }, + { + .extensionName =3D VK_KHR_DISPLAY_EXTENSION_NAME, + .specVersion =3D VK_KHR_DISPLAY_SPEC_VERSION + }, + { + .extensionName =3D VK_KEITHP_KMS_DISPLAY_EXTENSION_NAME, + .specVersion =3D 1, + } }; =20 static const VkExtensionProperties common_device_extensions[] =3D { @@ -187,6 +199,12 @@ is_extension_enabled(const VkExtensionProperties *exte= nsions, return false; } =20 +static bool +is_same_device(dev_t a, dev_t b) +{ + return major(a) =3D=3D major(b) && (minor(a) & 0x3f) =3D=3D (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; =2D int fd; =2D =2D fd =3D open(path, O_RDWR | O_CLOEXEC); + int fd =3D -1; + struct stat stat_info, stat_path; + + if (instance->master_fd >=3D 0) { + if (fstat(instance->master_fd, &stat_info) >=3D 0 && + stat(path, &stat_path) >=3D 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 =3D dup(instance->master_fd); + } else { + printf("no match for provided device info\n"); + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + } + + if (fd < 0) + fd =3D open(path, O_RDWR | O_CLOEXEC); if (fd < 0) return VK_ERROR_INCOMPATIBLE_DRIVER; =20 @@ -366,6 +401,21 @@ VkResult radv_CreateInstance( instance->debug_flags =3D parse_debug_string(getenv("RADV_DEBUG"), radv_debug_options); =20 + instance->master_fd =3D -1; + + vk_foreach_struct(ext, pCreateInfo->pNext) { + VkKmsDisplayInfoKEITHP *vk_kms; + switch (ext->sType) { + case VK_STRUCTURE_TYPE_KMS_DISPLAY_INFO_KEITHP: + vk_kms =3D (void *) ext; + fprintf(stderr, "Found kms display info keithp str= uct fd %d\n", vk_kms->fd); + instance->master_fd =3D vk_kms->fd; + break; + default: + break; + } + } + *pInstance =3D radv_instance_to_handle(instance); =20 return VK_SUCCESS; @@ -2004,6 +2054,21 @@ bool radv_get_memory_fd(struct radv_device *device, pFD); } =20 +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_e= ntrypoints_gen.py index 3474c789ea..e8e24b8da7 100644 =2D-- a/src/amd/vulkan/radv_entrypoints_gen.py +++ b/src/amd/vulkan/radv_entrypoints_gen.py @@ -42,6 +42,8 @@ supported_extensions =3D [ 'VK_KHR_wayland_surface', 'VK_KHR_xcb_surface', 'VK_KHR_xlib_surface', + 'VK_KEITHP_kms_display', + 'VK_KHR_display' ] =20 # 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 =2D-- a/src/amd/vulkan/radv_private.h +++ b/src/amd/vulkan/radv_private.h @@ -67,11 +67,13 @@ typedef uint32_t xcb_window_t; =20 #include #include +#include #include =20 #include "radv_entrypoints.h" =20 #include "wsi_common.h" +#include "wsi_common_display.h" =20 #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]; =20 + int master_fd; + uint64_t debug_flags; }; =20 @@ -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_rade= on_winsys.h index 84b1d73780..cc7bca73bc 100644 =2D-- 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); =20 + bool (*buffer_get_handle)(struct radeon_winsys *ws, + struct radeon_winsys_bo *bo, + uint32_t *handle); + void (*buffer_unmap)(struct radeon_winsys_bo *bo); =20 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 =2D-- 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_devi= ce) } #endif =20 +#ifdef VK_USE_PLATFORM_DISPLAY_KHR + result =3D wsi_display_init_wsi(&physical_device->wsi_device, + &physical_device->instance->alloc, + radv_physical_device_to_handle(physi= cal_device), + physical_device->instance->master_fd= >=3D 0 ? physical_device->local_fd : -1, + &wsi_cbs); + if (result !=3D VK_SUCCESS) { +#ifdef VK_USE_PLATFORM_XCB_KHR + wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_devi= ce->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; } =20 @@ -69,6 +86,9 @@ radv_finish_wsi(struct radv_physical_device *physical_dev= ice) #ifdef VK_USE_PLATFORM_XCB_KHR wsi_x11_finish_wsi(&physical_device->wsi_device, &physical_device->instan= ce->alloc); #endif +#ifdef VK_USE_PLATFORM_DISPLAY_KHR + wsi_display_finish_wsi(&physical_device->wsi_device, &physical_dev= ice->instance->alloc); +#endif } =20 void radv_DestroySurfaceKHR( @@ -147,7 +167,7 @@ radv_wsi_image_create(VkDevice device_h, VkDeviceMemory *memory_p, uint32_t *size, uint32_t *offset, =2D uint32_t *row_pitch, int *fd_p) + uint32_t *row_pitch, int *fd_p, uint32_t *handle_p) { VkResult result =3D 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); =2D if (!radv_get_memory_fd(device, memory, &fd)) =2D goto fail_alloc_memory; =2D *fd_p =3D fd; + + if (fd_p) { + if (!radv_get_memory_fd(device, memory, &fd)) + goto fail_alloc_memory; + *fd_p =3D fd; + } + if (handle_p) { + uint32_t handle; + if (!radv_get_memory_handle(device, memory, &handle)) + goto fail_alloc_memory; + *handle_p =3D handle; + } } =20 surface =3D &image->surface; diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_di= splay.c new file mode 100644 index 0000000000..7113b78593 =2D-- /dev/null +++ b/src/amd/vulkan/radv_wsi_display.c @@ -0,0 +1,144 @@ +/* + * Copyright =C2=A9 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 t= hat + * the above copyright notice appear in all copies and that both that copy= right + * notice and this permission notice appear in supporting documentation, a= nd + * 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 SOFTW= ARE, + * 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 PERFOR= MANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include "radv_private.h" +#include "radv_cs.h" +#include "util/disk_cache.h" +#include "util/strtod.h" +#include "util/vk_util.h" +#include +#include +#include +#include +#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 ph= ysical_device, + uint32_t *p= roperty_count, + VkDisplayPropertiesKHR *p= roperties) +{ + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); + + return wsi_display_get_physical_device_display_properties(physical_devi= ce, + &pdevice->wsi= _device, + property_coun= t, + properties); +} + +VkResult +radv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice = physical_device, + uint32_t = *property_count, + VkDisplayPlanePropertiesKH= R *properties) +{ + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); + + return wsi_display_get_physical_device_display_plane_properties(physica= l_device, + &pdevic= e->wsi_device, + propert= y_count, + propert= ies); +} + +VkResult +radv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice ph= ysical_device, + uint32_t pl= ane_index, + uint32_t *d= isplay_count, + VkDisplayKHR *d= isplays) +{ + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); + + return wsi_display_get_display_plane_supported_displays(physical_device, + &pdevice->wsi_d= evice, + plane_index, + display_count, + displays); +} + + +VkResult +radv_GetDisplayModePropertiesKHR(VkPhysicalDevice physical_d= evice, + VkDisplayKHR display, + uint32_t *property_= count, + VkDisplayModePropertiesKHR *propertie= s) +{ + 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_d= evice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR *create_in= fo, + const VkAllocationCallbacks *allocator, + VkDisplayModeKHR *mode) +{ + return VK_ERROR_INITIALIZATION_FAILED; +} + + +VkResult +radv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice ph= ysical_device, + VkDisplayModeKHR mo= de_khr, + uint32_t pl= ane_index, + VkDisplayPlaneCapabilitiesKHR *c= apabilities) +{ + 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 _i= nstance, + const VkDisplaySurfaceCreateInfoKHR *c= reate_info, + const VkAllocationCallbacks *a= llocator, + VkSurfaceKHR *s= urface) +{ + RADV_FROM_HANDLE(radv_instance, instance, _instance); + const VkAllocationCallbacks *alloc; + + if (allocator) + alloc =3D allocator; + else + alloc =3D &instance->alloc; + + return wsi_create_display_surface(_instance, alloc, create_info, surfac= e); +} 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 =2D-- 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; } =20 +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 =3D radv_amdgpu_winsys_bo(_bo); + enum amdgpu_bo_handle_type type =3D amdgpu_bo_handle_type_kms; + int r; + + r =3D amdgpu_bo_export(bo->bo, type, handle); + if (r) + return false; + + bo->is_shared =3D 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_w= insys *ws) ws->base.buffer_unmap =3D radv_amdgpu_winsys_bo_unmap; ws->base.buffer_from_fd =3D radv_amdgpu_winsys_bo_from_fd; ws->base.buffer_get_fd =3D radv_amdgpu_winsys_get_fd; + ws->base.buffer_get_handle =3D radv_amdgpu_winsys_get_handle; ws->base.buffer_set_metadata =3D radv_amdgpu_winsys_bo_set_metadata; ws->base.buffer_virtual_bind =3D 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 =2D-- 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, =2D uint32_t *row_pitch, int *fd_p) + uint32_t *row_pitch, int *fd_p, uint32_t *handle_p) { struct anv_device *device =3D 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 =2D-- a/src/vulkan/Makefile.am +++ b/src/vulkan/Makefile.am @@ -48,6 +48,15 @@ VULKAN_WSI_SOURCES +=3D $(VULKAN_WSI_X11_FILES) VULKAN_LIB_DEPS +=3D $(XCB_DRI3_LIBS) -lX11-xcb endif =20 +if HAVE_PLATFORM_DISPLAY +AM_CPPFLAGS +=3D \ + -DVK_USE_PLATFORM_DISPLAY + +VULKAN_WSI_SOURCES +=3D $(VULKAN_WSI_DISPLAY_FILES) + +VULKAN_LIB_DEPS +=3D $(LIBDRM_LIBS) +endif + BUILT_SOURCES +=3D $(VULKAN_WSI_WAYLAND_GENERATED_FILES) CLEANFILES =3D $(BUILT_SOURCES) =20 diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources index 63f4ac1162..109aa83e6b 100644 =2D-- a/src/vulkan/Makefile.sources +++ b/src/vulkan/Makefile.sources @@ -15,6 +15,10 @@ VULKAN_WSI_X11_FILES :=3D \ wsi/wsi_common_x11.c \ wsi/wsi_common_x11.h =20 +VULKAN_WSI_DISPLAY_FILES :=3D \ + wsi/wsi_common_display.c \ + wsi/wsi_common_display.h + VULKAN_UTIL_GENERATED_FILES :=3D \ 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 =2D-- 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 Git= Hub project. + =20 @@ -1538,6 +1539,16 @@ maintained in the master branch of the Khronos Vulka= n GitHub project. xcb_connection_t*= connection xcb_window_t wi= ndow + + VkSt= ructureType sType + VkStructureType sType + constvoid* pNext + int fd= + uint32_t crtc_id + uint32_t* connector= _ids + int connector= _count + drmModeModeInfoPtr mode + VkFormat fo= rmat VkColorSpaceKHR co= lorSpace @@ -5117,6 +5128,13 @@ maintained in the master branch of the Khronos Vulka= n GitHub project. + + + + + + + diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index 5e77518c09..ccf91ecac9 100644 =2D-- 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, =2D 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); }; =20 =2D#define VK_ICD_WSI_PLATFORM_MAX 5 +#define VK_ICD_WSI_PLATFORM_MAX 6 =20 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); =20 +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); =20 #endif diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_commo= n_display.c new file mode 100644 index 0000000000..9336b2ae67 =2D-- /dev/null +++ b/src/vulkan/wsi/wsi_common_display.c @@ -0,0 +1,1063 @@ +/* + * Copyright =C2=A9 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 t= hat + * the above copyright notice appear in all copies and that both that copy= right + * notice and this permission notice appear in supporting documentation, a= nd + * 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 SOFTW= ARE, + * 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 PERFOR= MANCE + * OF THIS SOFTWARE. + */ + +#include "util/macros.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 =3D (struct wsi_display *) wsi_device->wsi[VK= _ICD_WSI_PLATFORM_DISPLAY]; + + wsi->master_fd =3D master_fd; + + return VK_SUCCESS; +} + +static bool +same_mode(drmModeModeInfoPtr a, + drmModeModeInfoPtr b) +{ + return memcmp(a, b, sizeof (drmModeModeInfo)) =3D=3D 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 =3D (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 =3D 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 =3D=3D 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 =3D 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 =3D (struct wsi_display *) wsi_device= ->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_mode *display_mode; + + display_mode =3D wsi_display_find_mode(wsi_device, connector, mode); + + if (display_mode) + return VK_SUCCESS; + + display_mode =3D 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 =3D connector; + display_mode->mode =3D *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 =3D (struct wsi_display *) wsi_device= ->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_connector *connector; + + connector =3D NULL; + LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) { + if (connector->id =3D=3D 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 =3D (struct wsi_display *) wsi_device= ->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_connector *connector; + int master_fd =3D wsi->master_fd; + int p, m; + VkResult result; + + + connector =3D wsi_display_find_connector(wsi_device, connector_id); + + if (!connector) { + connector =3D vk_alloc(wsi->alloc, sizeof *connector, 8, VK_SYSTEM_A= LLOCATION_SCOPE_OBJECT); + if (!connector) + return NULL; + memset(connector, '\0', sizeof (*connector)); + connector->id =3D connector_id; + connector->wsi =3D wsi; + connector->active =3D false; + LIST_ADDTAIL(&connector->list, &wsi->connectors); + } + + if (connector->connector) + drmModeFreeConnector(connector->connector); + + connector->connector =3D drmModeGetConnector(master_fd, connector->id); + + if (!connector->connector) + return NULL; + + /* Look for an EDID property */ + for (p =3D 0; p < connector->connector->count_props; p++) { + drmModePropertyPtr prop =3D 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 =3D drmModeGetPropertyBlob(master_fd, + connector->connecto= r->prop_values[p]); + /* XXX dig name out of EDID data */ + } + } + } + + /* XXX use EDID name */ + connector->name =3D "monitor"; + + /* Register modes */ + for (m =3D 0; m < connector->connector->count_modes; m++) { + result =3D wsi_display_register_mode(wsi_device, + connector, + &connector->connector->modes[m]); + if (result !=3D 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 *w= si_device, + struct wsi_display_connector *c= onnector, + VkDisplayPropertiesKHR *p= roperties) +{ + int m; + drmModeModeInfoPtr preferred_mode; + + properties->display =3D wsi_display_connector_to_handle(connector); + properties->displayName =3D connector->name; + + /* Find the preferred mode and assume that's the physical resolution */ + if (connector->connector->count_modes > 0) { + preferred_mode =3D &connector->connector->modes[0]; + for (m =3D 0; m < connector->connector->count_modes; m++) + if (connector->connector->modes[m].type & DRM_MODE_TYPE_PREFERRED= ) { + preferred_mode =3D &connector->connector->modes[m]; + break; + } + + properties->physicalResolution.width =3D preferred_mode->hdisplay; + properties->physicalResolution.height =3D preferred_mode->vdisplay; + } else { + properties->physicalResolution.width =3D 1024; + properties->physicalResolution.height =3D 768; + } + + /* Make up physical size based on 96dpi */ + properties->physicalDimensions.width =3D floor(properties->physicalReso= lution.width * MM_PER_PIXEL + 0.5); + properties->physicalDimensions.height =3D floor(properties->physicalRes= olution.height * MM_PER_PIXEL + 0.5); + + properties->supportedTransforms =3D VK_SURFACE_TRANSFORM_IDENTITY_BIT_K= HR; + properties->persistentContent =3D 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 =3D (struct wsi_display *) wsi_device= ->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + int master_fd =3D wsi->master_fd; + struct wsi_display_connector *connector; + int c; + uint32_t connected =3D 0; + + if (wsi->mode_res) + drmModeFreeResources(wsi->mode_res); + + wsi->mode_res =3D drmModeGetResources(master_fd); + + if (!wsi->mode_res) + return VK_ERROR_INITIALIZATION_FAILED; + + connected =3D 0; + + /* Erase saved connector information */ + LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) { + if (connector->connector) { + drmModeFreeConnector(connector->connector); + connector->connector =3D NULL; + } + } + + /* Get current information */ + for (c =3D 0; c < wsi->mode_res->count_connectors; c++) { + connector =3D wsi_display_get_connector(wsi_device, wsi->mode_res->c= onnectors[c]); + + if (!connector) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + if (connector->connector->connection !=3D DRM_MODE_DISCONNECTED) + connected++; + } + + /* Asking only for count, return that */ + if (properties =3D=3D NULL) { + *property_count =3D connected; + return VK_SUCCESS; + } + + connected =3D 0; + + for (c =3D 0; c < wsi->mode_res->count_connectors; c++) { + connector =3D wsi_display_find_connector(wsi_device, wsi->mode_res-= >connectors[c]); + if (connector && connector->connector->connection !=3D DRM_MODE_DISC= ONNECTED) { + if (connected < *property_count) { + + wsi_display_fill_in_display_properties(wsi_device, + connector, + &properties[connected]); + } + connected++; + } + } + + *property_count =3D connected; + + if (connected <=3D *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, + VkDisplayPlanePro= pertiesKHR *properties) +{ + struct wsi_display *wsi =3D (struct wsi_display *) wsi_device= ->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_connector *connector; + int c; + + if (!properties) { + *property_count =3D wsi->mode_res->count_connectors; + return VK_SUCCESS; + } + + for (c =3D 0; c < wsi->mode_res->count_connectors; c++) { + connector =3D wsi_display_find_connector(wsi_device, wsi->mode_res->= connectors[c]); + if (c < *property_count) { + if (connector && connector->active) { + properties[c].currentDisplay =3D wsi_display_connector_to_hand= le(connector); + properties[c].currentStackIndex =3D c; + } else { + properties[c].currentDisplay =3D NULL; + properties[c].currentStackIndex =3D 0; + } + } + } + + if (c <=3D *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 =3D (struct wsi_display *) wsi_device= ->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + struct wsi_display_connector *connector; + + if (displays =3D=3D NULL) { + *display_count =3D 1; + return VK_SUCCESS; + } + + if (*display_count < 1) + return VK_INCOMPLETE; + + if (plane_index >=3D wsi->mode_res->count_connectors) + return VK_ERROR_OUT_OF_DATE_KHR; + + connector =3D wsi_display_find_connector(wsi_device, wsi->mode_res->con= nectors[plane_index]); + + if (connector) { + *displays =3D wsi_display_connector_to_handle(connector); + *display_count =3D 1; + } else { + *display_count =3D 0; + } + + return VK_SUCCESS; +} + +/* + * Implement vkGetDisplayModePropertiesKHR + */ + +VkResult +wsi_display_get_display_mode_properties(VkPhysicalDevice phy= sical_device, + struct wsi_device *ws= i_device, + VkDisplayKHR dis= play, + uint32_t *pr= operty_count, + VkDisplayModePropertiesKHR *pr= operties) +{ + struct wsi_display_connector *connector =3D wsi_display_connector_from_= handle(display); + int m, i; + struct wsi_display_mode *display_mode; + + if (properties =3D=3D NULL) { + *property_count =3D connector->connector->count_modes; + return VK_SUCCESS; + } + + i =3D 0; + for (m =3D 0; m < connector->connector->count_modes; m++) { + display_mode =3D wsi_display_find_mode(wsi_device, connector, &conne= ctor->connector->modes[m]); + if (display_mode) { + if (i < *property_count) { + properties[i].displayMode =3D wsi_display_mode_to_handle(displ= ay_mode); + properties[i].parameters.visibleRegion.width =3D display_mode-= >mode.hdisplay; + properties[i].parameters.visibleRegion.height =3D display_mode= ->mode.vdisplay; + properties[i].parameters.refreshRate =3D display_mode->mode.vr= efresh; + } + i++; + } + } + + if (i <=3D *property_count) + return VK_SUCCESS; + + return VK_INCOMPLETE; +} + +VkResult +wsi_get_display_plane_capabilities(VkPhysicalDevice ph= ysical_device, + struct wsi_device *w= si_device, + VkDisplayModeKHR mo= de_khr, + uint32_t pl= ane_index, + VkDisplayPlaneCapabilitiesKHR *c= apabilities) +{ + struct wsi_display_mode *mode =3D wsi_display_mode_from_handle(mod= e_khr); + + /* XXX use actual values */ + capabilities->supportedAlpha =3D VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + capabilities->minSrcPosition.x =3D 0; + capabilities->minSrcPosition.y =3D 0; + capabilities->maxSrcPosition.x =3D 0; + capabilities->maxSrcPosition.y =3D 0; + capabilities->minSrcExtent.width =3D mode->mode.hdisplay; + capabilities->minSrcExtent.height =3D mode->mode.vdisplay; + capabilities->maxSrcExtent.width =3D mode->mode.hdisplay; + capabilities->maxSrcExtent.height =3D mode->mode.vdisplay; + capabilities->minDstPosition.x =3D 0; + capabilities->minDstPosition.y =3D 0; + capabilities->maxDstPosition.x =3D 0; + capabilities->maxDstPosition.y =3D 0; + capabilities->minDstExtent.width =3D mode->mode.hdisplay; + capabilities->minDstExtent.height =3D mode->mode.vdisplay; + capabilities->maxDstExtent.width =3D mode->mode.hdisplay; + capabilities->maxDstExtent.height =3D mode->mode.vdisplay; + return VK_SUCCESS; +} + +VkResult +wsi_create_display_surface(VkInstance instance, + const VkAllocationCallbacks *allocator, + const VkDisplaySurfaceCreateInfoKHR *create_inf= o, + VkSurfaceKHR *surface_khr) +{ + VkIcdSurfaceDisplay *surface; + + surface =3D vk_alloc(allocator, sizeof *surface, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (surface =3D=3D NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + surface->base.platform =3D VK_ICD_WSI_PLATFORM_DISPLAY; + + surface->displayMode =3D create_info->displayMode; + surface->planeIndex =3D create_info->planeIndex; + surface->planeStackIndex =3D create_info->planeStackIndex; + surface->transform =3D create_info->transform; + surface->globalAlpha =3D create_info->globalAlpha; + surface->alphaMode =3D create_info->alphaMode; + surface->imageExtent =3D create_info->imageExtent; + + *surface_khr =3D 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 =3D (struct wsi_display *) wsi_device->wsi[VK_I= CD_WSI_PLATFORM_DISPLAY]; + + *pSupported =3D wsi->master_fd >=3D 0; + + return VK_SUCCESS; +} + +static VkResult +wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base, + VkSurfaceCapabilitiesKHR* caps) +{ + VkIcdSurfaceDisplay *surface =3D (VkIcdSurfaceDisplay *) surface_base; + wsi_display_mode *mode =3D wsi_display_mode_from_handle(surface->displa= yMode); + + caps->currentExtent.width =3D mode->mode.hdisplay; + caps->currentExtent.height =3D mode->mode.vdisplay; + + /* XXX Figure out extents based on driver capabilities */ + caps->maxImageExtent =3D caps->minImageExtent =3D caps->currentExtent; + + caps->supportedCompositeAlpha =3D (VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR | + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR); + + caps->minImageCount =3D 2; + caps->maxImageCount =3D 0; + + caps->supportedTransforms =3D VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + caps->currentTransform =3D VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + caps->maxImageArrayLayers =3D 1; + caps->supportedUsageFlags =3D + 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[] =3D { + { .format =3D VK_FORMAT_B8G8R8A8_SRGB, }, + { .format =3D VK_FORMAT_B8G8R8A8_UNORM, }, +}; + +static VkResult +wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface, + struct wsi_device *wsi_device, + uint32_t *surface_format_co= unt, + VkSurfaceFormatKHR *surface_formats) +{ + if (surface_formats =3D=3D NULL) { + *surface_format_count =3D ARRAY_SIZE(available_surface_formats); + return VK_SUCCESS; + } + + *surface_format_count =3D MIN2(*surface_format_count, ARRAY_SIZE(availa= ble_surface_formats)); + typed_memcpy(surface_formats, available_surface_formats, *surface_forma= t_count); + + return *surface_format_count < ARRAY_SIZE(available_surface_formats) ? + VK_INCOMPLETE : VK_SUCCESS; +} + +static const VkPresentModeKHR available_present_modes[] =3D { + 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_coun= t, + VkPresentModeKHR *present_modes) +{ + if (present_modes =3D=3D NULL) { + *present_mode_count =3D ARRAY_SIZE(available_present_modes); + return VK_SUCCESS; + } + + *present_mode_count =3D MIN2(*present_mode_count, ARRAY_SIZE(available_= present_modes)); + typed_memcpy(present_modes, available_present_modes, *present_mode_coun= t); + + 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 =3D (struct wsi_display_swapchain *= ) drv_chain; + VkResult result; + uint32_t row_pitch; + uint32_t offset; + uint32_t handle; + uint32_t size; + int ret; + + result =3D chain->base.image_fns->create_wsi_image(device_h, + create_info, + allocator, + chain->base.needs_line= ar_copy, + false, + &image->image, + &image->memory, + &size, + &offset, + &row_pitch, + NULL, + &handle); + + if (result !=3D VK_SUCCESS) + return result; + + if (chain->base.needs_linear_copy) { + result =3D chain->base.image_fns->create_wsi_image(device_h, + create_info, + allocator, + chain->base.needs_l= inear_copy, + true, + &image->linear_imag= e, + &image->linear_memo= ry, + &size, + &offset, + &row_pitch, + NULL, + &handle); + + if (result !=3D VK_SUCCESS) { + goto fail_linear; + } + } + + image->bo_handle =3D handle; + + /* XXX extract depth and bpp from image somehow */ + ret =3D drmModeAddFB(chain->fd, create_info->imageExtent.width, create_= info->imageExtent.height, + 24, 32, row_pitch, handle, &image->fb_id); + + if (ret) { + result =3D 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 =3D (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->li= near_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 =3D (struct wsi_display_swapchain *= ) drv_chain; + + for (uint32_t i =3D 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 =3D (struct wsi_display_swapchain *= ) drv_chain; + uint32_t ret_count; + VkResult result; + + if (images =3D=3D NULL) { + *count =3D chain->base.image_count; + return VK_SUCCESS; + } + + result =3D VK_SUCCESS; + ret_count =3D chain->base.image_count; + if (chain->base.image_count > *count) { + ret_count =3D *count; + result =3D VK_INCOMPLETE; + } + + for (uint32_t i =3D 0; i < ret_count; i++) + images[i] =3D 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 =3D (struct wsi_display_swapchain *= )drv_chain; + *image =3D chain->images[image_index].image; + *linear_image =3D 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 =3D data; + + /* XXX Deal with multiple CRTCs */ + image->busy =3D false; + image->sec =3D sec; + image->usec =3D usec; +} + +static void wsi_display_page_flip_handler(int fd, unsigned int frame, + unsigned int sec, unsigned int u= sec, 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 =3D 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 =3D (struct wsi_display_swapchain *= )drv_chain; + int ret_poll; + int timeout_ms; + struct pollfd pollfd; + drmEventContext event_context =3D { + .version =3D DRM_EVENT_CONTEXT_VERSION, + .page_flip_handler =3D wsi_display_page_flip_handler, +#if DRM_EVENT_CONTEXT_VERSION >=3D 3 + .page_flip_handler2 =3D wsi_display_page_flip_handler2, +#endif + }; + + if (timeout_ns =3D=3D UINT64_MAX) + timeout_ms =3D -1; + else + timeout_ms =3D timeout_ns / (1000 * 1000); + + pollfd.fd =3D chain->fd; + pollfd.events =3D POLLIN; + + ret_poll =3D 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 =3D (struct wsi_display_swapchain *= )drv_chain; + uint64_t abs_timeout; + int64_t timeout_remaining; + int ret =3D 1; + + if (timeout !=3D 0 && timeout !=3D UINT64_MAX) + abs_timeout =3D wsi_get_current_time() + timeout; + + for (;;) { + for (uint32_t i =3D 0; i < chain->base.image_count; i++) { + if (!chain->images[i].busy) { + *image_index =3D i; + chain->images[i].busy =3D true; + return VK_SUCCESS; + } + } + + if (ret =3D=3D 0) + return VK_TIMEOUT; + if (ret < 0) + return VK_ERROR_OUT_OF_DATE_KHR; + + ret =3D wsi_display_wait_for_event(drv_chain, timeout); + + if (ret < 0) + return VK_ERROR_OUT_OF_DATE_KHR; + + if (timeout !=3D 0 && timeout !=3D UINT64_MAX) { + timeout_remaining =3D abs_timeout - wsi_get_current_time(); + if (timeout_remaining < 0) + timeout_remaining =3D 0; + timeout =3D timeout_remaining; + } + } +} + +static uint32_t +wsi_display_select_crtc(struct wsi_display_connector *connector) +{ + struct wsi_display *wsi =3D connector->wsi; + int c; + drmModeResPtr mode_res =3D wsi->mode_res; + drmModeCrtcPtr crtc; + uint32_t crtc_id; + + if (!mode_res) + return 0; + + crtc_id =3D 0; + for (c =3D 0; crtc_id =3D=3D 0 && c < mode_res->count_crtcs; c++) { + crtc =3D drmModeGetCrtc(wsi->master_fd, mode_res->crtcs[c]); + if (crtc && crtc->buffer_id =3D=3D 0) + crtc_id =3D 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 =3D (struct wsi_display_swapchain *= ) drv_chain; + struct wsi_display_image *image =3D &chain->images[image_index]; + VkIcdSurfaceDisplay *surface =3D chain->surface; + wsi_display_mode *mode =3D wsi_display_mode_from_handle(sur= face->displayMode); + wsi_display_connector *connector =3D mode->connector; + drmModeModeInfoPtr mode_info; + int ret; + + if (!connector->crtc_id) { + connector->crtc_id =3D wsi_display_select_crtc(connector); + if (!connector->crtc_id) + return VK_ERROR_OUT_OF_DATE_KHR; + } + + for (;;) { + ret =3D drmModePageFlip(chain->fd, connector->crtc_id, image->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, image); + if (ret =3D=3D 0) { + image->busy =3D true; + connector->active =3D true; + return VK_SUCCESS; + } + + if (ret) { + switch(-ret) { + case EINVAL: + + /* XXX allow setting of position */ + mode_info =3D wsi_display_find_mode_info(connector, mode); + if (!mode_info) + return VK_ERROR_OUT_OF_DATE_KHR; + + ret =3D drmModeSetCrtc(chain->fd, connector->crtc_id, image->f= b_id, 0, 0, + &connector->id, 1, mode_info); + + if (ret =3D=3D 0) { + image->busy =3D true; + connector->active =3D 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 *i= cd_surface, + VkDevice de= vice, + struct wsi_device *w= si_device, + int lo= cal_fd, + const VkSwapchainCreateInfoKHR *c= reate_info, + const VkAllocationCallbacks *a= llocator, + const struct wsi_image_fns *i= mage_fns, + struct wsi_swapchain **= swapchain_out) +{ + VkResult result; + assert(create_info->sType =3D=3D VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INF= O_KHR); + + struct wsi_display_swapchain *chain; + const unsigned num_images =3D create_info->minImageCount; + size_t size =3D sizeof(*chain) + num_images * sizeof(chain->images[0]); + + chain =3D vk_alloc(allocator, size, 0, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (chain =3D=3D NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + chain->base.device =3D device; + chain->base.destroy =3D wsi_display_swapchain_destroy; + chain->base.get_images =3D wsi_display_get_images; + chain->base.get_image_and_linear =3D wsi_display_get_image_and_linear; + chain->base.acquire_next_image =3D wsi_display_acquire_next_image; + chain->base.queue_present =3D wsi_display_queue_present; + chain->base.image_fns =3D image_fns; + chain->base.present_mode =3D create_info->presentMode; + chain->base.image_count =3D num_images; + + chain->base.needs_linear_copy =3D false; + + chain->fd =3D local_fd; + + chain->surface =3D (VkIcdSurfaceDisplay *) icd_surface; + + for (uint32_t image =3D 0; image < chain->base.image_count; image++) { + result =3D wsi_display_image_init(device, &chain->base, create_info,= allocator, + &chain->images[image]); + if (result !=3D VK_SUCCESS) + goto fail_init_images; + } + + *swapchain_out =3D &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 =3D vk_alloc(alloc, sizeof(*wsi), 8, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + if (!wsi) { + result =3D VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + memset(wsi, '\0', sizeof (*wsi)); + + wsi->master_fd =3D master_fd; + wsi->physical_device =3D physical_device; + wsi->alloc =3D alloc; + wsi->cbs =3D cbs; + + LIST_INITHEAD(&wsi->display_modes); + LIST_INITHEAD(&wsi->connectors); + + wsi->base.get_support =3D wsi_display_surface_get_support; + wsi->base.get_capabilities =3D wsi_display_surface_get_capabilities; + wsi->base.get_formats =3D wsi_display_surface_get_formats; + wsi->base.get_present_modes =3D wsi_display_surface_get_present_modes; + wsi->base.create_swapchain =3D wsi_display_surface_create_swapchain; + + wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] =3D &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 =3D (struct wsi_display *) wsi_device->wsi[VK_I= CD_WSI_PLATFORM_DISPLAY]; + + if (wsi) { + vk_free(alloc, wsi); + } +} diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_commo= n_display.h new file mode 100644 index 0000000000..7c3db48758 =2D-- /dev/null +++ b/src/vulkan/wsi/wsi_common_display.h @@ -0,0 +1,80 @@ +/* + * Copyright =C2=A9 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 t= hat + * the above copyright notice appear in all copies and that both that copy= right + * notice and this permission notice appear in supporting documentation, a= nd + * 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 SOFTW= ARE, + * 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 PERFOR= MANCE + * OF THIS SOFTWARE. + */ + +#ifndef WSI_COMMON_DISPLAY_H +#define WSI_COMMON_DISPLAY_H + +#include "wsi_common.h" +#include +#include +#include + +#define typed_memcpy(dest, src, count) ({ \ + STATIC_ASSERT(sizeof(*src) =3D=3D 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, + VkDisplayPlanePro= pertiesKHR *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 phy= sical_device, + struct wsi_device *ws= i_device, + VkDisplayKHR dis= play, + uint32_t *pr= operty_count, + VkDisplayModePropertiesKHR *pr= operties); + +VkResult +wsi_get_display_plane_capabilities(VkPhysicalDevice ph= ysical_device, + struct wsi_device *w= si_device, + VkDisplayModeKHR mo= de_khr, + uint32_t pl= ane_index, + VkDisplayPlaneCapabilitiesKHR *c= apabilities); + +VkResult +wsi_create_display_surface(VkInstance instance, + const VkAllocationCallbacks *pAllocator, + const VkDisplaySurfaceCreateInfoKHR *pCreateInf= o, + VkSurfaceKHR *pSurface); + +#endif diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_commo= n_wayland.c index 5613283d9d..bba389faec 100644 =2D-- 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, =2D &fd); + &fd, NULL); if (result !=3D VK_SUCCESS) return result; =20 diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x1= 1.c index c399aae5af..c8659ee9c5 100644 =2D-- 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, =2D &fd); + &fd, NULL); if (result !=3D VK_SUCCESS) return result; =20 @@ -959,7 +959,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain = *chain, &size, &offset, &row_pitch, =2D &fd); + &fd, NULL); if (result !=3D VK_SUCCESS) { chain->base.image_fns->free_wsi_image(device_h, pAllocator, image->image, image->memory= ); =2D-=20 2.11.0 --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable =2D-=20 =2Dkeith --=-=-=-- --==-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEw4O3eCVWE9/bQJ2R2yIaaQAAABEFAlkvRoAACgkQ2yIaaQAA ABFKUBAAhQ3ISHGdexeuHZdh1iUpx3mGVP+3o16HxePrMCNOul9kHAqtZvm9HPcK v+EwhRpuab6IXNa9KLiWH9L7Jhpqm4injr+hR/AQYOciht5UGQpxqk41J82jGa9y jW5at0Mfj79r0NLOKKihOVLiobAeRWoNrisuV7JSlshMcu4nt5vFTw7IKeQl8YvC tjNlTp5aXuU+aPoa16me+4PhztQdZ1kBXVvPdu5LqFmMe1R3WZg/o9IRY8nX3V5X BEv6s92t3WVHss9T7wDtd2MlrWfgJ1/PG7sHAxkFLidjmC2gl9l04ezQ88RVOWra 5SqP8HugWodqKiyHvuFAhawZ2Uw1ymQUQ91TmoV4+0q29XoEBAjuyJ539WUKMtoo sj8bt+Htuzr2PjmD17noUEAu38hCXWEV5j1sMya7tkweppOzofc7BK0fB6Wepcjn kWd1x+tVCWmnMx7PtAPkBxRpoSf/IBFENDTlO+pBOes2xp8pclFl42jy8bucghZU ZNW8zbmdm3E7nJwJQzF2RtjJRQbK69KsLT2/wZoMM64cjhHKewrjOPa/FvyVOy3v DRv9fDhMXbfHyHZ/q7nLSdqPUP0qToAeh9t076k1i0aJNDuPF9hmOsIiowcgYREr avG6a7zw9mzRPxtRSjgEiJCmlhseQBAUn8uTd5xDfeEZMdHAJwg= =/oUM -----END PGP SIGNATURE----- --==-=-=-- --===============1909497287== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KZHJpLWRldmVs IG1haWxpbmcgbGlzdApkcmktZGV2ZWxAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHBzOi8vbGlz dHMuZnJlZWRlc2t0b3Aub3JnL21haWxtYW4vbGlzdGluZm8vZHJpLWRldmVsCg== --===============1909497287==--