101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2017 Keith Packard 301e04c3fSmrg * 401e04c3fSmrg * Permission to use, copy, modify, distribute, and sell this software and its 501e04c3fSmrg * documentation for any purpose is hereby granted without fee, provided that 601e04c3fSmrg * the above copyright notice appear in all copies and that both that copyright 701e04c3fSmrg * notice and this permission notice appear in supporting documentation, and 801e04c3fSmrg * that the name of the copyright holders not be used in advertising or 901e04c3fSmrg * publicity pertaining to distribution of the software without specific, 1001e04c3fSmrg * written prior permission. The copyright holders make no representations 1101e04c3fSmrg * about the suitability of this software for any purpose. It is provided "as 1201e04c3fSmrg * is" without express or implied warranty. 1301e04c3fSmrg * 1401e04c3fSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1501e04c3fSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 1601e04c3fSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1701e04c3fSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1801e04c3fSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1901e04c3fSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 2001e04c3fSmrg * OF THIS SOFTWARE. 2101e04c3fSmrg */ 2201e04c3fSmrg 2301e04c3fSmrg#include "util/macros.h" 2401e04c3fSmrg#include <stdlib.h> 2501e04c3fSmrg#include <stdio.h> 2601e04c3fSmrg#include <unistd.h> 2701e04c3fSmrg#include <errno.h> 2801e04c3fSmrg#include <string.h> 2901e04c3fSmrg#include <fcntl.h> 3001e04c3fSmrg#include <poll.h> 3101e04c3fSmrg#include <stdbool.h> 3201e04c3fSmrg#include <math.h> 3301e04c3fSmrg#include <xf86drm.h> 3401e04c3fSmrg#include <xf86drmMode.h> 358a1362adSmaya#include "drm-uapi/drm_fourcc.h" 3601e04c3fSmrg#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 3701e04c3fSmrg#include <xcb/randr.h> 3801e04c3fSmrg#include <X11/Xlib-xcb.h> 3901e04c3fSmrg#endif 4001e04c3fSmrg#include "util/hash_table.h" 4101e04c3fSmrg#include "util/list.h" 4201e04c3fSmrg 437ec681f3Smrg#include "vk_device.h" 447ec681f3Smrg#include "vk_instance.h" 457ec681f3Smrg#include "vk_physical_device.h" 4601e04c3fSmrg#include "vk_util.h" 477ec681f3Smrg#include "wsi_common_entrypoints.h" 4801e04c3fSmrg#include "wsi_common_private.h" 4901e04c3fSmrg#include "wsi_common_display.h" 5001e04c3fSmrg#include "wsi_common_queue.h" 5101e04c3fSmrg 5201e04c3fSmrg#if 0 5301e04c3fSmrg#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__) 5401e04c3fSmrg#define wsi_display_debug_code(...) __VA_ARGS__ 5501e04c3fSmrg#else 5601e04c3fSmrg#define wsi_display_debug(...) 5701e04c3fSmrg#define wsi_display_debug_code(...) 5801e04c3fSmrg#endif 5901e04c3fSmrg 6001e04c3fSmrg/* These have lifetime equal to the instance, so they effectively 6101e04c3fSmrg * never go away. This means we must keep track of them separately 6201e04c3fSmrg * from all other resources. 6301e04c3fSmrg */ 6401e04c3fSmrgtypedef struct wsi_display_mode { 6501e04c3fSmrg struct list_head list; 6601e04c3fSmrg struct wsi_display_connector *connector; 6701e04c3fSmrg bool valid; /* was found in most recent poll */ 6801e04c3fSmrg bool preferred; 6901e04c3fSmrg uint32_t clock; /* in kHz */ 7001e04c3fSmrg uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; 7101e04c3fSmrg uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; 7201e04c3fSmrg uint32_t flags; 7301e04c3fSmrg} wsi_display_mode; 7401e04c3fSmrg 7501e04c3fSmrgtypedef struct wsi_display_connector { 7601e04c3fSmrg struct list_head list; 7701e04c3fSmrg struct wsi_display *wsi; 7801e04c3fSmrg uint32_t id; 7901e04c3fSmrg uint32_t crtc_id; 8001e04c3fSmrg char *name; 8101e04c3fSmrg bool connected; 8201e04c3fSmrg bool active; 8301e04c3fSmrg struct list_head display_modes; 8401e04c3fSmrg wsi_display_mode *current_mode; 8501e04c3fSmrg drmModeModeInfo current_drm_mode; 8601e04c3fSmrg uint32_t dpms_property; 8701e04c3fSmrg#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 8801e04c3fSmrg xcb_randr_output_t output; 8901e04c3fSmrg#endif 9001e04c3fSmrg} wsi_display_connector; 9101e04c3fSmrg 9201e04c3fSmrgstruct wsi_display { 9301e04c3fSmrg struct wsi_interface base; 9401e04c3fSmrg 9501e04c3fSmrg const VkAllocationCallbacks *alloc; 9601e04c3fSmrg 9701e04c3fSmrg int fd; 9801e04c3fSmrg 9901e04c3fSmrg pthread_mutex_t wait_mutex; 10001e04c3fSmrg pthread_cond_t wait_cond; 10101e04c3fSmrg pthread_t wait_thread; 10201e04c3fSmrg 1038a1362adSmaya struct list_head connectors; /* list of all discovered connectors */ 10401e04c3fSmrg}; 10501e04c3fSmrg 10601e04c3fSmrg#define wsi_for_each_display_mode(_mode, _conn) \ 10701e04c3fSmrg list_for_each_entry_safe(struct wsi_display_mode, _mode, \ 10801e04c3fSmrg &(_conn)->display_modes, list) 10901e04c3fSmrg 11001e04c3fSmrg#define wsi_for_each_connector(_conn, _dev) \ 11101e04c3fSmrg list_for_each_entry_safe(struct wsi_display_connector, _conn, \ 11201e04c3fSmrg &(_dev)->connectors, list) 11301e04c3fSmrg 11401e04c3fSmrgenum wsi_image_state { 11501e04c3fSmrg WSI_IMAGE_IDLE, 11601e04c3fSmrg WSI_IMAGE_DRAWING, 11701e04c3fSmrg WSI_IMAGE_QUEUED, 11801e04c3fSmrg WSI_IMAGE_FLIPPING, 11901e04c3fSmrg WSI_IMAGE_DISPLAYING 12001e04c3fSmrg}; 12101e04c3fSmrg 12201e04c3fSmrgstruct wsi_display_image { 12301e04c3fSmrg struct wsi_image base; 12401e04c3fSmrg struct wsi_display_swapchain *chain; 12501e04c3fSmrg enum wsi_image_state state; 12601e04c3fSmrg uint32_t fb_id; 12701e04c3fSmrg uint32_t buffer[4]; 12801e04c3fSmrg uint64_t flip_sequence; 12901e04c3fSmrg}; 13001e04c3fSmrg 13101e04c3fSmrgstruct wsi_display_swapchain { 13201e04c3fSmrg struct wsi_swapchain base; 13301e04c3fSmrg struct wsi_display *wsi; 13401e04c3fSmrg VkIcdSurfaceDisplay *surface; 13501e04c3fSmrg uint64_t flip_sequence; 13601e04c3fSmrg VkResult status; 13701e04c3fSmrg struct wsi_display_image images[0]; 13801e04c3fSmrg}; 13901e04c3fSmrg 14001e04c3fSmrgstruct wsi_display_fence { 14101e04c3fSmrg struct wsi_fence base; 14201e04c3fSmrg bool event_received; 14301e04c3fSmrg bool destroyed; 1447ec681f3Smrg uint32_t syncobj; /* syncobj to signal on event */ 14501e04c3fSmrg uint64_t sequence; 14601e04c3fSmrg}; 14701e04c3fSmrg 14801e04c3fSmrgstatic uint64_t fence_sequence; 14901e04c3fSmrg 15001e04c3fSmrgICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR) 15101e04c3fSmrgICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR) 15201e04c3fSmrg 15301e04c3fSmrgstatic bool 15401e04c3fSmrgwsi_display_mode_matches_drm(wsi_display_mode *wsi, 15501e04c3fSmrg drmModeModeInfoPtr drm) 15601e04c3fSmrg{ 15701e04c3fSmrg return wsi->clock == drm->clock && 15801e04c3fSmrg wsi->hdisplay == drm->hdisplay && 15901e04c3fSmrg wsi->hsync_start == drm->hsync_start && 16001e04c3fSmrg wsi->hsync_end == drm->hsync_end && 16101e04c3fSmrg wsi->htotal == drm->htotal && 16201e04c3fSmrg wsi->hskew == drm->hskew && 16301e04c3fSmrg wsi->vdisplay == drm->vdisplay && 16401e04c3fSmrg wsi->vsync_start == drm->vsync_start && 16501e04c3fSmrg wsi->vsync_end == drm->vsync_end && 16601e04c3fSmrg wsi->vtotal == drm->vtotal && 16701e04c3fSmrg MAX2(wsi->vscan, 1) == MAX2(drm->vscan, 1) && 16801e04c3fSmrg wsi->flags == drm->flags; 16901e04c3fSmrg} 17001e04c3fSmrg 17101e04c3fSmrgstatic double 17201e04c3fSmrgwsi_display_mode_refresh(struct wsi_display_mode *wsi) 17301e04c3fSmrg{ 17401e04c3fSmrg return (double) wsi->clock * 1000.0 / ((double) wsi->htotal * 17501e04c3fSmrg (double) wsi->vtotal * 17601e04c3fSmrg (double) MAX2(wsi->vscan, 1)); 17701e04c3fSmrg} 17801e04c3fSmrg 17901e04c3fSmrgstatic uint64_t wsi_rel_to_abs_time(uint64_t rel_time) 18001e04c3fSmrg{ 1818a1362adSmaya uint64_t current_time = wsi_common_get_current_time(); 18201e04c3fSmrg 18301e04c3fSmrg /* check for overflow */ 18401e04c3fSmrg if (rel_time > UINT64_MAX - current_time) 18501e04c3fSmrg return UINT64_MAX; 18601e04c3fSmrg 18701e04c3fSmrg return current_time + rel_time; 18801e04c3fSmrg} 18901e04c3fSmrg 19001e04c3fSmrgstatic struct wsi_display_mode * 19101e04c3fSmrgwsi_display_find_drm_mode(struct wsi_device *wsi_device, 19201e04c3fSmrg struct wsi_display_connector *connector, 19301e04c3fSmrg drmModeModeInfoPtr mode) 19401e04c3fSmrg{ 19501e04c3fSmrg wsi_for_each_display_mode(display_mode, connector) { 19601e04c3fSmrg if (wsi_display_mode_matches_drm(display_mode, mode)) 19701e04c3fSmrg return display_mode; 19801e04c3fSmrg } 19901e04c3fSmrg return NULL; 20001e04c3fSmrg} 20101e04c3fSmrg 20201e04c3fSmrgstatic void 20301e04c3fSmrgwsi_display_invalidate_connector_modes(struct wsi_device *wsi_device, 20401e04c3fSmrg struct wsi_display_connector *connector) 20501e04c3fSmrg{ 20601e04c3fSmrg wsi_for_each_display_mode(display_mode, connector) { 20701e04c3fSmrg display_mode->valid = false; 20801e04c3fSmrg } 20901e04c3fSmrg} 21001e04c3fSmrg 21101e04c3fSmrgstatic VkResult 21201e04c3fSmrgwsi_display_register_drm_mode(struct wsi_device *wsi_device, 21301e04c3fSmrg struct wsi_display_connector *connector, 21401e04c3fSmrg drmModeModeInfoPtr drm_mode) 21501e04c3fSmrg{ 21601e04c3fSmrg struct wsi_display *wsi = 21701e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 21801e04c3fSmrg struct wsi_display_mode *display_mode = 21901e04c3fSmrg wsi_display_find_drm_mode(wsi_device, connector, drm_mode); 22001e04c3fSmrg 22101e04c3fSmrg if (display_mode) { 22201e04c3fSmrg display_mode->valid = true; 22301e04c3fSmrg return VK_SUCCESS; 22401e04c3fSmrg } 22501e04c3fSmrg 22601e04c3fSmrg display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode), 22701e04c3fSmrg 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 22801e04c3fSmrg if (!display_mode) 22901e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 23001e04c3fSmrg 23101e04c3fSmrg display_mode->connector = connector; 23201e04c3fSmrg display_mode->valid = true; 23301e04c3fSmrg display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0; 23401e04c3fSmrg display_mode->clock = drm_mode->clock; /* kHz */ 23501e04c3fSmrg display_mode->hdisplay = drm_mode->hdisplay; 23601e04c3fSmrg display_mode->hsync_start = drm_mode->hsync_start; 23701e04c3fSmrg display_mode->hsync_end = drm_mode->hsync_end; 23801e04c3fSmrg display_mode->htotal = drm_mode->htotal; 23901e04c3fSmrg display_mode->hskew = drm_mode->hskew; 24001e04c3fSmrg display_mode->vdisplay = drm_mode->vdisplay; 24101e04c3fSmrg display_mode->vsync_start = drm_mode->vsync_start; 24201e04c3fSmrg display_mode->vsync_end = drm_mode->vsync_end; 24301e04c3fSmrg display_mode->vtotal = drm_mode->vtotal; 24401e04c3fSmrg display_mode->vscan = drm_mode->vscan; 24501e04c3fSmrg display_mode->flags = drm_mode->flags; 24601e04c3fSmrg 24701e04c3fSmrg list_addtail(&display_mode->list, &connector->display_modes); 24801e04c3fSmrg return VK_SUCCESS; 24901e04c3fSmrg} 25001e04c3fSmrg 25101e04c3fSmrg/* 25201e04c3fSmrg * Update our information about a specific connector 25301e04c3fSmrg */ 25401e04c3fSmrg 25501e04c3fSmrgstatic struct wsi_display_connector * 25601e04c3fSmrgwsi_display_find_connector(struct wsi_device *wsi_device, 25701e04c3fSmrg uint32_t connector_id) 25801e04c3fSmrg{ 25901e04c3fSmrg struct wsi_display *wsi = 26001e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 26101e04c3fSmrg 26201e04c3fSmrg wsi_for_each_connector(connector, wsi) { 26301e04c3fSmrg if (connector->id == connector_id) 26401e04c3fSmrg return connector; 26501e04c3fSmrg } 26601e04c3fSmrg 26701e04c3fSmrg return NULL; 26801e04c3fSmrg} 26901e04c3fSmrg 27001e04c3fSmrgstatic struct wsi_display_connector * 27101e04c3fSmrgwsi_display_alloc_connector(struct wsi_display *wsi, 27201e04c3fSmrg uint32_t connector_id) 27301e04c3fSmrg{ 27401e04c3fSmrg struct wsi_display_connector *connector = 27501e04c3fSmrg vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector), 27601e04c3fSmrg 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 27701e04c3fSmrg 27801e04c3fSmrg connector->id = connector_id; 27901e04c3fSmrg connector->wsi = wsi; 28001e04c3fSmrg connector->active = false; 28101e04c3fSmrg /* XXX use EDID name */ 28201e04c3fSmrg connector->name = "monitor"; 28301e04c3fSmrg list_inithead(&connector->display_modes); 28401e04c3fSmrg return connector; 28501e04c3fSmrg} 28601e04c3fSmrg 28701e04c3fSmrgstatic struct wsi_display_connector * 28801e04c3fSmrgwsi_display_get_connector(struct wsi_device *wsi_device, 2897ec681f3Smrg int drm_fd, 29001e04c3fSmrg uint32_t connector_id) 29101e04c3fSmrg{ 29201e04c3fSmrg struct wsi_display *wsi = 29301e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 29401e04c3fSmrg 2957ec681f3Smrg if (drm_fd < 0) 29601e04c3fSmrg return NULL; 29701e04c3fSmrg 29801e04c3fSmrg drmModeConnectorPtr drm_connector = 2997ec681f3Smrg drmModeGetConnector(drm_fd, connector_id); 30001e04c3fSmrg 30101e04c3fSmrg if (!drm_connector) 30201e04c3fSmrg return NULL; 30301e04c3fSmrg 30401e04c3fSmrg struct wsi_display_connector *connector = 30501e04c3fSmrg wsi_display_find_connector(wsi_device, connector_id); 30601e04c3fSmrg 30701e04c3fSmrg if (!connector) { 30801e04c3fSmrg connector = wsi_display_alloc_connector(wsi, connector_id); 30901e04c3fSmrg if (!connector) { 31001e04c3fSmrg drmModeFreeConnector(drm_connector); 31101e04c3fSmrg return NULL; 31201e04c3fSmrg } 31301e04c3fSmrg list_addtail(&connector->list, &wsi->connectors); 31401e04c3fSmrg } 31501e04c3fSmrg 31601e04c3fSmrg connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED; 31701e04c3fSmrg 31801e04c3fSmrg /* Look for a DPMS property if we haven't already found one */ 31901e04c3fSmrg for (int p = 0; connector->dpms_property == 0 && 32001e04c3fSmrg p < drm_connector->count_props; p++) 32101e04c3fSmrg { 3227ec681f3Smrg drmModePropertyPtr prop = drmModeGetProperty(drm_fd, 32301e04c3fSmrg drm_connector->props[p]); 32401e04c3fSmrg if (!prop) 32501e04c3fSmrg continue; 32601e04c3fSmrg if (prop->flags & DRM_MODE_PROP_ENUM) { 32701e04c3fSmrg if (!strcmp(prop->name, "DPMS")) 32801e04c3fSmrg connector->dpms_property = drm_connector->props[p]; 32901e04c3fSmrg } 33001e04c3fSmrg drmModeFreeProperty(prop); 33101e04c3fSmrg } 33201e04c3fSmrg 33301e04c3fSmrg /* Mark all connector modes as invalid */ 33401e04c3fSmrg wsi_display_invalidate_connector_modes(wsi_device, connector); 33501e04c3fSmrg 33601e04c3fSmrg /* 33701e04c3fSmrg * List current modes, adding new ones and marking existing ones as 33801e04c3fSmrg * valid 33901e04c3fSmrg */ 34001e04c3fSmrg for (int m = 0; m < drm_connector->count_modes; m++) { 34101e04c3fSmrg VkResult result = wsi_display_register_drm_mode(wsi_device, 34201e04c3fSmrg connector, 34301e04c3fSmrg &drm_connector->modes[m]); 34401e04c3fSmrg if (result != VK_SUCCESS) { 34501e04c3fSmrg drmModeFreeConnector(drm_connector); 34601e04c3fSmrg return NULL; 34701e04c3fSmrg } 34801e04c3fSmrg } 34901e04c3fSmrg 35001e04c3fSmrg drmModeFreeConnector(drm_connector); 35101e04c3fSmrg 35201e04c3fSmrg return connector; 35301e04c3fSmrg} 35401e04c3fSmrg 35501e04c3fSmrg#define MM_PER_PIXEL (1.0/96.0 * 25.4) 35601e04c3fSmrg 35701e04c3fSmrgstatic uint32_t 35801e04c3fSmrgmode_size(struct wsi_display_mode *mode) 35901e04c3fSmrg{ 36001e04c3fSmrg /* fortunately, these are both uint16_t, so this is easy */ 36101e04c3fSmrg return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay; 36201e04c3fSmrg} 36301e04c3fSmrg 36401e04c3fSmrgstatic void 36501e04c3fSmrgwsi_display_fill_in_display_properties(struct wsi_device *wsi_device, 36601e04c3fSmrg struct wsi_display_connector *connector, 36701e04c3fSmrg VkDisplayProperties2KHR *properties2) 36801e04c3fSmrg{ 36901e04c3fSmrg assert(properties2->sType == VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR); 37001e04c3fSmrg VkDisplayPropertiesKHR *properties = &properties2->displayProperties; 37101e04c3fSmrg 37201e04c3fSmrg properties->display = wsi_display_connector_to_handle(connector); 37301e04c3fSmrg properties->displayName = connector->name; 37401e04c3fSmrg 37501e04c3fSmrg /* Find the first preferred mode and assume that's the physical 37601e04c3fSmrg * resolution. If there isn't a preferred mode, find the largest mode and 37701e04c3fSmrg * use that. 37801e04c3fSmrg */ 37901e04c3fSmrg 38001e04c3fSmrg struct wsi_display_mode *preferred_mode = NULL, *largest_mode = NULL; 38101e04c3fSmrg wsi_for_each_display_mode(display_mode, connector) { 38201e04c3fSmrg if (!display_mode->valid) 38301e04c3fSmrg continue; 38401e04c3fSmrg if (display_mode->preferred) { 38501e04c3fSmrg preferred_mode = display_mode; 38601e04c3fSmrg break; 38701e04c3fSmrg } 38801e04c3fSmrg if (largest_mode == NULL || 38901e04c3fSmrg mode_size(display_mode) > mode_size(largest_mode)) 39001e04c3fSmrg { 39101e04c3fSmrg largest_mode = display_mode; 39201e04c3fSmrg } 39301e04c3fSmrg } 39401e04c3fSmrg 39501e04c3fSmrg if (preferred_mode) { 39601e04c3fSmrg properties->physicalResolution.width = preferred_mode->hdisplay; 39701e04c3fSmrg properties->physicalResolution.height = preferred_mode->vdisplay; 39801e04c3fSmrg } else if (largest_mode) { 39901e04c3fSmrg properties->physicalResolution.width = largest_mode->hdisplay; 40001e04c3fSmrg properties->physicalResolution.height = largest_mode->vdisplay; 40101e04c3fSmrg } else { 40201e04c3fSmrg properties->physicalResolution.width = 1024; 40301e04c3fSmrg properties->physicalResolution.height = 768; 40401e04c3fSmrg } 40501e04c3fSmrg 40601e04c3fSmrg /* Make up physical size based on 96dpi */ 40701e04c3fSmrg properties->physicalDimensions.width = 40801e04c3fSmrg floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5); 40901e04c3fSmrg properties->physicalDimensions.height = 41001e04c3fSmrg floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5); 41101e04c3fSmrg 41201e04c3fSmrg properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 41301e04c3fSmrg properties->planeReorderPossible = VK_FALSE; 41401e04c3fSmrg properties->persistentContent = VK_FALSE; 41501e04c3fSmrg} 41601e04c3fSmrg 4177ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 4187ec681f3Smrgwsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, 4197ec681f3Smrg uint32_t *pPropertyCount, 4207ec681f3Smrg VkDisplayPropertiesKHR *pProperties) 42101e04c3fSmrg{ 4227ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 4237ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 42401e04c3fSmrg struct wsi_display *wsi = 42501e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 42601e04c3fSmrg 4277ec681f3Smrg if (pProperties == NULL) { 4287ec681f3Smrg return wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, 4297ec681f3Smrg pPropertyCount, 4307ec681f3Smrg NULL); 43101e04c3fSmrg } else { 43201e04c3fSmrg /* If we're actually returning properties, allocate a temporary array of 43301e04c3fSmrg * VkDisplayProperties2KHR structs, call properties2 to fill them out, 43401e04c3fSmrg * and then copy them to the client. This seems a bit expensive but 43501e04c3fSmrg * wsi_display_get_physical_device_display_properties2() calls 43601e04c3fSmrg * drmModeGetResources() which does an ioctl and then a bunch of 43701e04c3fSmrg * allocations so this should get lost in the noise. 43801e04c3fSmrg */ 43901e04c3fSmrg VkDisplayProperties2KHR *props2 = 4407ec681f3Smrg vk_zalloc(wsi->alloc, sizeof(*props2) * *pPropertyCount, 8, 44101e04c3fSmrg VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 44201e04c3fSmrg if (props2 == NULL) 44301e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 44401e04c3fSmrg 4457ec681f3Smrg for (uint32_t i = 0; i < *pPropertyCount; i++) 44601e04c3fSmrg props2[i].sType = VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR; 44701e04c3fSmrg 4487ec681f3Smrg VkResult result = 4497ec681f3Smrg wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, 4507ec681f3Smrg pPropertyCount, props2); 45101e04c3fSmrg 45201e04c3fSmrg if (result == VK_SUCCESS || result == VK_INCOMPLETE) { 4537ec681f3Smrg for (uint32_t i = 0; i < *pPropertyCount; i++) 4547ec681f3Smrg pProperties[i] = props2[i].displayProperties; 45501e04c3fSmrg } 45601e04c3fSmrg 45701e04c3fSmrg vk_free(wsi->alloc, props2); 45801e04c3fSmrg 45901e04c3fSmrg return result; 46001e04c3fSmrg } 46101e04c3fSmrg} 46201e04c3fSmrg 4637ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 4647ec681f3Smrgwsi_GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, 4657ec681f3Smrg uint32_t *pPropertyCount, 4667ec681f3Smrg VkDisplayProperties2KHR *pProperties) 46701e04c3fSmrg{ 4687ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 4697ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 47001e04c3fSmrg struct wsi_display *wsi = 47101e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 47201e04c3fSmrg 47301e04c3fSmrg if (wsi->fd < 0) 47401e04c3fSmrg goto bail; 47501e04c3fSmrg 47601e04c3fSmrg drmModeResPtr mode_res = drmModeGetResources(wsi->fd); 47701e04c3fSmrg 47801e04c3fSmrg if (!mode_res) 47901e04c3fSmrg goto bail; 48001e04c3fSmrg 4817ec681f3Smrg VK_OUTARRAY_MAKE(conn, pProperties, pPropertyCount); 48201e04c3fSmrg 48301e04c3fSmrg /* Get current information */ 48401e04c3fSmrg 48501e04c3fSmrg for (int c = 0; c < mode_res->count_connectors; c++) { 48601e04c3fSmrg struct wsi_display_connector *connector = 4877ec681f3Smrg wsi_display_get_connector(wsi_device, wsi->fd, 4887ec681f3Smrg mode_res->connectors[c]); 48901e04c3fSmrg 49001e04c3fSmrg if (!connector) { 49101e04c3fSmrg drmModeFreeResources(mode_res); 49201e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 49301e04c3fSmrg } 49401e04c3fSmrg 49501e04c3fSmrg if (connector->connected) { 49601e04c3fSmrg vk_outarray_append(&conn, prop) { 49701e04c3fSmrg wsi_display_fill_in_display_properties(wsi_device, 49801e04c3fSmrg connector, 49901e04c3fSmrg prop); 50001e04c3fSmrg } 50101e04c3fSmrg } 50201e04c3fSmrg } 50301e04c3fSmrg 50401e04c3fSmrg drmModeFreeResources(mode_res); 50501e04c3fSmrg 50601e04c3fSmrg return vk_outarray_status(&conn); 50701e04c3fSmrg 50801e04c3fSmrgbail: 5097ec681f3Smrg *pPropertyCount = 0; 51001e04c3fSmrg return VK_SUCCESS; 51101e04c3fSmrg} 51201e04c3fSmrg 51301e04c3fSmrg/* 51401e04c3fSmrg * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display 51501e04c3fSmrg */ 51601e04c3fSmrgstatic void 51701e04c3fSmrgwsi_display_fill_in_display_plane_properties( 51801e04c3fSmrg struct wsi_device *wsi_device, 51901e04c3fSmrg struct wsi_display_connector *connector, 52001e04c3fSmrg VkDisplayPlaneProperties2KHR *properties) 52101e04c3fSmrg{ 52201e04c3fSmrg assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR); 52301e04c3fSmrg VkDisplayPlanePropertiesKHR *prop = &properties->displayPlaneProperties; 52401e04c3fSmrg 52501e04c3fSmrg if (connector && connector->active) { 52601e04c3fSmrg prop->currentDisplay = wsi_display_connector_to_handle(connector); 52701e04c3fSmrg prop->currentStackIndex = 0; 52801e04c3fSmrg } else { 52901e04c3fSmrg prop->currentDisplay = VK_NULL_HANDLE; 53001e04c3fSmrg prop->currentStackIndex = 0; 53101e04c3fSmrg } 53201e04c3fSmrg} 53301e04c3fSmrg 5347ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 5357ec681f3Smrgwsi_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, 5367ec681f3Smrg uint32_t *pPropertyCount, 5377ec681f3Smrg VkDisplayPlanePropertiesKHR *pProperties) 53801e04c3fSmrg{ 5397ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 5407ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 54101e04c3fSmrg struct wsi_display *wsi = 54201e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 54301e04c3fSmrg 5447ec681f3Smrg VK_OUTARRAY_MAKE(conn, pProperties, pPropertyCount); 54501e04c3fSmrg 54601e04c3fSmrg wsi_for_each_connector(connector, wsi) { 54701e04c3fSmrg vk_outarray_append(&conn, prop) { 54801e04c3fSmrg VkDisplayPlaneProperties2KHR prop2 = { 54901e04c3fSmrg .sType = VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR, 55001e04c3fSmrg }; 55101e04c3fSmrg wsi_display_fill_in_display_plane_properties(wsi_device, connector, 55201e04c3fSmrg &prop2); 55301e04c3fSmrg *prop = prop2.displayPlaneProperties; 55401e04c3fSmrg } 55501e04c3fSmrg } 55601e04c3fSmrg return vk_outarray_status(&conn); 55701e04c3fSmrg} 55801e04c3fSmrg 5597ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 5607ec681f3Smrgwsi_GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice, 5617ec681f3Smrg uint32_t *pPropertyCount, 5627ec681f3Smrg VkDisplayPlaneProperties2KHR *pProperties) 56301e04c3fSmrg{ 5647ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 5657ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 56601e04c3fSmrg struct wsi_display *wsi = 56701e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 56801e04c3fSmrg 5697ec681f3Smrg VK_OUTARRAY_MAKE(conn, pProperties, pPropertyCount); 57001e04c3fSmrg 57101e04c3fSmrg wsi_for_each_connector(connector, wsi) { 57201e04c3fSmrg vk_outarray_append(&conn, prop) { 57301e04c3fSmrg wsi_display_fill_in_display_plane_properties(wsi_device, connector, 57401e04c3fSmrg prop); 57501e04c3fSmrg } 57601e04c3fSmrg } 57701e04c3fSmrg return vk_outarray_status(&conn); 57801e04c3fSmrg} 57901e04c3fSmrg 58001e04c3fSmrg/* 58101e04c3fSmrg * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display) 58201e04c3fSmrg */ 58301e04c3fSmrg 5847ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 5857ec681f3Smrgwsi_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, 5867ec681f3Smrg uint32_t planeIndex, 5877ec681f3Smrg uint32_t *pDisplayCount, 5887ec681f3Smrg VkDisplayKHR *pDisplays) 58901e04c3fSmrg{ 5907ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 5917ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 59201e04c3fSmrg struct wsi_display *wsi = 59301e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 59401e04c3fSmrg 5957ec681f3Smrg VK_OUTARRAY_MAKE(conn, pDisplays, pDisplayCount); 59601e04c3fSmrg 59701e04c3fSmrg int c = 0; 59801e04c3fSmrg 59901e04c3fSmrg wsi_for_each_connector(connector, wsi) { 6007ec681f3Smrg if (c == planeIndex && connector->connected) { 60101e04c3fSmrg vk_outarray_append(&conn, display) { 60201e04c3fSmrg *display = wsi_display_connector_to_handle(connector); 60301e04c3fSmrg } 60401e04c3fSmrg } 60501e04c3fSmrg c++; 60601e04c3fSmrg } 60701e04c3fSmrg return vk_outarray_status(&conn); 60801e04c3fSmrg} 60901e04c3fSmrg 61001e04c3fSmrg/* 61101e04c3fSmrg * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display) 61201e04c3fSmrg */ 61301e04c3fSmrg 61401e04c3fSmrgstatic void 61501e04c3fSmrgwsi_display_fill_in_display_mode_properties( 61601e04c3fSmrg struct wsi_device *wsi_device, 61701e04c3fSmrg struct wsi_display_mode *display_mode, 61801e04c3fSmrg VkDisplayModeProperties2KHR *properties) 61901e04c3fSmrg{ 62001e04c3fSmrg assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR); 62101e04c3fSmrg VkDisplayModePropertiesKHR *prop = &properties->displayModeProperties; 62201e04c3fSmrg 62301e04c3fSmrg prop->displayMode = wsi_display_mode_to_handle(display_mode); 62401e04c3fSmrg prop->parameters.visibleRegion.width = display_mode->hdisplay; 62501e04c3fSmrg prop->parameters.visibleRegion.height = display_mode->vdisplay; 62601e04c3fSmrg prop->parameters.refreshRate = 62701e04c3fSmrg (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5); 62801e04c3fSmrg} 62901e04c3fSmrg 6307ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 6317ec681f3Smrgwsi_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, 6327ec681f3Smrg VkDisplayKHR display, 6337ec681f3Smrg uint32_t *pPropertyCount, 6347ec681f3Smrg VkDisplayModePropertiesKHR *pProperties) 63501e04c3fSmrg{ 6367ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 6377ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 63801e04c3fSmrg struct wsi_display_connector *connector = 63901e04c3fSmrg wsi_display_connector_from_handle(display); 64001e04c3fSmrg 6417ec681f3Smrg VK_OUTARRAY_MAKE(conn, pProperties, pPropertyCount); 64201e04c3fSmrg 64301e04c3fSmrg wsi_for_each_display_mode(display_mode, connector) { 64401e04c3fSmrg if (!display_mode->valid) 64501e04c3fSmrg continue; 64601e04c3fSmrg 64701e04c3fSmrg vk_outarray_append(&conn, prop) { 64801e04c3fSmrg VkDisplayModeProperties2KHR prop2 = { 64901e04c3fSmrg .sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR, 65001e04c3fSmrg }; 65101e04c3fSmrg wsi_display_fill_in_display_mode_properties(wsi_device, 65201e04c3fSmrg display_mode, &prop2); 65301e04c3fSmrg *prop = prop2.displayModeProperties; 65401e04c3fSmrg } 65501e04c3fSmrg } 65601e04c3fSmrg return vk_outarray_status(&conn); 65701e04c3fSmrg} 65801e04c3fSmrg 6597ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 6607ec681f3Smrgwsi_GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, 6617ec681f3Smrg VkDisplayKHR display, 6627ec681f3Smrg uint32_t *pPropertyCount, 6637ec681f3Smrg VkDisplayModeProperties2KHR *pProperties) 66401e04c3fSmrg{ 6657ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 6667ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 66701e04c3fSmrg struct wsi_display_connector *connector = 66801e04c3fSmrg wsi_display_connector_from_handle(display); 66901e04c3fSmrg 6707ec681f3Smrg VK_OUTARRAY_MAKE(conn, pProperties, pPropertyCount); 67101e04c3fSmrg 67201e04c3fSmrg wsi_for_each_display_mode(display_mode, connector) { 67301e04c3fSmrg if (!display_mode->valid) 67401e04c3fSmrg continue; 67501e04c3fSmrg 67601e04c3fSmrg vk_outarray_append(&conn, prop) { 67701e04c3fSmrg wsi_display_fill_in_display_mode_properties(wsi_device, 67801e04c3fSmrg display_mode, prop); 67901e04c3fSmrg } 68001e04c3fSmrg } 68101e04c3fSmrg return vk_outarray_status(&conn); 68201e04c3fSmrg} 68301e04c3fSmrg 68401e04c3fSmrgstatic bool 68501e04c3fSmrgwsi_display_mode_matches_vk(wsi_display_mode *wsi, 68601e04c3fSmrg const VkDisplayModeParametersKHR *vk) 68701e04c3fSmrg{ 68801e04c3fSmrg return (vk->visibleRegion.width == wsi->hdisplay && 68901e04c3fSmrg vk->visibleRegion.height == wsi->vdisplay && 69001e04c3fSmrg fabs(wsi_display_mode_refresh(wsi) * 1000.0 - vk->refreshRate) < 10); 69101e04c3fSmrg} 69201e04c3fSmrg 69301e04c3fSmrg/* 69401e04c3fSmrg * Implement vkCreateDisplayModeKHR (VK_KHR_display) 69501e04c3fSmrg */ 6967ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 6977ec681f3Smrgwsi_CreateDisplayModeKHR(VkPhysicalDevice physicalDevice, 6987ec681f3Smrg VkDisplayKHR display, 6997ec681f3Smrg const VkDisplayModeCreateInfoKHR *pCreateInfo, 7007ec681f3Smrg const VkAllocationCallbacks *pAllocator, 7017ec681f3Smrg VkDisplayModeKHR *pMode) 70201e04c3fSmrg{ 70301e04c3fSmrg struct wsi_display_connector *connector = 70401e04c3fSmrg wsi_display_connector_from_handle(display); 70501e04c3fSmrg 7067ec681f3Smrg if (pCreateInfo->flags != 0) 70701e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 70801e04c3fSmrg 70901e04c3fSmrg /* Check and see if the requested mode happens to match an existing one and 71001e04c3fSmrg * return that. This makes the conformance suite happy. Doing more than 71101e04c3fSmrg * this would involve embedding the CVT function into the driver, which seems 71201e04c3fSmrg * excessive. 71301e04c3fSmrg */ 71401e04c3fSmrg wsi_for_each_display_mode(display_mode, connector) { 71501e04c3fSmrg if (display_mode->valid) { 7167ec681f3Smrg if (wsi_display_mode_matches_vk(display_mode, &pCreateInfo->parameters)) { 7177ec681f3Smrg *pMode = wsi_display_mode_to_handle(display_mode); 71801e04c3fSmrg return VK_SUCCESS; 71901e04c3fSmrg } 72001e04c3fSmrg } 72101e04c3fSmrg } 72201e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 72301e04c3fSmrg} 72401e04c3fSmrg 72501e04c3fSmrg/* 72601e04c3fSmrg * Implement vkGetDisplayPlaneCapabilities 72701e04c3fSmrg */ 7287ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 7297ec681f3Smrgwsi_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, 7307ec681f3Smrg VkDisplayModeKHR _mode, 7317ec681f3Smrg uint32_t planeIndex, 7327ec681f3Smrg VkDisplayPlaneCapabilitiesKHR *pCapabilities) 73301e04c3fSmrg{ 7347ec681f3Smrg struct wsi_display_mode *mode = wsi_display_mode_from_handle(_mode); 73501e04c3fSmrg 73601e04c3fSmrg /* XXX use actual values */ 7377ec681f3Smrg pCapabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; 7387ec681f3Smrg pCapabilities->minSrcPosition.x = 0; 7397ec681f3Smrg pCapabilities->minSrcPosition.y = 0; 7407ec681f3Smrg pCapabilities->maxSrcPosition.x = 0; 7417ec681f3Smrg pCapabilities->maxSrcPosition.y = 0; 7427ec681f3Smrg pCapabilities->minSrcExtent.width = mode->hdisplay; 7437ec681f3Smrg pCapabilities->minSrcExtent.height = mode->vdisplay; 7447ec681f3Smrg pCapabilities->maxSrcExtent.width = mode->hdisplay; 7457ec681f3Smrg pCapabilities->maxSrcExtent.height = mode->vdisplay; 7467ec681f3Smrg pCapabilities->minDstPosition.x = 0; 7477ec681f3Smrg pCapabilities->minDstPosition.y = 0; 7487ec681f3Smrg pCapabilities->maxDstPosition.x = 0; 7497ec681f3Smrg pCapabilities->maxDstPosition.y = 0; 7507ec681f3Smrg pCapabilities->minDstExtent.width = mode->hdisplay; 7517ec681f3Smrg pCapabilities->minDstExtent.height = mode->vdisplay; 7527ec681f3Smrg pCapabilities->maxDstExtent.width = mode->hdisplay; 7537ec681f3Smrg pCapabilities->maxDstExtent.height = mode->vdisplay; 75401e04c3fSmrg return VK_SUCCESS; 75501e04c3fSmrg} 75601e04c3fSmrg 7577ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 7587ec681f3Smrgwsi_GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice, 7597ec681f3Smrg const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, 7607ec681f3Smrg VkDisplayPlaneCapabilities2KHR *pCapabilities) 76101e04c3fSmrg{ 7627ec681f3Smrg assert(pCapabilities->sType == 76301e04c3fSmrg VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR); 76401e04c3fSmrg 7658a1362adSmaya VkResult result = 7667ec681f3Smrg wsi_GetDisplayPlaneCapabilitiesKHR(physicalDevice, 7678a1362adSmaya pDisplayPlaneInfo->mode, 7688a1362adSmaya pDisplayPlaneInfo->planeIndex, 7697ec681f3Smrg &pCapabilities->capabilities); 7708a1362adSmaya 7717ec681f3Smrg vk_foreach_struct(ext, pCapabilities->pNext) { 7728a1362adSmaya switch (ext->sType) { 7738a1362adSmaya case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { 7748a1362adSmaya VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext; 7758a1362adSmaya protected->supportsProtected = VK_FALSE; 7768a1362adSmaya break; 7778a1362adSmaya } 7788a1362adSmaya 7798a1362adSmaya default: 7808a1362adSmaya /* Ignored */ 7818a1362adSmaya break; 7828a1362adSmaya } 7838a1362adSmaya } 7848a1362adSmaya 7858a1362adSmaya return result; 78601e04c3fSmrg} 78701e04c3fSmrg 7887ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 7897ec681f3Smrgwsi_CreateDisplayPlaneSurfaceKHR(VkInstance _instance, 7907ec681f3Smrg const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, 7917ec681f3Smrg const VkAllocationCallbacks *pAllocator, 7927ec681f3Smrg VkSurfaceKHR *pSurface) 79301e04c3fSmrg{ 7947ec681f3Smrg VK_FROM_HANDLE(vk_instance, instance, _instance); 7957ec681f3Smrg VkIcdSurfaceDisplay *surface; 79601e04c3fSmrg 7977ec681f3Smrg assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR); 7987ec681f3Smrg 7997ec681f3Smrg surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8, 8007ec681f3Smrg VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 80101e04c3fSmrg if (surface == NULL) 80201e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 80301e04c3fSmrg 80401e04c3fSmrg surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY; 80501e04c3fSmrg 8067ec681f3Smrg surface->displayMode = pCreateInfo->displayMode; 8077ec681f3Smrg surface->planeIndex = pCreateInfo->planeIndex; 8087ec681f3Smrg surface->planeStackIndex = pCreateInfo->planeStackIndex; 8097ec681f3Smrg surface->transform = pCreateInfo->transform; 8107ec681f3Smrg surface->globalAlpha = pCreateInfo->globalAlpha; 8117ec681f3Smrg surface->alphaMode = pCreateInfo->alphaMode; 8127ec681f3Smrg surface->imageExtent = pCreateInfo->imageExtent; 8137ec681f3Smrg 8147ec681f3Smrg *pSurface = VkIcdSurfaceBase_to_handle(&surface->base); 81501e04c3fSmrg 81601e04c3fSmrg return VK_SUCCESS; 81701e04c3fSmrg} 81801e04c3fSmrg 81901e04c3fSmrgstatic VkResult 82001e04c3fSmrgwsi_display_surface_get_support(VkIcdSurfaceBase *surface, 82101e04c3fSmrg struct wsi_device *wsi_device, 82201e04c3fSmrg uint32_t queueFamilyIndex, 82301e04c3fSmrg VkBool32* pSupported) 82401e04c3fSmrg{ 8257ec681f3Smrg struct wsi_display *wsi = 8267ec681f3Smrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 8277ec681f3Smrg 8287ec681f3Smrg *pSupported = wsi->fd != -1; 82901e04c3fSmrg return VK_SUCCESS; 83001e04c3fSmrg} 83101e04c3fSmrg 83201e04c3fSmrgstatic VkResult 83301e04c3fSmrgwsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base, 8348a1362adSmaya struct wsi_device *wsi_device, 83501e04c3fSmrg VkSurfaceCapabilitiesKHR* caps) 83601e04c3fSmrg{ 83701e04c3fSmrg VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base; 83801e04c3fSmrg wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode); 83901e04c3fSmrg 84001e04c3fSmrg caps->currentExtent.width = mode->hdisplay; 84101e04c3fSmrg caps->currentExtent.height = mode->vdisplay; 84201e04c3fSmrg 8438a1362adSmaya caps->minImageExtent = (VkExtent2D) { 1, 1 }; 8448a1362adSmaya caps->maxImageExtent = (VkExtent2D) { 8458a1362adSmaya wsi_device->maxImageDimension2D, 8468a1362adSmaya wsi_device->maxImageDimension2D, 8478a1362adSmaya }; 84801e04c3fSmrg 84901e04c3fSmrg caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 85001e04c3fSmrg 85101e04c3fSmrg caps->minImageCount = 2; 85201e04c3fSmrg caps->maxImageCount = 0; 85301e04c3fSmrg 85401e04c3fSmrg caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 85501e04c3fSmrg caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 85601e04c3fSmrg caps->maxImageArrayLayers = 1; 85701e04c3fSmrg caps->supportedUsageFlags = 85801e04c3fSmrg VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 85901e04c3fSmrg VK_IMAGE_USAGE_SAMPLED_BIT | 86001e04c3fSmrg VK_IMAGE_USAGE_TRANSFER_DST_BIT | 8618a1362adSmaya VK_IMAGE_USAGE_STORAGE_BIT | 86201e04c3fSmrg VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 86301e04c3fSmrg 86401e04c3fSmrg return VK_SUCCESS; 86501e04c3fSmrg} 86601e04c3fSmrg 86701e04c3fSmrgstatic VkResult 86801e04c3fSmrgwsi_display_surface_get_surface_counters( 86901e04c3fSmrg VkIcdSurfaceBase *surface_base, 87001e04c3fSmrg VkSurfaceCounterFlagsEXT *counters) 87101e04c3fSmrg{ 87201e04c3fSmrg *counters = VK_SURFACE_COUNTER_VBLANK_EXT; 87301e04c3fSmrg return VK_SUCCESS; 87401e04c3fSmrg} 87501e04c3fSmrg 87601e04c3fSmrgstatic VkResult 87701e04c3fSmrgwsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface, 8788a1362adSmaya struct wsi_device *wsi_device, 87901e04c3fSmrg const void *info_next, 88001e04c3fSmrg VkSurfaceCapabilities2KHR *caps) 88101e04c3fSmrg{ 88201e04c3fSmrg assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); 88301e04c3fSmrg VkResult result; 88401e04c3fSmrg 8858a1362adSmaya result = wsi_display_surface_get_capabilities(icd_surface, wsi_device, 88601e04c3fSmrg &caps->surfaceCapabilities); 88701e04c3fSmrg if (result != VK_SUCCESS) 88801e04c3fSmrg return result; 88901e04c3fSmrg 89001e04c3fSmrg struct wsi_surface_supported_counters *counters = 89101e04c3fSmrg vk_find_struct( caps->pNext, WSI_SURFACE_SUPPORTED_COUNTERS_MESA); 89201e04c3fSmrg 89301e04c3fSmrg if (counters) { 89401e04c3fSmrg result = wsi_display_surface_get_surface_counters( 89501e04c3fSmrg icd_surface, 89601e04c3fSmrg &counters->supported_surface_counters); 89701e04c3fSmrg } 89801e04c3fSmrg 89901e04c3fSmrg return result; 90001e04c3fSmrg} 90101e04c3fSmrg 90201e04c3fSmrgstatic const struct { 90301e04c3fSmrg VkFormat format; 90401e04c3fSmrg uint32_t drm_format; 90501e04c3fSmrg} available_surface_formats[] = { 90601e04c3fSmrg { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 }, 90701e04c3fSmrg { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 }, 90801e04c3fSmrg}; 90901e04c3fSmrg 9107ec681f3Smrgstatic void 9117ec681f3Smrgget_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats) 9127ec681f3Smrg{ 9137ec681f3Smrg for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) 9147ec681f3Smrg sorted_formats[i] = available_surface_formats[i].format; 9157ec681f3Smrg 9167ec681f3Smrg if (wsi_device->force_bgra8_unorm_first) { 9177ec681f3Smrg for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { 9187ec681f3Smrg if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) { 9197ec681f3Smrg sorted_formats[i] = sorted_formats[0]; 9207ec681f3Smrg sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM; 9217ec681f3Smrg break; 9227ec681f3Smrg } 9237ec681f3Smrg } 9247ec681f3Smrg } 9257ec681f3Smrg} 9267ec681f3Smrg 92701e04c3fSmrgstatic VkResult 92801e04c3fSmrgwsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface, 92901e04c3fSmrg struct wsi_device *wsi_device, 93001e04c3fSmrg uint32_t *surface_format_count, 93101e04c3fSmrg VkSurfaceFormatKHR *surface_formats) 93201e04c3fSmrg{ 93301e04c3fSmrg VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count); 93401e04c3fSmrg 9357ec681f3Smrg VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; 9367ec681f3Smrg get_sorted_vk_formats(wsi_device, sorted_formats); 9377ec681f3Smrg 9387ec681f3Smrg for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { 93901e04c3fSmrg vk_outarray_append(&out, f) { 9407ec681f3Smrg f->format = sorted_formats[i]; 94101e04c3fSmrg f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 94201e04c3fSmrg } 94301e04c3fSmrg } 94401e04c3fSmrg 94501e04c3fSmrg return vk_outarray_status(&out); 94601e04c3fSmrg} 94701e04c3fSmrg 94801e04c3fSmrgstatic VkResult 94901e04c3fSmrgwsi_display_surface_get_formats2(VkIcdSurfaceBase *surface, 95001e04c3fSmrg struct wsi_device *wsi_device, 95101e04c3fSmrg const void *info_next, 95201e04c3fSmrg uint32_t *surface_format_count, 95301e04c3fSmrg VkSurfaceFormat2KHR *surface_formats) 95401e04c3fSmrg{ 95501e04c3fSmrg VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count); 95601e04c3fSmrg 9577ec681f3Smrg VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; 9587ec681f3Smrg get_sorted_vk_formats(wsi_device, sorted_formats); 9597ec681f3Smrg 9607ec681f3Smrg for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { 96101e04c3fSmrg vk_outarray_append(&out, f) { 96201e04c3fSmrg assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR); 9637ec681f3Smrg f->surfaceFormat.format = sorted_formats[i]; 96401e04c3fSmrg f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 96501e04c3fSmrg } 96601e04c3fSmrg } 96701e04c3fSmrg 96801e04c3fSmrg return vk_outarray_status(&out); 96901e04c3fSmrg} 97001e04c3fSmrg 97101e04c3fSmrgstatic VkResult 97201e04c3fSmrgwsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface, 97301e04c3fSmrg uint32_t *present_mode_count, 97401e04c3fSmrg VkPresentModeKHR *present_modes) 97501e04c3fSmrg{ 97601e04c3fSmrg VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count); 97701e04c3fSmrg 97801e04c3fSmrg vk_outarray_append(&conn, present) { 97901e04c3fSmrg *present = VK_PRESENT_MODE_FIFO_KHR; 98001e04c3fSmrg } 98101e04c3fSmrg 98201e04c3fSmrg return vk_outarray_status(&conn); 98301e04c3fSmrg} 98401e04c3fSmrg 98501e04c3fSmrgstatic VkResult 98601e04c3fSmrgwsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base, 98701e04c3fSmrg struct wsi_device *wsi_device, 98801e04c3fSmrg uint32_t* pRectCount, 98901e04c3fSmrg VkRect2D* pRects) 99001e04c3fSmrg{ 99101e04c3fSmrg VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base; 99201e04c3fSmrg wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode); 99301e04c3fSmrg VK_OUTARRAY_MAKE(out, pRects, pRectCount); 99401e04c3fSmrg 99501e04c3fSmrg if (wsi_device_matches_drm_fd(wsi_device, mode->connector->wsi->fd)) { 99601e04c3fSmrg vk_outarray_append(&out, rect) { 99701e04c3fSmrg *rect = (VkRect2D) { 99801e04c3fSmrg .offset = { 0, 0 }, 99901e04c3fSmrg .extent = { mode->hdisplay, mode->vdisplay }, 100001e04c3fSmrg }; 100101e04c3fSmrg } 100201e04c3fSmrg } 100301e04c3fSmrg 100401e04c3fSmrg return vk_outarray_status(&out); 100501e04c3fSmrg} 100601e04c3fSmrg 100701e04c3fSmrgstatic void 100801e04c3fSmrgwsi_display_destroy_buffer(struct wsi_display *wsi, 100901e04c3fSmrg uint32_t buffer) 101001e04c3fSmrg{ 10118a1362adSmaya (void) drmIoctl(wsi->fd, DRM_IOCTL_GEM_CLOSE, 10128a1362adSmaya &((struct drm_gem_close) { .handle = buffer })); 101301e04c3fSmrg} 101401e04c3fSmrg 101501e04c3fSmrgstatic VkResult 101601e04c3fSmrgwsi_display_image_init(VkDevice device_h, 101701e04c3fSmrg struct wsi_swapchain *drv_chain, 101801e04c3fSmrg const VkSwapchainCreateInfoKHR *create_info, 101901e04c3fSmrg const VkAllocationCallbacks *allocator, 102001e04c3fSmrg struct wsi_display_image *image) 102101e04c3fSmrg{ 102201e04c3fSmrg struct wsi_display_swapchain *chain = 102301e04c3fSmrg (struct wsi_display_swapchain *) drv_chain; 102401e04c3fSmrg struct wsi_display *wsi = chain->wsi; 102501e04c3fSmrg uint32_t drm_format = 0; 102601e04c3fSmrg 102701e04c3fSmrg for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { 102801e04c3fSmrg if (create_info->imageFormat == available_surface_formats[i].format) { 102901e04c3fSmrg drm_format = available_surface_formats[i].drm_format; 103001e04c3fSmrg break; 103101e04c3fSmrg } 103201e04c3fSmrg } 103301e04c3fSmrg 103401e04c3fSmrg /* the application provided an invalid format, bail */ 103501e04c3fSmrg if (drm_format == 0) 103601e04c3fSmrg return VK_ERROR_DEVICE_LOST; 103701e04c3fSmrg 103801e04c3fSmrg VkResult result = wsi_create_native_image(&chain->base, create_info, 10397ec681f3Smrg 0, NULL, NULL, NULL, 104001e04c3fSmrg &image->base); 104101e04c3fSmrg if (result != VK_SUCCESS) 104201e04c3fSmrg return result; 104301e04c3fSmrg 104401e04c3fSmrg memset(image->buffer, 0, sizeof (image->buffer)); 104501e04c3fSmrg 104601e04c3fSmrg for (unsigned int i = 0; i < image->base.num_planes; i++) { 104701e04c3fSmrg int ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i], 104801e04c3fSmrg &image->buffer[i]); 104901e04c3fSmrg 105001e04c3fSmrg close(image->base.fds[i]); 105101e04c3fSmrg image->base.fds[i] = -1; 105201e04c3fSmrg if (ret < 0) 105301e04c3fSmrg goto fail_handle; 105401e04c3fSmrg } 105501e04c3fSmrg 105601e04c3fSmrg image->chain = chain; 105701e04c3fSmrg image->state = WSI_IMAGE_IDLE; 105801e04c3fSmrg image->fb_id = 0; 105901e04c3fSmrg 106001e04c3fSmrg int ret = drmModeAddFB2(wsi->fd, 106101e04c3fSmrg create_info->imageExtent.width, 106201e04c3fSmrg create_info->imageExtent.height, 106301e04c3fSmrg drm_format, 106401e04c3fSmrg image->buffer, 106501e04c3fSmrg image->base.row_pitches, 106601e04c3fSmrg image->base.offsets, 106701e04c3fSmrg &image->fb_id, 0); 106801e04c3fSmrg 106901e04c3fSmrg if (ret) 107001e04c3fSmrg goto fail_fb; 107101e04c3fSmrg 107201e04c3fSmrg return VK_SUCCESS; 107301e04c3fSmrg 107401e04c3fSmrgfail_fb: 107501e04c3fSmrgfail_handle: 107601e04c3fSmrg for (unsigned int i = 0; i < image->base.num_planes; i++) { 107701e04c3fSmrg if (image->buffer[i]) 107801e04c3fSmrg wsi_display_destroy_buffer(wsi, image->buffer[i]); 107901e04c3fSmrg if (image->base.fds[i] != -1) { 108001e04c3fSmrg close(image->base.fds[i]); 108101e04c3fSmrg image->base.fds[i] = -1; 108201e04c3fSmrg } 108301e04c3fSmrg } 108401e04c3fSmrg 108501e04c3fSmrg wsi_destroy_image(&chain->base, &image->base); 108601e04c3fSmrg 108701e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 108801e04c3fSmrg} 108901e04c3fSmrg 109001e04c3fSmrgstatic void 109101e04c3fSmrgwsi_display_image_finish(struct wsi_swapchain *drv_chain, 109201e04c3fSmrg const VkAllocationCallbacks *allocator, 109301e04c3fSmrg struct wsi_display_image *image) 109401e04c3fSmrg{ 109501e04c3fSmrg struct wsi_display_swapchain *chain = 109601e04c3fSmrg (struct wsi_display_swapchain *) drv_chain; 109701e04c3fSmrg struct wsi_display *wsi = chain->wsi; 109801e04c3fSmrg 109901e04c3fSmrg drmModeRmFB(wsi->fd, image->fb_id); 110001e04c3fSmrg for (unsigned int i = 0; i < image->base.num_planes; i++) 110101e04c3fSmrg wsi_display_destroy_buffer(wsi, image->buffer[i]); 110201e04c3fSmrg wsi_destroy_image(&chain->base, &image->base); 110301e04c3fSmrg} 110401e04c3fSmrg 110501e04c3fSmrgstatic VkResult 110601e04c3fSmrgwsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain, 110701e04c3fSmrg const VkAllocationCallbacks *allocator) 110801e04c3fSmrg{ 110901e04c3fSmrg struct wsi_display_swapchain *chain = 111001e04c3fSmrg (struct wsi_display_swapchain *) drv_chain; 111101e04c3fSmrg 111201e04c3fSmrg for (uint32_t i = 0; i < chain->base.image_count; i++) 111301e04c3fSmrg wsi_display_image_finish(drv_chain, allocator, &chain->images[i]); 111401e04c3fSmrg 111501e04c3fSmrg wsi_swapchain_finish(&chain->base); 111601e04c3fSmrg vk_free(allocator, chain); 111701e04c3fSmrg return VK_SUCCESS; 111801e04c3fSmrg} 111901e04c3fSmrg 112001e04c3fSmrgstatic struct wsi_image * 112101e04c3fSmrgwsi_display_get_wsi_image(struct wsi_swapchain *drv_chain, 112201e04c3fSmrg uint32_t image_index) 112301e04c3fSmrg{ 112401e04c3fSmrg struct wsi_display_swapchain *chain = 112501e04c3fSmrg (struct wsi_display_swapchain *) drv_chain; 112601e04c3fSmrg 112701e04c3fSmrg return &chain->images[image_index].base; 112801e04c3fSmrg} 112901e04c3fSmrg 113001e04c3fSmrgstatic void 113101e04c3fSmrgwsi_display_idle_old_displaying(struct wsi_display_image *active_image) 113201e04c3fSmrg{ 113301e04c3fSmrg struct wsi_display_swapchain *chain = active_image->chain; 113401e04c3fSmrg 113501e04c3fSmrg wsi_display_debug("idle everyone but %ld\n", 113601e04c3fSmrg active_image - &(chain->images[0])); 113701e04c3fSmrg for (uint32_t i = 0; i < chain->base.image_count; i++) 113801e04c3fSmrg if (chain->images[i].state == WSI_IMAGE_DISPLAYING && 113901e04c3fSmrg &chain->images[i] != active_image) 114001e04c3fSmrg { 114101e04c3fSmrg wsi_display_debug("idle %d\n", i); 114201e04c3fSmrg chain->images[i].state = WSI_IMAGE_IDLE; 114301e04c3fSmrg } 114401e04c3fSmrg} 114501e04c3fSmrg 114601e04c3fSmrgstatic VkResult 114701e04c3fSmrg_wsi_display_queue_next(struct wsi_swapchain *drv_chain); 114801e04c3fSmrg 114901e04c3fSmrgstatic void 115001e04c3fSmrgwsi_display_page_flip_handler2(int fd, 115101e04c3fSmrg unsigned int frame, 115201e04c3fSmrg unsigned int sec, 115301e04c3fSmrg unsigned int usec, 115401e04c3fSmrg uint32_t crtc_id, 115501e04c3fSmrg void *data) 115601e04c3fSmrg{ 115701e04c3fSmrg struct wsi_display_image *image = data; 115801e04c3fSmrg struct wsi_display_swapchain *chain = image->chain; 115901e04c3fSmrg 116001e04c3fSmrg wsi_display_debug("image %ld displayed at %d\n", 116101e04c3fSmrg image - &(image->chain->images[0]), frame); 116201e04c3fSmrg image->state = WSI_IMAGE_DISPLAYING; 116301e04c3fSmrg wsi_display_idle_old_displaying(image); 116401e04c3fSmrg VkResult result = _wsi_display_queue_next(&(chain->base)); 116501e04c3fSmrg if (result != VK_SUCCESS) 116601e04c3fSmrg chain->status = result; 116701e04c3fSmrg} 116801e04c3fSmrg 116901e04c3fSmrgstatic void wsi_display_fence_event_handler(struct wsi_display_fence *fence); 117001e04c3fSmrg 117101e04c3fSmrgstatic void wsi_display_page_flip_handler(int fd, 117201e04c3fSmrg unsigned int frame, 117301e04c3fSmrg unsigned int sec, 117401e04c3fSmrg unsigned int usec, 117501e04c3fSmrg void *data) 117601e04c3fSmrg{ 117701e04c3fSmrg wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data); 117801e04c3fSmrg} 117901e04c3fSmrg 118001e04c3fSmrgstatic void wsi_display_vblank_handler(int fd, unsigned int frame, 118101e04c3fSmrg unsigned int sec, unsigned int usec, 118201e04c3fSmrg void *data) 118301e04c3fSmrg{ 118401e04c3fSmrg struct wsi_display_fence *fence = data; 118501e04c3fSmrg 118601e04c3fSmrg wsi_display_fence_event_handler(fence); 118701e04c3fSmrg} 118801e04c3fSmrg 118901e04c3fSmrgstatic void wsi_display_sequence_handler(int fd, uint64_t frame, 119001e04c3fSmrg uint64_t nsec, uint64_t user_data) 119101e04c3fSmrg{ 119201e04c3fSmrg struct wsi_display_fence *fence = 119301e04c3fSmrg (struct wsi_display_fence *) (uintptr_t) user_data; 119401e04c3fSmrg 119501e04c3fSmrg wsi_display_fence_event_handler(fence); 119601e04c3fSmrg} 119701e04c3fSmrg 119801e04c3fSmrgstatic drmEventContext event_context = { 119901e04c3fSmrg .version = DRM_EVENT_CONTEXT_VERSION, 120001e04c3fSmrg .page_flip_handler = wsi_display_page_flip_handler, 120101e04c3fSmrg#if DRM_EVENT_CONTEXT_VERSION >= 3 120201e04c3fSmrg .page_flip_handler2 = wsi_display_page_flip_handler2, 120301e04c3fSmrg#endif 120401e04c3fSmrg .vblank_handler = wsi_display_vblank_handler, 120501e04c3fSmrg .sequence_handler = wsi_display_sequence_handler, 120601e04c3fSmrg}; 120701e04c3fSmrg 120801e04c3fSmrgstatic void * 120901e04c3fSmrgwsi_display_wait_thread(void *data) 121001e04c3fSmrg{ 121101e04c3fSmrg struct wsi_display *wsi = data; 121201e04c3fSmrg struct pollfd pollfd = { 121301e04c3fSmrg .fd = wsi->fd, 121401e04c3fSmrg .events = POLLIN 121501e04c3fSmrg }; 121601e04c3fSmrg 121701e04c3fSmrg pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 121801e04c3fSmrg for (;;) { 121901e04c3fSmrg int ret = poll(&pollfd, 1, -1); 122001e04c3fSmrg if (ret > 0) { 122101e04c3fSmrg pthread_mutex_lock(&wsi->wait_mutex); 122201e04c3fSmrg (void) drmHandleEvent(wsi->fd, &event_context); 122301e04c3fSmrg pthread_cond_broadcast(&wsi->wait_cond); 12247ec681f3Smrg pthread_mutex_unlock(&wsi->wait_mutex); 122501e04c3fSmrg } 122601e04c3fSmrg } 122701e04c3fSmrg return NULL; 122801e04c3fSmrg} 122901e04c3fSmrg 123001e04c3fSmrgstatic int 123101e04c3fSmrgwsi_display_start_wait_thread(struct wsi_display *wsi) 123201e04c3fSmrg{ 123301e04c3fSmrg if (!wsi->wait_thread) { 123401e04c3fSmrg int ret = pthread_create(&wsi->wait_thread, NULL, 123501e04c3fSmrg wsi_display_wait_thread, wsi); 123601e04c3fSmrg if (ret) 123701e04c3fSmrg return ret; 123801e04c3fSmrg } 123901e04c3fSmrg return 0; 124001e04c3fSmrg} 124101e04c3fSmrg 12427ec681f3Smrgstatic void 12437ec681f3Smrgwsi_display_stop_wait_thread(struct wsi_display *wsi) 12447ec681f3Smrg{ 12457ec681f3Smrg pthread_mutex_lock(&wsi->wait_mutex); 12467ec681f3Smrg if (wsi->wait_thread) { 12477ec681f3Smrg pthread_cancel(wsi->wait_thread); 12487ec681f3Smrg pthread_join(wsi->wait_thread, NULL); 12497ec681f3Smrg wsi->wait_thread = 0; 12507ec681f3Smrg } 12517ec681f3Smrg pthread_mutex_unlock(&wsi->wait_mutex); 12527ec681f3Smrg} 12537ec681f3Smrg 125401e04c3fSmrg/* 125501e04c3fSmrg * Wait for at least one event from the kernel to be processed. 125601e04c3fSmrg * Call with wait_mutex held 125701e04c3fSmrg */ 125801e04c3fSmrgstatic int 125901e04c3fSmrgwsi_display_wait_for_event(struct wsi_display *wsi, 126001e04c3fSmrg uint64_t timeout_ns) 126101e04c3fSmrg{ 126201e04c3fSmrg int ret; 126301e04c3fSmrg 126401e04c3fSmrg ret = wsi_display_start_wait_thread(wsi); 126501e04c3fSmrg 126601e04c3fSmrg if (ret) 126701e04c3fSmrg return ret; 126801e04c3fSmrg 126901e04c3fSmrg struct timespec abs_timeout = { 127001e04c3fSmrg .tv_sec = timeout_ns / 1000000000ULL, 127101e04c3fSmrg .tv_nsec = timeout_ns % 1000000000ULL, 127201e04c3fSmrg }; 127301e04c3fSmrg 127401e04c3fSmrg ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex, 127501e04c3fSmrg &abs_timeout); 127601e04c3fSmrg 127701e04c3fSmrg wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret); 127801e04c3fSmrg return ret; 127901e04c3fSmrg} 128001e04c3fSmrg 128101e04c3fSmrgstatic VkResult 128201e04c3fSmrgwsi_display_acquire_next_image(struct wsi_swapchain *drv_chain, 128301e04c3fSmrg const VkAcquireNextImageInfoKHR *info, 128401e04c3fSmrg uint32_t *image_index) 128501e04c3fSmrg{ 128601e04c3fSmrg struct wsi_display_swapchain *chain = 128701e04c3fSmrg (struct wsi_display_swapchain *)drv_chain; 128801e04c3fSmrg struct wsi_display *wsi = chain->wsi; 128901e04c3fSmrg int ret = 0; 129001e04c3fSmrg VkResult result = VK_SUCCESS; 129101e04c3fSmrg 129201e04c3fSmrg /* Bail early if the swapchain is broken */ 129301e04c3fSmrg if (chain->status != VK_SUCCESS) 129401e04c3fSmrg return chain->status; 129501e04c3fSmrg 129601e04c3fSmrg uint64_t timeout = info->timeout; 129701e04c3fSmrg if (timeout != 0 && timeout != UINT64_MAX) 129801e04c3fSmrg timeout = wsi_rel_to_abs_time(timeout); 129901e04c3fSmrg 130001e04c3fSmrg pthread_mutex_lock(&wsi->wait_mutex); 130101e04c3fSmrg for (;;) { 130201e04c3fSmrg for (uint32_t i = 0; i < chain->base.image_count; i++) { 130301e04c3fSmrg if (chain->images[i].state == WSI_IMAGE_IDLE) { 130401e04c3fSmrg *image_index = i; 130501e04c3fSmrg wsi_display_debug("image %d available\n", i); 130601e04c3fSmrg chain->images[i].state = WSI_IMAGE_DRAWING; 130701e04c3fSmrg result = VK_SUCCESS; 130801e04c3fSmrg goto done; 130901e04c3fSmrg } 131001e04c3fSmrg wsi_display_debug("image %d state %d\n", i, chain->images[i].state); 131101e04c3fSmrg } 131201e04c3fSmrg 131301e04c3fSmrg if (ret == ETIMEDOUT) { 131401e04c3fSmrg result = VK_TIMEOUT; 131501e04c3fSmrg goto done; 131601e04c3fSmrg } 131701e04c3fSmrg 131801e04c3fSmrg ret = wsi_display_wait_for_event(wsi, timeout); 131901e04c3fSmrg 132001e04c3fSmrg if (ret && ret != ETIMEDOUT) { 132101e04c3fSmrg result = VK_ERROR_SURFACE_LOST_KHR; 132201e04c3fSmrg goto done; 132301e04c3fSmrg } 132401e04c3fSmrg } 132501e04c3fSmrgdone: 132601e04c3fSmrg pthread_mutex_unlock(&wsi->wait_mutex); 132701e04c3fSmrg 132801e04c3fSmrg if (result != VK_SUCCESS) 132901e04c3fSmrg return result; 133001e04c3fSmrg 133101e04c3fSmrg return chain->status; 133201e04c3fSmrg} 133301e04c3fSmrg 133401e04c3fSmrg/* 133501e04c3fSmrg * Check whether there are any other connectors driven by this crtc 133601e04c3fSmrg */ 133701e04c3fSmrgstatic bool 133801e04c3fSmrgwsi_display_crtc_solo(struct wsi_display *wsi, 133901e04c3fSmrg drmModeResPtr mode_res, 134001e04c3fSmrg drmModeConnectorPtr connector, 134101e04c3fSmrg uint32_t crtc_id) 134201e04c3fSmrg{ 134301e04c3fSmrg /* See if any other connectors share the same encoder */ 134401e04c3fSmrg for (int c = 0; c < mode_res->count_connectors; c++) { 134501e04c3fSmrg if (mode_res->connectors[c] == connector->connector_id) 134601e04c3fSmrg continue; 134701e04c3fSmrg 134801e04c3fSmrg drmModeConnectorPtr other_connector = 134901e04c3fSmrg drmModeGetConnector(wsi->fd, mode_res->connectors[c]); 135001e04c3fSmrg 135101e04c3fSmrg if (other_connector) { 135201e04c3fSmrg bool match = (other_connector->encoder_id == connector->encoder_id); 135301e04c3fSmrg drmModeFreeConnector(other_connector); 135401e04c3fSmrg if (match) 135501e04c3fSmrg return false; 135601e04c3fSmrg } 135701e04c3fSmrg } 135801e04c3fSmrg 135901e04c3fSmrg /* See if any other encoders share the same crtc */ 136001e04c3fSmrg for (int e = 0; e < mode_res->count_encoders; e++) { 136101e04c3fSmrg if (mode_res->encoders[e] == connector->encoder_id) 136201e04c3fSmrg continue; 136301e04c3fSmrg 136401e04c3fSmrg drmModeEncoderPtr other_encoder = 136501e04c3fSmrg drmModeGetEncoder(wsi->fd, mode_res->encoders[e]); 136601e04c3fSmrg 136701e04c3fSmrg if (other_encoder) { 136801e04c3fSmrg bool match = (other_encoder->crtc_id == crtc_id); 136901e04c3fSmrg drmModeFreeEncoder(other_encoder); 137001e04c3fSmrg if (match) 137101e04c3fSmrg return false; 137201e04c3fSmrg } 137301e04c3fSmrg } 137401e04c3fSmrg return true; 137501e04c3fSmrg} 137601e04c3fSmrg 137701e04c3fSmrg/* 137801e04c3fSmrg * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is 137901e04c3fSmrg * currently driving this connector and not any others. Settle for a CRTC 138001e04c3fSmrg * which is currently idle. 138101e04c3fSmrg */ 138201e04c3fSmrgstatic uint32_t 138301e04c3fSmrgwsi_display_select_crtc(const struct wsi_display_connector *connector, 138401e04c3fSmrg drmModeResPtr mode_res, 138501e04c3fSmrg drmModeConnectorPtr drm_connector) 138601e04c3fSmrg{ 138701e04c3fSmrg struct wsi_display *wsi = connector->wsi; 138801e04c3fSmrg 138901e04c3fSmrg /* See what CRTC is currently driving this connector */ 139001e04c3fSmrg if (drm_connector->encoder_id) { 139101e04c3fSmrg drmModeEncoderPtr encoder = 139201e04c3fSmrg drmModeGetEncoder(wsi->fd, drm_connector->encoder_id); 139301e04c3fSmrg 139401e04c3fSmrg if (encoder) { 139501e04c3fSmrg uint32_t crtc_id = encoder->crtc_id; 139601e04c3fSmrg drmModeFreeEncoder(encoder); 139701e04c3fSmrg if (crtc_id) { 139801e04c3fSmrg if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id)) 139901e04c3fSmrg return crtc_id; 140001e04c3fSmrg } 140101e04c3fSmrg } 140201e04c3fSmrg } 140301e04c3fSmrg uint32_t crtc_id = 0; 140401e04c3fSmrg for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) { 140501e04c3fSmrg drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]); 140601e04c3fSmrg if (crtc && crtc->buffer_id == 0) 140701e04c3fSmrg crtc_id = crtc->crtc_id; 140801e04c3fSmrg drmModeFreeCrtc(crtc); 140901e04c3fSmrg } 141001e04c3fSmrg return crtc_id; 141101e04c3fSmrg} 141201e04c3fSmrg 141301e04c3fSmrgstatic VkResult 141401e04c3fSmrgwsi_display_setup_connector(wsi_display_connector *connector, 141501e04c3fSmrg wsi_display_mode *display_mode) 141601e04c3fSmrg{ 141701e04c3fSmrg struct wsi_display *wsi = connector->wsi; 141801e04c3fSmrg 141901e04c3fSmrg if (connector->current_mode == display_mode && connector->crtc_id) 142001e04c3fSmrg return VK_SUCCESS; 142101e04c3fSmrg 142201e04c3fSmrg VkResult result = VK_SUCCESS; 142301e04c3fSmrg 142401e04c3fSmrg drmModeResPtr mode_res = drmModeGetResources(wsi->fd); 142501e04c3fSmrg if (!mode_res) { 142601e04c3fSmrg if (errno == ENOMEM) 142701e04c3fSmrg result = VK_ERROR_OUT_OF_HOST_MEMORY; 142801e04c3fSmrg else 142901e04c3fSmrg result = VK_ERROR_SURFACE_LOST_KHR; 143001e04c3fSmrg goto bail; 143101e04c3fSmrg } 143201e04c3fSmrg 143301e04c3fSmrg drmModeConnectorPtr drm_connector = 143401e04c3fSmrg drmModeGetConnectorCurrent(wsi->fd, connector->id); 143501e04c3fSmrg 143601e04c3fSmrg if (!drm_connector) { 143701e04c3fSmrg if (errno == ENOMEM) 143801e04c3fSmrg result = VK_ERROR_OUT_OF_HOST_MEMORY; 143901e04c3fSmrg else 144001e04c3fSmrg result = VK_ERROR_SURFACE_LOST_KHR; 144101e04c3fSmrg goto bail_mode_res; 144201e04c3fSmrg } 144301e04c3fSmrg 144401e04c3fSmrg /* Pick a CRTC if we don't have one */ 144501e04c3fSmrg if (!connector->crtc_id) { 144601e04c3fSmrg connector->crtc_id = wsi_display_select_crtc(connector, 144701e04c3fSmrg mode_res, drm_connector); 144801e04c3fSmrg if (!connector->crtc_id) { 144901e04c3fSmrg result = VK_ERROR_SURFACE_LOST_KHR; 145001e04c3fSmrg goto bail_connector; 145101e04c3fSmrg } 145201e04c3fSmrg } 145301e04c3fSmrg 145401e04c3fSmrg if (connector->current_mode != display_mode) { 145501e04c3fSmrg 145601e04c3fSmrg /* Find the drm mode corresponding to the requested VkDisplayMode */ 145701e04c3fSmrg drmModeModeInfoPtr drm_mode = NULL; 145801e04c3fSmrg 145901e04c3fSmrg for (int m = 0; m < drm_connector->count_modes; m++) { 146001e04c3fSmrg drm_mode = &drm_connector->modes[m]; 146101e04c3fSmrg if (wsi_display_mode_matches_drm(display_mode, drm_mode)) 146201e04c3fSmrg break; 146301e04c3fSmrg drm_mode = NULL; 146401e04c3fSmrg } 146501e04c3fSmrg 146601e04c3fSmrg if (!drm_mode) { 146701e04c3fSmrg result = VK_ERROR_SURFACE_LOST_KHR; 146801e04c3fSmrg goto bail_connector; 146901e04c3fSmrg } 147001e04c3fSmrg 147101e04c3fSmrg connector->current_mode = display_mode; 147201e04c3fSmrg connector->current_drm_mode = *drm_mode; 147301e04c3fSmrg } 147401e04c3fSmrg 147501e04c3fSmrgbail_connector: 147601e04c3fSmrg drmModeFreeConnector(drm_connector); 147701e04c3fSmrgbail_mode_res: 147801e04c3fSmrg drmModeFreeResources(mode_res); 147901e04c3fSmrgbail: 148001e04c3fSmrg return result; 148101e04c3fSmrg 148201e04c3fSmrg} 148301e04c3fSmrg 148401e04c3fSmrgstatic VkResult 148501e04c3fSmrgwsi_display_fence_wait(struct wsi_fence *fence_wsi, uint64_t timeout) 148601e04c3fSmrg{ 148701e04c3fSmrg const struct wsi_device *wsi_device = fence_wsi->wsi_device; 148801e04c3fSmrg struct wsi_display *wsi = 148901e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 149001e04c3fSmrg struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi; 149101e04c3fSmrg 149201e04c3fSmrg wsi_display_debug("%9lu wait fence %lu %ld\n", 149301e04c3fSmrg pthread_self(), fence->sequence, 14948a1362adSmaya (int64_t) (timeout - wsi_common_get_current_time())); 14958a1362adSmaya wsi_display_debug_code(uint64_t start_ns = wsi_common_get_current_time()); 149601e04c3fSmrg pthread_mutex_lock(&wsi->wait_mutex); 149701e04c3fSmrg 149801e04c3fSmrg VkResult result; 149901e04c3fSmrg int ret = 0; 150001e04c3fSmrg for (;;) { 150101e04c3fSmrg if (fence->event_received) { 150201e04c3fSmrg wsi_display_debug("%9lu fence %lu passed\n", 150301e04c3fSmrg pthread_self(), fence->sequence); 150401e04c3fSmrg result = VK_SUCCESS; 150501e04c3fSmrg break; 150601e04c3fSmrg } 150701e04c3fSmrg 150801e04c3fSmrg if (ret == ETIMEDOUT) { 150901e04c3fSmrg wsi_display_debug("%9lu fence %lu timeout\n", 151001e04c3fSmrg pthread_self(), fence->sequence); 151101e04c3fSmrg result = VK_TIMEOUT; 151201e04c3fSmrg break; 151301e04c3fSmrg } 151401e04c3fSmrg 151501e04c3fSmrg ret = wsi_display_wait_for_event(wsi, timeout); 151601e04c3fSmrg 151701e04c3fSmrg if (ret && ret != ETIMEDOUT) { 151801e04c3fSmrg wsi_display_debug("%9lu fence %lu error\n", 151901e04c3fSmrg pthread_self(), fence->sequence); 152001e04c3fSmrg result = VK_ERROR_DEVICE_LOST; 152101e04c3fSmrg break; 152201e04c3fSmrg } 152301e04c3fSmrg } 152401e04c3fSmrg pthread_mutex_unlock(&wsi->wait_mutex); 152501e04c3fSmrg wsi_display_debug("%9lu fence wait %f ms\n", 152601e04c3fSmrg pthread_self(), 15278a1362adSmaya ((int64_t) (wsi_common_get_current_time() - start_ns)) / 152801e04c3fSmrg 1.0e6); 152901e04c3fSmrg return result; 153001e04c3fSmrg} 153101e04c3fSmrg 153201e04c3fSmrgstatic void 153301e04c3fSmrgwsi_display_fence_check_free(struct wsi_display_fence *fence) 153401e04c3fSmrg{ 153501e04c3fSmrg if (fence->event_received && fence->destroyed) 153601e04c3fSmrg vk_free(fence->base.alloc, fence); 153701e04c3fSmrg} 153801e04c3fSmrg 153901e04c3fSmrgstatic void wsi_display_fence_event_handler(struct wsi_display_fence *fence) 154001e04c3fSmrg{ 15417ec681f3Smrg struct wsi_display *wsi = 15427ec681f3Smrg (struct wsi_display *) fence->base.wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 15437ec681f3Smrg 15447ec681f3Smrg if (fence->syncobj) { 15457ec681f3Smrg (void) drmSyncobjSignal(wsi->fd, &fence->syncobj, 1); 15467ec681f3Smrg (void) drmSyncobjDestroy(wsi->fd, fence->syncobj); 15477ec681f3Smrg } 15487ec681f3Smrg 154901e04c3fSmrg fence->event_received = true; 155001e04c3fSmrg wsi_display_fence_check_free(fence); 155101e04c3fSmrg} 155201e04c3fSmrg 155301e04c3fSmrgstatic void 155401e04c3fSmrgwsi_display_fence_destroy(struct wsi_fence *fence_wsi) 155501e04c3fSmrg{ 155601e04c3fSmrg struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi; 155701e04c3fSmrg 155801e04c3fSmrg assert(!fence->destroyed); 155901e04c3fSmrg fence->destroyed = true; 156001e04c3fSmrg wsi_display_fence_check_free(fence); 156101e04c3fSmrg} 156201e04c3fSmrg 156301e04c3fSmrgstatic struct wsi_display_fence * 156401e04c3fSmrgwsi_display_fence_alloc(VkDevice device, 156501e04c3fSmrg const struct wsi_device *wsi_device, 156601e04c3fSmrg VkDisplayKHR display, 15677ec681f3Smrg const VkAllocationCallbacks *allocator, 15687ec681f3Smrg int sync_fd) 156901e04c3fSmrg{ 157001e04c3fSmrg struct wsi_display *wsi = 157101e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 157201e04c3fSmrg struct wsi_display_fence *fence = 157301e04c3fSmrg vk_zalloc2(wsi->alloc, allocator, sizeof (*fence), 157401e04c3fSmrg 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 157501e04c3fSmrg 157601e04c3fSmrg if (!fence) 157701e04c3fSmrg return NULL; 157801e04c3fSmrg 15797ec681f3Smrg if (sync_fd >= 0) { 15807ec681f3Smrg int ret = drmSyncobjFDToHandle(wsi->fd, sync_fd, &fence->syncobj); 15817ec681f3Smrg if (ret) { 15827ec681f3Smrg vk_free2(wsi->alloc, allocator, fence); 15837ec681f3Smrg return NULL; 15847ec681f3Smrg } 15857ec681f3Smrg } 15867ec681f3Smrg 158701e04c3fSmrg fence->base.device = device; 158801e04c3fSmrg fence->base.display = display; 158901e04c3fSmrg fence->base.wsi_device = wsi_device; 159001e04c3fSmrg fence->base.alloc = allocator ? allocator : wsi->alloc; 159101e04c3fSmrg fence->base.wait = wsi_display_fence_wait; 159201e04c3fSmrg fence->base.destroy = wsi_display_fence_destroy; 159301e04c3fSmrg fence->event_received = false; 159401e04c3fSmrg fence->destroyed = false; 159501e04c3fSmrg fence->sequence = ++fence_sequence; 159601e04c3fSmrg return fence; 159701e04c3fSmrg} 159801e04c3fSmrg 159901e04c3fSmrgstatic VkResult 160001e04c3fSmrgwsi_register_vblank_event(struct wsi_display_fence *fence, 160101e04c3fSmrg const struct wsi_device *wsi_device, 160201e04c3fSmrg VkDisplayKHR display, 160301e04c3fSmrg uint32_t flags, 160401e04c3fSmrg uint64_t frame_requested, 160501e04c3fSmrg uint64_t *frame_queued) 160601e04c3fSmrg{ 160701e04c3fSmrg struct wsi_display *wsi = 160801e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 160901e04c3fSmrg struct wsi_display_connector *connector = 161001e04c3fSmrg wsi_display_connector_from_handle(display); 161101e04c3fSmrg 161201e04c3fSmrg if (wsi->fd < 0) 161301e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 161401e04c3fSmrg 161501e04c3fSmrg for (;;) { 161601e04c3fSmrg int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id, 161701e04c3fSmrg flags, 161801e04c3fSmrg frame_requested, 161901e04c3fSmrg frame_queued, 162001e04c3fSmrg (uintptr_t) fence); 162101e04c3fSmrg 162201e04c3fSmrg if (!ret) 162301e04c3fSmrg return VK_SUCCESS; 162401e04c3fSmrg 162501e04c3fSmrg if (errno != ENOMEM) { 162601e04c3fSmrg 162701e04c3fSmrg /* Something unexpected happened. Pause for a moment so the 162801e04c3fSmrg * application doesn't just spin and then return a failure indication 162901e04c3fSmrg */ 163001e04c3fSmrg 163101e04c3fSmrg wsi_display_debug("queue vblank event %lu failed\n", fence->sequence); 163201e04c3fSmrg struct timespec delay = { 163301e04c3fSmrg .tv_sec = 0, 163401e04c3fSmrg .tv_nsec = 100000000ull, 163501e04c3fSmrg }; 163601e04c3fSmrg nanosleep(&delay, NULL); 163701e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 163801e04c3fSmrg } 163901e04c3fSmrg 164001e04c3fSmrg /* The kernel event queue is full. Wait for some events to be 164101e04c3fSmrg * processed and try again 164201e04c3fSmrg */ 164301e04c3fSmrg 164401e04c3fSmrg pthread_mutex_lock(&wsi->wait_mutex); 164501e04c3fSmrg ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull)); 164601e04c3fSmrg pthread_mutex_unlock(&wsi->wait_mutex); 164701e04c3fSmrg 164801e04c3fSmrg if (ret) { 164901e04c3fSmrg wsi_display_debug("vblank queue full, event wait failed\n"); 165001e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 165101e04c3fSmrg } 165201e04c3fSmrg } 165301e04c3fSmrg} 165401e04c3fSmrg 165501e04c3fSmrg/* 165601e04c3fSmrg * Check to see if the kernel has no flip queued and if there's an image 165701e04c3fSmrg * waiting to be displayed. 165801e04c3fSmrg */ 165901e04c3fSmrgstatic VkResult 166001e04c3fSmrg_wsi_display_queue_next(struct wsi_swapchain *drv_chain) 166101e04c3fSmrg{ 166201e04c3fSmrg struct wsi_display_swapchain *chain = 166301e04c3fSmrg (struct wsi_display_swapchain *) drv_chain; 166401e04c3fSmrg struct wsi_display *wsi = chain->wsi; 166501e04c3fSmrg VkIcdSurfaceDisplay *surface = chain->surface; 166601e04c3fSmrg wsi_display_mode *display_mode = 166701e04c3fSmrg wsi_display_mode_from_handle(surface->displayMode); 166801e04c3fSmrg wsi_display_connector *connector = display_mode->connector; 166901e04c3fSmrg 167001e04c3fSmrg if (wsi->fd < 0) 167101e04c3fSmrg return VK_ERROR_SURFACE_LOST_KHR; 167201e04c3fSmrg 167301e04c3fSmrg if (display_mode != connector->current_mode) 167401e04c3fSmrg connector->active = false; 167501e04c3fSmrg 167601e04c3fSmrg for (;;) { 167701e04c3fSmrg 167801e04c3fSmrg /* Check to see if there is an image to display, or if some image is 167901e04c3fSmrg * already queued */ 168001e04c3fSmrg 168101e04c3fSmrg struct wsi_display_image *image = NULL; 168201e04c3fSmrg 168301e04c3fSmrg for (uint32_t i = 0; i < chain->base.image_count; i++) { 168401e04c3fSmrg struct wsi_display_image *tmp_image = &chain->images[i]; 168501e04c3fSmrg 168601e04c3fSmrg switch (tmp_image->state) { 168701e04c3fSmrg case WSI_IMAGE_FLIPPING: 168801e04c3fSmrg /* already flipping, don't send another to the kernel yet */ 168901e04c3fSmrg return VK_SUCCESS; 169001e04c3fSmrg case WSI_IMAGE_QUEUED: 169101e04c3fSmrg /* find the oldest queued */ 169201e04c3fSmrg if (!image || tmp_image->flip_sequence < image->flip_sequence) 169301e04c3fSmrg image = tmp_image; 169401e04c3fSmrg break; 169501e04c3fSmrg default: 169601e04c3fSmrg break; 169701e04c3fSmrg } 169801e04c3fSmrg } 169901e04c3fSmrg 170001e04c3fSmrg if (!image) 170101e04c3fSmrg return VK_SUCCESS; 170201e04c3fSmrg 170301e04c3fSmrg int ret; 170401e04c3fSmrg if (connector->active) { 170501e04c3fSmrg ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id, 170601e04c3fSmrg DRM_MODE_PAGE_FLIP_EVENT, image); 170701e04c3fSmrg if (ret == 0) { 170801e04c3fSmrg image->state = WSI_IMAGE_FLIPPING; 170901e04c3fSmrg return VK_SUCCESS; 171001e04c3fSmrg } 171101e04c3fSmrg wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret)); 171201e04c3fSmrg } else { 171301e04c3fSmrg ret = -EINVAL; 171401e04c3fSmrg } 171501e04c3fSmrg 171601e04c3fSmrg if (ret == -EINVAL) { 171701e04c3fSmrg VkResult result = wsi_display_setup_connector(connector, display_mode); 171801e04c3fSmrg 171901e04c3fSmrg if (result != VK_SUCCESS) { 172001e04c3fSmrg image->state = WSI_IMAGE_IDLE; 172101e04c3fSmrg return result; 172201e04c3fSmrg } 172301e04c3fSmrg 172401e04c3fSmrg /* XXX allow setting of position */ 172501e04c3fSmrg ret = drmModeSetCrtc(wsi->fd, connector->crtc_id, 172601e04c3fSmrg image->fb_id, 0, 0, 172701e04c3fSmrg &connector->id, 1, 172801e04c3fSmrg &connector->current_drm_mode); 172901e04c3fSmrg if (ret == 0) { 17307ec681f3Smrg /* Disable the HW cursor as the app doesn't have a mechanism 17317ec681f3Smrg * to control it. 17327ec681f3Smrg * Refer to question 12 of the VK_KHR_display spec. 17337ec681f3Smrg */ 17347ec681f3Smrg ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 ); 17357ec681f3Smrg if (ret != 0) { 17367ec681f3Smrg wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret)); 17377ec681f3Smrg } 17387ec681f3Smrg 173901e04c3fSmrg /* Assume that the mode set is synchronous and that any 174001e04c3fSmrg * previous image is now idle. 174101e04c3fSmrg */ 174201e04c3fSmrg image->state = WSI_IMAGE_DISPLAYING; 174301e04c3fSmrg wsi_display_idle_old_displaying(image); 174401e04c3fSmrg connector->active = true; 174501e04c3fSmrg return VK_SUCCESS; 174601e04c3fSmrg } 174701e04c3fSmrg } 174801e04c3fSmrg 174901e04c3fSmrg if (ret != -EACCES) { 175001e04c3fSmrg connector->active = false; 175101e04c3fSmrg image->state = WSI_IMAGE_IDLE; 175201e04c3fSmrg return VK_ERROR_SURFACE_LOST_KHR; 175301e04c3fSmrg } 175401e04c3fSmrg 175501e04c3fSmrg /* Some other VT is currently active. Sit here waiting for 175601e04c3fSmrg * our VT to become active again by polling once a second 175701e04c3fSmrg */ 175801e04c3fSmrg usleep(1000 * 1000); 175901e04c3fSmrg connector->active = false; 176001e04c3fSmrg } 176101e04c3fSmrg} 176201e04c3fSmrg 176301e04c3fSmrgstatic VkResult 176401e04c3fSmrgwsi_display_queue_present(struct wsi_swapchain *drv_chain, 176501e04c3fSmrg uint32_t image_index, 176601e04c3fSmrg const VkPresentRegionKHR *damage) 176701e04c3fSmrg{ 176801e04c3fSmrg struct wsi_display_swapchain *chain = 176901e04c3fSmrg (struct wsi_display_swapchain *) drv_chain; 177001e04c3fSmrg struct wsi_display *wsi = chain->wsi; 177101e04c3fSmrg struct wsi_display_image *image = &chain->images[image_index]; 177201e04c3fSmrg VkResult result; 177301e04c3fSmrg 177401e04c3fSmrg /* Bail early if the swapchain is broken */ 177501e04c3fSmrg if (chain->status != VK_SUCCESS) 177601e04c3fSmrg return chain->status; 177701e04c3fSmrg 177801e04c3fSmrg assert(image->state == WSI_IMAGE_DRAWING); 177901e04c3fSmrg wsi_display_debug("present %d\n", image_index); 178001e04c3fSmrg 178101e04c3fSmrg pthread_mutex_lock(&wsi->wait_mutex); 178201e04c3fSmrg 178301e04c3fSmrg image->flip_sequence = ++chain->flip_sequence; 178401e04c3fSmrg image->state = WSI_IMAGE_QUEUED; 178501e04c3fSmrg 178601e04c3fSmrg result = _wsi_display_queue_next(drv_chain); 178701e04c3fSmrg if (result != VK_SUCCESS) 178801e04c3fSmrg chain->status = result; 178901e04c3fSmrg 179001e04c3fSmrg pthread_mutex_unlock(&wsi->wait_mutex); 179101e04c3fSmrg 179201e04c3fSmrg if (result != VK_SUCCESS) 179301e04c3fSmrg return result; 179401e04c3fSmrg 179501e04c3fSmrg return chain->status; 179601e04c3fSmrg} 179701e04c3fSmrg 179801e04c3fSmrgstatic VkResult 179901e04c3fSmrgwsi_display_surface_create_swapchain( 180001e04c3fSmrg VkIcdSurfaceBase *icd_surface, 180101e04c3fSmrg VkDevice device, 180201e04c3fSmrg struct wsi_device *wsi_device, 180301e04c3fSmrg const VkSwapchainCreateInfoKHR *create_info, 180401e04c3fSmrg const VkAllocationCallbacks *allocator, 180501e04c3fSmrg struct wsi_swapchain **swapchain_out) 180601e04c3fSmrg{ 180701e04c3fSmrg struct wsi_display *wsi = 180801e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 180901e04c3fSmrg 181001e04c3fSmrg assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); 181101e04c3fSmrg 181201e04c3fSmrg const unsigned num_images = create_info->minImageCount; 181301e04c3fSmrg struct wsi_display_swapchain *chain = 181401e04c3fSmrg vk_zalloc(allocator, 181501e04c3fSmrg sizeof(*chain) + num_images * sizeof(chain->images[0]), 181601e04c3fSmrg 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 181701e04c3fSmrg 181801e04c3fSmrg if (chain == NULL) 181901e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 182001e04c3fSmrg 182101e04c3fSmrg VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device, 182201e04c3fSmrg create_info, allocator); 182301e04c3fSmrg if (result != VK_SUCCESS) { 182401e04c3fSmrg vk_free(allocator, chain); 182501e04c3fSmrg return result; 182601e04c3fSmrg } 182701e04c3fSmrg 182801e04c3fSmrg chain->base.destroy = wsi_display_swapchain_destroy; 182901e04c3fSmrg chain->base.get_wsi_image = wsi_display_get_wsi_image; 183001e04c3fSmrg chain->base.acquire_next_image = wsi_display_acquire_next_image; 183101e04c3fSmrg chain->base.queue_present = wsi_display_queue_present; 18328a1362adSmaya chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info); 183301e04c3fSmrg chain->base.image_count = num_images; 183401e04c3fSmrg 183501e04c3fSmrg chain->wsi = wsi; 183601e04c3fSmrg chain->status = VK_SUCCESS; 183701e04c3fSmrg 183801e04c3fSmrg chain->surface = (VkIcdSurfaceDisplay *) icd_surface; 183901e04c3fSmrg 184001e04c3fSmrg for (uint32_t image = 0; image < chain->base.image_count; image++) { 184101e04c3fSmrg result = wsi_display_image_init(device, &chain->base, 184201e04c3fSmrg create_info, allocator, 184301e04c3fSmrg &chain->images[image]); 184401e04c3fSmrg if (result != VK_SUCCESS) { 184501e04c3fSmrg while (image > 0) { 184601e04c3fSmrg --image; 184701e04c3fSmrg wsi_display_image_finish(&chain->base, allocator, 184801e04c3fSmrg &chain->images[image]); 184901e04c3fSmrg } 185001e04c3fSmrg vk_free(allocator, chain); 185101e04c3fSmrg goto fail_init_images; 185201e04c3fSmrg } 185301e04c3fSmrg } 185401e04c3fSmrg 185501e04c3fSmrg *swapchain_out = &chain->base; 185601e04c3fSmrg 185701e04c3fSmrg return VK_SUCCESS; 185801e04c3fSmrg 185901e04c3fSmrgfail_init_images: 186001e04c3fSmrg return result; 186101e04c3fSmrg} 186201e04c3fSmrg 186301e04c3fSmrgstatic bool 186401e04c3fSmrgwsi_init_pthread_cond_monotonic(pthread_cond_t *cond) 186501e04c3fSmrg{ 186601e04c3fSmrg pthread_condattr_t condattr; 186701e04c3fSmrg bool ret = false; 186801e04c3fSmrg 186901e04c3fSmrg if (pthread_condattr_init(&condattr) != 0) 187001e04c3fSmrg goto fail_attr_init; 187101e04c3fSmrg 187201e04c3fSmrg if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0) 187301e04c3fSmrg goto fail_attr_set; 187401e04c3fSmrg 187501e04c3fSmrg if (pthread_cond_init(cond, &condattr) != 0) 187601e04c3fSmrg goto fail_cond_init; 187701e04c3fSmrg 187801e04c3fSmrg ret = true; 187901e04c3fSmrg 188001e04c3fSmrgfail_cond_init: 188101e04c3fSmrgfail_attr_set: 188201e04c3fSmrg pthread_condattr_destroy(&condattr); 188301e04c3fSmrgfail_attr_init: 188401e04c3fSmrg return ret; 188501e04c3fSmrg} 188601e04c3fSmrg 18878a1362adSmaya 18888a1362adSmaya/* 18898a1362adSmaya * Local version fo the libdrm helper. Added to avoid depending on bleeding 18908a1362adSmaya * edge version of the library. 18918a1362adSmaya */ 18928a1362adSmayastatic int 18938a1362adSmayalocal_drmIsMaster(int fd) 18948a1362adSmaya{ 18958a1362adSmaya /* Detect master by attempting something that requires master. 18968a1362adSmaya * 18978a1362adSmaya * Authenticating magic tokens requires master and 0 is an 18988a1362adSmaya * internal kernel detail which we could use. Attempting this on 18998a1362adSmaya * a master fd would fail therefore fail with EINVAL because 0 19008a1362adSmaya * is invalid. 19018a1362adSmaya * 19028a1362adSmaya * A non-master fd will fail with EACCES, as the kernel checks 19038a1362adSmaya * for master before attempting to do anything else. 19048a1362adSmaya * 19058a1362adSmaya * Since we don't want to leak implementation details, use 19068a1362adSmaya * EACCES. 19078a1362adSmaya */ 19088a1362adSmaya return drmAuthMagic(fd, 0) != -EACCES; 19098a1362adSmaya} 19108a1362adSmaya 191101e04c3fSmrgVkResult 191201e04c3fSmrgwsi_display_init_wsi(struct wsi_device *wsi_device, 191301e04c3fSmrg const VkAllocationCallbacks *alloc, 191401e04c3fSmrg int display_fd) 191501e04c3fSmrg{ 191601e04c3fSmrg struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8, 191701e04c3fSmrg VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 191801e04c3fSmrg VkResult result; 191901e04c3fSmrg 192001e04c3fSmrg if (!wsi) { 192101e04c3fSmrg result = VK_ERROR_OUT_OF_HOST_MEMORY; 192201e04c3fSmrg goto fail; 192301e04c3fSmrg } 192401e04c3fSmrg 192501e04c3fSmrg wsi->fd = display_fd; 19268a1362adSmaya if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd)) 19278a1362adSmaya wsi->fd = -1; 19288a1362adSmaya 192901e04c3fSmrg wsi->alloc = alloc; 193001e04c3fSmrg 193101e04c3fSmrg list_inithead(&wsi->connectors); 193201e04c3fSmrg 193301e04c3fSmrg int ret = pthread_mutex_init(&wsi->wait_mutex, NULL); 193401e04c3fSmrg if (ret) { 193501e04c3fSmrg result = VK_ERROR_OUT_OF_HOST_MEMORY; 193601e04c3fSmrg goto fail_mutex; 193701e04c3fSmrg } 193801e04c3fSmrg 193901e04c3fSmrg if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) { 194001e04c3fSmrg result = VK_ERROR_OUT_OF_HOST_MEMORY; 194101e04c3fSmrg goto fail_cond; 194201e04c3fSmrg } 194301e04c3fSmrg 194401e04c3fSmrg wsi->base.get_support = wsi_display_surface_get_support; 194501e04c3fSmrg wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2; 194601e04c3fSmrg wsi->base.get_formats = wsi_display_surface_get_formats; 194701e04c3fSmrg wsi->base.get_formats2 = wsi_display_surface_get_formats2; 194801e04c3fSmrg wsi->base.get_present_modes = wsi_display_surface_get_present_modes; 194901e04c3fSmrg wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles; 195001e04c3fSmrg wsi->base.create_swapchain = wsi_display_surface_create_swapchain; 195101e04c3fSmrg 195201e04c3fSmrg wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base; 195301e04c3fSmrg 195401e04c3fSmrg return VK_SUCCESS; 195501e04c3fSmrg 195601e04c3fSmrgfail_cond: 195701e04c3fSmrg pthread_mutex_destroy(&wsi->wait_mutex); 195801e04c3fSmrgfail_mutex: 195901e04c3fSmrg vk_free(alloc, wsi); 196001e04c3fSmrgfail: 196101e04c3fSmrg return result; 196201e04c3fSmrg} 196301e04c3fSmrg 196401e04c3fSmrgvoid 196501e04c3fSmrgwsi_display_finish_wsi(struct wsi_device *wsi_device, 196601e04c3fSmrg const VkAllocationCallbacks *alloc) 196701e04c3fSmrg{ 196801e04c3fSmrg struct wsi_display *wsi = 196901e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 197001e04c3fSmrg 197101e04c3fSmrg if (wsi) { 197201e04c3fSmrg wsi_for_each_connector(connector, wsi) { 197301e04c3fSmrg wsi_for_each_display_mode(mode, connector) { 197401e04c3fSmrg vk_free(wsi->alloc, mode); 197501e04c3fSmrg } 197601e04c3fSmrg vk_free(wsi->alloc, connector); 197701e04c3fSmrg } 197801e04c3fSmrg 19797ec681f3Smrg wsi_display_stop_wait_thread(wsi); 198001e04c3fSmrg pthread_mutex_destroy(&wsi->wait_mutex); 198101e04c3fSmrg pthread_cond_destroy(&wsi->wait_cond); 198201e04c3fSmrg 198301e04c3fSmrg vk_free(alloc, wsi); 198401e04c3fSmrg } 198501e04c3fSmrg} 198601e04c3fSmrg 198701e04c3fSmrg/* 198801e04c3fSmrg * Implement vkReleaseDisplay 198901e04c3fSmrg */ 19907ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 19917ec681f3Smrgwsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, 19927ec681f3Smrg VkDisplayKHR display) 199301e04c3fSmrg{ 19947ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 19957ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 199601e04c3fSmrg struct wsi_display *wsi = 199701e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 199801e04c3fSmrg 199901e04c3fSmrg if (wsi->fd >= 0) { 20007ec681f3Smrg wsi_display_stop_wait_thread(wsi); 20017ec681f3Smrg 200201e04c3fSmrg close(wsi->fd); 200301e04c3fSmrg wsi->fd = -1; 200401e04c3fSmrg } 20057ec681f3Smrg 200601e04c3fSmrg#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 200701e04c3fSmrg wsi_display_connector_from_handle(display)->output = None; 200801e04c3fSmrg#endif 200901e04c3fSmrg 201001e04c3fSmrg return VK_SUCCESS; 201101e04c3fSmrg} 201201e04c3fSmrg 201301e04c3fSmrg#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 201401e04c3fSmrg 201501e04c3fSmrgstatic struct wsi_display_connector * 201601e04c3fSmrgwsi_display_find_output(struct wsi_device *wsi_device, 201701e04c3fSmrg xcb_randr_output_t output) 201801e04c3fSmrg{ 201901e04c3fSmrg struct wsi_display *wsi = 202001e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 202101e04c3fSmrg 202201e04c3fSmrg wsi_for_each_connector(connector, wsi) { 202301e04c3fSmrg if (connector->output == output) 202401e04c3fSmrg return connector; 202501e04c3fSmrg } 202601e04c3fSmrg 202701e04c3fSmrg return NULL; 202801e04c3fSmrg} 202901e04c3fSmrg 203001e04c3fSmrg/* 203101e04c3fSmrg * Given a RandR output, find the associated kernel connector_id by 203201e04c3fSmrg * looking at the CONNECTOR_ID property provided by the X server 203301e04c3fSmrg */ 203401e04c3fSmrg 203501e04c3fSmrgstatic uint32_t 203601e04c3fSmrgwsi_display_output_to_connector_id(xcb_connection_t *connection, 203701e04c3fSmrg xcb_atom_t *connector_id_atom_p, 203801e04c3fSmrg xcb_randr_output_t output) 203901e04c3fSmrg{ 204001e04c3fSmrg uint32_t connector_id = 0; 204101e04c3fSmrg xcb_atom_t connector_id_atom = *connector_id_atom_p; 204201e04c3fSmrg 204301e04c3fSmrg if (connector_id_atom == 0) { 204401e04c3fSmrg /* Go dig out the CONNECTOR_ID property */ 204501e04c3fSmrg xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection, 204601e04c3fSmrg true, 204701e04c3fSmrg 12, 204801e04c3fSmrg "CONNECTOR_ID"); 204901e04c3fSmrg xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection, 205001e04c3fSmrg ia_c, 205101e04c3fSmrg NULL); 205201e04c3fSmrg if (ia_r) { 205301e04c3fSmrg *connector_id_atom_p = connector_id_atom = ia_r->atom; 205401e04c3fSmrg free(ia_r); 205501e04c3fSmrg } 205601e04c3fSmrg } 205701e04c3fSmrg 205801e04c3fSmrg /* If there's an CONNECTOR_ID atom in the server, then there may be a 205901e04c3fSmrg * CONNECTOR_ID property. Otherwise, there will not be and we don't even 206001e04c3fSmrg * need to bother. 206101e04c3fSmrg */ 206201e04c3fSmrg if (connector_id_atom) { 206301e04c3fSmrg 206401e04c3fSmrg xcb_randr_query_version_cookie_t qv_c = 206501e04c3fSmrg xcb_randr_query_version(connection, 1, 6); 206601e04c3fSmrg xcb_randr_get_output_property_cookie_t gop_c = 206701e04c3fSmrg xcb_randr_get_output_property(connection, 206801e04c3fSmrg output, 206901e04c3fSmrg connector_id_atom, 207001e04c3fSmrg 0, 207101e04c3fSmrg 0, 207201e04c3fSmrg 0xffffffffUL, 207301e04c3fSmrg 0, 207401e04c3fSmrg 0); 207501e04c3fSmrg xcb_randr_query_version_reply_t *qv_r = 207601e04c3fSmrg xcb_randr_query_version_reply(connection, qv_c, NULL); 207701e04c3fSmrg free(qv_r); 207801e04c3fSmrg xcb_randr_get_output_property_reply_t *gop_r = 207901e04c3fSmrg xcb_randr_get_output_property_reply(connection, gop_c, NULL); 208001e04c3fSmrg if (gop_r) { 208101e04c3fSmrg if (gop_r->num_items == 1 && gop_r->format == 32) 208201e04c3fSmrg memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4); 208301e04c3fSmrg free(gop_r); 208401e04c3fSmrg } 208501e04c3fSmrg } 208601e04c3fSmrg return connector_id; 208701e04c3fSmrg} 208801e04c3fSmrg 208901e04c3fSmrgstatic bool 209001e04c3fSmrgwsi_display_check_randr_version(xcb_connection_t *connection) 209101e04c3fSmrg{ 209201e04c3fSmrg xcb_randr_query_version_cookie_t qv_c = 209301e04c3fSmrg xcb_randr_query_version(connection, 1, 6); 209401e04c3fSmrg xcb_randr_query_version_reply_t *qv_r = 209501e04c3fSmrg xcb_randr_query_version_reply(connection, qv_c, NULL); 209601e04c3fSmrg bool ret = false; 209701e04c3fSmrg 209801e04c3fSmrg if (!qv_r) 209901e04c3fSmrg return false; 210001e04c3fSmrg 210101e04c3fSmrg /* Check for version 1.6 or newer */ 210201e04c3fSmrg ret = (qv_r->major_version > 1 || 210301e04c3fSmrg (qv_r->major_version == 1 && qv_r->minor_version >= 6)); 210401e04c3fSmrg 210501e04c3fSmrg free(qv_r); 210601e04c3fSmrg return ret; 210701e04c3fSmrg} 210801e04c3fSmrg 210901e04c3fSmrg/* 211001e04c3fSmrg * Given a kernel connector id, find the associated RandR output using the 211101e04c3fSmrg * CONNECTOR_ID property 211201e04c3fSmrg */ 211301e04c3fSmrg 211401e04c3fSmrgstatic xcb_randr_output_t 211501e04c3fSmrgwsi_display_connector_id_to_output(xcb_connection_t *connection, 211601e04c3fSmrg uint32_t connector_id) 211701e04c3fSmrg{ 211801e04c3fSmrg if (!wsi_display_check_randr_version(connection)) 211901e04c3fSmrg return 0; 212001e04c3fSmrg 212101e04c3fSmrg const xcb_setup_t *setup = xcb_get_setup(connection); 212201e04c3fSmrg 212301e04c3fSmrg xcb_atom_t connector_id_atom = 0; 212401e04c3fSmrg xcb_randr_output_t output = 0; 212501e04c3fSmrg 212601e04c3fSmrg /* Search all of the screens for the provided output */ 212701e04c3fSmrg xcb_screen_iterator_t iter; 212801e04c3fSmrg for (iter = xcb_setup_roots_iterator(setup); 212901e04c3fSmrg output == 0 && iter.rem; 213001e04c3fSmrg xcb_screen_next(&iter)) 213101e04c3fSmrg { 213201e04c3fSmrg xcb_randr_get_screen_resources_cookie_t gsr_c = 213301e04c3fSmrg xcb_randr_get_screen_resources(connection, iter.data->root); 213401e04c3fSmrg xcb_randr_get_screen_resources_reply_t *gsr_r = 213501e04c3fSmrg xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 213601e04c3fSmrg 213701e04c3fSmrg if (!gsr_r) 213801e04c3fSmrg return 0; 213901e04c3fSmrg 214001e04c3fSmrg xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); 214101e04c3fSmrg int o; 214201e04c3fSmrg 214301e04c3fSmrg for (o = 0; o < gsr_r->num_outputs; o++) { 214401e04c3fSmrg if (wsi_display_output_to_connector_id(connection, 214501e04c3fSmrg &connector_id_atom, ro[o]) 214601e04c3fSmrg == connector_id) 214701e04c3fSmrg { 214801e04c3fSmrg output = ro[o]; 214901e04c3fSmrg break; 215001e04c3fSmrg } 215101e04c3fSmrg } 215201e04c3fSmrg free(gsr_r); 215301e04c3fSmrg } 215401e04c3fSmrg return output; 215501e04c3fSmrg} 215601e04c3fSmrg 215701e04c3fSmrg/* 215801e04c3fSmrg * Given a RandR output, find out which screen it's associated with 215901e04c3fSmrg */ 216001e04c3fSmrgstatic xcb_window_t 216101e04c3fSmrgwsi_display_output_to_root(xcb_connection_t *connection, 216201e04c3fSmrg xcb_randr_output_t output) 216301e04c3fSmrg{ 216401e04c3fSmrg if (!wsi_display_check_randr_version(connection)) 216501e04c3fSmrg return 0; 216601e04c3fSmrg 216701e04c3fSmrg const xcb_setup_t *setup = xcb_get_setup(connection); 216801e04c3fSmrg xcb_window_t root = 0; 216901e04c3fSmrg 217001e04c3fSmrg /* Search all of the screens for the provided output */ 217101e04c3fSmrg for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); 217201e04c3fSmrg root == 0 && iter.rem; 217301e04c3fSmrg xcb_screen_next(&iter)) 217401e04c3fSmrg { 217501e04c3fSmrg xcb_randr_get_screen_resources_cookie_t gsr_c = 217601e04c3fSmrg xcb_randr_get_screen_resources(connection, iter.data->root); 217701e04c3fSmrg xcb_randr_get_screen_resources_reply_t *gsr_r = 217801e04c3fSmrg xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 217901e04c3fSmrg 218001e04c3fSmrg if (!gsr_r) 218101e04c3fSmrg return 0; 218201e04c3fSmrg 218301e04c3fSmrg xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); 218401e04c3fSmrg 218501e04c3fSmrg for (int o = 0; o < gsr_r->num_outputs; o++) { 218601e04c3fSmrg if (ro[o] == output) { 218701e04c3fSmrg root = iter.data->root; 218801e04c3fSmrg break; 218901e04c3fSmrg } 219001e04c3fSmrg } 219101e04c3fSmrg free(gsr_r); 219201e04c3fSmrg } 219301e04c3fSmrg return root; 219401e04c3fSmrg} 219501e04c3fSmrg 219601e04c3fSmrgstatic bool 219701e04c3fSmrgwsi_display_mode_matches_x(struct wsi_display_mode *wsi, 219801e04c3fSmrg xcb_randr_mode_info_t *xcb) 219901e04c3fSmrg{ 220001e04c3fSmrg return wsi->clock == (xcb->dot_clock + 500) / 1000 && 220101e04c3fSmrg wsi->hdisplay == xcb->width && 220201e04c3fSmrg wsi->hsync_start == xcb->hsync_start && 220301e04c3fSmrg wsi->hsync_end == xcb->hsync_end && 220401e04c3fSmrg wsi->htotal == xcb->htotal && 220501e04c3fSmrg wsi->hskew == xcb->hskew && 220601e04c3fSmrg wsi->vdisplay == xcb->height && 220701e04c3fSmrg wsi->vsync_start == xcb->vsync_start && 220801e04c3fSmrg wsi->vsync_end == xcb->vsync_end && 220901e04c3fSmrg wsi->vtotal == xcb->vtotal && 221001e04c3fSmrg wsi->vscan <= 1 && 221101e04c3fSmrg wsi->flags == xcb->mode_flags; 221201e04c3fSmrg} 221301e04c3fSmrg 221401e04c3fSmrgstatic struct wsi_display_mode * 221501e04c3fSmrgwsi_display_find_x_mode(struct wsi_device *wsi_device, 221601e04c3fSmrg struct wsi_display_connector *connector, 221701e04c3fSmrg xcb_randr_mode_info_t *mode) 221801e04c3fSmrg{ 221901e04c3fSmrg wsi_for_each_display_mode(display_mode, connector) { 222001e04c3fSmrg if (wsi_display_mode_matches_x(display_mode, mode)) 222101e04c3fSmrg return display_mode; 222201e04c3fSmrg } 222301e04c3fSmrg return NULL; 222401e04c3fSmrg} 222501e04c3fSmrg 222601e04c3fSmrgstatic VkResult 222701e04c3fSmrgwsi_display_register_x_mode(struct wsi_device *wsi_device, 222801e04c3fSmrg struct wsi_display_connector *connector, 222901e04c3fSmrg xcb_randr_mode_info_t *x_mode, 223001e04c3fSmrg bool preferred) 223101e04c3fSmrg{ 223201e04c3fSmrg struct wsi_display *wsi = 223301e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 223401e04c3fSmrg struct wsi_display_mode *display_mode = 223501e04c3fSmrg wsi_display_find_x_mode(wsi_device, connector, x_mode); 223601e04c3fSmrg 223701e04c3fSmrg if (display_mode) { 223801e04c3fSmrg display_mode->valid = true; 223901e04c3fSmrg return VK_SUCCESS; 224001e04c3fSmrg } 224101e04c3fSmrg 224201e04c3fSmrg display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode), 224301e04c3fSmrg 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 224401e04c3fSmrg if (!display_mode) 224501e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 224601e04c3fSmrg 224701e04c3fSmrg display_mode->connector = connector; 224801e04c3fSmrg display_mode->valid = true; 224901e04c3fSmrg display_mode->preferred = preferred; 225001e04c3fSmrg display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */ 225101e04c3fSmrg display_mode->hdisplay = x_mode->width; 225201e04c3fSmrg display_mode->hsync_start = x_mode->hsync_start; 225301e04c3fSmrg display_mode->hsync_end = x_mode->hsync_end; 225401e04c3fSmrg display_mode->htotal = x_mode->htotal; 225501e04c3fSmrg display_mode->hskew = x_mode->hskew; 225601e04c3fSmrg display_mode->vdisplay = x_mode->height; 225701e04c3fSmrg display_mode->vsync_start = x_mode->vsync_start; 225801e04c3fSmrg display_mode->vsync_end = x_mode->vsync_end; 225901e04c3fSmrg display_mode->vtotal = x_mode->vtotal; 226001e04c3fSmrg display_mode->vscan = 0; 226101e04c3fSmrg display_mode->flags = x_mode->mode_flags; 226201e04c3fSmrg 226301e04c3fSmrg list_addtail(&display_mode->list, &connector->display_modes); 226401e04c3fSmrg return VK_SUCCESS; 226501e04c3fSmrg} 226601e04c3fSmrg 226701e04c3fSmrgstatic struct wsi_display_connector * 226801e04c3fSmrgwsi_display_get_output(struct wsi_device *wsi_device, 226901e04c3fSmrg xcb_connection_t *connection, 227001e04c3fSmrg xcb_randr_output_t output) 227101e04c3fSmrg{ 227201e04c3fSmrg struct wsi_display *wsi = 227301e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 227401e04c3fSmrg struct wsi_display_connector *connector; 227501e04c3fSmrg uint32_t connector_id; 227601e04c3fSmrg 227701e04c3fSmrg xcb_window_t root = wsi_display_output_to_root(connection, output); 227801e04c3fSmrg if (!root) 227901e04c3fSmrg return NULL; 228001e04c3fSmrg 228101e04c3fSmrg /* See if we already have a connector for this output */ 228201e04c3fSmrg connector = wsi_display_find_output(wsi_device, output); 228301e04c3fSmrg 228401e04c3fSmrg if (!connector) { 228501e04c3fSmrg xcb_atom_t connector_id_atom = 0; 228601e04c3fSmrg 228701e04c3fSmrg /* 228801e04c3fSmrg * Go get the kernel connector ID for this X output 228901e04c3fSmrg */ 229001e04c3fSmrg connector_id = wsi_display_output_to_connector_id(connection, 229101e04c3fSmrg &connector_id_atom, 229201e04c3fSmrg output); 229301e04c3fSmrg 229401e04c3fSmrg /* Any X server with lease support will have this atom */ 229501e04c3fSmrg if (!connector_id) { 229601e04c3fSmrg return NULL; 229701e04c3fSmrg } 229801e04c3fSmrg 229901e04c3fSmrg /* See if we already have a connector for this id */ 230001e04c3fSmrg connector = wsi_display_find_connector(wsi_device, connector_id); 230101e04c3fSmrg 230201e04c3fSmrg if (connector == NULL) { 230301e04c3fSmrg connector = wsi_display_alloc_connector(wsi, connector_id); 230401e04c3fSmrg if (!connector) { 230501e04c3fSmrg return NULL; 230601e04c3fSmrg } 230701e04c3fSmrg list_addtail(&connector->list, &wsi->connectors); 230801e04c3fSmrg } 230901e04c3fSmrg connector->output = output; 231001e04c3fSmrg } 231101e04c3fSmrg 231201e04c3fSmrg xcb_randr_get_screen_resources_cookie_t src = 231301e04c3fSmrg xcb_randr_get_screen_resources(connection, root); 231401e04c3fSmrg xcb_randr_get_output_info_cookie_t oic = 231501e04c3fSmrg xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME); 231601e04c3fSmrg xcb_randr_get_screen_resources_reply_t *srr = 231701e04c3fSmrg xcb_randr_get_screen_resources_reply(connection, src, NULL); 231801e04c3fSmrg xcb_randr_get_output_info_reply_t *oir = 231901e04c3fSmrg xcb_randr_get_output_info_reply(connection, oic, NULL); 232001e04c3fSmrg 232101e04c3fSmrg if (oir && srr) { 232201e04c3fSmrg /* Get X modes and add them */ 232301e04c3fSmrg 232401e04c3fSmrg connector->connected = 232501e04c3fSmrg oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED; 232601e04c3fSmrg 232701e04c3fSmrg wsi_display_invalidate_connector_modes(wsi_device, connector); 232801e04c3fSmrg 232901e04c3fSmrg xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir); 233001e04c3fSmrg for (int m = 0; m < oir->num_modes; m++) { 233101e04c3fSmrg xcb_randr_mode_info_iterator_t i = 233201e04c3fSmrg xcb_randr_get_screen_resources_modes_iterator(srr); 233301e04c3fSmrg while (i.rem) { 233401e04c3fSmrg xcb_randr_mode_info_t *mi = i.data; 233501e04c3fSmrg if (mi->id == x_modes[m]) { 233601e04c3fSmrg VkResult result = wsi_display_register_x_mode( 233701e04c3fSmrg wsi_device, connector, mi, m < oir->num_preferred); 233801e04c3fSmrg if (result != VK_SUCCESS) { 233901e04c3fSmrg free(oir); 234001e04c3fSmrg free(srr); 234101e04c3fSmrg return NULL; 234201e04c3fSmrg } 234301e04c3fSmrg break; 234401e04c3fSmrg } 234501e04c3fSmrg xcb_randr_mode_info_next(&i); 234601e04c3fSmrg } 234701e04c3fSmrg } 234801e04c3fSmrg } 234901e04c3fSmrg 235001e04c3fSmrg free(oir); 235101e04c3fSmrg free(srr); 235201e04c3fSmrg return connector; 235301e04c3fSmrg} 235401e04c3fSmrg 235501e04c3fSmrgstatic xcb_randr_crtc_t 235601e04c3fSmrgwsi_display_find_crtc_for_output(xcb_connection_t *connection, 235701e04c3fSmrg xcb_window_t root, 235801e04c3fSmrg xcb_randr_output_t output) 235901e04c3fSmrg{ 236001e04c3fSmrg xcb_randr_get_screen_resources_cookie_t gsr_c = 236101e04c3fSmrg xcb_randr_get_screen_resources(connection, root); 236201e04c3fSmrg xcb_randr_get_screen_resources_reply_t *gsr_r = 236301e04c3fSmrg xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 236401e04c3fSmrg 236501e04c3fSmrg if (!gsr_r) 236601e04c3fSmrg return 0; 236701e04c3fSmrg 236801e04c3fSmrg xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r); 236901e04c3fSmrg xcb_randr_crtc_t idle_crtc = 0; 237001e04c3fSmrg xcb_randr_crtc_t active_crtc = 0; 237101e04c3fSmrg 237201e04c3fSmrg /* Find either a crtc already connected to the desired output or idle */ 237301e04c3fSmrg for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) { 237401e04c3fSmrg xcb_randr_get_crtc_info_cookie_t gci_c = 237501e04c3fSmrg xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp); 237601e04c3fSmrg xcb_randr_get_crtc_info_reply_t *gci_r = 237701e04c3fSmrg xcb_randr_get_crtc_info_reply(connection, gci_c, NULL); 237801e04c3fSmrg 237901e04c3fSmrg if (gci_r) { 238001e04c3fSmrg if (gci_r->mode) { 238101e04c3fSmrg int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r); 238201e04c3fSmrg xcb_randr_output_t *outputs = 238301e04c3fSmrg xcb_randr_get_crtc_info_outputs(gci_r); 238401e04c3fSmrg 238501e04c3fSmrg if (num_outputs == 1 && outputs[0] == output) 238601e04c3fSmrg active_crtc = rc[c]; 238701e04c3fSmrg 238801e04c3fSmrg } else if (idle_crtc == 0) { 238901e04c3fSmrg int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r); 239001e04c3fSmrg xcb_randr_output_t *possible = 239101e04c3fSmrg xcb_randr_get_crtc_info_possible(gci_r); 239201e04c3fSmrg 239301e04c3fSmrg for (int p = 0; p < num_possible; p++) 239401e04c3fSmrg if (possible[p] == output) { 239501e04c3fSmrg idle_crtc = rc[c]; 239601e04c3fSmrg break; 239701e04c3fSmrg } 239801e04c3fSmrg } 239901e04c3fSmrg free(gci_r); 240001e04c3fSmrg } 240101e04c3fSmrg } 240201e04c3fSmrg free(gsr_r); 240301e04c3fSmrg 240401e04c3fSmrg if (active_crtc) 240501e04c3fSmrg return active_crtc; 240601e04c3fSmrg return idle_crtc; 240701e04c3fSmrg} 240801e04c3fSmrg 24097ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 24107ec681f3Smrgwsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, 24117ec681f3Smrg Display *dpy, 24127ec681f3Smrg VkDisplayKHR display) 241301e04c3fSmrg{ 24147ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 24157ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 241601e04c3fSmrg struct wsi_display *wsi = 241701e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 241801e04c3fSmrg xcb_connection_t *connection = XGetXCBConnection(dpy); 241901e04c3fSmrg struct wsi_display_connector *connector = 242001e04c3fSmrg wsi_display_connector_from_handle(display); 242101e04c3fSmrg xcb_window_t root; 242201e04c3fSmrg 242301e04c3fSmrg /* XXX no support for multiple leases yet */ 242401e04c3fSmrg if (wsi->fd >= 0) 242501e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 242601e04c3fSmrg 242701e04c3fSmrg if (!connector->output) { 242801e04c3fSmrg connector->output = wsi_display_connector_id_to_output(connection, 242901e04c3fSmrg connector->id); 243001e04c3fSmrg 243101e04c3fSmrg /* Check and see if we found the output */ 243201e04c3fSmrg if (!connector->output) 243301e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 243401e04c3fSmrg } 243501e04c3fSmrg 243601e04c3fSmrg root = wsi_display_output_to_root(connection, connector->output); 243701e04c3fSmrg if (!root) 243801e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 243901e04c3fSmrg 244001e04c3fSmrg xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection, 244101e04c3fSmrg root, 244201e04c3fSmrg connector->output); 244301e04c3fSmrg 244401e04c3fSmrg if (!crtc) 244501e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 244601e04c3fSmrg 244701e04c3fSmrg#ifdef HAVE_DRI3_MODIFIERS 244801e04c3fSmrg xcb_randr_lease_t lease = xcb_generate_id(connection); 244901e04c3fSmrg xcb_randr_create_lease_cookie_t cl_c = 245001e04c3fSmrg xcb_randr_create_lease(connection, root, lease, 1, 1, 245101e04c3fSmrg &crtc, &connector->output); 245201e04c3fSmrg xcb_randr_create_lease_reply_t *cl_r = 245301e04c3fSmrg xcb_randr_create_lease_reply(connection, cl_c, NULL); 245401e04c3fSmrg if (!cl_r) 245501e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 245601e04c3fSmrg 245701e04c3fSmrg int fd = -1; 245801e04c3fSmrg if (cl_r->nfd > 0) { 245901e04c3fSmrg int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r); 246001e04c3fSmrg 246101e04c3fSmrg fd = rcl_f[0]; 246201e04c3fSmrg } 246301e04c3fSmrg free (cl_r); 246401e04c3fSmrg if (fd < 0) 246501e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 246601e04c3fSmrg 246701e04c3fSmrg wsi->fd = fd; 246801e04c3fSmrg#endif 246901e04c3fSmrg 247001e04c3fSmrg return VK_SUCCESS; 247101e04c3fSmrg} 247201e04c3fSmrg 24737ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 24747ec681f3Smrgwsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, 247501e04c3fSmrg Display *dpy, 24767ec681f3Smrg RROutput rrOutput, 24777ec681f3Smrg VkDisplayKHR *pDisplay) 247801e04c3fSmrg{ 24797ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 24807ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 248101e04c3fSmrg xcb_connection_t *connection = XGetXCBConnection(dpy); 248201e04c3fSmrg struct wsi_display_connector *connector = 24837ec681f3Smrg wsi_display_get_output(wsi_device, connection, 24847ec681f3Smrg (xcb_randr_output_t) rrOutput); 248501e04c3fSmrg 248601e04c3fSmrg if (connector) 24877ec681f3Smrg *pDisplay = wsi_display_connector_to_handle(connector); 248801e04c3fSmrg else 24897ec681f3Smrg *pDisplay = VK_NULL_HANDLE; 249001e04c3fSmrg return VK_SUCCESS; 249101e04c3fSmrg} 249201e04c3fSmrg 249301e04c3fSmrg#endif 249401e04c3fSmrg 249501e04c3fSmrg/* VK_EXT_display_control */ 24967ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 24977ec681f3Smrgwsi_DisplayPowerControlEXT(VkDevice _device, 24987ec681f3Smrg VkDisplayKHR display, 24997ec681f3Smrg const VkDisplayPowerInfoEXT *pDisplayPowerInfo) 250001e04c3fSmrg{ 25017ec681f3Smrg VK_FROM_HANDLE(vk_device, device, _device); 25027ec681f3Smrg struct wsi_device *wsi_device = device->physical->wsi_device; 250301e04c3fSmrg struct wsi_display *wsi = 250401e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 250501e04c3fSmrg struct wsi_display_connector *connector = 250601e04c3fSmrg wsi_display_connector_from_handle(display); 250701e04c3fSmrg int mode; 250801e04c3fSmrg 250901e04c3fSmrg if (wsi->fd < 0) 251001e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 251101e04c3fSmrg 25127ec681f3Smrg switch (pDisplayPowerInfo->powerState) { 251301e04c3fSmrg case VK_DISPLAY_POWER_STATE_OFF_EXT: 251401e04c3fSmrg mode = DRM_MODE_DPMS_OFF; 251501e04c3fSmrg break; 251601e04c3fSmrg case VK_DISPLAY_POWER_STATE_SUSPEND_EXT: 251701e04c3fSmrg mode = DRM_MODE_DPMS_SUSPEND; 251801e04c3fSmrg break; 251901e04c3fSmrg default: 252001e04c3fSmrg mode = DRM_MODE_DPMS_ON; 252101e04c3fSmrg break; 252201e04c3fSmrg } 252301e04c3fSmrg drmModeConnectorSetProperty(wsi->fd, 252401e04c3fSmrg connector->id, 252501e04c3fSmrg connector->dpms_property, 252601e04c3fSmrg mode); 252701e04c3fSmrg return VK_SUCCESS; 252801e04c3fSmrg} 252901e04c3fSmrg 253001e04c3fSmrgVkResult 253101e04c3fSmrgwsi_register_device_event(VkDevice device, 253201e04c3fSmrg struct wsi_device *wsi_device, 253301e04c3fSmrg const VkDeviceEventInfoEXT *device_event_info, 253401e04c3fSmrg const VkAllocationCallbacks *allocator, 25357ec681f3Smrg struct wsi_fence **fence_p, 25367ec681f3Smrg int sync_fd) 253701e04c3fSmrg{ 253801e04c3fSmrg return VK_ERROR_FEATURE_NOT_PRESENT; 253901e04c3fSmrg} 254001e04c3fSmrg 25417ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 25427ec681f3Smrgwsi_RegisterDeviceEventEXT(VkDevice device, 25437ec681f3Smrg const VkDeviceEventInfoEXT *pDeviceEventInfo, 25447ec681f3Smrg const VkAllocationCallbacks *pAllocator, 25457ec681f3Smrg VkFence *pFence) 25467ec681f3Smrg{ 25477ec681f3Smrg unreachable("Not enough common infrastructure to implement this yet"); 25487ec681f3Smrg} 25497ec681f3Smrg 255001e04c3fSmrgVkResult 255101e04c3fSmrgwsi_register_display_event(VkDevice device, 255201e04c3fSmrg struct wsi_device *wsi_device, 255301e04c3fSmrg VkDisplayKHR display, 255401e04c3fSmrg const VkDisplayEventInfoEXT *display_event_info, 255501e04c3fSmrg const VkAllocationCallbacks *allocator, 25567ec681f3Smrg struct wsi_fence **fence_p, 25577ec681f3Smrg int sync_fd) 255801e04c3fSmrg{ 255901e04c3fSmrg struct wsi_display *wsi = 256001e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 256101e04c3fSmrg struct wsi_display_fence *fence; 256201e04c3fSmrg VkResult ret; 256301e04c3fSmrg 256401e04c3fSmrg switch (display_event_info->displayEvent) { 256501e04c3fSmrg case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT: 256601e04c3fSmrg 25677ec681f3Smrg fence = wsi_display_fence_alloc(device, wsi_device, display, allocator, sync_fd); 256801e04c3fSmrg 256901e04c3fSmrg if (!fence) 257001e04c3fSmrg return VK_ERROR_OUT_OF_HOST_MEMORY; 257101e04c3fSmrg 257201e04c3fSmrg ret = wsi_register_vblank_event(fence, wsi_device, display, 257301e04c3fSmrg DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL); 257401e04c3fSmrg 25757ec681f3Smrg if (ret == VK_SUCCESS) { 25767ec681f3Smrg if (fence_p) 25777ec681f3Smrg *fence_p = &fence->base; 25787ec681f3Smrg else 25797ec681f3Smrg fence->base.destroy(&fence->base); 25807ec681f3Smrg } else if (fence != NULL) { 25817ec681f3Smrg if (fence->syncobj) 25827ec681f3Smrg drmSyncobjDestroy(wsi->fd, fence->syncobj); 258301e04c3fSmrg vk_free2(wsi->alloc, allocator, fence); 25847ec681f3Smrg } 258501e04c3fSmrg 258601e04c3fSmrg break; 258701e04c3fSmrg default: 258801e04c3fSmrg ret = VK_ERROR_FEATURE_NOT_PRESENT; 258901e04c3fSmrg break; 259001e04c3fSmrg } 259101e04c3fSmrg 259201e04c3fSmrg return ret; 259301e04c3fSmrg} 259401e04c3fSmrg 25957ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 25967ec681f3Smrgwsi_RegisterDisplayEventEXT(VkDevice device, 25977ec681f3Smrg VkDisplayKHR display, 25987ec681f3Smrg const VkDisplayEventInfoEXT *pDisplayEventInfo, 25997ec681f3Smrg const VkAllocationCallbacks *pAllocator, 26007ec681f3Smrg VkFence *pFence) 26017ec681f3Smrg{ 26027ec681f3Smrg unreachable("Not enough common infrastructure to implement this yet"); 26037ec681f3Smrg} 260401e04c3fSmrg 26057ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 26067ec681f3Smrgwsi_GetSwapchainCounterEXT(VkDevice _device, 26077ec681f3Smrg VkSwapchainKHR _swapchain, 26087ec681f3Smrg VkSurfaceCounterFlagBitsEXT counter, 26097ec681f3Smrg uint64_t *pCounterValue) 261001e04c3fSmrg{ 26117ec681f3Smrg VK_FROM_HANDLE(vk_device, device, _device); 26127ec681f3Smrg struct wsi_device *wsi_device = device->physical->wsi_device; 261301e04c3fSmrg struct wsi_display *wsi = 261401e04c3fSmrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 261501e04c3fSmrg struct wsi_display_swapchain *swapchain = 261601e04c3fSmrg (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain); 261701e04c3fSmrg struct wsi_display_connector *connector = 261801e04c3fSmrg wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector; 261901e04c3fSmrg 262001e04c3fSmrg if (wsi->fd < 0) 262101e04c3fSmrg return VK_ERROR_INITIALIZATION_FAILED; 262201e04c3fSmrg 262301e04c3fSmrg if (!connector->active) { 26247ec681f3Smrg *pCounterValue = 0; 262501e04c3fSmrg return VK_SUCCESS; 262601e04c3fSmrg } 262701e04c3fSmrg 26287ec681f3Smrg int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, 26297ec681f3Smrg pCounterValue, NULL); 263001e04c3fSmrg if (ret) 26317ec681f3Smrg *pCounterValue = 0; 263201e04c3fSmrg 263301e04c3fSmrg return VK_SUCCESS; 263401e04c3fSmrg} 263501e04c3fSmrg 26367ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 26377ec681f3Smrgwsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice, 26387ec681f3Smrg int32_t drmFd, 26397ec681f3Smrg VkDisplayKHR display) 26407ec681f3Smrg{ 26417ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 26427ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 26437ec681f3Smrg 26447ec681f3Smrg if (!wsi_device_matches_drm_fd(wsi_device, drmFd)) 26457ec681f3Smrg return VK_ERROR_UNKNOWN; 26467ec681f3Smrg 26477ec681f3Smrg struct wsi_display *wsi = 26487ec681f3Smrg (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 26497ec681f3Smrg 26507ec681f3Smrg /* XXX no support for mulitple leases yet */ 26517ec681f3Smrg if (wsi->fd >= 0 || !local_drmIsMaster(drmFd)) 26527ec681f3Smrg return VK_ERROR_INITIALIZATION_FAILED; 26537ec681f3Smrg 26547ec681f3Smrg struct wsi_display_connector *connector = 26557ec681f3Smrg wsi_display_connector_from_handle(display); 26567ec681f3Smrg 26577ec681f3Smrg drmModeConnectorPtr drm_connector = 26587ec681f3Smrg drmModeGetConnectorCurrent(drmFd, connector->id); 26597ec681f3Smrg 26607ec681f3Smrg if (!drm_connector) 26617ec681f3Smrg return VK_ERROR_INITIALIZATION_FAILED; 26627ec681f3Smrg 26637ec681f3Smrg drmModeFreeConnector(drm_connector); 26647ec681f3Smrg 26657ec681f3Smrg wsi->fd = drmFd; 26667ec681f3Smrg return VK_SUCCESS; 26677ec681f3Smrg} 26687ec681f3Smrg 26697ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL 26707ec681f3Smrgwsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice, 26717ec681f3Smrg int32_t drmFd, 26727ec681f3Smrg uint32_t connectorId, 26737ec681f3Smrg VkDisplayKHR *pDisplay) 26747ec681f3Smrg{ 26757ec681f3Smrg VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 26767ec681f3Smrg struct wsi_device *wsi_device = pdevice->wsi_device; 26777ec681f3Smrg 26787ec681f3Smrg if (!wsi_device_matches_drm_fd(wsi_device, drmFd)) 26797ec681f3Smrg return VK_ERROR_UNKNOWN; 26807ec681f3Smrg 26817ec681f3Smrg struct wsi_display_connector *connector = 26827ec681f3Smrg wsi_display_get_connector(wsi_device, drmFd, connectorId); 26837ec681f3Smrg 26847ec681f3Smrg if (!connector) { 26857ec681f3Smrg *pDisplay = VK_NULL_HANDLE; 26867ec681f3Smrg return VK_ERROR_UNKNOWN; 26877ec681f3Smrg } 26887ec681f3Smrg 26897ec681f3Smrg *pDisplay = wsi_display_connector_to_handle(connector); 26907ec681f3Smrg return VK_SUCCESS; 26917ec681f3Smrg} 2692