On Friday, 2018-02-09 20:45:10 -0800, Keith Packard wrote: > This adds support for the KHR_display extension to the anv and radv > Vulkan drivers. The drivers now attempt to open the master DRM node > when the KHR_display extension is requested so that the common winsys > code can perform the necessary operations. > > Signed-off-by: Keith Packard <keithp@xxxxxxxxxx> > --- > configure.ac | 1 + > meson.build | 4 +- > src/amd/vulkan/Makefile.am | 8 + > src/amd/vulkan/Makefile.sources | 3 + > src/amd/vulkan/meson.build | 7 + > src/amd/vulkan/radv_device.c | 28 +- > src/amd/vulkan/radv_extensions.py | 7 +- > src/amd/vulkan/radv_private.h | 2 + > src/amd/vulkan/radv_wsi.c | 3 +- > src/amd/vulkan/radv_wsi_display.c | 143 ++++ > src/intel/Makefile.sources | 3 + > src/intel/Makefile.vulkan.am | 7 + > src/intel/vulkan/anv_device.c | 18 +- > src/intel/vulkan/anv_extensions.py | 1 + > src/intel/vulkan/anv_extensions_gen.py | 5 +- > src/intel/vulkan/anv_wsi.c | 3 +- > src/intel/vulkan/anv_wsi_display.c | 129 +++ > src/intel/vulkan/meson.build | 7 + > src/vulkan/Makefile.am | 7 + > src/vulkan/Makefile.sources | 4 + > src/vulkan/wsi/meson.build | 10 + > src/vulkan/wsi/wsi_common.c | 19 +- > src/vulkan/wsi/wsi_common.h | 5 +- > src/vulkan/wsi/wsi_common_display.c | 1368 ++++++++++++++++++++++++++++++++ > src/vulkan/wsi/wsi_common_display.h | 72 ++ > src/vulkan/wsi/wsi_common_private.h | 10 + > 26 files changed, 1858 insertions(+), 16 deletions(-) > create mode 100644 src/amd/vulkan/radv_wsi_display.c > create mode 100644 src/intel/vulkan/anv_wsi_display.c > create mode 100644 src/vulkan/wsi/wsi_common_display.c > create mode 100644 src/vulkan/wsi/wsi_common_display.h > > diff --git a/configure.ac b/configure.ac > index 8ed606c7694..46318365603 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -1849,6 +1849,7 @@ fi > AM_CONDITIONAL(HAVE_PLATFORM_X11, echo "$platforms" | grep -q 'x11') > AM_CONDITIONAL(HAVE_PLATFORM_WAYLAND, echo "$platforms" | grep -q 'wayland') > AM_CONDITIONAL(HAVE_PLATFORM_DRM, echo "$platforms" | grep -q 'drm') > +AM_CONDITIONAL(HAVE_PLATFORM_DISPLAY, echo "$platforms" | grep -q 'drm') copy/paste error: s/drm/display/ > AM_CONDITIONAL(HAVE_PLATFORM_SURFACELESS, echo "$platforms" | grep -q 'surfaceless') > AM_CONDITIONAL(HAVE_PLATFORM_ANDROID, echo "$platforms" | grep -q 'android') > > diff --git a/meson.build b/meson.build > index b39e2f8ab96..aeb7f5e2917 100644 > --- a/meson.build > +++ b/meson.build > @@ -239,11 +239,12 @@ with_platform_wayland = false > with_platform_x11 = false > with_platform_drm = false > with_platform_surfaceless = false > +with_platform_display = false > egl_native_platform = '' > _platforms = get_option('platforms') > if _platforms == 'auto' > if system_has_kms_drm > - _platforms = 'x11,wayland,drm,surfaceless' > + _platforms = 'x11,wayland,drm,surfaceless,display' > elif ['darwin', 'windows', 'cygwin'].contains(host_machine.system()) > _platforms = 'x11,surfaceless' > else > @@ -257,6 +258,7 @@ if _platforms != '' > with_platform_wayland = _split.contains('wayland') > with_platform_drm = _split.contains('drm') > with_platform_surfaceless = _split.contains('surfaceless') > + with_platform_display = _split.contains('display') > egl_native_platform = _split[0] > endif > > diff --git a/src/amd/vulkan/Makefile.am b/src/amd/vulkan/Makefile.am > index 61025968942..061b8144b88 100644 > --- a/src/amd/vulkan/Makefile.am > +++ b/src/amd/vulkan/Makefile.am > @@ -76,6 +76,14 @@ VULKAN_LIB_DEPS = \ > $(DLOPEN_LIBS) \ > -lm > > +if HAVE_PLATFORM_DISPLAY > +AM_CPPFLAGS += \ > + -DVK_USE_PLATFORM_DISPLAY_KHR > + > +VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES) > + > +endif > + > if HAVE_PLATFORM_X11 > AM_CPPFLAGS += \ > $(XCB_DRI3_CFLAGS) \ > diff --git a/src/amd/vulkan/Makefile.sources b/src/amd/vulkan/Makefile.sources > index a510d88d965..618a6cdaed0 100644 > --- a/src/amd/vulkan/Makefile.sources > +++ b/src/amd/vulkan/Makefile.sources > @@ -78,6 +78,9 @@ VULKAN_WSI_WAYLAND_FILES := \ > VULKAN_WSI_X11_FILES := \ > radv_wsi_x11.c > > +VULKAN_WSI_DISPLAY_FILES := \ > + radv_wsi_display.c > + > VULKAN_GENERATED_FILES := \ > radv_entrypoints.c \ > radv_entrypoints.h \ > diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build > index 0a7b7c0bf3c..b7bb1075e7d 100644 > --- a/src/amd/vulkan/meson.build > +++ b/src/amd/vulkan/meson.build > @@ -112,6 +112,13 @@ if with_platform_wayland > libradv_files += files('radv_wsi_wayland.c') > endif > > +if with_platform_display > + radv_flags += [ > + '-DVK_USE_PLATFORM_DISPLAY_KHR', > + ] Nit: this can be a simple radv_flags += '-DVK_USE_PLATFORM_DISPLAY_KHR' > + libradv_files += files('radv_wsi_display.c') > +endif > + > libvulkan_radeon = shared_library( > 'vulkan_radeon', > [libradv_files, radv_entrypoints, radv_extensions_c, vk_format_table_c], > diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c > index 09bb382eeb8..adf33eb35dc 100644 > --- a/src/amd/vulkan/radv_device.c > +++ b/src/amd/vulkan/radv_device.c > @@ -191,9 +191,26 @@ radv_physical_device_init(struct radv_physical_device *device, > const char *path = drm_device->nodes[DRM_NODE_RENDER]; > VkResult result; > drmVersionPtr version; > - int fd; > - > - fd = open(path, O_RDWR | O_CLOEXEC); > + int fd = -1; > + > + if (instance->khr_display_requested) { > + fd = open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC); > + if (fd >= 0) { > + uint32_t accel_working = 0; > + struct drm_amdgpu_info request = { > + .return_pointer = (uintptr_t)&accel_working, > + .return_size = sizeof(accel_working), > + .query = AMDGPU_INFO_ACCEL_WORKING > + }; > + > + if (drmCommandWrite(fd, DRM_AMDGPU_INFO, &request, sizeof (struct drm_amdgpu_info)) < 0 || !accel_working) { > + close(fd); > + fd = -1; > + } > + } > + } > + if (fd < 0) > + fd = open(path, O_RDWR | O_CLOEXEC); Nit: src/amd/vulkan/ uses tabs for indent, you used spaces. > if (fd < 0) > return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER); > > @@ -209,6 +226,7 @@ radv_physical_device_init(struct radv_physical_device *device, > close(fd); > return VK_ERROR_INCOMPATIBLE_DRIVER; > } > + > drmFreeVersion(version); > > device->_loader_data.loaderMagic = ICD_LOADER_MAGIC; > @@ -387,6 +405,7 @@ VkResult radv_CreateInstance( > { > struct radv_instance *instance; > VkResult result; > + bool khr_display_requested = false; > > assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO); > > @@ -411,6 +430,8 @@ VkResult radv_CreateInstance( > const char *ext_name = pCreateInfo->ppEnabledExtensionNames[i]; > if (!radv_instance_extension_supported(ext_name)) > return vk_error(VK_ERROR_EXTENSION_NOT_PRESENT); > + if (strcmp(ext_name, VK_KHR_DISPLAY_EXTENSION_NAME) == 0) > + khr_display_requested = true; > } > > instance = vk_zalloc2(&default_alloc, pAllocator, sizeof(*instance), 8, > @@ -427,6 +448,7 @@ VkResult radv_CreateInstance( > > instance->apiVersion = client_version; > instance->physicalDeviceCount = -1; > + instance->khr_display_requested = khr_display_requested; > > result = vk_debug_report_instance_init(&instance->debug_report_callbacks); > if (result != VK_SUCCESS) { > diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py > index d761895d3a0..24cab8cbb39 100644 > --- a/src/amd/vulkan/radv_extensions.py > +++ b/src/amd/vulkan/radv_extensions.py > @@ -81,6 +81,7 @@ EXTENSIONS = [ > Extension('VK_KHR_wayland_surface', 6, 'VK_USE_PLATFORM_WAYLAND_KHR'), > Extension('VK_KHR_xcb_surface', 6, 'VK_USE_PLATFORM_XCB_KHR'), > Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'), > + Extension('VK_KHR_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), > Extension('VK_KHX_multiview', 1, '!ANDROID'), > Extension('VK_EXT_debug_report', 9, True), > Extension('VK_EXT_discard_rectangles', 1, True), > @@ -168,7 +169,7 @@ _TEMPLATE = Template(COPYRIGHT + """ > #include "vk_util.h" > > /* Convert the VK_USE_PLATFORM_* defines to booleans */ > -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']: > +%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']: > #ifdef VK_USE_PLATFORM_${platform}_KHR > # undef VK_USE_PLATFORM_${platform}_KHR > # define VK_USE_PLATFORM_${platform}_KHR true > @@ -187,7 +188,9 @@ _TEMPLATE = Template(COPYRIGHT + """ > > #define RADV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\ > VK_USE_PLATFORM_XCB_KHR || \\ > - VK_USE_PLATFORM_XLIB_KHR) > + VK_USE_PLATFORM_XLIB_KHR || \\ > + VK_USE_PLATFORM_DISPLAY_KHR) > + > > bool > radv_instance_extension_supported(const char *name) > diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h > index be9e8f43964..1e3719bcc4f 100644 > --- a/src/amd/vulkan/radv_private.h > +++ b/src/amd/vulkan/radv_private.h > @@ -75,6 +75,7 @@ typedef uint32_t xcb_window_t; > #include "radv_entrypoints.h" > > #include "wsi_common.h" > +#include "wsi_common_display.h" > > #define ATI_VENDOR_ID 0x1002 > > @@ -300,6 +301,7 @@ struct radv_instance { > uint64_t perftest_flags; > > struct vk_debug_report_instance debug_report_callbacks; > + bool khr_display_requested; > }; > > VkResult radv_init_wsi(struct radv_physical_device *physical_device); > diff --git a/src/amd/vulkan/radv_wsi.c b/src/amd/vulkan/radv_wsi.c > index e016e837102..5ec872a63d0 100644 > --- a/src/amd/vulkan/radv_wsi.c > +++ b/src/amd/vulkan/radv_wsi.c > @@ -41,7 +41,8 @@ radv_init_wsi(struct radv_physical_device *physical_device) > return wsi_device_init(&physical_device->wsi_device, > radv_physical_device_to_handle(physical_device), > radv_wsi_proc_addr, > - &physical_device->instance->alloc); > + &physical_device->instance->alloc, > + physical_device->local_fd); > } > > void > diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c > new file mode 100644 > index 00000000000..b0a4db0344b > --- /dev/null > +++ b/src/amd/vulkan/radv_wsi_display.c > @@ -0,0 +1,143 @@ > +/* > + * Copyright © 2017 Keith Packard > + * > + * Permission to use, copy, modify, distribute, and sell this software and its > + * documentation for any purpose is hereby granted without fee, provided that > + * the above copyright notice appear in all copies and that both that copyright > + * notice and this permission notice appear in supporting documentation, and > + * that the name of the copyright holders not be used in advertising or > + * publicity pertaining to distribution of the software without specific, > + * written prior permission. The copyright holders make no representations > + * about the suitability of this software for any purpose. It is provided "as > + * is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO > + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR > + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, > + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE > + * OF THIS SOFTWARE. > + */ > + > +#include <stdbool.h> > +#include <string.h> > +#include <unistd.h> > +#include <fcntl.h> > +#include "radv_private.h" > +#include "radv_cs.h" > +#include "util/disk_cache.h" > +#include "util/strtod.h" > +#include "vk_util.h" > +#include <xf86drm.h> > +#include <xf86drmMode.h> > +#include <amdgpu.h> > +#include <amdgpu_drm.h> > +#include "winsys/amdgpu/radv_amdgpu_winsys_public.h" > +#include "ac_llvm_util.h" > +#include "vk_format.h" > +#include "sid.h" > +#include "util/debug.h" > +#include "wsi_common_display.h" > + > +#define MM_PER_PIXEL (1.0/96.0 * 25.4) unused > + > +VkResult > +radv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physical_device, > + uint32_t *property_count, > + VkDisplayPropertiesKHR *properties) > +{ > + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_physical_device_display_properties(physical_device, > + &pdevice->wsi_device, > + property_count, > + properties); > +} > + > +VkResult > +radv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physical_device, > + uint32_t *property_count, > + VkDisplayPlanePropertiesKHR *properties) > +{ > + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_physical_device_display_plane_properties(physical_device, > + &pdevice->wsi_device, > + property_count, > + properties); > +} > + > +VkResult > +radv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physical_device, > + uint32_t plane_index, > + uint32_t *display_count, > + VkDisplayKHR *displays) > +{ > + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_display_plane_supported_displays(physical_device, > + &pdevice->wsi_device, > + plane_index, > + display_count, > + displays); > +} > + > + > +VkResult > +radv_GetDisplayModePropertiesKHR(VkPhysicalDevice physical_device, > + VkDisplayKHR display, > + uint32_t *property_count, > + VkDisplayModePropertiesKHR *properties) > +{ > + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_display_mode_properties(physical_device, > + &pdevice->wsi_device, > + display, > + property_count, > + properties); > +} > + > +VkResult > +radv_CreateDisplayModeKHR(VkPhysicalDevice physical_device, > + VkDisplayKHR display, > + const VkDisplayModeCreateInfoKHR *create_info, > + const VkAllocationCallbacks *allocator, > + VkDisplayModeKHR *mode) > +{ > + return VK_ERROR_INITIALIZATION_FAILED; > +} > + > + > +VkResult > +radv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physical_device, > + VkDisplayModeKHR mode_khr, > + uint32_t plane_index, > + VkDisplayPlaneCapabilitiesKHR *capabilities) > +{ > + RADV_FROM_HANDLE(radv_physical_device, pdevice, physical_device); > + > + return wsi_get_display_plane_capabilities(physical_device, > + &pdevice->wsi_device, > + mode_khr, > + plane_index, > + capabilities); > +} > + > +VkResult > +radv_CreateDisplayPlaneSurfaceKHR(VkInstance _instance, > + const VkDisplaySurfaceCreateInfoKHR *create_info, > + const VkAllocationCallbacks *allocator, > + VkSurfaceKHR *surface) > +{ > + RADV_FROM_HANDLE(radv_instance, instance, _instance); > + const VkAllocationCallbacks *alloc; > + > + if (allocator) > + alloc = allocator; > + else > + alloc = &instance->alloc; > + > + return wsi_create_display_surface(_instance, alloc, create_info, surface); > +} > diff --git a/src/intel/Makefile.sources b/src/intel/Makefile.sources > index 9595bf42582..6c142729d94 100644 > --- a/src/intel/Makefile.sources > +++ b/src/intel/Makefile.sources > @@ -240,6 +240,9 @@ VULKAN_WSI_WAYLAND_FILES := \ > VULKAN_WSI_X11_FILES := \ > vulkan/anv_wsi_x11.c > > +VULKAN_WSI_DISPLAY_FILES := \ > + vulkan/anv_wsi_display.c > + > VULKAN_GEM_FILES := \ > vulkan/anv_gem.c > > diff --git a/src/intel/Makefile.vulkan.am b/src/intel/Makefile.vulkan.am > index 23fa877e77d..7c428a799d7 100644 > --- a/src/intel/Makefile.vulkan.am > +++ b/src/intel/Makefile.vulkan.am > @@ -187,6 +187,13 @@ VULKAN_SOURCES += $(VULKAN_WSI_WAYLAND_FILES) > VULKAN_LIB_DEPS += $(WAYLAND_CLIENT_LIBS) > endif > > +if HAVE_PLATFORM_DISPLAY > +VULKAN_CPPFLAGS += \ > + -DVK_USE_PLATFORM_DISPLAY_KHR > + > +VULKAN_SOURCES += $(VULKAN_WSI_DISPLAY_FILES) > +endif > + > noinst_LTLIBRARIES += vulkan/libvulkan_common.la > vulkan_libvulkan_common_la_SOURCES = $(VULKAN_SOURCES) > vulkan_libvulkan_common_la_CFLAGS = $(VULKAN_CFLAGS) > diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c > index 86c1bdc1d51..9614907fda3 100644 > --- a/src/intel/vulkan/anv_device.c > +++ b/src/intel/vulkan/anv_device.c > @@ -277,14 +277,25 @@ anv_physical_device_init_uuids(struct anv_physical_device *device) > static VkResult > anv_physical_device_init(struct anv_physical_device *device, > struct anv_instance *instance, > - const char *path) > + const char *primary_path, > + const char *render_path) > { > VkResult result; > - int fd; > + int fd = -1; > + const char *path; > > brw_process_intel_debug_variable(); > > - fd = open(path, O_RDWR | O_CLOEXEC); > + if (instance->enabled_extensions.KHR_display) { > + path = primary_path; > + fd = open(path, O_RDWR | O_CLOEXEC); > + } > + > + if (fd < 0) { > + path = render_path; > + fd = open(path, O_RDWR | O_CLOEXEC); > + } > + > if (fd < 0) > return vk_error(VK_ERROR_INCOMPATIBLE_DRIVER); > > @@ -652,6 +663,7 @@ anv_enumerate_devices(struct anv_instance *instance) > > result = anv_physical_device_init(&instance->physicalDevice, > instance, > + devices[i]->nodes[DRM_NODE_PRIMARY], > devices[i]->nodes[DRM_NODE_RENDER]); > if (result != VK_ERROR_INCOMPATIBLE_DRIVER) > break; > diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py > index 581921e62a1..978a219e2b2 100644 > --- a/src/intel/vulkan/anv_extensions.py > +++ b/src/intel/vulkan/anv_extensions.py > @@ -83,6 +83,7 @@ EXTENSIONS = [ > Extension('VK_KHR_wayland_surface', 6, 'VK_USE_PLATFORM_WAYLAND_KHR'), > Extension('VK_KHR_xcb_surface', 6, 'VK_USE_PLATFORM_XCB_KHR'), > Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'), > + Extension('VK_KHR_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), > Extension('VK_KHX_multiview', 1, True), > Extension('VK_EXT_debug_report', 8, True), > Extension('VK_EXT_external_memory_dma_buf', 1, True), > diff --git a/src/intel/vulkan/anv_extensions_gen.py b/src/intel/vulkan/anv_extensions_gen.py > index 33827ecd015..84d07f9767a 100644 > --- a/src/intel/vulkan/anv_extensions_gen.py > +++ b/src/intel/vulkan/anv_extensions_gen.py > @@ -113,7 +113,7 @@ _TEMPLATE_C = Template(COPYRIGHT + """ > #include "vk_util.h" > > /* Convert the VK_USE_PLATFORM_* defines to booleans */ > -%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB']: > +%for platform in ['ANDROID', 'WAYLAND', 'XCB', 'XLIB', 'DISPLAY']: > #ifdef VK_USE_PLATFORM_${platform}_KHR > # undef VK_USE_PLATFORM_${platform}_KHR > # define VK_USE_PLATFORM_${platform}_KHR true > @@ -132,7 +132,8 @@ _TEMPLATE_C = Template(COPYRIGHT + """ > > #define ANV_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\ > VK_USE_PLATFORM_XCB_KHR || \\ > - VK_USE_PLATFORM_XLIB_KHR) > + VK_USE_PLATFORM_XLIB_KHR || \\ > + VK_USE_PLATFORM_DISPLAY_KHR) > > const VkExtensionProperties anv_instance_extensions[ANV_INSTANCE_EXTENSION_COUNT] = { > %for ext in instance_extensions: > diff --git a/src/intel/vulkan/anv_wsi.c b/src/intel/vulkan/anv_wsi.c > index 6082c3dd093..f86d83589ea 100644 > --- a/src/intel/vulkan/anv_wsi.c > +++ b/src/intel/vulkan/anv_wsi.c > @@ -39,7 +39,8 @@ anv_init_wsi(struct anv_physical_device *physical_device) > return wsi_device_init(&physical_device->wsi_device, > anv_physical_device_to_handle(physical_device), > anv_wsi_proc_addr, > - &physical_device->instance->alloc); > + &physical_device->instance->alloc, > + physical_device->local_fd); > } > > void > diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c > new file mode 100644 > index 00000000000..9b00d7f02e4 > --- /dev/null > +++ b/src/intel/vulkan/anv_wsi_display.c > @@ -0,0 +1,129 @@ > +/* > + * Copyright © 2017 Keith Packard > + * > + * Permission to use, copy, modify, distribute, and sell this software and its > + * documentation for any purpose is hereby granted without fee, provided that > + * the above copyright notice appear in all copies and that both that copyright > + * notice and this permission notice appear in supporting documentation, and > + * that the name of the copyright holders not be used in advertising or > + * publicity pertaining to distribution of the software without specific, > + * written prior permission. The copyright holders make no representations > + * about the suitability of this software for any purpose. It is provided "as > + * is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO > + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR > + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, > + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE > + * OF THIS SOFTWARE. > + */ > + > +#include "anv_private.h" > +#include "wsi_common.h" > +#include "vk_format_info.h" > +#include "vk_util.h" > +#include "wsi_common_display.h" > + > +#define MM_PER_PIXEL (1.0/96.0 * 25.4) unused > + > +VkResult > +anv_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physical_device, > + uint32_t *property_count, > + VkDisplayPropertiesKHR *properties) > +{ > + ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_physical_device_display_properties(physical_device, > + &pdevice->wsi_device, > + property_count, > + properties); > +} > + > +VkResult > +anv_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physical_device, > + uint32_t *property_count, > + VkDisplayPlanePropertiesKHR *properties) > +{ > + ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_physical_device_display_plane_properties(physical_device, > + &pdevice->wsi_device, > + property_count, > + properties); > +} > + > +VkResult > +anv_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physical_device, > + uint32_t plane_index, > + uint32_t *display_count, > + VkDisplayKHR *displays) > +{ > + ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_display_plane_supported_displays(physical_device, > + &pdevice->wsi_device, > + plane_index, > + display_count, > + displays); > +} > + > + > +VkResult > +anv_GetDisplayModePropertiesKHR(VkPhysicalDevice physical_device, > + VkDisplayKHR display, > + uint32_t *property_count, > + VkDisplayModePropertiesKHR *properties) > +{ > + ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device); > + > + return wsi_display_get_display_mode_properties(physical_device, > + &pdevice->wsi_device, > + display, > + property_count, > + properties); > +} > + > +VkResult > +anv_CreateDisplayModeKHR(VkPhysicalDevice physical_device, > + VkDisplayKHR display, > + const VkDisplayModeCreateInfoKHR *create_info, > + const VkAllocationCallbacks *allocator, > + VkDisplayModeKHR *mode) > +{ > + return VK_ERROR_INITIALIZATION_FAILED; > +} > + > + > +VkResult > +anv_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physical_device, > + VkDisplayModeKHR mode_khr, > + uint32_t plane_index, > + VkDisplayPlaneCapabilitiesKHR *capabilities) > +{ > + ANV_FROM_HANDLE(anv_physical_device, pdevice, physical_device); > + > + return wsi_get_display_plane_capabilities(physical_device, > + &pdevice->wsi_device, > + mode_khr, > + plane_index, > + capabilities); > +} > + > +VkResult > +anv_CreateDisplayPlaneSurfaceKHR(VkInstance _instance, > + const VkDisplaySurfaceCreateInfoKHR *create_info, > + const VkAllocationCallbacks *allocator, > + VkSurfaceKHR *surface) > +{ > + ANV_FROM_HANDLE(anv_instance, instance, _instance); > + const VkAllocationCallbacks *alloc; > + > + if (allocator) > + alloc = allocator; > + else > + alloc = &instance->alloc; > + > + return wsi_create_display_surface(_instance, alloc, create_info, surface); > +} > diff --git a/src/intel/vulkan/meson.build b/src/intel/vulkan/meson.build > index 69ec26e19b6..2e2ab8f7ecd 100644 > --- a/src/intel/vulkan/meson.build > +++ b/src/intel/vulkan/meson.build > @@ -171,6 +171,13 @@ if with_platform_wayland > libanv_files += files('anv_wsi_wayland.c') > endif > > +if with_platform_display > + anv_flags += [ > + '-DVK_USE_PLATFORM_DISPLAY_KHR', > + ] > + libanv_files += files('anv_wsi_display.c') > +endif > + > libanv_common = static_library( > 'anv_common', > [libanv_files, anv_entrypoints, anv_extensions_c, anv_extensions_h], > diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am > index 037436c1cd7..c33ac5758f7 100644 > --- a/src/vulkan/Makefile.am > +++ b/src/vulkan/Makefile.am > @@ -57,6 +57,13 @@ AM_CPPFLAGS += \ > VULKAN_WSI_SOURCES += $(VULKAN_WSI_X11_FILES) > endif > > +if HAVE_PLATFORM_DISPLAY > +AM_CPPFLAGS += \ > + -DVK_USE_PLATFORM_DISPLAY_KHR > + > +VULKAN_WSI_SOURCES += $(VULKAN_WSI_DISPLAY_FILES) > +endif > + > BUILT_SOURCES += $(VULKAN_WSI_WAYLAND_GENERATED_FILES) > CLEANFILES = $(BUILT_SOURCES) > > diff --git a/src/vulkan/Makefile.sources b/src/vulkan/Makefile.sources > index a0a24ce7de8..3642c7662c4 100644 > --- a/src/vulkan/Makefile.sources > +++ b/src/vulkan/Makefile.sources > @@ -17,6 +17,10 @@ VULKAN_WSI_X11_FILES := \ > wsi/wsi_common_x11.c \ > wsi/wsi_common_x11.h > > +VULKAN_WSI_DISPLAY_FILES := \ > + wsi/wsi_common_display.c \ > + wsi/wsi_common_display.h > + > VULKAN_UTIL_FILES := \ > util/vk_alloc.h \ > util/vk_debug_report.c \ > diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build > index bd0fd3cc53e..743631a6113 100644 > --- a/src/vulkan/wsi/meson.build > +++ b/src/vulkan/wsi/meson.build > @@ -57,6 +57,16 @@ if with_platform_wayland > ] > endif > > +if with_platform_display > + vulkan_wsi_args += [ > + '-DVK_USE_PLATFORM_DISPLAY_KHR', > + ] Ditto: vulkan_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_KHR' > + files_vulkan_wsi += files( > + 'wsi_common_display.c', > + 'wsi_common_display.h', > + ) > +endif > + > libvulkan_wsi = static_library( > 'vulkan_wsi', > files_vulkan_wsi, > diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c > index 90ed07b7857..c0a285e5814 100644 > --- a/src/vulkan/wsi/wsi_common.c > +++ b/src/vulkan/wsi/wsi_common.c > @@ -29,7 +29,8 @@ VkResult > wsi_device_init(struct wsi_device *wsi, > VkPhysicalDevice pdevice, > WSI_FN_GetPhysicalDeviceProcAddr proc_addr, > - const VkAllocationCallbacks *alloc) > + const VkAllocationCallbacks *alloc, > + int device_fd) > { > VkResult result; > > @@ -89,6 +90,19 @@ wsi_device_init(struct wsi_device *wsi, > } > #endif > > +#ifdef VK_USE_PLATFORM_DISPLAY_KHR > + result = wsi_display_init_wsi(wsi, alloc, pdevice, device_fd); > + if (result != VK_SUCCESS) { > +#ifdef VK_USE_PLATFORM_WAYLAND_KHR > + wsi_wl_finish_wsi(wsi, alloc); > +#endif > +#ifdef VK_USE_PLATFORM_XCB_KHR > + wsi_x11_finish_wsi(wsi, alloc); > +#endif > + return result; > + } > +#endif > + > return VK_SUCCESS; > } > > @@ -96,6 +110,9 @@ void > wsi_device_finish(struct wsi_device *wsi, > const VkAllocationCallbacks *alloc) > { > +#ifdef VK_USE_PLATFORM_DISPLAY_KHR > + wsi_display_finish_wsi(wsi, alloc); > +#endif > #ifdef VK_USE_PLATFORM_WAYLAND_KHR > wsi_wl_finish_wsi(wsi, alloc); > #endif > diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h > index 3e0d3be1c24..1cb6aaebca0 100644 > --- a/src/vulkan/wsi/wsi_common.h > +++ b/src/vulkan/wsi/wsi_common.h > @@ -50,7 +50,7 @@ struct wsi_memory_allocate_info { > > struct wsi_interface; > > -#define VK_ICD_WSI_PLATFORM_MAX 5 > +#define VK_ICD_WSI_PLATFORM_MAX 6 > > struct wsi_device { > VkPhysicalDeviceMemoryProperties memory_props; > @@ -93,7 +93,8 @@ VkResult > wsi_device_init(struct wsi_device *wsi, > VkPhysicalDevice pdevice, > WSI_FN_GetPhysicalDeviceProcAddr proc_addr, > - const VkAllocationCallbacks *alloc); > + const VkAllocationCallbacks *alloc, > + int device_fd); > > void > wsi_device_finish(struct wsi_device *wsi, > diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c > new file mode 100644 > index 00000000000..2732b1dd721 > --- /dev/null > +++ b/src/vulkan/wsi/wsi_common_display.c > @@ -0,0 +1,1368 @@ > +/* > + * Copyright © 2017 Keith Packard > + * > + * Permission to use, copy, modify, distribute, and sell this software and its > + * documentation for any purpose is hereby granted without fee, provided that > + * the above copyright notice appear in all copies and that both that copyright > + * notice and this permission notice appear in supporting documentation, and > + * that the name of the copyright holders not be used in advertising or > + * publicity pertaining to distribution of the software without specific, > + * written prior permission. The copyright holders make no representations > + * about the suitability of this software for any purpose. It is provided "as > + * is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO > + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR > + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, > + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE > + * OF THIS SOFTWARE. > + */ > + > +#include "util/macros.h" > +#include <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <errno.h> > +#include <string.h> > +#include <fcntl.h> > +#include <poll.h> > +#include <stdbool.h> > +#include <math.h> > +#include <xf86drm.h> > +#include <xf86drmMode.h> > +#include "util/hash_table.h" > +#include "util/list.h" > + > +#include "vk_util.h" > +#include "wsi_common_private.h" > +#include "wsi_common_display.h" > +#include "wsi_common_queue.h" > + > +#if 0 `#if DEBUG` maybe? > +#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__) > +#define wsi_display_debug_code(...) __VA_ARGS__ that 2nd one is unused > +#else > +#define wsi_display_debug(...) > +#define wsi_display_debug_code(...) > +#endif > + > +/* These have lifetime equal to the instance, so they effectively > + * never go away. This means we must keep track of them separately > + * from all other resources. > + */ > +typedef struct wsi_display_mode { > + struct list_head list; > + struct wsi_display_connector *connector; > + bool valid; /* was found in most recent poll */ > + bool preferred; > + uint32_t clock; /* in kHz */ > + uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; > + uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; > + uint32_t flags; > +} wsi_display_mode; > + > +typedef struct wsi_display_connector { > + struct list_head list; > + struct wsi_display *wsi; > + uint32_t id; > + uint32_t crtc_id; > + char *name; > + bool connected; > + bool active; > + wsi_display_mode *current_mode; > + drmModeModeInfo current_drm_mode; > +} wsi_display_connector; > + > +struct wsi_display { > + struct wsi_interface base; > + > + const VkAllocationCallbacks *alloc; > + VkPhysicalDevice physical_device; > + > + int master_fd; > + int render_fd; > + > + pthread_mutex_t wait_mutex; > + pthread_cond_t wait_cond; > + pthread_t wait_thread; > + > + struct list_head connectors; > + > + struct list_head display_modes; > +}; > + > +enum wsi_image_state { > + wsi_image_idle, > + wsi_image_drawing, > + wsi_image_queued, > + wsi_image_flipping, > + wsi_image_displaying > +}; > + > +struct wsi_display_image { > + struct wsi_image base; > + struct wsi_display_swapchain *chain; > + enum wsi_image_state state; > + uint32_t fb_id; > + uint64_t flip_sequence; > +}; > + > +struct wsi_display_swapchain { > + struct wsi_swapchain base; > + struct wsi_display *wsi; > + VkIcdSurfaceDisplay *surface; > + uint64_t flip_sequence; > + struct wsi_display_image images[0]; > +}; > + > +ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR) > +ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR) > + > +static bool > +wsi_display_mode_matches_drm(wsi_display_mode *wsi, > + drmModeModeInfoPtr drm) > +{ > + return wsi->clock == drm->clock && > + wsi->hdisplay == drm->hdisplay && > + wsi->hsync_start == drm->hsync_start && > + wsi->hsync_end == drm->hsync_end && > + wsi->htotal == drm->htotal && > + wsi->hskew == drm->hskew && > + wsi->vdisplay == drm->vdisplay && > + wsi->vsync_start == drm->vsync_start && > + wsi->vsync_end == drm->vsync_end && > + wsi->vtotal == drm->vtotal && > + wsi->vscan == drm->vscan && > + wsi->flags == drm->flags; > +} > + > +static double > +wsi_display_mode_refresh(struct wsi_display_mode *wsi) > +{ > + return (double) wsi->clock * 1000.0 / ((double) wsi->htotal * (double) wsi->vtotal * (double) (wsi->vscan + 1)); > +} > + > +static uint64_t wsi_get_current_monotonic(void) > +{ > + struct timespec tv; > + > + clock_gettime(CLOCK_MONOTONIC, &tv); > + return tv.tv_nsec + tv.tv_sec*1000000000ull; > +} > + > +static struct wsi_display_mode * > +wsi_display_find_drm_mode(struct wsi_device *wsi_device, > + struct wsi_display_connector *connector, > + drmModeModeInfoPtr mode) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_mode *display_mode; > + > + LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) { > + if (display_mode->connector == connector && > + wsi_display_mode_matches_drm(display_mode, mode)) > + return display_mode; > + } > + return NULL; > +} > + > +static void > +wsi_display_invalidate_connector_modes(struct wsi_device *wsi_device, > + struct wsi_display_connector *connector) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_mode *display_mode; > + > + LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) > + if (display_mode->connector == connector) > + display_mode->valid = false; > +} > + > +static VkResult > +wsi_display_register_drm_mode(struct wsi_device *wsi_device, > + struct wsi_display_connector *connector, > + drmModeModeInfoPtr drm_mode) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_mode *display_mode; > + > + display_mode = wsi_display_find_drm_mode(wsi_device, connector, drm_mode); > + > + if (display_mode) { > + display_mode->valid = true; > + return VK_SUCCESS; > + } > + > + display_mode = vk_alloc(wsi->alloc, sizeof (struct wsi_display_mode), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); > + if (!display_mode) > + return VK_ERROR_OUT_OF_HOST_MEMORY; > + > + display_mode->connector = connector; > + display_mode->valid = true; > + display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0; > + display_mode->clock = drm_mode->clock; /* kHz */ > + display_mode->hdisplay = drm_mode->hdisplay; > + display_mode->hsync_start = drm_mode->hsync_start; > + display_mode->hsync_end = drm_mode->hsync_end; > + display_mode->htotal = drm_mode->htotal; > + display_mode->hskew = drm_mode->hskew; > + display_mode->vdisplay = drm_mode->vdisplay; > + display_mode->vsync_start = drm_mode->vsync_start; > + display_mode->vsync_end = drm_mode->vsync_end; > + display_mode->vtotal = drm_mode->vtotal; > + display_mode->vscan = drm_mode->vscan; > + display_mode->flags = drm_mode->flags; > + > + LIST_ADDTAIL(&display_mode->list, &wsi->display_modes); > + return VK_SUCCESS; > +} > + > +/* > + * Update our information about a specific connector > + */ > + > +static struct wsi_display_connector * > +wsi_display_find_connector(struct wsi_device *wsi_device, > + uint32_t connector_id) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector; > + > + connector = NULL; > + LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) { > + if (connector->id == connector_id) > + return connector; > + } > + > + return NULL; > +} > + > +static struct wsi_display_connector * > +wsi_display_alloc_connector(struct wsi_display *wsi, > + uint32_t connector_id) > +{ > + struct wsi_display_connector *connector; > + > + connector = vk_alloc(wsi->alloc, sizeof (struct wsi_display_connector), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); > + memset(connector, '\0', sizeof (*connector)); > + connector->id = connector_id; > + connector->wsi = wsi; > + connector->active = false; > + /* XXX use EDID name */ > + connector->name = "monitor"; > + return connector; > +} > + > +static struct wsi_display_connector * > +wsi_display_get_connector(struct wsi_device *wsi_device, > + uint32_t connector_id) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector; > + drmModeConnectorPtr drm_connector; > + VkResult result; > + int m; > + > + if (wsi->master_fd < 0) > + return NULL; > + > + drm_connector = drmModeGetConnector(wsi->master_fd, connector_id); > + if (!drm_connector) > + return NULL; > + > + connector = wsi_display_find_connector(wsi_device, connector_id); > + > + if (!connector) { > + connector = wsi_display_alloc_connector(wsi, connector_id); > + if (!connector) { > + drmModeFreeConnector(drm_connector); > + return NULL; > + } > + LIST_ADDTAIL(&connector->list, &wsi->connectors); > + } > + > + connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED; > + > + /* Mark all connector modes as invalid */ > + wsi_display_invalidate_connector_modes(wsi_device, connector); > + > + /* > + * List current modes, adding new ones and marking existing ones as > + * valid > + */ > + for (m = 0; m < drm_connector->count_modes; m++) { > + result = wsi_display_register_drm_mode(wsi_device, > + connector, > + &drm_connector->modes[m]); > + if (result != VK_SUCCESS) { > + drmModeFreeConnector(drm_connector); > + return NULL; > + } > + } > + > + drmModeFreeConnector(drm_connector); > + > + return connector; > +} > + > +#define MM_PER_PIXEL (1.0/96.0 * 25.4) > + > +static void > +wsi_display_fill_in_display_properties(struct wsi_device *wsi_device, > + struct wsi_display_connector *connector, > + VkDisplayPropertiesKHR *properties) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_mode *display_mode, *preferred_mode = NULL;; > + > + properties->display = wsi_display_connector_to_handle(connector); > + properties->displayName = connector->name; > + > + /* Find the preferred mode and assume that's the physical resolution */ > + > + LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) { > + if (display_mode->valid && display_mode->connector == connector && display_mode->preferred) { > + preferred_mode = display_mode; > + break; > + } > + } > + > + if (preferred_mode) { > + properties->physicalResolution.width = preferred_mode->hdisplay; > + properties->physicalResolution.height = preferred_mode->vdisplay; > + } else { > + properties->physicalResolution.width = 1024; > + properties->physicalResolution.height = 768; > + } > + > + /* Make up physical size based on 96dpi */ > + properties->physicalDimensions.width = floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5); > + properties->physicalDimensions.height = floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5); > + > + properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; > + properties->persistentContent = 0; > +} > + > +/* > + * Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display) > + */ > +VkResult > +wsi_display_get_physical_device_display_properties(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + uint32_t *property_count, > + VkDisplayPropertiesKHR *properties) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector; > + int c; > + uint32_t connected; > + uint32_t property_count_requested = *property_count; > + drmModeResPtr mode_res; > + > + if (wsi->master_fd < 0) > + return VK_ERROR_INITIALIZATION_FAILED; > + > + mode_res = drmModeGetResources(wsi->master_fd); > + > + if (!mode_res) > + return VK_ERROR_INITIALIZATION_FAILED; > + > + connected = 0; > + > + /* Get current information */ > + for (c = 0; c < mode_res->count_connectors; c++) { > + connector = wsi_display_get_connector(wsi_device, mode_res->connectors[c]); > + > + if (!connector) { > + drmModeFreeResources(mode_res); > + return VK_ERROR_OUT_OF_HOST_MEMORY; > + } > + > + if (connector->connected) > + connected++; > + } > + > + /* Fill in property information if requested */ > + if (properties != NULL) { > + connected = 0; > + > + for (c = 0; c < mode_res->count_connectors; c++) { > + connector = wsi_display_find_connector(wsi_device, mode_res->connectors[c]); > + > + if (connector && connector->connected) { > + if (connected < property_count_requested) { > + wsi_display_fill_in_display_properties(wsi_device, > + connector, > + &properties[connected]); > + } > + connected++; > + } > + } > + } > + > + drmModeFreeResources(mode_res); > + > + *property_count = connected; > + > + if (connected > property_count_requested && properties != NULL) > + return VK_INCOMPLETE; > + > + return VK_SUCCESS; > +} > + > +/* > + * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display > + */ > +VkResult > +wsi_display_get_physical_device_display_plane_properties(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + uint32_t *property_count, > + VkDisplayPlanePropertiesKHR *properties) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector; > + uint32_t property_count_requested = *property_count; > + int c; > + > + if (!properties) > + property_count_requested = 0; > + > + c = 0; > + LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) { > + if (c < property_count_requested) { > + if (connector && connector->active) { > + properties[c].currentDisplay = wsi_display_connector_to_handle(connector); > + properties[c].currentStackIndex = c; > + } else { > + properties[c].currentDisplay = NULL; > + properties[c].currentStackIndex = 0; > + } > + } > + c++; > + } > + > + *property_count = c; > + > + if (c > property_count_requested && properties != NULL) > + return VK_INCOMPLETE; > + > + return VK_SUCCESS; > +} > + > +/* > + * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display) > + */ > + > +VkResult > +wsi_display_get_display_plane_supported_displays(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + uint32_t plane_index, > + uint32_t *display_count, > + VkDisplayKHR *displays) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector; > + int c; > + > + > + if (displays == NULL) { > + *display_count = 1; > + return VK_SUCCESS; > + } > + > + if (*display_count < 1) > + return VK_INCOMPLETE; > + > + c = 0; > + LIST_FOR_EACH_ENTRY(connector, &wsi->connectors, list) { > + if (c == plane_index) { > + *displays = wsi_display_connector_to_handle(connector); > + *display_count = 1; > + return VK_SUCCESS; > + } > + c++; > + } > + > + *displays = 0; > + *display_count = 0; > + > + return VK_SUCCESS; > +} > + > +/* > + * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display) > + */ > + > +VkResult > +wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + VkDisplayKHR display, > + uint32_t *property_count, > + VkDisplayModePropertiesKHR *properties) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + struct wsi_display_connector *connector = wsi_display_connector_from_handle(display); > + int i; > + struct wsi_display_mode *display_mode; > + uint32_t property_count_requested = *property_count; > + > + i = 0; > + > + if (properties == NULL) > + property_count_requested = 0; > + > + LIST_FOR_EACH_ENTRY(display_mode, &wsi->display_modes, list) { > + if (display_mode->valid && display_mode->connector == connector) { > + if (i < property_count_requested) { > + properties[i].displayMode = wsi_display_mode_to_handle(display_mode); > + properties[i].parameters.visibleRegion.width = display_mode->hdisplay; > + properties[i].parameters.visibleRegion.height = display_mode->vdisplay; > + properties[i].parameters.refreshRate = (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5); > + } > + i++; > + } > + } > + > + *property_count = i; > + > + if (i > property_count_requested && properties != NULL) > + return VK_INCOMPLETE; > + > + return VK_SUCCESS; > + > +} > + > +/* > + * Implement vkGetDisplayPlaneCapabilities > + */ > +VkResult > +wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + VkDisplayModeKHR mode_khr, > + uint32_t plane_index, > + VkDisplayPlaneCapabilitiesKHR *capabilities) > +{ > + struct wsi_display_mode *mode = wsi_display_mode_from_handle(mode_khr); > + > + /* XXX use actual values */ > + capabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; > + capabilities->minSrcPosition.x = 0; > + capabilities->minSrcPosition.y = 0; > + capabilities->maxSrcPosition.x = 0; > + capabilities->maxSrcPosition.y = 0; > + capabilities->minSrcExtent.width = mode->hdisplay; > + capabilities->minSrcExtent.height = mode->vdisplay; > + capabilities->maxSrcExtent.width = mode->hdisplay; > + capabilities->maxSrcExtent.height = mode->vdisplay; > + capabilities->minDstPosition.x = 0; > + capabilities->minDstPosition.y = 0; > + capabilities->maxDstPosition.x = 0; > + capabilities->maxDstPosition.y = 0; > + capabilities->minDstExtent.width = mode->hdisplay; > + capabilities->minDstExtent.height = mode->vdisplay; > + capabilities->maxDstExtent.width = mode->hdisplay; > + capabilities->maxDstExtent.height = mode->vdisplay; > + return VK_SUCCESS; > +} > + > +VkResult > +wsi_create_display_surface(VkInstance instance, > + const VkAllocationCallbacks *allocator, > + const VkDisplaySurfaceCreateInfoKHR *create_info, > + VkSurfaceKHR *surface_khr) > +{ > + VkIcdSurfaceDisplay *surface; > + > + surface = vk_alloc(allocator, sizeof *surface, 8, > + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); > + if (surface == NULL) > + return VK_ERROR_OUT_OF_HOST_MEMORY; > + > + surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY; > + > + surface->displayMode = create_info->displayMode; > + surface->planeIndex = create_info->planeIndex; > + surface->planeStackIndex = create_info->planeStackIndex; > + surface->transform = create_info->transform; > + surface->globalAlpha = create_info->globalAlpha; > + surface->alphaMode = create_info->alphaMode; > + surface->imageExtent = create_info->imageExtent; > + > + *surface_khr = VkIcdSurfaceBase_to_handle(&surface->base); > + return VK_SUCCESS; > +} > + > + > +static VkResult > +wsi_display_surface_get_support(VkIcdSurfaceBase *surface, > + struct wsi_device *wsi_device, > + const VkAllocationCallbacks *allocator, > + uint32_t queueFamilyIndex, > + int local_fd, > + VkBool32* pSupported) > +{ > + *pSupported = VK_TRUE; > + return VK_SUCCESS; > +} > + > +static VkResult > +wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base, > + VkSurfaceCapabilitiesKHR* caps) > +{ > + VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base; > + wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode); > + > + caps->currentExtent.width = mode->hdisplay; > + caps->currentExtent.height = mode->vdisplay; > + > + /* XXX Figure out extents based on driver capabilities */ > + caps->maxImageExtent = caps->minImageExtent = caps->currentExtent; > + > + caps->supportedCompositeAlpha = (VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR | > + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR); > + > + caps->minImageCount = 2; > + caps->maxImageCount = 0; > + > + caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; > + caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; > + caps->maxImageArrayLayers = 1; > + caps->supportedUsageFlags = > + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | > + VK_IMAGE_USAGE_SAMPLED_BIT | > + VK_IMAGE_USAGE_TRANSFER_DST_BIT | > + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; > + > + return VK_SUCCESS; > +} > + > +static VkResult > +wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface, > + const void *info_next, > + VkSurfaceCapabilities2KHR *caps) > +{ > + assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); > + > + return wsi_display_surface_get_capabilities(icd_surface, &caps->surfaceCapabilities); > +} > + > +static const VkFormat available_surface_formats[] = { > + VK_FORMAT_B8G8R8A8_SRGB, > + VK_FORMAT_B8G8R8A8_UNORM, > +}; > + > +static VkResult > +wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface, > + struct wsi_device *wsi_device, > + uint32_t *surface_format_count, > + VkSurfaceFormatKHR *surface_formats) > +{ > + VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count); > + > + for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { > + vk_outarray_append(&out, f) { > + f->format = available_surface_formats[i]; > + f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; > + } > + } > + > + return vk_outarray_status(&out); > +} > + > +static VkResult > +wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface, > + struct wsi_device *wsi_device, > + const void *info_next, > + uint32_t *surface_format_count, > + VkSurfaceFormat2KHR *surface_formats) > +{ > + VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count); > + > + for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { > + vk_outarray_append(&out, f) { > + assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR); > + f->surfaceFormat.format = available_surface_formats[i]; > + f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; > + } > + } > + > + return vk_outarray_status(&out); > +} > + > +static const VkPresentModeKHR available_present_modes[] = { > + VK_PRESENT_MODE_FIFO_KHR, > +}; > + > +static VkResult > +wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface, > + uint32_t *present_mode_count, > + VkPresentModeKHR *present_modes) > +{ > + if (present_modes == NULL) { > + *present_mode_count = ARRAY_SIZE(available_present_modes); > + return VK_SUCCESS; > + } > + > + *present_mode_count = MIN2(*present_mode_count, ARRAY_SIZE(available_present_modes)); > + typed_memcpy(present_modes, available_present_modes, *present_mode_count); > + > + if (*present_mode_count < ARRAY_SIZE(available_present_modes)) > + return VK_INCOMPLETE; > + return VK_SUCCESS; > +} > + > +static VkResult > +wsi_display_image_init(VkDevice device_h, > + struct wsi_swapchain *drv_chain, > + const VkSwapchainCreateInfoKHR *create_info, > + const VkAllocationCallbacks *allocator, > + struct wsi_display_image *image) > +{ > + struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain; > + struct wsi_display *wsi = chain->wsi; > + VkResult result; > + int ret; > + uint32_t image_handle; > + > + if (chain->base.use_prime_blit) > + result = wsi_create_prime_image(&chain->base, create_info, &image->base); > + else > + result = wsi_create_native_image(&chain->base, create_info, &image->base); > + if (result != VK_SUCCESS) > + return result; > + > + ret = drmPrimeFDToHandle(wsi->master_fd, image->base.fd, &image_handle); > + > + close(image->base.fd); > + image->base.fd = -1; > + > + if (ret < 0) > + goto fail_handle; > + > + image->chain = chain; > + image->state = wsi_image_idle; > + image->fb_id = 0; > + > + /* XXX extract depth and bpp from image somehow */ > + ret = drmModeAddFB(wsi->master_fd, create_info->imageExtent.width, create_info->imageExtent.height, > + 24, 32, image->base.row_pitch, image_handle, &image->fb_id); > + > + if (ret) > + goto fail_fb; > + > + return VK_SUCCESS; > + > +fail_fb: > + /* fall through */ > + > +fail_handle: > + wsi_destroy_image(&chain->base, &image->base); > + > + return VK_ERROR_OUT_OF_HOST_MEMORY; > +} > + > +static void > +wsi_display_image_finish(struct wsi_swapchain *drv_chain, > + const VkAllocationCallbacks *allocator, > + struct wsi_display_image *image) > +{ > + struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain; > + > + wsi_destroy_image(&chain->base, &image->base); > +} > + > +static VkResult > +wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain, > + const VkAllocationCallbacks *allocator) > +{ > + struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain; > + > + for (uint32_t i = 0; i < chain->base.image_count; i++) > + wsi_display_image_finish(drv_chain, allocator, &chain->images[i]); > + vk_free(allocator, chain); > + return VK_SUCCESS; > +} > + > +static struct wsi_image * > +wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain, > + uint32_t image_index) > +{ > + struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain; > + > + return &chain->images[image_index].base; > +} > + > +static void > +wsi_display_idle_old_displaying(struct wsi_display_image *active_image) > +{ > + struct wsi_display_swapchain *chain = active_image->chain; > + > + wsi_display_debug("idle everyone but %ld\n", active_image - &(chain->images[0])); > + for (uint32_t i = 0; i < chain->base.image_count; i++) > + if (chain->images[i].state == wsi_image_displaying && &chain->images[i] != active_image) { > + wsi_display_debug("idle %d\n", i); > + chain->images[i].state = wsi_image_idle; > + } > +} > + > +static VkResult > +_wsi_display_queue_next(struct wsi_swapchain *drv_chain); > + > +static void > +wsi_display_page_flip_handler2(int fd, > + unsigned int frame, > + unsigned int sec, > + unsigned int usec, > + uint32_t crtc_id, > + void *data) > +{ > + struct wsi_display_image *image = data; > + > + wsi_display_debug("image %ld displayed at %d\n", image - &(image->chain->images[0]), frame); > + image->state = wsi_image_displaying; > + wsi_display_idle_old_displaying(image); > + (void) _wsi_display_queue_next(&(image->chain->base)); > +} > + > +static void wsi_display_page_flip_handler(int fd, unsigned int frame, > + unsigned int sec, unsigned int usec, void *data) > +{ > + wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data); > +} > + > +static drmEventContext event_context = { > + .version = DRM_EVENT_CONTEXT_VERSION, > + .page_flip_handler = wsi_display_page_flip_handler, > +#if DRM_EVENT_CONTEXT_VERSION >= 3 > + .page_flip_handler2 = wsi_display_page_flip_handler2, > +#endif > +}; > + > +static void * > +wsi_display_wait_thread(void *data) > +{ > + struct wsi_display *wsi = data; > + struct pollfd pollfd = { > + .fd = wsi->master_fd, > + .events = POLLIN > + }; > + int ret; > + > + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); > + for (;;) { > + ret = poll(&pollfd, 1, -1); > + if (ret > 0) { > + pthread_mutex_lock(&wsi->wait_mutex); > + (void) drmHandleEvent(wsi->master_fd, &event_context); > + pthread_mutex_unlock(&wsi->wait_mutex); > + pthread_cond_broadcast(&wsi->wait_cond); > + } > + } > + return NULL; > +} > + > +static int > +wsi_display_start_wait_thread(struct wsi_display *wsi) > +{ > + if (!wsi->wait_thread) { > + int ret = pthread_create(&wsi->wait_thread, NULL, wsi_display_wait_thread, wsi); > + if (ret) > + return ret; > + } > + return 0; > +} > + > +/* call with wait_mutex held */ > +static int > +wsi_display_wait_for_event(struct wsi_display *wsi, > + uint64_t timeout_ns) > +{ > + int ret; > + > + ret = wsi_display_start_wait_thread(wsi); > + > + if (ret) > + return ret; > + > + struct timespec abs_timeout = { > + .tv_sec = timeout_ns / ((uint64_t) 1000 * (uint64_t) 1000 * (uint64_t) 1000), > + .tv_nsec = timeout_ns % ((uint64_t) 1000 * (uint64_t) 1000 * (uint64_t) 1000) > + }; > + > + ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex, &abs_timeout); > + > + wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret); > + return ret; > +} > + > +static VkResult > +wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain, > + uint64_t timeout, > + VkSemaphore semaphore, > + uint32_t *image_index) > +{ > + struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)drv_chain; > + struct wsi_display *wsi = chain->wsi; > + int ret = 0; > + VkResult result = VK_SUCCESS; > + > + if (timeout != 0 && timeout != UINT64_MAX) > + timeout += wsi_get_current_monotonic(); > + > + pthread_mutex_lock(&wsi->wait_mutex); > + for (;;) { > + for (uint32_t i = 0; i < chain->base.image_count; i++) { > + if (chain->images[i].state == wsi_image_idle) { > + *image_index = i; > + wsi_display_debug("image %d available\n", i); > + chain->images[i].state = wsi_image_drawing; > + result = VK_SUCCESS; > + goto done; > + } > + wsi_display_debug("image %d state %d\n", i, chain->images[i].state); > + } > + > + if (ret == ETIMEDOUT) { > + result = VK_TIMEOUT; > + goto done; > + } > + > + ret = wsi_display_wait_for_event(wsi, timeout); > + > + if (ret && ret != ETIMEDOUT) { > + result = VK_ERROR_OUT_OF_DATE_KHR; > + goto done; > + } > + } > +done: > + pthread_mutex_unlock(&wsi->wait_mutex); > + return result; > +} > + > +/* > + * Check whether there are any other connectors driven by this crtc > + */ > +static bool > +wsi_display_crtc_solo(struct wsi_display *wsi, > + drmModeResPtr mode_res, > + drmModeConnectorPtr connector, > + uint32_t crtc_id) > +{ > + int c, e; > + > + /* See if any other connectors share the same encoder */ > + for (c = 0; c < mode_res->count_connectors; c++) { > + if (mode_res->connectors[c] == connector->connector_id) > + continue; > + > + drmModeConnectorPtr other_connector = drmModeGetConnector(wsi->master_fd, mode_res->connectors[c]); > + if (other_connector) { > + bool match = (other_connector->encoder_id == connector->encoder_id); > + drmModeFreeConnector(other_connector); > + if (match) > + return false; > + } > + } > + > + /* See if any other encoders share the same crtc */ > + for (e = 0; e < mode_res->count_encoders; e++) { > + if (mode_res->encoders[e] == connector->encoder_id) > + continue; > + > + drmModeEncoderPtr other_encoder = drmModeGetEncoder(wsi->master_fd, mode_res->encoders[e]); > + if (other_encoder) { > + bool match = (other_encoder->crtc_id == crtc_id); > + drmModeFreeEncoder(other_encoder); > + if (match) > + return false; > + } > + } > + return true; > +} > + > +/* > + * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is > + * currently driving this connector and not any others. Settle for a CRTC > + * which is currently idle. > + */ > +static uint32_t > +wsi_display_select_crtc(struct wsi_display_connector *connector, > + drmModeResPtr mode_res, > + drmModeConnectorPtr drm_connector) > +{ > + struct wsi_display *wsi = connector->wsi; > + int c; > + uint32_t crtc_id; > + > + /* See what CRTC is currently driving this connector */ > + if (drm_connector->encoder_id) { > + drmModeEncoderPtr encoder = drmModeGetEncoder(wsi->master_fd, drm_connector->encoder_id); > + if (encoder) { > + crtc_id = encoder->crtc_id; > + drmModeFreeEncoder(encoder); > + if (crtc_id) { > + if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id)) > + return crtc_id; > + } > + } > + } > + crtc_id = 0; > + for (c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) { > + drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->master_fd, mode_res->crtcs[c]); > + if (crtc && crtc->buffer_id == 0) > + crtc_id = crtc->crtc_id; > + drmModeFreeCrtc(crtc); > + } > + return crtc_id; > +} > + > +static VkResult > +wsi_display_setup_connector(wsi_display_connector *connector, > + wsi_display_mode *display_mode) > +{ > + struct wsi_display *wsi = connector->wsi; > + drmModeModeInfoPtr drm_mode; > + drmModeConnectorPtr drm_connector; > + drmModeResPtr mode_res; > + VkResult result; > + int m; > + > + if (connector->current_mode == display_mode && connector->crtc_id) > + return VK_SUCCESS; > + > + mode_res = drmModeGetResources(wsi->master_fd); > + if (!mode_res) { > + result = VK_ERROR_INITIALIZATION_FAILED; > + goto bail; > + } > + > + drm_connector = drmModeGetConnectorCurrent(wsi->master_fd, connector->id); > + if (!drm_connector) { > + result = VK_ERROR_INITIALIZATION_FAILED; > + goto bail_mode_res; > + } > + > + /* Pick a CRTC if we don't have one */ > + if (!connector->crtc_id) { > + connector->crtc_id = wsi_display_select_crtc(connector, mode_res, drm_connector); > + if (!connector->crtc_id) { > + result = VK_ERROR_OUT_OF_DATE_KHR; > + goto bail_connector; > + } > + } > + > + if (connector->current_mode != display_mode) { > + > + /* Find the drm mode cooresponding to the requested VkDisplayMode */ > + drm_mode = NULL; > + for (m = 0; m < drm_connector->count_modes; m++) { > + drm_mode = &drm_connector->modes[m]; > + if (wsi_display_mode_matches_drm(display_mode, drm_mode)) > + break; > + drm_mode = NULL; > + } > + > + if (!drm_mode) { > + result = VK_ERROR_OUT_OF_DATE_KHR; > + goto bail_connector; > + } > + > + connector->current_mode = display_mode; > + connector->current_drm_mode = *drm_mode; > + } > + > + result = VK_SUCCESS; > + > +bail_connector: > + drmModeFreeConnector(drm_connector); > +bail_mode_res: > + drmModeFreeResources(mode_res); > +bail: > + return result; > + > +} > + > +/* > + * Check to see if the kernel has no flip queued and if there's an image > + * waiting to be displayed. > + */ > +static VkResult > +_wsi_display_queue_next(struct wsi_swapchain *drv_chain) > +{ > + struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain; > + struct wsi_display *wsi = chain->wsi; > + uint32_t i; > + struct wsi_display_image *image = NULL; > + VkIcdSurfaceDisplay *surface = chain->surface; > + wsi_display_mode *display_mode = wsi_display_mode_from_handle(surface->displayMode); > + wsi_display_connector *connector = display_mode->connector; > + int ret; > + VkResult result; > + > + if (wsi->master_fd < 0) > + return VK_ERROR_INITIALIZATION_FAILED; > + > + if (display_mode != connector->current_mode) > + connector->active = false; > + > + for (;;) { > + /* Check to see if there is an image to display, or if some image is already queued */ > + > + for (i = 0; i < chain->base.image_count; i++) { > + struct wsi_display_image *tmp_image = &chain->images[i]; > + > + switch (tmp_image->state) { > + case wsi_image_flipping: > + /* already flipping, don't send another to the kernel yet */ > + return VK_SUCCESS; > + case wsi_image_queued: > + /* find the oldest queued */ > + if (!image || tmp_image->flip_sequence < image->flip_sequence) > + image = tmp_image; > + break; > + default: > + break; > + } > + } > + > + if (!image) > + return VK_SUCCESS; > + > + if (connector->active) { > + ret = drmModePageFlip(wsi->master_fd, connector->crtc_id, image->fb_id, > + DRM_MODE_PAGE_FLIP_EVENT, image); > + if (ret == 0) { > + image->state = wsi_image_flipping; > + return VK_SUCCESS; > + } > + wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret)); > + } else > + ret = -EINVAL; > + > + if (ret) { > + switch(-ret) { > + case EINVAL: > + > + result = wsi_display_setup_connector(connector, display_mode); > + > + if (result != VK_SUCCESS) { > + image->state = wsi_image_idle; > + return result; > + } > + > + /* XXX allow setting of position */ > + > + ret = drmModeSetCrtc(wsi->master_fd, connector->crtc_id, image->fb_id, 0, 0, > + &connector->id, 1, &connector->current_drm_mode); > + > + if (ret == 0) { > + image->state = wsi_image_displaying; > + wsi_display_idle_old_displaying(image); > + connector->active = true; > + return VK_SUCCESS; > + } > + break; > + case EACCES: > + usleep(1000 * 1000); > + connector->active = false; > + break; > + default: > + connector->active = false; > + image->state = wsi_image_idle; > + return VK_ERROR_OUT_OF_DATE_KHR; > + } > + } > + } > +} > + > +static VkResult > +wsi_display_queue_present(struct wsi_swapchain *drv_chain, > + uint32_t image_index, > + const VkPresentRegionKHR *damage) > +{ > + struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *) drv_chain; > + struct wsi_display *wsi = chain->wsi; > + struct wsi_display_image *image = &chain->images[image_index]; > + VkResult result; > + > + assert(image->state == wsi_image_drawing); > + wsi_display_debug("present %d\n", image_index); > + > + pthread_mutex_lock(&wsi->wait_mutex); > + > + image->flip_sequence = ++chain->flip_sequence; > + image->state = wsi_image_queued; > + > + result = _wsi_display_queue_next(drv_chain); > + > + pthread_mutex_unlock(&wsi->wait_mutex); > + > + return result; > +} > + > +static VkResult > +wsi_display_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, > + VkDevice device, > + struct wsi_device *wsi_device, > + int local_fd, > + const VkSwapchainCreateInfoKHR *create_info, > + const VkAllocationCallbacks *allocator, > + struct wsi_swapchain **swapchain_out) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + VkResult result; > + > + assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); > + > + struct wsi_display_swapchain *chain; > + const unsigned num_images = create_info->minImageCount; > + size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); > + > + chain = vk_alloc(allocator, size, 8, > + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); > + > + if (chain == NULL) > + return VK_ERROR_OUT_OF_HOST_MEMORY; > + > + result = wsi_swapchain_init(wsi_device, &chain->base, device, > + create_info, allocator); > + > + chain->base.destroy = wsi_display_swapchain_destroy; > + chain->base.get_wsi_image = wsi_display_get_wsi_image; > + chain->base.acquire_next_image = wsi_display_acquire_next_image; > + chain->base.queue_present = wsi_display_queue_present; > + chain->base.present_mode = create_info->presentMode; > + chain->base.image_count = num_images; > + > + chain->wsi = wsi; > + > + chain->surface = (VkIcdSurfaceDisplay *) icd_surface; > + > + for (uint32_t image = 0; image < chain->base.image_count; image++) { > + result = wsi_display_image_init(device, &chain->base, create_info, allocator, > + &chain->images[image]); > + if (result != VK_SUCCESS) > + goto fail_init_images; > + } > + > + *swapchain_out = &chain->base; > + > + return VK_SUCCESS; > + > +fail_init_images: > + return result; > +} > + > +VkResult > +wsi_display_init_wsi(struct wsi_device *wsi_device, > + const VkAllocationCallbacks *alloc, > + VkPhysicalDevice physical_device, > + int device_fd) > +{ > + struct wsi_display *wsi; > + VkResult result; > + > + wsi = vk_alloc(alloc, sizeof(*wsi), 8, > + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); > + if (!wsi) { > + result = VK_ERROR_OUT_OF_HOST_MEMORY; > + goto fail; > + } > + memset(wsi, '\0', sizeof (*wsi)); > + > + wsi->master_fd = -1; > + if (drmGetNodeTypeFromFd(device_fd) == DRM_NODE_PRIMARY) > + wsi->master_fd = device_fd; > + wsi->render_fd = device_fd; > + > + pthread_mutex_init(&wsi->wait_mutex, NULL); > + wsi->physical_device = physical_device; > + wsi->alloc = alloc; > + > + LIST_INITHEAD(&wsi->display_modes); > + LIST_INITHEAD(&wsi->connectors); > + > + pthread_condattr_t condattr; > + int ret; > + > + ret = pthread_mutex_init(&wsi->wait_mutex, NULL); > + if (ret) { > + result = VK_ERROR_OUT_OF_HOST_MEMORY; > + goto fail_mutex; > + } > + > + ret = pthread_condattr_init(&condattr); > + if (ret) { > + result = VK_ERROR_OUT_OF_HOST_MEMORY; > + goto fail_condattr; > + } > + > + ret = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); > + if (ret) { > + result = VK_ERROR_OUT_OF_HOST_MEMORY; > + goto fail_setclock; > + } > + > + ret = pthread_cond_init(&wsi->wait_cond, &condattr); > + if (ret) { > + result = VK_ERROR_OUT_OF_HOST_MEMORY; > + goto fail_cond; > + } > + > + pthread_condattr_destroy(&condattr); > + > + wsi->base.get_support = wsi_display_surface_get_support; > + wsi->base.get_capabilities = wsi_display_surface_get_capabilities; > + wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2; > + wsi->base.get_formats = wsi_display_surface_get_formats; > + wsi->base.get_formats2 = wsi_display_surface_get_formats2; > + wsi->base.get_present_modes = wsi_display_surface_get_present_modes; > + wsi->base.create_swapchain = wsi_display_surface_create_swapchain; > + > + wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base; > + > + return VK_SUCCESS; > + > +fail_cond: > +fail_setclock: > + pthread_condattr_destroy(&condattr); > +fail_condattr: > + pthread_mutex_destroy(&wsi->wait_mutex); > +fail_mutex: > + vk_free(alloc, wsi); > +fail: > + return result; > +} > + > +void > +wsi_display_finish_wsi(struct wsi_device *wsi_device, > + const VkAllocationCallbacks *alloc) > +{ > + struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; > + > + if (wsi) { if (!wsi) return; and carry on without the extra indent I don't know enough for this to be an actual review though, but the rest of this file looks reasonable to me :) > + > + struct wsi_display_connector *connector, *connector_storage; > + LIST_FOR_EACH_ENTRY_SAFE(connector, connector_storage, &wsi->connectors, list) { > + vk_free(wsi->alloc, connector); > + } > + > + struct wsi_display_mode *mode, *mode_storage; > + LIST_FOR_EACH_ENTRY_SAFE(mode, mode_storage, &wsi->display_modes, list) { > + vk_free(wsi->alloc, mode); > + } > + > + pthread_mutex_lock(&wsi->wait_mutex); > + if (wsi->wait_thread) { > + pthread_cancel(wsi->wait_thread); > + pthread_join(wsi->wait_thread, NULL); > + } > + pthread_mutex_unlock(&wsi->wait_mutex); > + pthread_mutex_destroy(&wsi->wait_mutex); > + pthread_cond_destroy(&wsi->wait_cond); > + > + vk_free(alloc, wsi); > + } > +} > diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h > new file mode 100644 > index 00000000000..b414a226293 > --- /dev/null > +++ b/src/vulkan/wsi/wsi_common_display.h > @@ -0,0 +1,72 @@ > +/* > + * Copyright © 2017 Keith Packard > + * > + * Permission to use, copy, modify, distribute, and sell this software and its > + * documentation for any purpose is hereby granted without fee, provided that > + * the above copyright notice appear in all copies and that both that copyright > + * notice and this permission notice appear in supporting documentation, and > + * that the name of the copyright holders not be used in advertising or > + * publicity pertaining to distribution of the software without specific, > + * written prior permission. The copyright holders make no representations > + * about the suitability of this software for any purpose. It is provided "as > + * is" without express or implied warranty. > + * > + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, > + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO > + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR > + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, > + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE > + * OF THIS SOFTWARE. > + */ > + > +#ifndef WSI_COMMON_DISPLAY_H > +#define WSI_COMMON_DISPLAY_H > + > +#include "wsi_common.h" > +#include <xf86drm.h> > +#include <xf86drmMode.h> > + > +#define typed_memcpy(dest, src, count) ({ \ > + STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \ > + memcpy((dest), (src), (count) * sizeof(*(src))); \ > +}) > + > +VkResult > +wsi_display_get_physical_device_display_properties(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + uint32_t *property_count, > + VkDisplayPropertiesKHR *properties); > +VkResult > +wsi_display_get_physical_device_display_plane_properties(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + uint32_t *property_count, > + VkDisplayPlanePropertiesKHR *properties); > + > +VkResult > +wsi_display_get_display_plane_supported_displays(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + uint32_t plane_index, > + uint32_t *display_count, > + VkDisplayKHR *displays); > +VkResult > +wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + VkDisplayKHR display, > + uint32_t *property_count, > + VkDisplayModePropertiesKHR *properties); > + > +VkResult > +wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device, > + struct wsi_device *wsi_device, > + VkDisplayModeKHR mode_khr, > + uint32_t plane_index, > + VkDisplayPlaneCapabilitiesKHR *capabilities); > + > +VkResult > +wsi_create_display_surface(VkInstance instance, > + const VkAllocationCallbacks *pAllocator, > + const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, > + VkSurfaceKHR *pSurface); > + > +#endif > diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h > index 503b2a015dc..d38d2efa116 100644 > --- a/src/vulkan/wsi/wsi_common_private.h > +++ b/src/vulkan/wsi/wsi_common_private.h > @@ -135,6 +135,16 @@ void wsi_wl_finish_wsi(struct wsi_device *wsi_device, > const VkAllocationCallbacks *alloc); > > > +VkResult > +wsi_display_init_wsi(struct wsi_device *wsi_device, > + const VkAllocationCallbacks *alloc, > + VkPhysicalDevice physical_device, > + int device_fd); > + > +void > +wsi_display_finish_wsi(struct wsi_device *wsi_device, > + const VkAllocationCallbacks *alloc); > + > #define WSI_DEFINE_NONDISP_HANDLE_CASTS(__wsi_type, __VkType) \ > \ > static inline struct __wsi_type * \ > -- > 2.15.1 > > _______________________________________________ > dri-devel mailing list > dri-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel