1/* 2 * Copyright © 2017 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#include "util/macros.h" 24#include <stdlib.h> 25#include <stdio.h> 26#include <sys/stat.h> 27#include <unistd.h> 28#include <errno.h> 29#include <string.h> 30#include <fcntl.h> 31#include <poll.h> 32#include <stdbool.h> 33#include <math.h> 34#include <xf86drm.h> 35#include <xf86drmMode.h> 36#ifdef HAVE_LIBUDEV 37#include <libudev.h> 38#endif 39#include "drm-uapi/drm_fourcc.h" 40#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 41#include <xcb/randr.h> 42#include <X11/Xlib-xcb.h> 43#endif 44#include "util/hash_table.h" 45#include "util/list.h" 46#include "util/os_time.h" 47 48#include "vk_device.h" 49#include "vk_fence.h" 50#include "vk_instance.h" 51#include "vk_physical_device.h" 52#include "vk_sync.h" 53#include "vk_util.h" 54#include "wsi_common_entrypoints.h" 55#include "wsi_common_private.h" 56#include "wsi_common_display.h" 57#include "wsi_common_queue.h" 58 59#if 0 60#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__) 61#define wsi_display_debug_code(...) __VA_ARGS__ 62#else 63#define wsi_display_debug(...) 64#define wsi_display_debug_code(...) 65#endif 66 67/* These have lifetime equal to the instance, so they effectively 68 * never go away. This means we must keep track of them separately 69 * from all other resources. 70 */ 71typedef struct wsi_display_mode { 72 struct list_head list; 73 struct wsi_display_connector *connector; 74 bool valid; /* was found in most recent poll */ 75 bool preferred; 76 uint32_t clock; /* in kHz */ 77 uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; 78 uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; 79 uint32_t flags; 80} wsi_display_mode; 81 82typedef struct wsi_display_connector { 83 struct list_head list; 84 struct wsi_display *wsi; 85 uint32_t id; 86 uint32_t crtc_id; 87 char *name; 88 bool connected; 89 bool active; 90 struct list_head display_modes; 91 wsi_display_mode *current_mode; 92 drmModeModeInfo current_drm_mode; 93 uint32_t dpms_property; 94#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 95 xcb_randr_output_t output; 96#endif 97} wsi_display_connector; 98 99struct wsi_display { 100 struct wsi_interface base; 101 102 const VkAllocationCallbacks *alloc; 103 104 int fd; 105 106 /* Used with syncobj imported from driver side. */ 107 int syncobj_fd; 108 109 pthread_mutex_t wait_mutex; 110 pthread_cond_t wait_cond; 111 pthread_t wait_thread; 112 113 pthread_cond_t hotplug_cond; 114 pthread_t hotplug_thread; 115 116 struct list_head connectors; /* list of all discovered connectors */ 117}; 118 119#define wsi_for_each_display_mode(_mode, _conn) \ 120 list_for_each_entry_safe(struct wsi_display_mode, _mode, \ 121 &(_conn)->display_modes, list) 122 123#define wsi_for_each_connector(_conn, _dev) \ 124 list_for_each_entry_safe(struct wsi_display_connector, _conn, \ 125 &(_dev)->connectors, list) 126 127enum wsi_image_state { 128 WSI_IMAGE_IDLE, 129 WSI_IMAGE_DRAWING, 130 WSI_IMAGE_QUEUED, 131 WSI_IMAGE_FLIPPING, 132 WSI_IMAGE_DISPLAYING 133}; 134 135struct wsi_display_image { 136 struct wsi_image base; 137 struct wsi_display_swapchain *chain; 138 enum wsi_image_state state; 139 uint32_t fb_id; 140 uint32_t buffer[4]; 141 uint64_t flip_sequence; 142}; 143 144struct wsi_display_swapchain { 145 struct wsi_swapchain base; 146 struct wsi_display *wsi; 147 VkIcdSurfaceDisplay *surface; 148 uint64_t flip_sequence; 149 VkResult status; 150 struct wsi_display_image images[0]; 151}; 152 153struct wsi_display_fence { 154 struct list_head link; 155 struct wsi_display *wsi; 156 bool event_received; 157 bool destroyed; 158 uint32_t syncobj; /* syncobj to signal on event */ 159 uint64_t sequence; 160 bool device_event; /* fence is used for device events */ 161}; 162 163struct wsi_display_sync { 164 struct vk_sync sync; 165 struct wsi_display_fence *fence; 166}; 167 168static uint64_t fence_sequence; 169 170ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR) 171ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR) 172 173static bool 174wsi_display_mode_matches_drm(wsi_display_mode *wsi, 175 drmModeModeInfoPtr drm) 176{ 177 return wsi->clock == drm->clock && 178 wsi->hdisplay == drm->hdisplay && 179 wsi->hsync_start == drm->hsync_start && 180 wsi->hsync_end == drm->hsync_end && 181 wsi->htotal == drm->htotal && 182 wsi->hskew == drm->hskew && 183 wsi->vdisplay == drm->vdisplay && 184 wsi->vsync_start == drm->vsync_start && 185 wsi->vsync_end == drm->vsync_end && 186 wsi->vtotal == drm->vtotal && 187 MAX2(wsi->vscan, 1) == MAX2(drm->vscan, 1) && 188 wsi->flags == drm->flags; 189} 190 191static double 192wsi_display_mode_refresh(struct wsi_display_mode *wsi) 193{ 194 return (double) wsi->clock * 1000.0 / ((double) wsi->htotal * 195 (double) wsi->vtotal * 196 (double) MAX2(wsi->vscan, 1)); 197} 198 199static uint64_t wsi_rel_to_abs_time(uint64_t rel_time) 200{ 201 uint64_t current_time = os_time_get_nano(); 202 203 /* check for overflow */ 204 if (rel_time > UINT64_MAX - current_time) 205 return UINT64_MAX; 206 207 return current_time + rel_time; 208} 209 210static struct wsi_display_mode * 211wsi_display_find_drm_mode(struct wsi_device *wsi_device, 212 struct wsi_display_connector *connector, 213 drmModeModeInfoPtr mode) 214{ 215 wsi_for_each_display_mode(display_mode, connector) { 216 if (wsi_display_mode_matches_drm(display_mode, mode)) 217 return display_mode; 218 } 219 return NULL; 220} 221 222static void 223wsi_display_invalidate_connector_modes(struct wsi_device *wsi_device, 224 struct wsi_display_connector *connector) 225{ 226 wsi_for_each_display_mode(display_mode, connector) { 227 display_mode->valid = false; 228 } 229} 230 231static VkResult 232wsi_display_register_drm_mode(struct wsi_device *wsi_device, 233 struct wsi_display_connector *connector, 234 drmModeModeInfoPtr drm_mode) 235{ 236 struct wsi_display *wsi = 237 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 238 struct wsi_display_mode *display_mode = 239 wsi_display_find_drm_mode(wsi_device, connector, drm_mode); 240 241 if (display_mode) { 242 display_mode->valid = true; 243 return VK_SUCCESS; 244 } 245 246 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode), 247 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 248 if (!display_mode) 249 return VK_ERROR_OUT_OF_HOST_MEMORY; 250 251 display_mode->connector = connector; 252 display_mode->valid = true; 253 display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0; 254 display_mode->clock = drm_mode->clock; /* kHz */ 255 display_mode->hdisplay = drm_mode->hdisplay; 256 display_mode->hsync_start = drm_mode->hsync_start; 257 display_mode->hsync_end = drm_mode->hsync_end; 258 display_mode->htotal = drm_mode->htotal; 259 display_mode->hskew = drm_mode->hskew; 260 display_mode->vdisplay = drm_mode->vdisplay; 261 display_mode->vsync_start = drm_mode->vsync_start; 262 display_mode->vsync_end = drm_mode->vsync_end; 263 display_mode->vtotal = drm_mode->vtotal; 264 display_mode->vscan = drm_mode->vscan; 265 display_mode->flags = drm_mode->flags; 266 267 list_addtail(&display_mode->list, &connector->display_modes); 268 return VK_SUCCESS; 269} 270 271/* 272 * Update our information about a specific connector 273 */ 274 275static struct wsi_display_connector * 276wsi_display_find_connector(struct wsi_device *wsi_device, 277 uint32_t connector_id) 278{ 279 struct wsi_display *wsi = 280 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 281 282 wsi_for_each_connector(connector, wsi) { 283 if (connector->id == connector_id) 284 return connector; 285 } 286 287 return NULL; 288} 289 290static struct wsi_display_connector * 291wsi_display_alloc_connector(struct wsi_display *wsi, 292 uint32_t connector_id) 293{ 294 struct wsi_display_connector *connector = 295 vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector), 296 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 297 298 connector->id = connector_id; 299 connector->wsi = wsi; 300 connector->active = false; 301 /* XXX use EDID name */ 302 connector->name = "monitor"; 303 list_inithead(&connector->display_modes); 304 return connector; 305} 306 307static struct wsi_display_connector * 308wsi_display_get_connector(struct wsi_device *wsi_device, 309 int drm_fd, 310 uint32_t connector_id) 311{ 312 struct wsi_display *wsi = 313 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 314 315 if (drm_fd < 0) 316 return NULL; 317 318 drmModeConnectorPtr drm_connector = 319 drmModeGetConnector(drm_fd, connector_id); 320 321 if (!drm_connector) 322 return NULL; 323 324 struct wsi_display_connector *connector = 325 wsi_display_find_connector(wsi_device, connector_id); 326 327 if (!connector) { 328 connector = wsi_display_alloc_connector(wsi, connector_id); 329 if (!connector) { 330 drmModeFreeConnector(drm_connector); 331 return NULL; 332 } 333 list_addtail(&connector->list, &wsi->connectors); 334 } 335 336 connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED; 337 338 /* Look for a DPMS property if we haven't already found one */ 339 for (int p = 0; connector->dpms_property == 0 && 340 p < drm_connector->count_props; p++) 341 { 342 drmModePropertyPtr prop = drmModeGetProperty(drm_fd, 343 drm_connector->props[p]); 344 if (!prop) 345 continue; 346 if (prop->flags & DRM_MODE_PROP_ENUM) { 347 if (!strcmp(prop->name, "DPMS")) 348 connector->dpms_property = drm_connector->props[p]; 349 } 350 drmModeFreeProperty(prop); 351 } 352 353 /* Mark all connector modes as invalid */ 354 wsi_display_invalidate_connector_modes(wsi_device, connector); 355 356 /* 357 * List current modes, adding new ones and marking existing ones as 358 * valid 359 */ 360 for (int m = 0; m < drm_connector->count_modes; m++) { 361 VkResult result = wsi_display_register_drm_mode(wsi_device, 362 connector, 363 &drm_connector->modes[m]); 364 if (result != VK_SUCCESS) { 365 drmModeFreeConnector(drm_connector); 366 return NULL; 367 } 368 } 369 370 drmModeFreeConnector(drm_connector); 371 372 return connector; 373} 374 375#define MM_PER_PIXEL (1.0/96.0 * 25.4) 376 377static uint32_t 378mode_size(struct wsi_display_mode *mode) 379{ 380 /* fortunately, these are both uint16_t, so this is easy */ 381 return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay; 382} 383 384static void 385wsi_display_fill_in_display_properties(struct wsi_device *wsi_device, 386 struct wsi_display_connector *connector, 387 VkDisplayProperties2KHR *properties2) 388{ 389 assert(properties2->sType == VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR); 390 VkDisplayPropertiesKHR *properties = &properties2->displayProperties; 391 392 properties->display = wsi_display_connector_to_handle(connector); 393 properties->displayName = connector->name; 394 395 /* Find the first preferred mode and assume that's the physical 396 * resolution. If there isn't a preferred mode, find the largest mode and 397 * use that. 398 */ 399 400 struct wsi_display_mode *preferred_mode = NULL, *largest_mode = NULL; 401 wsi_for_each_display_mode(display_mode, connector) { 402 if (!display_mode->valid) 403 continue; 404 if (display_mode->preferred) { 405 preferred_mode = display_mode; 406 break; 407 } 408 if (largest_mode == NULL || 409 mode_size(display_mode) > mode_size(largest_mode)) 410 { 411 largest_mode = display_mode; 412 } 413 } 414 415 if (preferred_mode) { 416 properties->physicalResolution.width = preferred_mode->hdisplay; 417 properties->physicalResolution.height = preferred_mode->vdisplay; 418 } else if (largest_mode) { 419 properties->physicalResolution.width = largest_mode->hdisplay; 420 properties->physicalResolution.height = largest_mode->vdisplay; 421 } else { 422 properties->physicalResolution.width = 1024; 423 properties->physicalResolution.height = 768; 424 } 425 426 /* Make up physical size based on 96dpi */ 427 properties->physicalDimensions.width = 428 floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5); 429 properties->physicalDimensions.height = 430 floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5); 431 432 properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 433 properties->planeReorderPossible = VK_FALSE; 434 properties->persistentContent = VK_FALSE; 435} 436 437VKAPI_ATTR VkResult VKAPI_CALL 438wsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, 439 uint32_t *pPropertyCount, 440 VkDisplayPropertiesKHR *pProperties) 441{ 442 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 443 struct wsi_device *wsi_device = pdevice->wsi_device; 444 struct wsi_display *wsi = 445 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 446 447 if (pProperties == NULL) { 448 return wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, 449 pPropertyCount, 450 NULL); 451 } else { 452 /* If we're actually returning properties, allocate a temporary array of 453 * VkDisplayProperties2KHR structs, call properties2 to fill them out, 454 * and then copy them to the client. This seems a bit expensive but 455 * wsi_display_get_physical_device_display_properties2() calls 456 * drmModeGetResources() which does an ioctl and then a bunch of 457 * allocations so this should get lost in the noise. 458 */ 459 VkDisplayProperties2KHR *props2 = 460 vk_zalloc(wsi->alloc, sizeof(*props2) * *pPropertyCount, 8, 461 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 462 if (props2 == NULL) 463 return VK_ERROR_OUT_OF_HOST_MEMORY; 464 465 for (uint32_t i = 0; i < *pPropertyCount; i++) 466 props2[i].sType = VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR; 467 468 VkResult result = 469 wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, 470 pPropertyCount, props2); 471 472 if (result == VK_SUCCESS || result == VK_INCOMPLETE) { 473 for (uint32_t i = 0; i < *pPropertyCount; i++) 474 pProperties[i] = props2[i].displayProperties; 475 } 476 477 vk_free(wsi->alloc, props2); 478 479 return result; 480 } 481} 482 483static VkResult 484wsi_get_connectors(VkPhysicalDevice physicalDevice) 485{ 486 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 487 struct wsi_device *wsi_device = pdevice->wsi_device; 488 struct wsi_display *wsi = 489 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 490 491 if (wsi->fd < 0) 492 return VK_SUCCESS; 493 494 drmModeResPtr mode_res = drmModeGetResources(wsi->fd); 495 496 if (!mode_res) 497 return VK_ERROR_OUT_OF_HOST_MEMORY; 498 499 /* Get current information */ 500 for (int c = 0; c < mode_res->count_connectors; c++) { 501 struct wsi_display_connector *connector = 502 wsi_display_get_connector(wsi_device, wsi->fd, 503 mode_res->connectors[c]); 504 if (!connector) { 505 drmModeFreeResources(mode_res); 506 return VK_ERROR_OUT_OF_HOST_MEMORY; 507 } 508 } 509 510 drmModeFreeResources(mode_res); 511 return VK_SUCCESS; 512} 513 514VKAPI_ATTR VkResult VKAPI_CALL 515wsi_GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, 516 uint32_t *pPropertyCount, 517 VkDisplayProperties2KHR *pProperties) 518{ 519 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 520 struct wsi_device *wsi_device = pdevice->wsi_device; 521 struct wsi_display *wsi = 522 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 523 524 /* Get current information */ 525 VkResult result = wsi_get_connectors(physicalDevice); 526 if (result != VK_SUCCESS) 527 goto bail; 528 529 VK_OUTARRAY_MAKE_TYPED(VkDisplayProperties2KHR, conn, 530 pProperties, pPropertyCount); 531 532 wsi_for_each_connector(connector, wsi) { 533 if (connector->connected) { 534 vk_outarray_append_typed(VkDisplayProperties2KHR, &conn, prop) { 535 wsi_display_fill_in_display_properties(wsi_device, 536 connector, 537 prop); 538 } 539 } 540 } 541 542 return vk_outarray_status(&conn); 543 544bail: 545 *pPropertyCount = 0; 546 return result; 547} 548 549/* 550 * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display 551 */ 552static void 553wsi_display_fill_in_display_plane_properties( 554 struct wsi_device *wsi_device, 555 struct wsi_display_connector *connector, 556 VkDisplayPlaneProperties2KHR *properties) 557{ 558 assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR); 559 VkDisplayPlanePropertiesKHR *prop = &properties->displayPlaneProperties; 560 561 if (connector && connector->active) { 562 prop->currentDisplay = wsi_display_connector_to_handle(connector); 563 prop->currentStackIndex = 0; 564 } else { 565 prop->currentDisplay = VK_NULL_HANDLE; 566 prop->currentStackIndex = 0; 567 } 568} 569 570VKAPI_ATTR VkResult VKAPI_CALL 571wsi_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, 572 uint32_t *pPropertyCount, 573 VkDisplayPlanePropertiesKHR *pProperties) 574{ 575 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 576 struct wsi_device *wsi_device = pdevice->wsi_device; 577 struct wsi_display *wsi = 578 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 579 580 VkResult result = wsi_get_connectors(physicalDevice); 581 if (result != VK_SUCCESS) 582 goto bail; 583 584 VK_OUTARRAY_MAKE_TYPED(VkDisplayPlanePropertiesKHR, conn, 585 pProperties, pPropertyCount); 586 587 wsi_for_each_connector(connector, wsi) { 588 vk_outarray_append_typed(VkDisplayPlanePropertiesKHR, &conn, prop) { 589 VkDisplayPlaneProperties2KHR prop2 = { 590 .sType = VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR, 591 }; 592 wsi_display_fill_in_display_plane_properties(wsi_device, connector, 593 &prop2); 594 *prop = prop2.displayPlaneProperties; 595 } 596 } 597 return vk_outarray_status(&conn); 598 599bail: 600 *pPropertyCount = 0; 601 return result; 602} 603 604VKAPI_ATTR VkResult VKAPI_CALL 605wsi_GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice, 606 uint32_t *pPropertyCount, 607 VkDisplayPlaneProperties2KHR *pProperties) 608{ 609 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 610 struct wsi_device *wsi_device = pdevice->wsi_device; 611 struct wsi_display *wsi = 612 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 613 614 /* Get current information */ 615 VkResult result = wsi_get_connectors(physicalDevice); 616 if (result != VK_SUCCESS) 617 goto bail; 618 619 VK_OUTARRAY_MAKE_TYPED(VkDisplayPlaneProperties2KHR, conn, 620 pProperties, pPropertyCount); 621 622 wsi_for_each_connector(connector, wsi) { 623 vk_outarray_append_typed(VkDisplayPlaneProperties2KHR, &conn, prop) { 624 wsi_display_fill_in_display_plane_properties(wsi_device, connector, 625 prop); 626 } 627 } 628 return vk_outarray_status(&conn); 629 630bail: 631 *pPropertyCount = 0; 632 return result; 633} 634 635/* 636 * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display) 637 */ 638 639VKAPI_ATTR VkResult VKAPI_CALL 640wsi_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, 641 uint32_t planeIndex, 642 uint32_t *pDisplayCount, 643 VkDisplayKHR *pDisplays) 644{ 645 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 646 struct wsi_device *wsi_device = pdevice->wsi_device; 647 struct wsi_display *wsi = 648 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 649 650 VK_OUTARRAY_MAKE_TYPED(VkDisplayKHR, conn, pDisplays, pDisplayCount); 651 652 int c = 0; 653 654 wsi_for_each_connector(connector, wsi) { 655 if (c == planeIndex && connector->connected) { 656 vk_outarray_append_typed(VkDisplayKHR, &conn, display) { 657 *display = wsi_display_connector_to_handle(connector); 658 } 659 } 660 c++; 661 } 662 return vk_outarray_status(&conn); 663} 664 665/* 666 * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display) 667 */ 668 669static void 670wsi_display_fill_in_display_mode_properties( 671 struct wsi_device *wsi_device, 672 struct wsi_display_mode *display_mode, 673 VkDisplayModeProperties2KHR *properties) 674{ 675 assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR); 676 VkDisplayModePropertiesKHR *prop = &properties->displayModeProperties; 677 678 prop->displayMode = wsi_display_mode_to_handle(display_mode); 679 prop->parameters.visibleRegion.width = display_mode->hdisplay; 680 prop->parameters.visibleRegion.height = display_mode->vdisplay; 681 prop->parameters.refreshRate = 682 (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5); 683} 684 685VKAPI_ATTR VkResult VKAPI_CALL 686wsi_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, 687 VkDisplayKHR display, 688 uint32_t *pPropertyCount, 689 VkDisplayModePropertiesKHR *pProperties) 690{ 691 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 692 struct wsi_device *wsi_device = pdevice->wsi_device; 693 struct wsi_display_connector *connector = 694 wsi_display_connector_from_handle(display); 695 696 VK_OUTARRAY_MAKE_TYPED(VkDisplayModePropertiesKHR, conn, 697 pProperties, pPropertyCount); 698 699 wsi_for_each_display_mode(display_mode, connector) { 700 if (!display_mode->valid) 701 continue; 702 703 vk_outarray_append_typed(VkDisplayModePropertiesKHR, &conn, prop) { 704 VkDisplayModeProperties2KHR prop2 = { 705 .sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR, 706 }; 707 wsi_display_fill_in_display_mode_properties(wsi_device, 708 display_mode, &prop2); 709 *prop = prop2.displayModeProperties; 710 } 711 } 712 return vk_outarray_status(&conn); 713} 714 715VKAPI_ATTR VkResult VKAPI_CALL 716wsi_GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, 717 VkDisplayKHR display, 718 uint32_t *pPropertyCount, 719 VkDisplayModeProperties2KHR *pProperties) 720{ 721 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 722 struct wsi_device *wsi_device = pdevice->wsi_device; 723 struct wsi_display_connector *connector = 724 wsi_display_connector_from_handle(display); 725 726 VK_OUTARRAY_MAKE_TYPED(VkDisplayModeProperties2KHR, conn, 727 pProperties, pPropertyCount); 728 729 wsi_for_each_display_mode(display_mode, connector) { 730 if (!display_mode->valid) 731 continue; 732 733 vk_outarray_append_typed(VkDisplayModeProperties2KHR, &conn, prop) { 734 wsi_display_fill_in_display_mode_properties(wsi_device, 735 display_mode, prop); 736 } 737 } 738 return vk_outarray_status(&conn); 739} 740 741static bool 742wsi_display_mode_matches_vk(wsi_display_mode *wsi, 743 const VkDisplayModeParametersKHR *vk) 744{ 745 return (vk->visibleRegion.width == wsi->hdisplay && 746 vk->visibleRegion.height == wsi->vdisplay && 747 fabs(wsi_display_mode_refresh(wsi) * 1000.0 - vk->refreshRate) < 10); 748} 749 750/* 751 * Implement vkCreateDisplayModeKHR (VK_KHR_display) 752 */ 753VKAPI_ATTR VkResult VKAPI_CALL 754wsi_CreateDisplayModeKHR(VkPhysicalDevice physicalDevice, 755 VkDisplayKHR display, 756 const VkDisplayModeCreateInfoKHR *pCreateInfo, 757 const VkAllocationCallbacks *pAllocator, 758 VkDisplayModeKHR *pMode) 759{ 760 struct wsi_display_connector *connector = 761 wsi_display_connector_from_handle(display); 762 763 if (pCreateInfo->flags != 0) 764 return VK_ERROR_INITIALIZATION_FAILED; 765 766 /* Check and see if the requested mode happens to match an existing one and 767 * return that. This makes the conformance suite happy. Doing more than 768 * this would involve embedding the CVT function into the driver, which seems 769 * excessive. 770 */ 771 wsi_for_each_display_mode(display_mode, connector) { 772 if (display_mode->valid) { 773 if (wsi_display_mode_matches_vk(display_mode, &pCreateInfo->parameters)) { 774 *pMode = wsi_display_mode_to_handle(display_mode); 775 return VK_SUCCESS; 776 } 777 } 778 } 779 return VK_ERROR_INITIALIZATION_FAILED; 780} 781 782/* 783 * Implement vkGetDisplayPlaneCapabilities 784 */ 785VKAPI_ATTR VkResult VKAPI_CALL 786wsi_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, 787 VkDisplayModeKHR _mode, 788 uint32_t planeIndex, 789 VkDisplayPlaneCapabilitiesKHR *pCapabilities) 790{ 791 struct wsi_display_mode *mode = wsi_display_mode_from_handle(_mode); 792 793 /* XXX use actual values */ 794 pCapabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; 795 pCapabilities->minSrcPosition.x = 0; 796 pCapabilities->minSrcPosition.y = 0; 797 pCapabilities->maxSrcPosition.x = 0; 798 pCapabilities->maxSrcPosition.y = 0; 799 pCapabilities->minSrcExtent.width = mode->hdisplay; 800 pCapabilities->minSrcExtent.height = mode->vdisplay; 801 pCapabilities->maxSrcExtent.width = mode->hdisplay; 802 pCapabilities->maxSrcExtent.height = mode->vdisplay; 803 pCapabilities->minDstPosition.x = 0; 804 pCapabilities->minDstPosition.y = 0; 805 pCapabilities->maxDstPosition.x = 0; 806 pCapabilities->maxDstPosition.y = 0; 807 pCapabilities->minDstExtent.width = mode->hdisplay; 808 pCapabilities->minDstExtent.height = mode->vdisplay; 809 pCapabilities->maxDstExtent.width = mode->hdisplay; 810 pCapabilities->maxDstExtent.height = mode->vdisplay; 811 return VK_SUCCESS; 812} 813 814VKAPI_ATTR VkResult VKAPI_CALL 815wsi_GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice, 816 const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, 817 VkDisplayPlaneCapabilities2KHR *pCapabilities) 818{ 819 assert(pCapabilities->sType == 820 VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR); 821 822 VkResult result = 823 wsi_GetDisplayPlaneCapabilitiesKHR(physicalDevice, 824 pDisplayPlaneInfo->mode, 825 pDisplayPlaneInfo->planeIndex, 826 &pCapabilities->capabilities); 827 828 vk_foreach_struct(ext, pCapabilities->pNext) { 829 switch (ext->sType) { 830 case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { 831 VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext; 832 protected->supportsProtected = VK_FALSE; 833 break; 834 } 835 836 default: 837 /* Ignored */ 838 break; 839 } 840 } 841 842 return result; 843} 844 845VKAPI_ATTR VkResult VKAPI_CALL 846wsi_CreateDisplayPlaneSurfaceKHR(VkInstance _instance, 847 const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, 848 const VkAllocationCallbacks *pAllocator, 849 VkSurfaceKHR *pSurface) 850{ 851 VK_FROM_HANDLE(vk_instance, instance, _instance); 852 VkIcdSurfaceDisplay *surface; 853 854 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR); 855 856 surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8, 857 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 858 if (surface == NULL) 859 return VK_ERROR_OUT_OF_HOST_MEMORY; 860 861 surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY; 862 863 surface->displayMode = pCreateInfo->displayMode; 864 surface->planeIndex = pCreateInfo->planeIndex; 865 surface->planeStackIndex = pCreateInfo->planeStackIndex; 866 surface->transform = pCreateInfo->transform; 867 surface->globalAlpha = pCreateInfo->globalAlpha; 868 surface->alphaMode = pCreateInfo->alphaMode; 869 surface->imageExtent = pCreateInfo->imageExtent; 870 871 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base); 872 873 return VK_SUCCESS; 874} 875 876static VkResult 877wsi_display_surface_get_support(VkIcdSurfaceBase *surface, 878 struct wsi_device *wsi_device, 879 uint32_t queueFamilyIndex, 880 VkBool32* pSupported) 881{ 882 struct wsi_display *wsi = 883 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 884 885 *pSupported = wsi->fd != -1; 886 return VK_SUCCESS; 887} 888 889static VkResult 890wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base, 891 struct wsi_device *wsi_device, 892 VkSurfaceCapabilitiesKHR* caps) 893{ 894 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base; 895 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode); 896 897 caps->currentExtent.width = mode->hdisplay; 898 caps->currentExtent.height = mode->vdisplay; 899 900 caps->minImageExtent = (VkExtent2D) { 1, 1 }; 901 caps->maxImageExtent = (VkExtent2D) { 902 wsi_device->maxImageDimension2D, 903 wsi_device->maxImageDimension2D, 904 }; 905 906 caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 907 908 caps->minImageCount = 2; 909 caps->maxImageCount = 0; 910 911 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 912 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 913 caps->maxImageArrayLayers = 1; 914 caps->supportedUsageFlags = 915 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 916 VK_IMAGE_USAGE_SAMPLED_BIT | 917 VK_IMAGE_USAGE_TRANSFER_DST_BIT | 918 VK_IMAGE_USAGE_STORAGE_BIT | 919 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 920 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; 921 922 return VK_SUCCESS; 923} 924 925static VkResult 926wsi_display_surface_get_surface_counters( 927 VkIcdSurfaceBase *surface_base, 928 VkSurfaceCounterFlagsEXT *counters) 929{ 930 *counters = VK_SURFACE_COUNTER_VBLANK_BIT_EXT; 931 return VK_SUCCESS; 932} 933 934static VkResult 935wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface, 936 struct wsi_device *wsi_device, 937 const void *info_next, 938 VkSurfaceCapabilities2KHR *caps) 939{ 940 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); 941 VkResult result; 942 943 result = wsi_display_surface_get_capabilities(icd_surface, wsi_device, 944 &caps->surfaceCapabilities); 945 if (result != VK_SUCCESS) 946 return result; 947 948 struct wsi_surface_supported_counters *counters = 949 vk_find_struct( caps->pNext, WSI_SURFACE_SUPPORTED_COUNTERS_MESA); 950 951 if (counters) { 952 result = wsi_display_surface_get_surface_counters( 953 icd_surface, 954 &counters->supported_surface_counters); 955 } 956 957 return result; 958} 959 960static const struct { 961 VkFormat format; 962 uint32_t drm_format; 963} available_surface_formats[] = { 964 { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 }, 965 { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 }, 966}; 967 968static void 969get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats) 970{ 971 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) 972 sorted_formats[i] = available_surface_formats[i].format; 973 974 if (wsi_device->force_bgra8_unorm_first) { 975 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { 976 if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) { 977 sorted_formats[i] = sorted_formats[0]; 978 sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM; 979 break; 980 } 981 } 982 } 983} 984 985static VkResult 986wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface, 987 struct wsi_device *wsi_device, 988 uint32_t *surface_format_count, 989 VkSurfaceFormatKHR *surface_formats) 990{ 991 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, 992 surface_formats, surface_format_count); 993 994 VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; 995 get_sorted_vk_formats(wsi_device, sorted_formats); 996 997 for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { 998 vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) { 999 f->format = sorted_formats[i]; 1000 f->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; 1001 } 1002 } 1003 1004 return vk_outarray_status(&out); 1005} 1006 1007static VkResult 1008wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface, 1009 struct wsi_device *wsi_device, 1010 const void *info_next, 1011 uint32_t *surface_format_count, 1012 VkSurfaceFormat2KHR *surface_formats) 1013{ 1014 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, 1015 surface_formats, surface_format_count); 1016 1017 VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; 1018 get_sorted_vk_formats(wsi_device, sorted_formats); 1019 1020 for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { 1021 vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) { 1022 assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR); 1023 f->surfaceFormat.format = sorted_formats[i]; 1024 f->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; 1025 } 1026 } 1027 1028 return vk_outarray_status(&out); 1029} 1030 1031static VkResult 1032wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface, 1033 uint32_t *present_mode_count, 1034 VkPresentModeKHR *present_modes) 1035{ 1036 VK_OUTARRAY_MAKE_TYPED(VkPresentModeKHR, conn, 1037 present_modes, present_mode_count); 1038 1039 vk_outarray_append_typed(VkPresentModeKHR, &conn, present) { 1040 *present = VK_PRESENT_MODE_FIFO_KHR; 1041 } 1042 1043 return vk_outarray_status(&conn); 1044} 1045 1046static VkResult 1047wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base, 1048 struct wsi_device *wsi_device, 1049 uint32_t* pRectCount, 1050 VkRect2D* pRects) 1051{ 1052 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base; 1053 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode); 1054 VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount); 1055 1056 if (wsi_device_matches_drm_fd(wsi_device, mode->connector->wsi->fd)) { 1057 vk_outarray_append_typed(VkRect2D, &out, rect) { 1058 *rect = (VkRect2D) { 1059 .offset = { 0, 0 }, 1060 .extent = { mode->hdisplay, mode->vdisplay }, 1061 }; 1062 } 1063 } 1064 1065 return vk_outarray_status(&out); 1066} 1067 1068static void 1069wsi_display_destroy_buffer(struct wsi_display *wsi, 1070 uint32_t buffer) 1071{ 1072 (void) drmIoctl(wsi->fd, DRM_IOCTL_GEM_CLOSE, 1073 &((struct drm_gem_close) { .handle = buffer })); 1074} 1075 1076static VkResult 1077wsi_display_image_init(VkDevice device_h, 1078 struct wsi_swapchain *drv_chain, 1079 const VkSwapchainCreateInfoKHR *create_info, 1080 const VkAllocationCallbacks *allocator, 1081 struct wsi_display_image *image) 1082{ 1083 struct wsi_display_swapchain *chain = 1084 (struct wsi_display_swapchain *) drv_chain; 1085 struct wsi_display *wsi = chain->wsi; 1086 uint32_t drm_format = 0; 1087 1088 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { 1089 if (create_info->imageFormat == available_surface_formats[i].format) { 1090 drm_format = available_surface_formats[i].drm_format; 1091 break; 1092 } 1093 } 1094 1095 /* the application provided an invalid format, bail */ 1096 if (drm_format == 0) 1097 return VK_ERROR_DEVICE_LOST; 1098 1099 VkResult result = wsi_create_image(&chain->base, &chain->base.image_info, 1100 &image->base); 1101 if (result != VK_SUCCESS) 1102 return result; 1103 1104 memset(image->buffer, 0, sizeof (image->buffer)); 1105 1106 for (unsigned int i = 0; i < image->base.num_planes; i++) { 1107 int ret = drmPrimeFDToHandle(wsi->fd, image->base.dma_buf_fd, 1108 &image->buffer[i]); 1109 if (ret < 0) 1110 goto fail_handle; 1111 } 1112 1113 image->chain = chain; 1114 image->state = WSI_IMAGE_IDLE; 1115 image->fb_id = 0; 1116 1117 int ret = drmModeAddFB2(wsi->fd, 1118 create_info->imageExtent.width, 1119 create_info->imageExtent.height, 1120 drm_format, 1121 image->buffer, 1122 image->base.row_pitches, 1123 image->base.offsets, 1124 &image->fb_id, 0); 1125 1126 if (ret) 1127 goto fail_fb; 1128 1129 return VK_SUCCESS; 1130 1131fail_fb: 1132fail_handle: 1133 for (unsigned int i = 0; i < image->base.num_planes; i++) { 1134 if (image->buffer[i]) 1135 wsi_display_destroy_buffer(wsi, image->buffer[i]); 1136 } 1137 1138 wsi_destroy_image(&chain->base, &image->base); 1139 1140 return VK_ERROR_OUT_OF_HOST_MEMORY; 1141} 1142 1143static void 1144wsi_display_image_finish(struct wsi_swapchain *drv_chain, 1145 const VkAllocationCallbacks *allocator, 1146 struct wsi_display_image *image) 1147{ 1148 struct wsi_display_swapchain *chain = 1149 (struct wsi_display_swapchain *) drv_chain; 1150 struct wsi_display *wsi = chain->wsi; 1151 1152 drmModeRmFB(wsi->fd, image->fb_id); 1153 for (unsigned int i = 0; i < image->base.num_planes; i++) 1154 wsi_display_destroy_buffer(wsi, image->buffer[i]); 1155 wsi_destroy_image(&chain->base, &image->base); 1156} 1157 1158static VkResult 1159wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain, 1160 const VkAllocationCallbacks *allocator) 1161{ 1162 struct wsi_display_swapchain *chain = 1163 (struct wsi_display_swapchain *) drv_chain; 1164 1165 for (uint32_t i = 0; i < chain->base.image_count; i++) 1166 wsi_display_image_finish(drv_chain, allocator, &chain->images[i]); 1167 wsi_destroy_image_info(&chain->base, &chain->base.image_info); 1168 1169 wsi_swapchain_finish(&chain->base); 1170 vk_free(allocator, chain); 1171 return VK_SUCCESS; 1172} 1173 1174static struct wsi_image * 1175wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain, 1176 uint32_t image_index) 1177{ 1178 struct wsi_display_swapchain *chain = 1179 (struct wsi_display_swapchain *) drv_chain; 1180 1181 return &chain->images[image_index].base; 1182} 1183 1184static void 1185wsi_display_idle_old_displaying(struct wsi_display_image *active_image) 1186{ 1187 struct wsi_display_swapchain *chain = active_image->chain; 1188 1189 wsi_display_debug("idle everyone but %ld\n", 1190 active_image - &(chain->images[0])); 1191 for (uint32_t i = 0; i < chain->base.image_count; i++) 1192 if (chain->images[i].state == WSI_IMAGE_DISPLAYING && 1193 &chain->images[i] != active_image) 1194 { 1195 wsi_display_debug("idle %d\n", i); 1196 chain->images[i].state = WSI_IMAGE_IDLE; 1197 } 1198} 1199 1200static VkResult 1201_wsi_display_queue_next(struct wsi_swapchain *drv_chain); 1202 1203static void 1204wsi_display_page_flip_handler2(int fd, 1205 unsigned int frame, 1206 unsigned int sec, 1207 unsigned int usec, 1208 uint32_t crtc_id, 1209 void *data) 1210{ 1211 struct wsi_display_image *image = data; 1212 struct wsi_display_swapchain *chain = image->chain; 1213 1214 wsi_display_debug("image %ld displayed at %d\n", 1215 image - &(image->chain->images[0]), frame); 1216 image->state = WSI_IMAGE_DISPLAYING; 1217 wsi_display_idle_old_displaying(image); 1218 VkResult result = _wsi_display_queue_next(&(chain->base)); 1219 if (result != VK_SUCCESS) 1220 chain->status = result; 1221} 1222 1223static void wsi_display_fence_event_handler(struct wsi_display_fence *fence); 1224 1225static void wsi_display_page_flip_handler(int fd, 1226 unsigned int frame, 1227 unsigned int sec, 1228 unsigned int usec, 1229 void *data) 1230{ 1231 wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data); 1232} 1233 1234static void wsi_display_vblank_handler(int fd, unsigned int frame, 1235 unsigned int sec, unsigned int usec, 1236 void *data) 1237{ 1238 struct wsi_display_fence *fence = data; 1239 1240 wsi_display_fence_event_handler(fence); 1241} 1242 1243static void wsi_display_sequence_handler(int fd, uint64_t frame, 1244 uint64_t nsec, uint64_t user_data) 1245{ 1246 struct wsi_display_fence *fence = 1247 (struct wsi_display_fence *) (uintptr_t) user_data; 1248 1249 wsi_display_fence_event_handler(fence); 1250} 1251 1252static drmEventContext event_context = { 1253 .version = DRM_EVENT_CONTEXT_VERSION, 1254 .page_flip_handler = wsi_display_page_flip_handler, 1255#if DRM_EVENT_CONTEXT_VERSION >= 3 1256 .page_flip_handler2 = wsi_display_page_flip_handler2, 1257#endif 1258 .vblank_handler = wsi_display_vblank_handler, 1259 .sequence_handler = wsi_display_sequence_handler, 1260}; 1261 1262static void * 1263wsi_display_wait_thread(void *data) 1264{ 1265 struct wsi_display *wsi = data; 1266 struct pollfd pollfd = { 1267 .fd = wsi->fd, 1268 .events = POLLIN 1269 }; 1270 1271 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 1272 for (;;) { 1273 int ret = poll(&pollfd, 1, -1); 1274 if (ret > 0) { 1275 pthread_mutex_lock(&wsi->wait_mutex); 1276 (void) drmHandleEvent(wsi->fd, &event_context); 1277 pthread_cond_broadcast(&wsi->wait_cond); 1278 pthread_mutex_unlock(&wsi->wait_mutex); 1279 } 1280 } 1281 return NULL; 1282} 1283 1284static int 1285wsi_display_start_wait_thread(struct wsi_display *wsi) 1286{ 1287 if (!wsi->wait_thread) { 1288 int ret = pthread_create(&wsi->wait_thread, NULL, 1289 wsi_display_wait_thread, wsi); 1290 if (ret) 1291 return ret; 1292 } 1293 return 0; 1294} 1295 1296static void 1297wsi_display_stop_wait_thread(struct wsi_display *wsi) 1298{ 1299 pthread_mutex_lock(&wsi->wait_mutex); 1300 if (wsi->wait_thread) { 1301 pthread_cancel(wsi->wait_thread); 1302 pthread_join(wsi->wait_thread, NULL); 1303 wsi->wait_thread = 0; 1304 } 1305 pthread_mutex_unlock(&wsi->wait_mutex); 1306} 1307 1308static int 1309cond_timedwait_ns(pthread_cond_t *cond, 1310 pthread_mutex_t *mutex, 1311 uint64_t timeout_ns) 1312{ 1313 struct timespec abs_timeout = { 1314 .tv_sec = timeout_ns / 1000000000ULL, 1315 .tv_nsec = timeout_ns % 1000000000ULL, 1316 }; 1317 1318 int ret = pthread_cond_timedwait(cond, mutex, &abs_timeout); 1319 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret); 1320 return ret; 1321} 1322 1323/* 1324 * Wait for at least one event from the kernel to be processed. 1325 * Call with wait_mutex held 1326 */ 1327static int 1328wsi_display_wait_for_event(struct wsi_display *wsi, 1329 uint64_t timeout_ns) 1330{ 1331 int ret = wsi_display_start_wait_thread(wsi); 1332 1333 if (ret) 1334 return ret; 1335 1336 return cond_timedwait_ns(&wsi->wait_cond, &wsi->wait_mutex, timeout_ns); 1337} 1338 1339/* Wait for device event to be processed. 1340 * Call with wait_mutex held 1341 */ 1342static int 1343wsi_device_wait_for_event(struct wsi_display *wsi, 1344 uint64_t timeout_ns) 1345{ 1346 return cond_timedwait_ns(&wsi->hotplug_cond, &wsi->wait_mutex, timeout_ns); 1347} 1348 1349static VkResult 1350wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain, 1351 const VkAcquireNextImageInfoKHR *info, 1352 uint32_t *image_index) 1353{ 1354 struct wsi_display_swapchain *chain = 1355 (struct wsi_display_swapchain *)drv_chain; 1356 struct wsi_display *wsi = chain->wsi; 1357 int ret = 0; 1358 VkResult result = VK_SUCCESS; 1359 1360 /* Bail early if the swapchain is broken */ 1361 if (chain->status != VK_SUCCESS) 1362 return chain->status; 1363 1364 uint64_t timeout = info->timeout; 1365 if (timeout != 0 && timeout != UINT64_MAX) 1366 timeout = wsi_rel_to_abs_time(timeout); 1367 1368 pthread_mutex_lock(&wsi->wait_mutex); 1369 for (;;) { 1370 for (uint32_t i = 0; i < chain->base.image_count; i++) { 1371 if (chain->images[i].state == WSI_IMAGE_IDLE) { 1372 *image_index = i; 1373 wsi_display_debug("image %d available\n", i); 1374 chain->images[i].state = WSI_IMAGE_DRAWING; 1375 result = VK_SUCCESS; 1376 goto done; 1377 } 1378 wsi_display_debug("image %d state %d\n", i, chain->images[i].state); 1379 } 1380 1381 if (ret == ETIMEDOUT) { 1382 result = VK_TIMEOUT; 1383 goto done; 1384 } 1385 1386 ret = wsi_display_wait_for_event(wsi, timeout); 1387 1388 if (ret && ret != ETIMEDOUT) { 1389 result = VK_ERROR_SURFACE_LOST_KHR; 1390 goto done; 1391 } 1392 } 1393done: 1394 pthread_mutex_unlock(&wsi->wait_mutex); 1395 1396 if (result != VK_SUCCESS) 1397 return result; 1398 1399 return chain->status; 1400} 1401 1402/* 1403 * Check whether there are any other connectors driven by this crtc 1404 */ 1405static bool 1406wsi_display_crtc_solo(struct wsi_display *wsi, 1407 drmModeResPtr mode_res, 1408 drmModeConnectorPtr connector, 1409 uint32_t crtc_id) 1410{ 1411 /* See if any other connectors share the same encoder */ 1412 for (int c = 0; c < mode_res->count_connectors; c++) { 1413 if (mode_res->connectors[c] == connector->connector_id) 1414 continue; 1415 1416 drmModeConnectorPtr other_connector = 1417 drmModeGetConnector(wsi->fd, mode_res->connectors[c]); 1418 1419 if (other_connector) { 1420 bool match = (other_connector->encoder_id == connector->encoder_id); 1421 drmModeFreeConnector(other_connector); 1422 if (match) 1423 return false; 1424 } 1425 } 1426 1427 /* See if any other encoders share the same crtc */ 1428 for (int e = 0; e < mode_res->count_encoders; e++) { 1429 if (mode_res->encoders[e] == connector->encoder_id) 1430 continue; 1431 1432 drmModeEncoderPtr other_encoder = 1433 drmModeGetEncoder(wsi->fd, mode_res->encoders[e]); 1434 1435 if (other_encoder) { 1436 bool match = (other_encoder->crtc_id == crtc_id); 1437 drmModeFreeEncoder(other_encoder); 1438 if (match) 1439 return false; 1440 } 1441 } 1442 return true; 1443} 1444 1445/* 1446 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is 1447 * currently driving this connector and not any others. Settle for a CRTC 1448 * which is currently idle. 1449 */ 1450static uint32_t 1451wsi_display_select_crtc(const struct wsi_display_connector *connector, 1452 drmModeResPtr mode_res, 1453 drmModeConnectorPtr drm_connector) 1454{ 1455 struct wsi_display *wsi = connector->wsi; 1456 1457 /* See what CRTC is currently driving this connector */ 1458 if (drm_connector->encoder_id) { 1459 drmModeEncoderPtr encoder = 1460 drmModeGetEncoder(wsi->fd, drm_connector->encoder_id); 1461 1462 if (encoder) { 1463 uint32_t crtc_id = encoder->crtc_id; 1464 drmModeFreeEncoder(encoder); 1465 if (crtc_id) { 1466 if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id)) 1467 return crtc_id; 1468 } 1469 } 1470 } 1471 uint32_t crtc_id = 0; 1472 for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) { 1473 drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]); 1474 if (crtc && crtc->buffer_id == 0) 1475 crtc_id = crtc->crtc_id; 1476 drmModeFreeCrtc(crtc); 1477 } 1478 return crtc_id; 1479} 1480 1481static VkResult 1482wsi_display_setup_connector(wsi_display_connector *connector, 1483 wsi_display_mode *display_mode) 1484{ 1485 struct wsi_display *wsi = connector->wsi; 1486 1487 if (connector->current_mode == display_mode && connector->crtc_id) 1488 return VK_SUCCESS; 1489 1490 VkResult result = VK_SUCCESS; 1491 1492 drmModeResPtr mode_res = drmModeGetResources(wsi->fd); 1493 if (!mode_res) { 1494 if (errno == ENOMEM) 1495 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1496 else 1497 result = VK_ERROR_SURFACE_LOST_KHR; 1498 goto bail; 1499 } 1500 1501 drmModeConnectorPtr drm_connector = 1502 drmModeGetConnectorCurrent(wsi->fd, connector->id); 1503 1504 if (!drm_connector) { 1505 if (errno == ENOMEM) 1506 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1507 else 1508 result = VK_ERROR_SURFACE_LOST_KHR; 1509 goto bail_mode_res; 1510 } 1511 1512 /* Pick a CRTC if we don't have one */ 1513 if (!connector->crtc_id) { 1514 connector->crtc_id = wsi_display_select_crtc(connector, 1515 mode_res, drm_connector); 1516 if (!connector->crtc_id) { 1517 result = VK_ERROR_SURFACE_LOST_KHR; 1518 goto bail_connector; 1519 } 1520 } 1521 1522 if (connector->current_mode != display_mode) { 1523 1524 /* Find the drm mode corresponding to the requested VkDisplayMode */ 1525 drmModeModeInfoPtr drm_mode = NULL; 1526 1527 for (int m = 0; m < drm_connector->count_modes; m++) { 1528 drm_mode = &drm_connector->modes[m]; 1529 if (wsi_display_mode_matches_drm(display_mode, drm_mode)) 1530 break; 1531 drm_mode = NULL; 1532 } 1533 1534 if (!drm_mode) { 1535 result = VK_ERROR_SURFACE_LOST_KHR; 1536 goto bail_connector; 1537 } 1538 1539 connector->current_mode = display_mode; 1540 connector->current_drm_mode = *drm_mode; 1541 } 1542 1543bail_connector: 1544 drmModeFreeConnector(drm_connector); 1545bail_mode_res: 1546 drmModeFreeResources(mode_res); 1547bail: 1548 return result; 1549 1550} 1551 1552static VkResult 1553wsi_display_fence_wait(struct wsi_display_fence *fence, uint64_t timeout) 1554{ 1555 wsi_display_debug("%9lu wait fence %lu %ld\n", 1556 pthread_self(), fence->sequence, 1557 (int64_t) (timeout - os_time_get_nano())); 1558 wsi_display_debug_code(uint64_t start_ns = os_time_get_nano()); 1559 pthread_mutex_lock(&fence->wsi->wait_mutex); 1560 1561 VkResult result; 1562 int ret = 0; 1563 for (;;) { 1564 if (fence->event_received) { 1565 wsi_display_debug("%9lu fence %lu passed\n", 1566 pthread_self(), fence->sequence); 1567 result = VK_SUCCESS; 1568 break; 1569 } 1570 1571 if (ret == ETIMEDOUT) { 1572 wsi_display_debug("%9lu fence %lu timeout\n", 1573 pthread_self(), fence->sequence); 1574 result = VK_TIMEOUT; 1575 break; 1576 } 1577 1578 if (fence->device_event) 1579 ret = wsi_device_wait_for_event(fence->wsi, timeout); 1580 else 1581 ret = wsi_display_wait_for_event(fence->wsi, timeout); 1582 1583 if (ret && ret != ETIMEDOUT) { 1584 wsi_display_debug("%9lu fence %lu error\n", 1585 pthread_self(), fence->sequence); 1586 result = VK_ERROR_DEVICE_LOST; 1587 break; 1588 } 1589 } 1590 pthread_mutex_unlock(&fence->wsi->wait_mutex); 1591 wsi_display_debug("%9lu fence wait %f ms\n", 1592 pthread_self(), 1593 ((int64_t) (os_time_get_nano() - start_ns)) / 1594 1.0e6); 1595 return result; 1596} 1597 1598static void 1599wsi_display_fence_check_free(struct wsi_display_fence *fence) 1600{ 1601 if (fence->event_received && fence->destroyed) 1602 vk_free(fence->wsi->alloc, fence); 1603} 1604 1605static void wsi_display_fence_event_handler(struct wsi_display_fence *fence) 1606{ 1607 if (fence->syncobj) { 1608 (void) drmSyncobjSignal(fence->wsi->syncobj_fd, &fence->syncobj, 1); 1609 (void) drmSyncobjDestroy(fence->wsi->syncobj_fd, fence->syncobj); 1610 } 1611 1612 fence->event_received = true; 1613 wsi_display_fence_check_free(fence); 1614} 1615 1616static void 1617wsi_display_fence_destroy(struct wsi_display_fence *fence) 1618{ 1619 /* Destroy hotplug fence list. */ 1620 if (fence->device_event) { 1621 mtx_lock(&fence->wsi->wait_mutex); 1622 list_del(&fence->link); 1623 mtx_unlock(&fence->wsi->wait_mutex); 1624 fence->event_received = true; 1625 } 1626 1627 assert(!fence->destroyed); 1628 fence->destroyed = true; 1629 wsi_display_fence_check_free(fence); 1630} 1631 1632static struct wsi_display_fence * 1633wsi_display_fence_alloc(struct wsi_display *wsi, int sync_fd) 1634{ 1635 struct wsi_display_fence *fence = 1636 vk_zalloc(wsi->alloc, sizeof (*fence), 1637 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 1638 1639 if (!fence) 1640 return NULL; 1641 1642 if (sync_fd >= 0) { 1643 int ret = drmSyncobjFDToHandle(wsi->syncobj_fd, sync_fd, &fence->syncobj); 1644 1645 if (ret) { 1646 vk_free(wsi->alloc, fence); 1647 return NULL; 1648 } 1649 } 1650 1651 fence->wsi = wsi; 1652 fence->event_received = false; 1653 fence->destroyed = false; 1654 fence->sequence = ++fence_sequence; 1655 return fence; 1656} 1657 1658static VkResult 1659wsi_display_sync_init(struct vk_device *device, 1660 struct vk_sync *sync, 1661 uint64_t initial_value) 1662{ 1663 assert(initial_value == 0); 1664 return VK_SUCCESS; 1665} 1666 1667static void 1668wsi_display_sync_finish(struct vk_device *device, 1669 struct vk_sync *sync) 1670{ 1671 struct wsi_display_sync *wsi_sync = 1672 container_of(sync, struct wsi_display_sync, sync); 1673 if (wsi_sync->fence) 1674 wsi_display_fence_destroy(wsi_sync->fence); 1675} 1676 1677static VkResult 1678wsi_display_sync_wait(struct vk_device *device, 1679 struct vk_sync *sync, 1680 uint64_t wait_value, 1681 enum vk_sync_wait_flags wait_flags, 1682 uint64_t abs_timeout_ns) 1683{ 1684 struct wsi_display_sync *wsi_sync = 1685 container_of(sync, struct wsi_display_sync, sync); 1686 1687 assert(wait_value == 0); 1688 assert(wait_flags == VK_SYNC_WAIT_COMPLETE); 1689 1690 return wsi_display_fence_wait(wsi_sync->fence, abs_timeout_ns); 1691} 1692 1693static const struct vk_sync_type wsi_display_sync_type = { 1694 .size = sizeof(struct wsi_display_sync), 1695 .features = VK_SYNC_FEATURE_BINARY | 1696 VK_SYNC_FEATURE_CPU_WAIT, 1697 .init = wsi_display_sync_init, 1698 .finish = wsi_display_sync_finish, 1699 .wait = wsi_display_sync_wait, 1700}; 1701 1702static VkResult 1703wsi_display_sync_create(struct vk_device *device, 1704 struct wsi_display_fence *fence, 1705 struct vk_sync **sync_out) 1706{ 1707 VkResult result = vk_sync_create(device, &wsi_display_sync_type, 1708 0 /* flags */, 1709 0 /* initial_value */, sync_out); 1710 if (result != VK_SUCCESS) 1711 return result; 1712 1713 struct wsi_display_sync *sync = 1714 container_of(*sync_out, struct wsi_display_sync, sync); 1715 1716 sync->fence = fence; 1717 1718 return VK_SUCCESS; 1719} 1720 1721static VkResult 1722wsi_register_vblank_event(struct wsi_display_fence *fence, 1723 const struct wsi_device *wsi_device, 1724 VkDisplayKHR display, 1725 uint32_t flags, 1726 uint64_t frame_requested, 1727 uint64_t *frame_queued) 1728{ 1729 struct wsi_display *wsi = 1730 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1731 struct wsi_display_connector *connector = 1732 wsi_display_connector_from_handle(display); 1733 1734 if (wsi->fd < 0) 1735 return VK_ERROR_INITIALIZATION_FAILED; 1736 1737 /* A display event may be registered before the first page flip at which 1738 * point crtc_id will be 0. If this is the case we setup the connector 1739 * here to allow drmCrtcQueueSequence to succeed. 1740 */ 1741 if (!connector->crtc_id) { 1742 VkResult ret = wsi_display_setup_connector(connector, 1743 connector->current_mode); 1744 if (ret != VK_SUCCESS) 1745 return VK_ERROR_INITIALIZATION_FAILED; 1746 } 1747 1748 for (;;) { 1749 int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id, 1750 flags, 1751 frame_requested, 1752 frame_queued, 1753 (uintptr_t) fence); 1754 1755 if (!ret) 1756 return VK_SUCCESS; 1757 1758 if (errno != ENOMEM) { 1759 1760 /* Something unexpected happened. Pause for a moment so the 1761 * application doesn't just spin and then return a failure indication 1762 */ 1763 1764 wsi_display_debug("queue vblank event %lu failed\n", fence->sequence); 1765 struct timespec delay = { 1766 .tv_sec = 0, 1767 .tv_nsec = 100000000ull, 1768 }; 1769 nanosleep(&delay, NULL); 1770 return VK_ERROR_OUT_OF_HOST_MEMORY; 1771 } 1772 1773 /* The kernel event queue is full. Wait for some events to be 1774 * processed and try again 1775 */ 1776 1777 pthread_mutex_lock(&wsi->wait_mutex); 1778 ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull)); 1779 pthread_mutex_unlock(&wsi->wait_mutex); 1780 1781 if (ret) { 1782 wsi_display_debug("vblank queue full, event wait failed\n"); 1783 return VK_ERROR_OUT_OF_HOST_MEMORY; 1784 } 1785 } 1786} 1787 1788/* 1789 * Check to see if the kernel has no flip queued and if there's an image 1790 * waiting to be displayed. 1791 */ 1792static VkResult 1793_wsi_display_queue_next(struct wsi_swapchain *drv_chain) 1794{ 1795 struct wsi_display_swapchain *chain = 1796 (struct wsi_display_swapchain *) drv_chain; 1797 struct wsi_display *wsi = chain->wsi; 1798 VkIcdSurfaceDisplay *surface = chain->surface; 1799 wsi_display_mode *display_mode = 1800 wsi_display_mode_from_handle(surface->displayMode); 1801 wsi_display_connector *connector = display_mode->connector; 1802 1803 if (wsi->fd < 0) 1804 return VK_ERROR_SURFACE_LOST_KHR; 1805 1806 if (display_mode != connector->current_mode) 1807 connector->active = false; 1808 1809 for (;;) { 1810 1811 /* Check to see if there is an image to display, or if some image is 1812 * already queued */ 1813 1814 struct wsi_display_image *image = NULL; 1815 1816 for (uint32_t i = 0; i < chain->base.image_count; i++) { 1817 struct wsi_display_image *tmp_image = &chain->images[i]; 1818 1819 switch (tmp_image->state) { 1820 case WSI_IMAGE_FLIPPING: 1821 /* already flipping, don't send another to the kernel yet */ 1822 return VK_SUCCESS; 1823 case WSI_IMAGE_QUEUED: 1824 /* find the oldest queued */ 1825 if (!image || tmp_image->flip_sequence < image->flip_sequence) 1826 image = tmp_image; 1827 break; 1828 default: 1829 break; 1830 } 1831 } 1832 1833 if (!image) 1834 return VK_SUCCESS; 1835 1836 int ret; 1837 if (connector->active) { 1838 ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id, 1839 DRM_MODE_PAGE_FLIP_EVENT, image); 1840 if (ret == 0) { 1841 image->state = WSI_IMAGE_FLIPPING; 1842 return VK_SUCCESS; 1843 } 1844 wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret)); 1845 } else { 1846 ret = -EINVAL; 1847 } 1848 1849 if (ret == -EINVAL) { 1850 VkResult result = wsi_display_setup_connector(connector, display_mode); 1851 1852 if (result != VK_SUCCESS) { 1853 image->state = WSI_IMAGE_IDLE; 1854 return result; 1855 } 1856 1857 /* XXX allow setting of position */ 1858 ret = drmModeSetCrtc(wsi->fd, connector->crtc_id, 1859 image->fb_id, 0, 0, 1860 &connector->id, 1, 1861 &connector->current_drm_mode); 1862 if (ret == 0) { 1863 /* Disable the HW cursor as the app doesn't have a mechanism 1864 * to control it. 1865 * Refer to question 12 of the VK_KHR_display spec. 1866 */ 1867 ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 ); 1868 if (ret != 0) { 1869 wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret)); 1870 } 1871 1872 /* Assume that the mode set is synchronous and that any 1873 * previous image is now idle. 1874 */ 1875 image->state = WSI_IMAGE_DISPLAYING; 1876 wsi_display_idle_old_displaying(image); 1877 connector->active = true; 1878 return VK_SUCCESS; 1879 } 1880 } 1881 1882 if (ret != -EACCES) { 1883 connector->active = false; 1884 image->state = WSI_IMAGE_IDLE; 1885 return VK_ERROR_SURFACE_LOST_KHR; 1886 } 1887 1888 /* Some other VT is currently active. Sit here waiting for 1889 * our VT to become active again by polling once a second 1890 */ 1891 usleep(1000 * 1000); 1892 connector->active = false; 1893 } 1894} 1895 1896static VkResult 1897wsi_display_queue_present(struct wsi_swapchain *drv_chain, 1898 uint32_t image_index, 1899 const VkPresentRegionKHR *damage) 1900{ 1901 struct wsi_display_swapchain *chain = 1902 (struct wsi_display_swapchain *) drv_chain; 1903 struct wsi_display *wsi = chain->wsi; 1904 struct wsi_display_image *image = &chain->images[image_index]; 1905 VkResult result; 1906 1907 /* Bail early if the swapchain is broken */ 1908 if (chain->status != VK_SUCCESS) 1909 return chain->status; 1910 1911 assert(image->state == WSI_IMAGE_DRAWING); 1912 wsi_display_debug("present %d\n", image_index); 1913 1914 pthread_mutex_lock(&wsi->wait_mutex); 1915 1916 image->flip_sequence = ++chain->flip_sequence; 1917 image->state = WSI_IMAGE_QUEUED; 1918 1919 result = _wsi_display_queue_next(drv_chain); 1920 if (result != VK_SUCCESS) 1921 chain->status = result; 1922 1923 pthread_mutex_unlock(&wsi->wait_mutex); 1924 1925 if (result != VK_SUCCESS) 1926 return result; 1927 1928 return chain->status; 1929} 1930 1931static VkResult 1932wsi_display_surface_create_swapchain( 1933 VkIcdSurfaceBase *icd_surface, 1934 VkDevice device, 1935 struct wsi_device *wsi_device, 1936 const VkSwapchainCreateInfoKHR *create_info, 1937 const VkAllocationCallbacks *allocator, 1938 struct wsi_swapchain **swapchain_out) 1939{ 1940 struct wsi_display *wsi = 1941 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1942 1943 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); 1944 1945 const unsigned num_images = create_info->minImageCount; 1946 struct wsi_display_swapchain *chain = 1947 vk_zalloc(allocator, 1948 sizeof(*chain) + num_images * sizeof(chain->images[0]), 1949 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 1950 1951 if (chain == NULL) 1952 return VK_ERROR_OUT_OF_HOST_MEMORY; 1953 1954 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device, 1955 create_info, allocator, false); 1956 if (result != VK_SUCCESS) { 1957 vk_free(allocator, chain); 1958 return result; 1959 } 1960 1961 chain->base.destroy = wsi_display_swapchain_destroy; 1962 chain->base.get_wsi_image = wsi_display_get_wsi_image; 1963 chain->base.acquire_next_image = wsi_display_acquire_next_image; 1964 chain->base.queue_present = wsi_display_queue_present; 1965 chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info); 1966 chain->base.image_count = num_images; 1967 1968 chain->wsi = wsi; 1969 chain->status = VK_SUCCESS; 1970 1971 chain->surface = (VkIcdSurfaceDisplay *) icd_surface; 1972 1973 result = wsi_configure_native_image(&chain->base, create_info, 1974 0, NULL, NULL, 1975 &chain->base.image_info); 1976 if (result != VK_SUCCESS) { 1977 vk_free(allocator, chain); 1978 goto fail_init_images; 1979 } 1980 1981 for (uint32_t image = 0; image < chain->base.image_count; image++) { 1982 result = wsi_display_image_init(device, &chain->base, 1983 create_info, allocator, 1984 &chain->images[image]); 1985 if (result != VK_SUCCESS) { 1986 while (image > 0) { 1987 --image; 1988 wsi_display_image_finish(&chain->base, allocator, 1989 &chain->images[image]); 1990 } 1991 wsi_destroy_image_info(&chain->base, &chain->base.image_info); 1992 vk_free(allocator, chain); 1993 goto fail_init_images; 1994 } 1995 } 1996 1997 *swapchain_out = &chain->base; 1998 1999 return VK_SUCCESS; 2000 2001fail_init_images: 2002 return result; 2003} 2004 2005static bool 2006wsi_init_pthread_cond_monotonic(pthread_cond_t *cond) 2007{ 2008 pthread_condattr_t condattr; 2009 bool ret = false; 2010 2011 if (pthread_condattr_init(&condattr) != 0) 2012 goto fail_attr_init; 2013 2014 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0) 2015 goto fail_attr_set; 2016 2017 if (pthread_cond_init(cond, &condattr) != 0) 2018 goto fail_cond_init; 2019 2020 ret = true; 2021 2022fail_cond_init: 2023fail_attr_set: 2024 pthread_condattr_destroy(&condattr); 2025fail_attr_init: 2026 return ret; 2027} 2028 2029 2030/* 2031 * Local version fo the libdrm helper. Added to avoid depending on bleeding 2032 * edge version of the library. 2033 */ 2034static int 2035local_drmIsMaster(int fd) 2036{ 2037 /* Detect master by attempting something that requires master. 2038 * 2039 * Authenticating magic tokens requires master and 0 is an 2040 * internal kernel detail which we could use. Attempting this on 2041 * a master fd would fail therefore fail with EINVAL because 0 2042 * is invalid. 2043 * 2044 * A non-master fd will fail with EACCES, as the kernel checks 2045 * for master before attempting to do anything else. 2046 * 2047 * Since we don't want to leak implementation details, use 2048 * EACCES. 2049 */ 2050 return drmAuthMagic(fd, 0) != -EACCES; 2051} 2052 2053#ifdef HAVE_LIBUDEV 2054static void * 2055udev_event_listener_thread(void *data) 2056{ 2057 struct wsi_device *wsi_device = data; 2058 struct wsi_display *wsi = 2059 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2060 2061 struct udev *u = udev_new(); 2062 if (!u) 2063 goto fail; 2064 2065 struct udev_monitor *mon = 2066 udev_monitor_new_from_netlink(u, "udev"); 2067 if (!mon) 2068 goto fail_udev; 2069 2070 int ret = 2071 udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor"); 2072 if (ret < 0) 2073 goto fail_udev_monitor; 2074 2075 ret = udev_monitor_enable_receiving(mon); 2076 if (ret < 0) 2077 goto fail_udev_monitor; 2078 2079 int udev_fd = udev_monitor_get_fd(mon); 2080 2081 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 2082 2083 for (;;) { 2084 nfds_t nfds = 1; 2085 struct pollfd fds[1] = { 2086 { 2087 .fd = udev_fd, 2088 .events = POLLIN, 2089 }, 2090 }; 2091 2092 int ret = poll(fds, nfds, -1); 2093 if (ret > 0) { 2094 if (fds[0].revents & POLLIN) { 2095 struct udev_device *dev = udev_monitor_receive_device(mon); 2096 2097 /* Ignore event if it is not a hotplug event */ 2098 if (!atoi(udev_device_get_property_value(dev, "HOTPLUG"))) 2099 continue; 2100 2101 /* Note, this supports both drmSyncobjWait for fence->syncobj 2102 * and wsi_display_wait_for_event. 2103 */ 2104 mtx_lock(&wsi->wait_mutex); 2105 pthread_cond_broadcast(&wsi->hotplug_cond); 2106 list_for_each_entry(struct wsi_display_fence, fence, 2107 &wsi_device->hotplug_fences, link) { 2108 if (fence->syncobj) 2109 drmSyncobjSignal(wsi->syncobj_fd, &fence->syncobj, 1); 2110 fence->event_received = true; 2111 } 2112 mtx_unlock(&wsi->wait_mutex); 2113 udev_device_unref(dev); 2114 } 2115 } else if (ret < 0) { 2116 goto fail; 2117 } 2118 } 2119 2120 udev_monitor_unref(mon); 2121 udev_unref(u); 2122 2123 return 0; 2124 2125fail_udev_monitor: 2126 udev_monitor_unref(mon); 2127fail_udev: 2128 udev_unref(u); 2129fail: 2130 wsi_display_debug("critical hotplug thread error\n"); 2131 return 0; 2132} 2133#endif 2134 2135VkResult 2136wsi_display_init_wsi(struct wsi_device *wsi_device, 2137 const VkAllocationCallbacks *alloc, 2138 int display_fd) 2139{ 2140 struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8, 2141 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2142 VkResult result; 2143 2144 if (!wsi) { 2145 result = VK_ERROR_OUT_OF_HOST_MEMORY; 2146 goto fail; 2147 } 2148 2149 wsi->fd = display_fd; 2150 if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd)) 2151 wsi->fd = -1; 2152 2153 wsi->syncobj_fd = wsi->fd; 2154 2155 wsi->alloc = alloc; 2156 2157 list_inithead(&wsi->connectors); 2158 2159 int ret = pthread_mutex_init(&wsi->wait_mutex, NULL); 2160 if (ret) { 2161 result = VK_ERROR_OUT_OF_HOST_MEMORY; 2162 goto fail_mutex; 2163 } 2164 2165 if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) { 2166 result = VK_ERROR_OUT_OF_HOST_MEMORY; 2167 goto fail_cond; 2168 } 2169 2170 if (!wsi_init_pthread_cond_monotonic(&wsi->hotplug_cond)) { 2171 result = VK_ERROR_OUT_OF_HOST_MEMORY; 2172 goto fail_hotplug_cond; 2173 } 2174 2175 wsi->base.get_support = wsi_display_surface_get_support; 2176 wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2; 2177 wsi->base.get_formats = wsi_display_surface_get_formats; 2178 wsi->base.get_formats2 = wsi_display_surface_get_formats2; 2179 wsi->base.get_present_modes = wsi_display_surface_get_present_modes; 2180 wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles; 2181 wsi->base.create_swapchain = wsi_display_surface_create_swapchain; 2182 2183 wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base; 2184 2185 return VK_SUCCESS; 2186 2187fail_hotplug_cond: 2188 pthread_cond_destroy(&wsi->wait_cond); 2189fail_cond: 2190 pthread_mutex_destroy(&wsi->wait_mutex); 2191fail_mutex: 2192 vk_free(alloc, wsi); 2193fail: 2194 return result; 2195} 2196 2197void 2198wsi_display_finish_wsi(struct wsi_device *wsi_device, 2199 const VkAllocationCallbacks *alloc) 2200{ 2201 struct wsi_display *wsi = 2202 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2203 2204 if (wsi) { 2205 wsi_for_each_connector(connector, wsi) { 2206 wsi_for_each_display_mode(mode, connector) { 2207 vk_free(wsi->alloc, mode); 2208 } 2209 vk_free(wsi->alloc, connector); 2210 } 2211 2212 wsi_display_stop_wait_thread(wsi); 2213 2214 if (wsi->hotplug_thread) { 2215 pthread_cancel(wsi->hotplug_thread); 2216 pthread_join(wsi->hotplug_thread, NULL); 2217 } 2218 2219 pthread_mutex_destroy(&wsi->wait_mutex); 2220 pthread_cond_destroy(&wsi->wait_cond); 2221 pthread_cond_destroy(&wsi->hotplug_cond); 2222 2223 vk_free(alloc, wsi); 2224 } 2225} 2226 2227/* 2228 * Implement vkReleaseDisplay 2229 */ 2230VKAPI_ATTR VkResult VKAPI_CALL 2231wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, 2232 VkDisplayKHR display) 2233{ 2234 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 2235 struct wsi_device *wsi_device = pdevice->wsi_device; 2236 struct wsi_display *wsi = 2237 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2238 2239 if (wsi->fd >= 0) { 2240 wsi_display_stop_wait_thread(wsi); 2241 2242 close(wsi->fd); 2243 wsi->fd = -1; 2244 } 2245 2246 wsi_display_connector_from_handle(display)->active = false; 2247 2248#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 2249 wsi_display_connector_from_handle(display)->output = None; 2250#endif 2251 2252 return VK_SUCCESS; 2253} 2254 2255#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 2256 2257static struct wsi_display_connector * 2258wsi_display_find_output(struct wsi_device *wsi_device, 2259 xcb_randr_output_t output) 2260{ 2261 struct wsi_display *wsi = 2262 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2263 2264 wsi_for_each_connector(connector, wsi) { 2265 if (connector->output == output) 2266 return connector; 2267 } 2268 2269 return NULL; 2270} 2271 2272/* 2273 * Given a RandR output, find the associated kernel connector_id by 2274 * looking at the CONNECTOR_ID property provided by the X server 2275 */ 2276 2277static uint32_t 2278wsi_display_output_to_connector_id(xcb_connection_t *connection, 2279 xcb_atom_t *connector_id_atom_p, 2280 xcb_randr_output_t output) 2281{ 2282 uint32_t connector_id = 0; 2283 xcb_atom_t connector_id_atom = *connector_id_atom_p; 2284 2285 if (connector_id_atom == 0) { 2286 /* Go dig out the CONNECTOR_ID property */ 2287 xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection, 2288 true, 2289 12, 2290 "CONNECTOR_ID"); 2291 xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection, 2292 ia_c, 2293 NULL); 2294 if (ia_r) { 2295 *connector_id_atom_p = connector_id_atom = ia_r->atom; 2296 free(ia_r); 2297 } 2298 } 2299 2300 /* If there's an CONNECTOR_ID atom in the server, then there may be a 2301 * CONNECTOR_ID property. Otherwise, there will not be and we don't even 2302 * need to bother. 2303 */ 2304 if (connector_id_atom) { 2305 2306 xcb_randr_query_version_cookie_t qv_c = 2307 xcb_randr_query_version(connection, 1, 6); 2308 xcb_randr_get_output_property_cookie_t gop_c = 2309 xcb_randr_get_output_property(connection, 2310 output, 2311 connector_id_atom, 2312 0, 2313 0, 2314 0xffffffffUL, 2315 0, 2316 0); 2317 xcb_randr_query_version_reply_t *qv_r = 2318 xcb_randr_query_version_reply(connection, qv_c, NULL); 2319 free(qv_r); 2320 xcb_randr_get_output_property_reply_t *gop_r = 2321 xcb_randr_get_output_property_reply(connection, gop_c, NULL); 2322 if (gop_r) { 2323 if (gop_r->num_items == 1 && gop_r->format == 32) 2324 memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4); 2325 free(gop_r); 2326 } 2327 } 2328 return connector_id; 2329} 2330 2331static bool 2332wsi_display_check_randr_version(xcb_connection_t *connection) 2333{ 2334 xcb_randr_query_version_cookie_t qv_c = 2335 xcb_randr_query_version(connection, 1, 6); 2336 xcb_randr_query_version_reply_t *qv_r = 2337 xcb_randr_query_version_reply(connection, qv_c, NULL); 2338 bool ret = false; 2339 2340 if (!qv_r) 2341 return false; 2342 2343 /* Check for version 1.6 or newer */ 2344 ret = (qv_r->major_version > 1 || 2345 (qv_r->major_version == 1 && qv_r->minor_version >= 6)); 2346 2347 free(qv_r); 2348 return ret; 2349} 2350 2351/* 2352 * Given a kernel connector id, find the associated RandR output using the 2353 * CONNECTOR_ID property 2354 */ 2355 2356static xcb_randr_output_t 2357wsi_display_connector_id_to_output(xcb_connection_t *connection, 2358 uint32_t connector_id) 2359{ 2360 if (!wsi_display_check_randr_version(connection)) 2361 return 0; 2362 2363 const xcb_setup_t *setup = xcb_get_setup(connection); 2364 2365 xcb_atom_t connector_id_atom = 0; 2366 xcb_randr_output_t output = 0; 2367 2368 /* Search all of the screens for the provided output */ 2369 xcb_screen_iterator_t iter; 2370 for (iter = xcb_setup_roots_iterator(setup); 2371 output == 0 && iter.rem; 2372 xcb_screen_next(&iter)) 2373 { 2374 xcb_randr_get_screen_resources_cookie_t gsr_c = 2375 xcb_randr_get_screen_resources(connection, iter.data->root); 2376 xcb_randr_get_screen_resources_reply_t *gsr_r = 2377 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 2378 2379 if (!gsr_r) 2380 return 0; 2381 2382 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); 2383 int o; 2384 2385 for (o = 0; o < gsr_r->num_outputs; o++) { 2386 if (wsi_display_output_to_connector_id(connection, 2387 &connector_id_atom, ro[o]) 2388 == connector_id) 2389 { 2390 output = ro[o]; 2391 break; 2392 } 2393 } 2394 free(gsr_r); 2395 } 2396 return output; 2397} 2398 2399/* 2400 * Given a RandR output, find out which screen it's associated with 2401 */ 2402static xcb_window_t 2403wsi_display_output_to_root(xcb_connection_t *connection, 2404 xcb_randr_output_t output) 2405{ 2406 if (!wsi_display_check_randr_version(connection)) 2407 return 0; 2408 2409 const xcb_setup_t *setup = xcb_get_setup(connection); 2410 xcb_window_t root = 0; 2411 2412 /* Search all of the screens for the provided output */ 2413 for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); 2414 root == 0 && iter.rem; 2415 xcb_screen_next(&iter)) 2416 { 2417 xcb_randr_get_screen_resources_cookie_t gsr_c = 2418 xcb_randr_get_screen_resources(connection, iter.data->root); 2419 xcb_randr_get_screen_resources_reply_t *gsr_r = 2420 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 2421 2422 if (!gsr_r) 2423 return 0; 2424 2425 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); 2426 2427 for (int o = 0; o < gsr_r->num_outputs; o++) { 2428 if (ro[o] == output) { 2429 root = iter.data->root; 2430 break; 2431 } 2432 } 2433 free(gsr_r); 2434 } 2435 return root; 2436} 2437 2438static bool 2439wsi_display_mode_matches_x(struct wsi_display_mode *wsi, 2440 xcb_randr_mode_info_t *xcb) 2441{ 2442 return wsi->clock == (xcb->dot_clock + 500) / 1000 && 2443 wsi->hdisplay == xcb->width && 2444 wsi->hsync_start == xcb->hsync_start && 2445 wsi->hsync_end == xcb->hsync_end && 2446 wsi->htotal == xcb->htotal && 2447 wsi->hskew == xcb->hskew && 2448 wsi->vdisplay == xcb->height && 2449 wsi->vsync_start == xcb->vsync_start && 2450 wsi->vsync_end == xcb->vsync_end && 2451 wsi->vtotal == xcb->vtotal && 2452 wsi->vscan <= 1 && 2453 wsi->flags == xcb->mode_flags; 2454} 2455 2456static struct wsi_display_mode * 2457wsi_display_find_x_mode(struct wsi_device *wsi_device, 2458 struct wsi_display_connector *connector, 2459 xcb_randr_mode_info_t *mode) 2460{ 2461 wsi_for_each_display_mode(display_mode, connector) { 2462 if (wsi_display_mode_matches_x(display_mode, mode)) 2463 return display_mode; 2464 } 2465 return NULL; 2466} 2467 2468static VkResult 2469wsi_display_register_x_mode(struct wsi_device *wsi_device, 2470 struct wsi_display_connector *connector, 2471 xcb_randr_mode_info_t *x_mode, 2472 bool preferred) 2473{ 2474 struct wsi_display *wsi = 2475 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2476 struct wsi_display_mode *display_mode = 2477 wsi_display_find_x_mode(wsi_device, connector, x_mode); 2478 2479 if (display_mode) { 2480 display_mode->valid = true; 2481 return VK_SUCCESS; 2482 } 2483 2484 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode), 2485 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2486 if (!display_mode) 2487 return VK_ERROR_OUT_OF_HOST_MEMORY; 2488 2489 display_mode->connector = connector; 2490 display_mode->valid = true; 2491 display_mode->preferred = preferred; 2492 display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */ 2493 display_mode->hdisplay = x_mode->width; 2494 display_mode->hsync_start = x_mode->hsync_start; 2495 display_mode->hsync_end = x_mode->hsync_end; 2496 display_mode->htotal = x_mode->htotal; 2497 display_mode->hskew = x_mode->hskew; 2498 display_mode->vdisplay = x_mode->height; 2499 display_mode->vsync_start = x_mode->vsync_start; 2500 display_mode->vsync_end = x_mode->vsync_end; 2501 display_mode->vtotal = x_mode->vtotal; 2502 display_mode->vscan = 0; 2503 display_mode->flags = x_mode->mode_flags; 2504 2505 list_addtail(&display_mode->list, &connector->display_modes); 2506 return VK_SUCCESS; 2507} 2508 2509static struct wsi_display_connector * 2510wsi_display_get_output(struct wsi_device *wsi_device, 2511 xcb_connection_t *connection, 2512 xcb_randr_output_t output) 2513{ 2514 struct wsi_display *wsi = 2515 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2516 struct wsi_display_connector *connector; 2517 uint32_t connector_id; 2518 2519 xcb_window_t root = wsi_display_output_to_root(connection, output); 2520 if (!root) 2521 return NULL; 2522 2523 /* See if we already have a connector for this output */ 2524 connector = wsi_display_find_output(wsi_device, output); 2525 2526 if (!connector) { 2527 xcb_atom_t connector_id_atom = 0; 2528 2529 /* 2530 * Go get the kernel connector ID for this X output 2531 */ 2532 connector_id = wsi_display_output_to_connector_id(connection, 2533 &connector_id_atom, 2534 output); 2535 2536 /* Any X server with lease support will have this atom */ 2537 if (!connector_id) { 2538 return NULL; 2539 } 2540 2541 /* See if we already have a connector for this id */ 2542 connector = wsi_display_find_connector(wsi_device, connector_id); 2543 2544 if (connector == NULL) { 2545 connector = wsi_display_alloc_connector(wsi, connector_id); 2546 if (!connector) { 2547 return NULL; 2548 } 2549 list_addtail(&connector->list, &wsi->connectors); 2550 } 2551 connector->output = output; 2552 } 2553 2554 xcb_randr_get_screen_resources_cookie_t src = 2555 xcb_randr_get_screen_resources(connection, root); 2556 xcb_randr_get_output_info_cookie_t oic = 2557 xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME); 2558 xcb_randr_get_screen_resources_reply_t *srr = 2559 xcb_randr_get_screen_resources_reply(connection, src, NULL); 2560 xcb_randr_get_output_info_reply_t *oir = 2561 xcb_randr_get_output_info_reply(connection, oic, NULL); 2562 2563 if (oir && srr) { 2564 /* Get X modes and add them */ 2565 2566 connector->connected = 2567 oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED; 2568 2569 wsi_display_invalidate_connector_modes(wsi_device, connector); 2570 2571 xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir); 2572 for (int m = 0; m < oir->num_modes; m++) { 2573 xcb_randr_mode_info_iterator_t i = 2574 xcb_randr_get_screen_resources_modes_iterator(srr); 2575 while (i.rem) { 2576 xcb_randr_mode_info_t *mi = i.data; 2577 if (mi->id == x_modes[m]) { 2578 VkResult result = wsi_display_register_x_mode( 2579 wsi_device, connector, mi, m < oir->num_preferred); 2580 if (result != VK_SUCCESS) { 2581 free(oir); 2582 free(srr); 2583 return NULL; 2584 } 2585 break; 2586 } 2587 xcb_randr_mode_info_next(&i); 2588 } 2589 } 2590 } 2591 2592 free(oir); 2593 free(srr); 2594 return connector; 2595} 2596 2597static xcb_randr_crtc_t 2598wsi_display_find_crtc_for_output(xcb_connection_t *connection, 2599 xcb_window_t root, 2600 xcb_randr_output_t output) 2601{ 2602 xcb_randr_get_screen_resources_cookie_t gsr_c = 2603 xcb_randr_get_screen_resources(connection, root); 2604 xcb_randr_get_screen_resources_reply_t *gsr_r = 2605 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 2606 2607 if (!gsr_r) 2608 return 0; 2609 2610 xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r); 2611 xcb_randr_crtc_t idle_crtc = 0; 2612 xcb_randr_crtc_t active_crtc = 0; 2613 2614 /* Find either a crtc already connected to the desired output or idle */ 2615 for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) { 2616 xcb_randr_get_crtc_info_cookie_t gci_c = 2617 xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp); 2618 xcb_randr_get_crtc_info_reply_t *gci_r = 2619 xcb_randr_get_crtc_info_reply(connection, gci_c, NULL); 2620 2621 if (gci_r) { 2622 if (gci_r->mode) { 2623 int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r); 2624 xcb_randr_output_t *outputs = 2625 xcb_randr_get_crtc_info_outputs(gci_r); 2626 2627 if (num_outputs == 1 && outputs[0] == output) 2628 active_crtc = rc[c]; 2629 2630 } else if (idle_crtc == 0) { 2631 int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r); 2632 xcb_randr_output_t *possible = 2633 xcb_randr_get_crtc_info_possible(gci_r); 2634 2635 for (int p = 0; p < num_possible; p++) 2636 if (possible[p] == output) { 2637 idle_crtc = rc[c]; 2638 break; 2639 } 2640 } 2641 free(gci_r); 2642 } 2643 } 2644 free(gsr_r); 2645 2646 if (active_crtc) 2647 return active_crtc; 2648 return idle_crtc; 2649} 2650 2651VKAPI_ATTR VkResult VKAPI_CALL 2652wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, 2653 Display *dpy, 2654 VkDisplayKHR display) 2655{ 2656 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 2657 struct wsi_device *wsi_device = pdevice->wsi_device; 2658 struct wsi_display *wsi = 2659 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2660 xcb_connection_t *connection = XGetXCBConnection(dpy); 2661 struct wsi_display_connector *connector = 2662 wsi_display_connector_from_handle(display); 2663 xcb_window_t root; 2664 2665 /* XXX no support for multiple leases yet */ 2666 if (wsi->fd >= 0) 2667 return VK_ERROR_INITIALIZATION_FAILED; 2668 2669 if (!connector->output) { 2670 connector->output = wsi_display_connector_id_to_output(connection, 2671 connector->id); 2672 2673 /* Check and see if we found the output */ 2674 if (!connector->output) 2675 return VK_ERROR_INITIALIZATION_FAILED; 2676 } 2677 2678 root = wsi_display_output_to_root(connection, connector->output); 2679 if (!root) 2680 return VK_ERROR_INITIALIZATION_FAILED; 2681 2682 xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection, 2683 root, 2684 connector->output); 2685 2686 if (!crtc) 2687 return VK_ERROR_INITIALIZATION_FAILED; 2688 2689#ifdef HAVE_DRI3_MODIFIERS 2690 xcb_randr_lease_t lease = xcb_generate_id(connection); 2691 xcb_randr_create_lease_cookie_t cl_c = 2692 xcb_randr_create_lease(connection, root, lease, 1, 1, 2693 &crtc, &connector->output); 2694 xcb_randr_create_lease_reply_t *cl_r = 2695 xcb_randr_create_lease_reply(connection, cl_c, NULL); 2696 if (!cl_r) 2697 return VK_ERROR_INITIALIZATION_FAILED; 2698 2699 int fd = -1; 2700 if (cl_r->nfd > 0) { 2701 int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r); 2702 2703 fd = rcl_f[0]; 2704 } 2705 free (cl_r); 2706 if (fd < 0) 2707 return VK_ERROR_INITIALIZATION_FAILED; 2708 2709 wsi->fd = fd; 2710#endif 2711 2712 return VK_SUCCESS; 2713} 2714 2715VKAPI_ATTR VkResult VKAPI_CALL 2716wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, 2717 Display *dpy, 2718 RROutput rrOutput, 2719 VkDisplayKHR *pDisplay) 2720{ 2721 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 2722 struct wsi_device *wsi_device = pdevice->wsi_device; 2723 xcb_connection_t *connection = XGetXCBConnection(dpy); 2724 struct wsi_display_connector *connector = 2725 wsi_display_get_output(wsi_device, connection, 2726 (xcb_randr_output_t) rrOutput); 2727 2728 if (connector) 2729 *pDisplay = wsi_display_connector_to_handle(connector); 2730 else 2731 *pDisplay = VK_NULL_HANDLE; 2732 return VK_SUCCESS; 2733} 2734 2735#endif 2736 2737/* VK_EXT_display_control */ 2738VKAPI_ATTR VkResult VKAPI_CALL 2739wsi_DisplayPowerControlEXT(VkDevice _device, 2740 VkDisplayKHR display, 2741 const VkDisplayPowerInfoEXT *pDisplayPowerInfo) 2742{ 2743 VK_FROM_HANDLE(vk_device, device, _device); 2744 struct wsi_device *wsi_device = device->physical->wsi_device; 2745 struct wsi_display *wsi = 2746 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2747 struct wsi_display_connector *connector = 2748 wsi_display_connector_from_handle(display); 2749 int mode; 2750 2751 if (wsi->fd < 0) 2752 return VK_ERROR_INITIALIZATION_FAILED; 2753 2754 switch (pDisplayPowerInfo->powerState) { 2755 case VK_DISPLAY_POWER_STATE_OFF_EXT: 2756 mode = DRM_MODE_DPMS_OFF; 2757 break; 2758 case VK_DISPLAY_POWER_STATE_SUSPEND_EXT: 2759 mode = DRM_MODE_DPMS_SUSPEND; 2760 break; 2761 default: 2762 mode = DRM_MODE_DPMS_ON; 2763 break; 2764 } 2765 drmModeConnectorSetProperty(wsi->fd, 2766 connector->id, 2767 connector->dpms_property, 2768 mode); 2769 return VK_SUCCESS; 2770} 2771 2772VkResult 2773wsi_register_device_event(VkDevice _device, 2774 struct wsi_device *wsi_device, 2775 const VkDeviceEventInfoEXT *device_event_info, 2776 const VkAllocationCallbacks *allocator, 2777 struct vk_sync **sync_out, 2778 int sync_fd) 2779{ 2780 VK_FROM_HANDLE(vk_device, device, _device); 2781 struct wsi_display *wsi = 2782 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2783 VkResult ret = VK_SUCCESS; 2784 2785#ifdef HAVE_LIBUDEV 2786 /* Start listening for output change notifications. */ 2787 mtx_lock(&wsi->wait_mutex); 2788 if (!wsi->hotplug_thread) { 2789 if (pthread_create(&wsi->hotplug_thread, NULL, udev_event_listener_thread, 2790 wsi_device)) { 2791 mtx_unlock(&wsi->wait_mutex); 2792 return VK_ERROR_OUT_OF_HOST_MEMORY; 2793 } 2794 } 2795 mtx_unlock(&wsi->wait_mutex); 2796#endif 2797 2798 struct wsi_display_fence *fence; 2799 assert(device_event_info->deviceEvent == 2800 VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT); 2801 2802 fence = wsi_display_fence_alloc(wsi, sync_fd); 2803 2804 if (!fence) 2805 return VK_ERROR_OUT_OF_HOST_MEMORY; 2806 2807 fence->device_event = true; 2808 2809 mtx_lock(&wsi->wait_mutex); 2810 list_addtail(&fence->link, &wsi_device->hotplug_fences); 2811 mtx_unlock(&wsi->wait_mutex); 2812 2813 if (sync_out) { 2814 ret = wsi_display_sync_create(device, fence, sync_out); 2815 if (ret != VK_SUCCESS) 2816 wsi_display_fence_destroy(fence); 2817 } else { 2818 wsi_display_fence_destroy(fence); 2819 } 2820 2821 return ret; 2822} 2823 2824VKAPI_ATTR VkResult VKAPI_CALL 2825wsi_RegisterDeviceEventEXT(VkDevice _device, const VkDeviceEventInfoEXT *device_event_info, 2826 const VkAllocationCallbacks *allocator, VkFence *_fence) 2827{ 2828 VK_FROM_HANDLE(vk_device, device, _device); 2829 struct vk_fence *fence; 2830 VkResult ret; 2831 2832 const VkFenceCreateInfo info = { 2833 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 2834 .flags = 0, 2835 }; 2836 ret = vk_fence_create(device, &info, allocator, &fence); 2837 if (ret != VK_SUCCESS) 2838 return ret; 2839 2840 ret = wsi_register_device_event(_device, 2841 device->physical->wsi_device, 2842 device_event_info, 2843 allocator, 2844 &fence->temporary, 2845 -1); 2846 if (ret == VK_SUCCESS) 2847 *_fence = vk_fence_to_handle(fence); 2848 else 2849 vk_fence_destroy(device, fence, allocator); 2850 return ret; 2851} 2852 2853VkResult 2854wsi_register_display_event(VkDevice _device, 2855 struct wsi_device *wsi_device, 2856 VkDisplayKHR display, 2857 const VkDisplayEventInfoEXT *display_event_info, 2858 const VkAllocationCallbacks *allocator, 2859 struct vk_sync **sync_out, 2860 int sync_fd) 2861{ 2862 VK_FROM_HANDLE(vk_device, device, _device); 2863 struct wsi_display *wsi = 2864 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2865 struct wsi_display_fence *fence; 2866 VkResult ret; 2867 2868 switch (display_event_info->displayEvent) { 2869 case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT: 2870 2871 fence = wsi_display_fence_alloc(wsi, sync_fd); 2872 2873 if (!fence) 2874 return VK_ERROR_OUT_OF_HOST_MEMORY; 2875 2876 ret = wsi_register_vblank_event(fence, wsi_device, display, 2877 DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL); 2878 2879 if (ret == VK_SUCCESS) { 2880 if (sync_out) { 2881 ret = wsi_display_sync_create(device, fence, sync_out); 2882 if (ret != VK_SUCCESS) 2883 wsi_display_fence_destroy(fence); 2884 } else { 2885 wsi_display_fence_destroy(fence); 2886 } 2887 } else if (fence != NULL) { 2888 if (fence->syncobj) 2889 drmSyncobjDestroy(wsi->syncobj_fd, fence->syncobj); 2890 vk_free2(wsi->alloc, allocator, fence); 2891 } 2892 2893 break; 2894 default: 2895 ret = VK_ERROR_FEATURE_NOT_PRESENT; 2896 break; 2897 } 2898 2899 return ret; 2900} 2901 2902VKAPI_ATTR VkResult VKAPI_CALL 2903wsi_RegisterDisplayEventEXT(VkDevice _device, VkDisplayKHR display, 2904 const VkDisplayEventInfoEXT *display_event_info, 2905 const VkAllocationCallbacks *allocator, VkFence *_fence) 2906{ 2907 VK_FROM_HANDLE(vk_device, device, _device); 2908 struct vk_fence *fence; 2909 VkResult ret; 2910 2911 const VkFenceCreateInfo info = { 2912 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 2913 .flags = 0, 2914 }; 2915 ret = vk_fence_create(device, &info, allocator, &fence); 2916 if (ret != VK_SUCCESS) 2917 return ret; 2918 2919 ret = wsi_register_display_event( 2920 _device, device->physical->wsi_device, 2921 display, display_event_info, allocator, &fence->temporary, -1); 2922 2923 if (ret == VK_SUCCESS) 2924 *_fence = vk_fence_to_handle(fence); 2925 else 2926 vk_fence_destroy(device, fence, allocator); 2927 return ret; 2928} 2929 2930void 2931wsi_display_setup_syncobj_fd(struct wsi_device *wsi_device, 2932 int fd) 2933{ 2934 struct wsi_display *wsi = 2935 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2936 wsi->syncobj_fd = fd; 2937} 2938 2939VKAPI_ATTR VkResult VKAPI_CALL 2940wsi_GetSwapchainCounterEXT(VkDevice _device, 2941 VkSwapchainKHR _swapchain, 2942 VkSurfaceCounterFlagBitsEXT counter, 2943 uint64_t *pCounterValue) 2944{ 2945 VK_FROM_HANDLE(vk_device, device, _device); 2946 struct wsi_device *wsi_device = device->physical->wsi_device; 2947 struct wsi_display *wsi = 2948 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2949 struct wsi_display_swapchain *swapchain = 2950 (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain); 2951 struct wsi_display_connector *connector = 2952 wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector; 2953 2954 if (wsi->fd < 0) 2955 return VK_ERROR_INITIALIZATION_FAILED; 2956 2957 if (!connector->active) { 2958 *pCounterValue = 0; 2959 return VK_SUCCESS; 2960 } 2961 2962 int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, 2963 pCounterValue, NULL); 2964 if (ret) 2965 *pCounterValue = 0; 2966 2967 return VK_SUCCESS; 2968} 2969 2970VKAPI_ATTR VkResult VKAPI_CALL 2971wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice, 2972 int32_t drmFd, 2973 VkDisplayKHR display) 2974{ 2975 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 2976 struct wsi_device *wsi_device = pdevice->wsi_device; 2977 2978 if (!wsi_device_matches_drm_fd(wsi_device, drmFd)) 2979 return VK_ERROR_UNKNOWN; 2980 2981 struct wsi_display *wsi = 2982 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2983 2984 /* XXX no support for mulitple leases yet */ 2985 if (wsi->fd >= 0 || !local_drmIsMaster(drmFd)) 2986 return VK_ERROR_INITIALIZATION_FAILED; 2987 2988 struct wsi_display_connector *connector = 2989 wsi_display_connector_from_handle(display); 2990 2991 drmModeConnectorPtr drm_connector = 2992 drmModeGetConnectorCurrent(drmFd, connector->id); 2993 2994 if (!drm_connector) 2995 return VK_ERROR_INITIALIZATION_FAILED; 2996 2997 drmModeFreeConnector(drm_connector); 2998 2999 wsi->fd = drmFd; 3000 return VK_SUCCESS; 3001} 3002 3003VKAPI_ATTR VkResult VKAPI_CALL 3004wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice, 3005 int32_t drmFd, 3006 uint32_t connectorId, 3007 VkDisplayKHR *pDisplay) 3008{ 3009 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 3010 struct wsi_device *wsi_device = pdevice->wsi_device; 3011 3012 if (!wsi_device_matches_drm_fd(wsi_device, drmFd)) 3013 return VK_ERROR_UNKNOWN; 3014 3015 struct wsi_display_connector *connector = 3016 wsi_display_get_connector(wsi_device, drmFd, connectorId); 3017 3018 if (!connector) { 3019 *pDisplay = VK_NULL_HANDLE; 3020 return VK_ERROR_UNKNOWN; 3021 } 3022 3023 *pDisplay = wsi_display_connector_to_handle(connector); 3024 return VK_SUCCESS; 3025} 3026