wsi_common_display.c revision 01e04c3f
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 <unistd.h> 27#include <errno.h> 28#include <string.h> 29#include <fcntl.h> 30#include <poll.h> 31#include <stdbool.h> 32#include <math.h> 33#include <xf86drm.h> 34#include <xf86drmMode.h> 35#include <drm_fourcc.h> 36#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 37#include <xcb/randr.h> 38#include <X11/Xlib-xcb.h> 39#endif 40#include "util/hash_table.h" 41#include "util/list.h" 42 43#include "vk_util.h" 44#include "wsi_common_private.h" 45#include "wsi_common_display.h" 46#include "wsi_common_queue.h" 47 48#if 0 49#define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__) 50#define wsi_display_debug_code(...) __VA_ARGS__ 51#else 52#define wsi_display_debug(...) 53#define wsi_display_debug_code(...) 54#endif 55 56/* These have lifetime equal to the instance, so they effectively 57 * never go away. This means we must keep track of them separately 58 * from all other resources. 59 */ 60typedef struct wsi_display_mode { 61 struct list_head list; 62 struct wsi_display_connector *connector; 63 bool valid; /* was found in most recent poll */ 64 bool preferred; 65 uint32_t clock; /* in kHz */ 66 uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; 67 uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; 68 uint32_t flags; 69} wsi_display_mode; 70 71typedef struct wsi_display_connector { 72 struct list_head list; 73 struct wsi_display *wsi; 74 uint32_t id; 75 uint32_t crtc_id; 76 char *name; 77 bool connected; 78 bool active; 79 struct list_head display_modes; 80 wsi_display_mode *current_mode; 81 drmModeModeInfo current_drm_mode; 82 uint32_t dpms_property; 83#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 84 xcb_randr_output_t output; 85#endif 86} wsi_display_connector; 87 88struct wsi_display { 89 struct wsi_interface base; 90 91 const VkAllocationCallbacks *alloc; 92 93 int fd; 94 95 pthread_mutex_t wait_mutex; 96 pthread_cond_t wait_cond; 97 pthread_t wait_thread; 98 99 struct list_head connectors; 100}; 101 102#define wsi_for_each_display_mode(_mode, _conn) \ 103 list_for_each_entry_safe(struct wsi_display_mode, _mode, \ 104 &(_conn)->display_modes, list) 105 106#define wsi_for_each_connector(_conn, _dev) \ 107 list_for_each_entry_safe(struct wsi_display_connector, _conn, \ 108 &(_dev)->connectors, list) 109 110enum wsi_image_state { 111 WSI_IMAGE_IDLE, 112 WSI_IMAGE_DRAWING, 113 WSI_IMAGE_QUEUED, 114 WSI_IMAGE_FLIPPING, 115 WSI_IMAGE_DISPLAYING 116}; 117 118struct wsi_display_image { 119 struct wsi_image base; 120 struct wsi_display_swapchain *chain; 121 enum wsi_image_state state; 122 uint32_t fb_id; 123 uint32_t buffer[4]; 124 uint64_t flip_sequence; 125}; 126 127struct wsi_display_swapchain { 128 struct wsi_swapchain base; 129 struct wsi_display *wsi; 130 VkIcdSurfaceDisplay *surface; 131 uint64_t flip_sequence; 132 VkResult status; 133 struct wsi_display_image images[0]; 134}; 135 136struct wsi_display_fence { 137 struct wsi_fence base; 138 bool event_received; 139 bool destroyed; 140 uint64_t sequence; 141}; 142 143static uint64_t fence_sequence; 144 145ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR) 146ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR) 147 148static bool 149wsi_display_mode_matches_drm(wsi_display_mode *wsi, 150 drmModeModeInfoPtr drm) 151{ 152 return wsi->clock == drm->clock && 153 wsi->hdisplay == drm->hdisplay && 154 wsi->hsync_start == drm->hsync_start && 155 wsi->hsync_end == drm->hsync_end && 156 wsi->htotal == drm->htotal && 157 wsi->hskew == drm->hskew && 158 wsi->vdisplay == drm->vdisplay && 159 wsi->vsync_start == drm->vsync_start && 160 wsi->vsync_end == drm->vsync_end && 161 wsi->vtotal == drm->vtotal && 162 MAX2(wsi->vscan, 1) == MAX2(drm->vscan, 1) && 163 wsi->flags == drm->flags; 164} 165 166static double 167wsi_display_mode_refresh(struct wsi_display_mode *wsi) 168{ 169 return (double) wsi->clock * 1000.0 / ((double) wsi->htotal * 170 (double) wsi->vtotal * 171 (double) MAX2(wsi->vscan, 1)); 172} 173 174static uint64_t wsi_get_current_monotonic(void) 175{ 176 struct timespec tv; 177 178 clock_gettime(CLOCK_MONOTONIC, &tv); 179 return tv.tv_nsec + tv.tv_sec*1000000000ull; 180} 181 182static uint64_t wsi_rel_to_abs_time(uint64_t rel_time) 183{ 184 uint64_t current_time = wsi_get_current_monotonic(); 185 186 /* check for overflow */ 187 if (rel_time > UINT64_MAX - current_time) 188 return UINT64_MAX; 189 190 return current_time + rel_time; 191} 192 193static struct wsi_display_mode * 194wsi_display_find_drm_mode(struct wsi_device *wsi_device, 195 struct wsi_display_connector *connector, 196 drmModeModeInfoPtr mode) 197{ 198 wsi_for_each_display_mode(display_mode, connector) { 199 if (wsi_display_mode_matches_drm(display_mode, mode)) 200 return display_mode; 201 } 202 return NULL; 203} 204 205static void 206wsi_display_invalidate_connector_modes(struct wsi_device *wsi_device, 207 struct wsi_display_connector *connector) 208{ 209 wsi_for_each_display_mode(display_mode, connector) { 210 display_mode->valid = false; 211 } 212} 213 214static VkResult 215wsi_display_register_drm_mode(struct wsi_device *wsi_device, 216 struct wsi_display_connector *connector, 217 drmModeModeInfoPtr drm_mode) 218{ 219 struct wsi_display *wsi = 220 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 221 struct wsi_display_mode *display_mode = 222 wsi_display_find_drm_mode(wsi_device, connector, drm_mode); 223 224 if (display_mode) { 225 display_mode->valid = true; 226 return VK_SUCCESS; 227 } 228 229 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode), 230 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 231 if (!display_mode) 232 return VK_ERROR_OUT_OF_HOST_MEMORY; 233 234 display_mode->connector = connector; 235 display_mode->valid = true; 236 display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0; 237 display_mode->clock = drm_mode->clock; /* kHz */ 238 display_mode->hdisplay = drm_mode->hdisplay; 239 display_mode->hsync_start = drm_mode->hsync_start; 240 display_mode->hsync_end = drm_mode->hsync_end; 241 display_mode->htotal = drm_mode->htotal; 242 display_mode->hskew = drm_mode->hskew; 243 display_mode->vdisplay = drm_mode->vdisplay; 244 display_mode->vsync_start = drm_mode->vsync_start; 245 display_mode->vsync_end = drm_mode->vsync_end; 246 display_mode->vtotal = drm_mode->vtotal; 247 display_mode->vscan = drm_mode->vscan; 248 display_mode->flags = drm_mode->flags; 249 250 list_addtail(&display_mode->list, &connector->display_modes); 251 return VK_SUCCESS; 252} 253 254/* 255 * Update our information about a specific connector 256 */ 257 258static struct wsi_display_connector * 259wsi_display_find_connector(struct wsi_device *wsi_device, 260 uint32_t connector_id) 261{ 262 struct wsi_display *wsi = 263 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 264 265 wsi_for_each_connector(connector, wsi) { 266 if (connector->id == connector_id) 267 return connector; 268 } 269 270 return NULL; 271} 272 273static struct wsi_display_connector * 274wsi_display_alloc_connector(struct wsi_display *wsi, 275 uint32_t connector_id) 276{ 277 struct wsi_display_connector *connector = 278 vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector), 279 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 280 281 connector->id = connector_id; 282 connector->wsi = wsi; 283 connector->active = false; 284 /* XXX use EDID name */ 285 connector->name = "monitor"; 286 list_inithead(&connector->display_modes); 287 return connector; 288} 289 290static struct wsi_display_connector * 291wsi_display_get_connector(struct wsi_device *wsi_device, 292 uint32_t connector_id) 293{ 294 struct wsi_display *wsi = 295 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 296 297 if (wsi->fd < 0) 298 return NULL; 299 300 drmModeConnectorPtr drm_connector = 301 drmModeGetConnector(wsi->fd, connector_id); 302 303 if (!drm_connector) 304 return NULL; 305 306 struct wsi_display_connector *connector = 307 wsi_display_find_connector(wsi_device, connector_id); 308 309 if (!connector) { 310 connector = wsi_display_alloc_connector(wsi, connector_id); 311 if (!connector) { 312 drmModeFreeConnector(drm_connector); 313 return NULL; 314 } 315 list_addtail(&connector->list, &wsi->connectors); 316 } 317 318 connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED; 319 320 /* Look for a DPMS property if we haven't already found one */ 321 for (int p = 0; connector->dpms_property == 0 && 322 p < drm_connector->count_props; p++) 323 { 324 drmModePropertyPtr prop = drmModeGetProperty(wsi->fd, 325 drm_connector->props[p]); 326 if (!prop) 327 continue; 328 if (prop->flags & DRM_MODE_PROP_ENUM) { 329 if (!strcmp(prop->name, "DPMS")) 330 connector->dpms_property = drm_connector->props[p]; 331 } 332 drmModeFreeProperty(prop); 333 } 334 335 /* Mark all connector modes as invalid */ 336 wsi_display_invalidate_connector_modes(wsi_device, connector); 337 338 /* 339 * List current modes, adding new ones and marking existing ones as 340 * valid 341 */ 342 for (int m = 0; m < drm_connector->count_modes; m++) { 343 VkResult result = wsi_display_register_drm_mode(wsi_device, 344 connector, 345 &drm_connector->modes[m]); 346 if (result != VK_SUCCESS) { 347 drmModeFreeConnector(drm_connector); 348 return NULL; 349 } 350 } 351 352 drmModeFreeConnector(drm_connector); 353 354 return connector; 355} 356 357#define MM_PER_PIXEL (1.0/96.0 * 25.4) 358 359static uint32_t 360mode_size(struct wsi_display_mode *mode) 361{ 362 /* fortunately, these are both uint16_t, so this is easy */ 363 return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay; 364} 365 366static void 367wsi_display_fill_in_display_properties(struct wsi_device *wsi_device, 368 struct wsi_display_connector *connector, 369 VkDisplayProperties2KHR *properties2) 370{ 371 assert(properties2->sType == VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR); 372 VkDisplayPropertiesKHR *properties = &properties2->displayProperties; 373 374 properties->display = wsi_display_connector_to_handle(connector); 375 properties->displayName = connector->name; 376 377 /* Find the first preferred mode and assume that's the physical 378 * resolution. If there isn't a preferred mode, find the largest mode and 379 * use that. 380 */ 381 382 struct wsi_display_mode *preferred_mode = NULL, *largest_mode = NULL; 383 wsi_for_each_display_mode(display_mode, connector) { 384 if (!display_mode->valid) 385 continue; 386 if (display_mode->preferred) { 387 preferred_mode = display_mode; 388 break; 389 } 390 if (largest_mode == NULL || 391 mode_size(display_mode) > mode_size(largest_mode)) 392 { 393 largest_mode = display_mode; 394 } 395 } 396 397 if (preferred_mode) { 398 properties->physicalResolution.width = preferred_mode->hdisplay; 399 properties->physicalResolution.height = preferred_mode->vdisplay; 400 } else if (largest_mode) { 401 properties->physicalResolution.width = largest_mode->hdisplay; 402 properties->physicalResolution.height = largest_mode->vdisplay; 403 } else { 404 properties->physicalResolution.width = 1024; 405 properties->physicalResolution.height = 768; 406 } 407 408 /* Make up physical size based on 96dpi */ 409 properties->physicalDimensions.width = 410 floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5); 411 properties->physicalDimensions.height = 412 floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5); 413 414 properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 415 properties->planeReorderPossible = VK_FALSE; 416 properties->persistentContent = VK_FALSE; 417} 418 419/* 420 * Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display) 421 */ 422VkResult 423wsi_display_get_physical_device_display_properties( 424 VkPhysicalDevice physical_device, 425 struct wsi_device *wsi_device, 426 uint32_t *property_count, 427 VkDisplayPropertiesKHR *properties) 428{ 429 struct wsi_display *wsi = 430 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 431 432 if (properties == NULL) { 433 return wsi_display_get_physical_device_display_properties2( 434 physical_device, wsi_device, property_count, NULL); 435 } else { 436 /* If we're actually returning properties, allocate a temporary array of 437 * VkDisplayProperties2KHR structs, call properties2 to fill them out, 438 * and then copy them to the client. This seems a bit expensive but 439 * wsi_display_get_physical_device_display_properties2() calls 440 * drmModeGetResources() which does an ioctl and then a bunch of 441 * allocations so this should get lost in the noise. 442 */ 443 VkDisplayProperties2KHR *props2 = 444 vk_zalloc(wsi->alloc, sizeof(*props2) * *property_count, 8, 445 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 446 if (props2 == NULL) 447 return VK_ERROR_OUT_OF_HOST_MEMORY; 448 449 for (uint32_t i = 0; i < *property_count; i++) 450 props2[i].sType = VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR; 451 452 VkResult result = wsi_display_get_physical_device_display_properties2( 453 physical_device, wsi_device, property_count, props2); 454 455 if (result == VK_SUCCESS || result == VK_INCOMPLETE) { 456 for (uint32_t i = 0; i < *property_count; i++) 457 properties[i] = props2[i].displayProperties; 458 } 459 460 vk_free(wsi->alloc, props2); 461 462 return result; 463 } 464} 465 466VkResult 467wsi_display_get_physical_device_display_properties2( 468 VkPhysicalDevice physical_device, 469 struct wsi_device *wsi_device, 470 uint32_t *property_count, 471 VkDisplayProperties2KHR *properties) 472{ 473 struct wsi_display *wsi = 474 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 475 476 if (wsi->fd < 0) 477 goto bail; 478 479 drmModeResPtr mode_res = drmModeGetResources(wsi->fd); 480 481 if (!mode_res) 482 goto bail; 483 484 VK_OUTARRAY_MAKE(conn, properties, property_count); 485 486 /* Get current information */ 487 488 for (int c = 0; c < mode_res->count_connectors; c++) { 489 struct wsi_display_connector *connector = 490 wsi_display_get_connector(wsi_device, mode_res->connectors[c]); 491 492 if (!connector) { 493 drmModeFreeResources(mode_res); 494 return VK_ERROR_OUT_OF_HOST_MEMORY; 495 } 496 497 if (connector->connected) { 498 vk_outarray_append(&conn, prop) { 499 wsi_display_fill_in_display_properties(wsi_device, 500 connector, 501 prop); 502 } 503 } 504 } 505 506 drmModeFreeResources(mode_res); 507 508 return vk_outarray_status(&conn); 509 510bail: 511 *property_count = 0; 512 return VK_SUCCESS; 513} 514 515/* 516 * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display 517 */ 518static void 519wsi_display_fill_in_display_plane_properties( 520 struct wsi_device *wsi_device, 521 struct wsi_display_connector *connector, 522 VkDisplayPlaneProperties2KHR *properties) 523{ 524 assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR); 525 VkDisplayPlanePropertiesKHR *prop = &properties->displayPlaneProperties; 526 527 if (connector && connector->active) { 528 prop->currentDisplay = wsi_display_connector_to_handle(connector); 529 prop->currentStackIndex = 0; 530 } else { 531 prop->currentDisplay = VK_NULL_HANDLE; 532 prop->currentStackIndex = 0; 533 } 534} 535 536VkResult 537wsi_display_get_physical_device_display_plane_properties( 538 VkPhysicalDevice physical_device, 539 struct wsi_device *wsi_device, 540 uint32_t *property_count, 541 VkDisplayPlanePropertiesKHR *properties) 542{ 543 struct wsi_display *wsi = 544 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 545 546 VK_OUTARRAY_MAKE(conn, properties, property_count); 547 548 wsi_for_each_connector(connector, wsi) { 549 vk_outarray_append(&conn, prop) { 550 VkDisplayPlaneProperties2KHR prop2 = { 551 .sType = VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR, 552 }; 553 wsi_display_fill_in_display_plane_properties(wsi_device, connector, 554 &prop2); 555 *prop = prop2.displayPlaneProperties; 556 } 557 } 558 return vk_outarray_status(&conn); 559} 560 561VkResult 562wsi_display_get_physical_device_display_plane_properties2( 563 VkPhysicalDevice physical_device, 564 struct wsi_device *wsi_device, 565 uint32_t *property_count, 566 VkDisplayPlaneProperties2KHR *properties) 567{ 568 struct wsi_display *wsi = 569 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 570 571 VK_OUTARRAY_MAKE(conn, properties, property_count); 572 573 wsi_for_each_connector(connector, wsi) { 574 vk_outarray_append(&conn, prop) { 575 wsi_display_fill_in_display_plane_properties(wsi_device, connector, 576 prop); 577 } 578 } 579 return vk_outarray_status(&conn); 580} 581 582/* 583 * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display) 584 */ 585 586VkResult 587wsi_display_get_display_plane_supported_displays( 588 VkPhysicalDevice physical_device, 589 struct wsi_device *wsi_device, 590 uint32_t plane_index, 591 uint32_t *display_count, 592 VkDisplayKHR *displays) 593{ 594 struct wsi_display *wsi = 595 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 596 597 VK_OUTARRAY_MAKE(conn, displays, display_count); 598 599 int c = 0; 600 601 wsi_for_each_connector(connector, wsi) { 602 if (c == plane_index && connector->connected) { 603 vk_outarray_append(&conn, display) { 604 *display = wsi_display_connector_to_handle(connector); 605 } 606 } 607 c++; 608 } 609 return vk_outarray_status(&conn); 610} 611 612/* 613 * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display) 614 */ 615 616static void 617wsi_display_fill_in_display_mode_properties( 618 struct wsi_device *wsi_device, 619 struct wsi_display_mode *display_mode, 620 VkDisplayModeProperties2KHR *properties) 621{ 622 assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR); 623 VkDisplayModePropertiesKHR *prop = &properties->displayModeProperties; 624 625 prop->displayMode = wsi_display_mode_to_handle(display_mode); 626 prop->parameters.visibleRegion.width = display_mode->hdisplay; 627 prop->parameters.visibleRegion.height = display_mode->vdisplay; 628 prop->parameters.refreshRate = 629 (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5); 630} 631 632VkResult 633wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device, 634 struct wsi_device *wsi_device, 635 VkDisplayKHR display, 636 uint32_t *property_count, 637 VkDisplayModePropertiesKHR *properties) 638{ 639 struct wsi_display_connector *connector = 640 wsi_display_connector_from_handle(display); 641 642 VK_OUTARRAY_MAKE(conn, properties, property_count); 643 644 wsi_for_each_display_mode(display_mode, connector) { 645 if (!display_mode->valid) 646 continue; 647 648 vk_outarray_append(&conn, prop) { 649 VkDisplayModeProperties2KHR prop2 = { 650 .sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR, 651 }; 652 wsi_display_fill_in_display_mode_properties(wsi_device, 653 display_mode, &prop2); 654 *prop = prop2.displayModeProperties; 655 } 656 } 657 return vk_outarray_status(&conn); 658} 659 660VkResult 661wsi_display_get_display_mode_properties2(VkPhysicalDevice physical_device, 662 struct wsi_device *wsi_device, 663 VkDisplayKHR display, 664 uint32_t *property_count, 665 VkDisplayModeProperties2KHR *properties) 666{ 667 struct wsi_display_connector *connector = 668 wsi_display_connector_from_handle(display); 669 670 VK_OUTARRAY_MAKE(conn, properties, property_count); 671 672 wsi_for_each_display_mode(display_mode, connector) { 673 if (!display_mode->valid) 674 continue; 675 676 vk_outarray_append(&conn, prop) { 677 wsi_display_fill_in_display_mode_properties(wsi_device, 678 display_mode, prop); 679 } 680 } 681 return vk_outarray_status(&conn); 682} 683 684static bool 685wsi_display_mode_matches_vk(wsi_display_mode *wsi, 686 const VkDisplayModeParametersKHR *vk) 687{ 688 return (vk->visibleRegion.width == wsi->hdisplay && 689 vk->visibleRegion.height == wsi->vdisplay && 690 fabs(wsi_display_mode_refresh(wsi) * 1000.0 - vk->refreshRate) < 10); 691} 692 693/* 694 * Implement vkCreateDisplayModeKHR (VK_KHR_display) 695 */ 696VkResult 697wsi_display_create_display_mode(VkPhysicalDevice physical_device, 698 struct wsi_device *wsi_device, 699 VkDisplayKHR display, 700 const VkDisplayModeCreateInfoKHR *create_info, 701 const VkAllocationCallbacks *allocator, 702 VkDisplayModeKHR *mode) 703{ 704 struct wsi_display_connector *connector = 705 wsi_display_connector_from_handle(display); 706 707 if (create_info->flags != 0) 708 return VK_ERROR_INITIALIZATION_FAILED; 709 710 /* Check and see if the requested mode happens to match an existing one and 711 * return that. This makes the conformance suite happy. Doing more than 712 * this would involve embedding the CVT function into the driver, which seems 713 * excessive. 714 */ 715 wsi_for_each_display_mode(display_mode, connector) { 716 if (display_mode->valid) { 717 if (wsi_display_mode_matches_vk(display_mode, &create_info->parameters)) { 718 *mode = wsi_display_mode_to_handle(display_mode); 719 return VK_SUCCESS; 720 } 721 } 722 } 723 return VK_ERROR_INITIALIZATION_FAILED; 724} 725 726/* 727 * Implement vkGetDisplayPlaneCapabilities 728 */ 729VkResult 730wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device, 731 struct wsi_device *wsi_device, 732 VkDisplayModeKHR mode_khr, 733 uint32_t plane_index, 734 VkDisplayPlaneCapabilitiesKHR *capabilities) 735{ 736 struct wsi_display_mode *mode = wsi_display_mode_from_handle(mode_khr); 737 738 /* XXX use actual values */ 739 capabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; 740 capabilities->minSrcPosition.x = 0; 741 capabilities->minSrcPosition.y = 0; 742 capabilities->maxSrcPosition.x = 0; 743 capabilities->maxSrcPosition.y = 0; 744 capabilities->minSrcExtent.width = mode->hdisplay; 745 capabilities->minSrcExtent.height = mode->vdisplay; 746 capabilities->maxSrcExtent.width = mode->hdisplay; 747 capabilities->maxSrcExtent.height = mode->vdisplay; 748 capabilities->minDstPosition.x = 0; 749 capabilities->minDstPosition.y = 0; 750 capabilities->maxDstPosition.x = 0; 751 capabilities->maxDstPosition.y = 0; 752 capabilities->minDstExtent.width = mode->hdisplay; 753 capabilities->minDstExtent.height = mode->vdisplay; 754 capabilities->maxDstExtent.width = mode->hdisplay; 755 capabilities->maxDstExtent.height = mode->vdisplay; 756 return VK_SUCCESS; 757} 758 759VkResult 760wsi_get_display_plane_capabilities2( 761 VkPhysicalDevice physical_device, 762 struct wsi_device *wsi_device, 763 const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, 764 VkDisplayPlaneCapabilities2KHR *capabilities) 765{ 766 assert(capabilities->sType == 767 VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR); 768 769 return wsi_get_display_plane_capabilities(physical_device, wsi_device, 770 pDisplayPlaneInfo->mode, 771 pDisplayPlaneInfo->planeIndex, 772 &capabilities->capabilities); 773} 774 775VkResult 776wsi_create_display_surface(VkInstance instance, 777 const VkAllocationCallbacks *allocator, 778 const VkDisplaySurfaceCreateInfoKHR *create_info, 779 VkSurfaceKHR *surface_khr) 780{ 781 VkIcdSurfaceDisplay *surface = vk_zalloc(allocator, sizeof *surface, 8, 782 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 783 784 if (surface == NULL) 785 return VK_ERROR_OUT_OF_HOST_MEMORY; 786 787 surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY; 788 789 surface->displayMode = create_info->displayMode; 790 surface->planeIndex = create_info->planeIndex; 791 surface->planeStackIndex = create_info->planeStackIndex; 792 surface->transform = create_info->transform; 793 surface->globalAlpha = create_info->globalAlpha; 794 surface->alphaMode = create_info->alphaMode; 795 surface->imageExtent = create_info->imageExtent; 796 797 *surface_khr = VkIcdSurfaceBase_to_handle(&surface->base); 798 return VK_SUCCESS; 799} 800 801 802static VkResult 803wsi_display_surface_get_support(VkIcdSurfaceBase *surface, 804 struct wsi_device *wsi_device, 805 uint32_t queueFamilyIndex, 806 VkBool32* pSupported) 807{ 808 *pSupported = VK_TRUE; 809 return VK_SUCCESS; 810} 811 812static VkResult 813wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base, 814 VkSurfaceCapabilitiesKHR* caps) 815{ 816 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base; 817 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode); 818 819 caps->currentExtent.width = mode->hdisplay; 820 caps->currentExtent.height = mode->vdisplay; 821 822 /* XXX Figure out extents based on driver capabilities */ 823 caps->maxImageExtent = caps->minImageExtent = caps->currentExtent; 824 825 caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 826 827 caps->minImageCount = 2; 828 caps->maxImageCount = 0; 829 830 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 831 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 832 caps->maxImageArrayLayers = 1; 833 caps->supportedUsageFlags = 834 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 835 VK_IMAGE_USAGE_SAMPLED_BIT | 836 VK_IMAGE_USAGE_TRANSFER_DST_BIT | 837 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 838 839 return VK_SUCCESS; 840} 841 842static VkResult 843wsi_display_surface_get_surface_counters( 844 VkIcdSurfaceBase *surface_base, 845 VkSurfaceCounterFlagsEXT *counters) 846{ 847 *counters = VK_SURFACE_COUNTER_VBLANK_EXT; 848 return VK_SUCCESS; 849} 850 851static VkResult 852wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface, 853 const void *info_next, 854 VkSurfaceCapabilities2KHR *caps) 855{ 856 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); 857 VkResult result; 858 859 result = wsi_display_surface_get_capabilities(icd_surface, 860 &caps->surfaceCapabilities); 861 if (result != VK_SUCCESS) 862 return result; 863 864 struct wsi_surface_supported_counters *counters = 865 vk_find_struct( caps->pNext, WSI_SURFACE_SUPPORTED_COUNTERS_MESA); 866 867 if (counters) { 868 result = wsi_display_surface_get_surface_counters( 869 icd_surface, 870 &counters->supported_surface_counters); 871 } 872 873 return result; 874} 875 876static const struct { 877 VkFormat format; 878 uint32_t drm_format; 879} available_surface_formats[] = { 880 { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 }, 881 { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 }, 882}; 883 884static VkResult 885wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface, 886 struct wsi_device *wsi_device, 887 uint32_t *surface_format_count, 888 VkSurfaceFormatKHR *surface_formats) 889{ 890 VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count); 891 892 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { 893 vk_outarray_append(&out, f) { 894 f->format = available_surface_formats[i].format; 895 f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 896 } 897 } 898 899 return vk_outarray_status(&out); 900} 901 902static VkResult 903wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface, 904 struct wsi_device *wsi_device, 905 const void *info_next, 906 uint32_t *surface_format_count, 907 VkSurfaceFormat2KHR *surface_formats) 908{ 909 VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count); 910 911 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { 912 vk_outarray_append(&out, f) { 913 assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR); 914 f->surfaceFormat.format = available_surface_formats[i].format; 915 f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 916 } 917 } 918 919 return vk_outarray_status(&out); 920} 921 922static VkResult 923wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface, 924 uint32_t *present_mode_count, 925 VkPresentModeKHR *present_modes) 926{ 927 VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count); 928 929 vk_outarray_append(&conn, present) { 930 *present = VK_PRESENT_MODE_FIFO_KHR; 931 } 932 933 return vk_outarray_status(&conn); 934} 935 936static VkResult 937wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base, 938 struct wsi_device *wsi_device, 939 uint32_t* pRectCount, 940 VkRect2D* pRects) 941{ 942 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base; 943 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode); 944 VK_OUTARRAY_MAKE(out, pRects, pRectCount); 945 946 if (wsi_device_matches_drm_fd(wsi_device, mode->connector->wsi->fd)) { 947 vk_outarray_append(&out, rect) { 948 *rect = (VkRect2D) { 949 .offset = { 0, 0 }, 950 .extent = { mode->hdisplay, mode->vdisplay }, 951 }; 952 } 953 } 954 955 return vk_outarray_status(&out); 956} 957 958static void 959wsi_display_destroy_buffer(struct wsi_display *wsi, 960 uint32_t buffer) 961{ 962 (void) drmIoctl(wsi->fd, DRM_IOCTL_MODE_DESTROY_DUMB, 963 &((struct drm_mode_destroy_dumb) { .handle = buffer })); 964} 965 966static VkResult 967wsi_display_image_init(VkDevice device_h, 968 struct wsi_swapchain *drv_chain, 969 const VkSwapchainCreateInfoKHR *create_info, 970 const VkAllocationCallbacks *allocator, 971 struct wsi_display_image *image) 972{ 973 struct wsi_display_swapchain *chain = 974 (struct wsi_display_swapchain *) drv_chain; 975 struct wsi_display *wsi = chain->wsi; 976 uint32_t drm_format = 0; 977 978 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { 979 if (create_info->imageFormat == available_surface_formats[i].format) { 980 drm_format = available_surface_formats[i].drm_format; 981 break; 982 } 983 } 984 985 /* the application provided an invalid format, bail */ 986 if (drm_format == 0) 987 return VK_ERROR_DEVICE_LOST; 988 989 VkResult result = wsi_create_native_image(&chain->base, create_info, 990 0, NULL, NULL, 991 &image->base); 992 if (result != VK_SUCCESS) 993 return result; 994 995 memset(image->buffer, 0, sizeof (image->buffer)); 996 997 for (unsigned int i = 0; i < image->base.num_planes; i++) { 998 int ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i], 999 &image->buffer[i]); 1000 1001 close(image->base.fds[i]); 1002 image->base.fds[i] = -1; 1003 if (ret < 0) 1004 goto fail_handle; 1005 } 1006 1007 image->chain = chain; 1008 image->state = WSI_IMAGE_IDLE; 1009 image->fb_id = 0; 1010 1011 int ret = drmModeAddFB2(wsi->fd, 1012 create_info->imageExtent.width, 1013 create_info->imageExtent.height, 1014 drm_format, 1015 image->buffer, 1016 image->base.row_pitches, 1017 image->base.offsets, 1018 &image->fb_id, 0); 1019 1020 if (ret) 1021 goto fail_fb; 1022 1023 return VK_SUCCESS; 1024 1025fail_fb: 1026fail_handle: 1027 for (unsigned int i = 0; i < image->base.num_planes; i++) { 1028 if (image->buffer[i]) 1029 wsi_display_destroy_buffer(wsi, image->buffer[i]); 1030 if (image->base.fds[i] != -1) { 1031 close(image->base.fds[i]); 1032 image->base.fds[i] = -1; 1033 } 1034 } 1035 1036 wsi_destroy_image(&chain->base, &image->base); 1037 1038 return VK_ERROR_OUT_OF_HOST_MEMORY; 1039} 1040 1041static void 1042wsi_display_image_finish(struct wsi_swapchain *drv_chain, 1043 const VkAllocationCallbacks *allocator, 1044 struct wsi_display_image *image) 1045{ 1046 struct wsi_display_swapchain *chain = 1047 (struct wsi_display_swapchain *) drv_chain; 1048 struct wsi_display *wsi = chain->wsi; 1049 1050 drmModeRmFB(wsi->fd, image->fb_id); 1051 for (unsigned int i = 0; i < image->base.num_planes; i++) 1052 wsi_display_destroy_buffer(wsi, image->buffer[i]); 1053 wsi_destroy_image(&chain->base, &image->base); 1054} 1055 1056static VkResult 1057wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain, 1058 const VkAllocationCallbacks *allocator) 1059{ 1060 struct wsi_display_swapchain *chain = 1061 (struct wsi_display_swapchain *) drv_chain; 1062 1063 for (uint32_t i = 0; i < chain->base.image_count; i++) 1064 wsi_display_image_finish(drv_chain, allocator, &chain->images[i]); 1065 1066 wsi_swapchain_finish(&chain->base); 1067 vk_free(allocator, chain); 1068 return VK_SUCCESS; 1069} 1070 1071static struct wsi_image * 1072wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain, 1073 uint32_t image_index) 1074{ 1075 struct wsi_display_swapchain *chain = 1076 (struct wsi_display_swapchain *) drv_chain; 1077 1078 return &chain->images[image_index].base; 1079} 1080 1081static void 1082wsi_display_idle_old_displaying(struct wsi_display_image *active_image) 1083{ 1084 struct wsi_display_swapchain *chain = active_image->chain; 1085 1086 wsi_display_debug("idle everyone but %ld\n", 1087 active_image - &(chain->images[0])); 1088 for (uint32_t i = 0; i < chain->base.image_count; i++) 1089 if (chain->images[i].state == WSI_IMAGE_DISPLAYING && 1090 &chain->images[i] != active_image) 1091 { 1092 wsi_display_debug("idle %d\n", i); 1093 chain->images[i].state = WSI_IMAGE_IDLE; 1094 } 1095} 1096 1097static VkResult 1098_wsi_display_queue_next(struct wsi_swapchain *drv_chain); 1099 1100static void 1101wsi_display_page_flip_handler2(int fd, 1102 unsigned int frame, 1103 unsigned int sec, 1104 unsigned int usec, 1105 uint32_t crtc_id, 1106 void *data) 1107{ 1108 struct wsi_display_image *image = data; 1109 struct wsi_display_swapchain *chain = image->chain; 1110 1111 wsi_display_debug("image %ld displayed at %d\n", 1112 image - &(image->chain->images[0]), frame); 1113 image->state = WSI_IMAGE_DISPLAYING; 1114 wsi_display_idle_old_displaying(image); 1115 VkResult result = _wsi_display_queue_next(&(chain->base)); 1116 if (result != VK_SUCCESS) 1117 chain->status = result; 1118} 1119 1120static void wsi_display_fence_event_handler(struct wsi_display_fence *fence); 1121 1122static void wsi_display_page_flip_handler(int fd, 1123 unsigned int frame, 1124 unsigned int sec, 1125 unsigned int usec, 1126 void *data) 1127{ 1128 wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data); 1129} 1130 1131static void wsi_display_vblank_handler(int fd, unsigned int frame, 1132 unsigned int sec, unsigned int usec, 1133 void *data) 1134{ 1135 struct wsi_display_fence *fence = data; 1136 1137 wsi_display_fence_event_handler(fence); 1138} 1139 1140static void wsi_display_sequence_handler(int fd, uint64_t frame, 1141 uint64_t nsec, uint64_t user_data) 1142{ 1143 struct wsi_display_fence *fence = 1144 (struct wsi_display_fence *) (uintptr_t) user_data; 1145 1146 wsi_display_fence_event_handler(fence); 1147} 1148 1149static drmEventContext event_context = { 1150 .version = DRM_EVENT_CONTEXT_VERSION, 1151 .page_flip_handler = wsi_display_page_flip_handler, 1152#if DRM_EVENT_CONTEXT_VERSION >= 3 1153 .page_flip_handler2 = wsi_display_page_flip_handler2, 1154#endif 1155 .vblank_handler = wsi_display_vblank_handler, 1156 .sequence_handler = wsi_display_sequence_handler, 1157}; 1158 1159static void * 1160wsi_display_wait_thread(void *data) 1161{ 1162 struct wsi_display *wsi = data; 1163 struct pollfd pollfd = { 1164 .fd = wsi->fd, 1165 .events = POLLIN 1166 }; 1167 1168 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 1169 for (;;) { 1170 int ret = poll(&pollfd, 1, -1); 1171 if (ret > 0) { 1172 pthread_mutex_lock(&wsi->wait_mutex); 1173 (void) drmHandleEvent(wsi->fd, &event_context); 1174 pthread_mutex_unlock(&wsi->wait_mutex); 1175 pthread_cond_broadcast(&wsi->wait_cond); 1176 } 1177 } 1178 return NULL; 1179} 1180 1181static int 1182wsi_display_start_wait_thread(struct wsi_display *wsi) 1183{ 1184 if (!wsi->wait_thread) { 1185 int ret = pthread_create(&wsi->wait_thread, NULL, 1186 wsi_display_wait_thread, wsi); 1187 if (ret) 1188 return ret; 1189 } 1190 return 0; 1191} 1192 1193/* 1194 * Wait for at least one event from the kernel to be processed. 1195 * Call with wait_mutex held 1196 */ 1197static int 1198wsi_display_wait_for_event(struct wsi_display *wsi, 1199 uint64_t timeout_ns) 1200{ 1201 int ret; 1202 1203 ret = wsi_display_start_wait_thread(wsi); 1204 1205 if (ret) 1206 return ret; 1207 1208 struct timespec abs_timeout = { 1209 .tv_sec = timeout_ns / 1000000000ULL, 1210 .tv_nsec = timeout_ns % 1000000000ULL, 1211 }; 1212 1213 ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex, 1214 &abs_timeout); 1215 1216 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret); 1217 return ret; 1218} 1219 1220static VkResult 1221wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain, 1222 const VkAcquireNextImageInfoKHR *info, 1223 uint32_t *image_index) 1224{ 1225 struct wsi_display_swapchain *chain = 1226 (struct wsi_display_swapchain *)drv_chain; 1227 struct wsi_display *wsi = chain->wsi; 1228 int ret = 0; 1229 VkResult result = VK_SUCCESS; 1230 1231 /* Bail early if the swapchain is broken */ 1232 if (chain->status != VK_SUCCESS) 1233 return chain->status; 1234 1235 uint64_t timeout = info->timeout; 1236 if (timeout != 0 && timeout != UINT64_MAX) 1237 timeout = wsi_rel_to_abs_time(timeout); 1238 1239 pthread_mutex_lock(&wsi->wait_mutex); 1240 for (;;) { 1241 for (uint32_t i = 0; i < chain->base.image_count; i++) { 1242 if (chain->images[i].state == WSI_IMAGE_IDLE) { 1243 *image_index = i; 1244 wsi_display_debug("image %d available\n", i); 1245 chain->images[i].state = WSI_IMAGE_DRAWING; 1246 result = VK_SUCCESS; 1247 goto done; 1248 } 1249 wsi_display_debug("image %d state %d\n", i, chain->images[i].state); 1250 } 1251 1252 if (ret == ETIMEDOUT) { 1253 result = VK_TIMEOUT; 1254 goto done; 1255 } 1256 1257 ret = wsi_display_wait_for_event(wsi, timeout); 1258 1259 if (ret && ret != ETIMEDOUT) { 1260 result = VK_ERROR_SURFACE_LOST_KHR; 1261 goto done; 1262 } 1263 } 1264done: 1265 pthread_mutex_unlock(&wsi->wait_mutex); 1266 1267 if (result != VK_SUCCESS) 1268 return result; 1269 1270 return chain->status; 1271} 1272 1273/* 1274 * Check whether there are any other connectors driven by this crtc 1275 */ 1276static bool 1277wsi_display_crtc_solo(struct wsi_display *wsi, 1278 drmModeResPtr mode_res, 1279 drmModeConnectorPtr connector, 1280 uint32_t crtc_id) 1281{ 1282 /* See if any other connectors share the same encoder */ 1283 for (int c = 0; c < mode_res->count_connectors; c++) { 1284 if (mode_res->connectors[c] == connector->connector_id) 1285 continue; 1286 1287 drmModeConnectorPtr other_connector = 1288 drmModeGetConnector(wsi->fd, mode_res->connectors[c]); 1289 1290 if (other_connector) { 1291 bool match = (other_connector->encoder_id == connector->encoder_id); 1292 drmModeFreeConnector(other_connector); 1293 if (match) 1294 return false; 1295 } 1296 } 1297 1298 /* See if any other encoders share the same crtc */ 1299 for (int e = 0; e < mode_res->count_encoders; e++) { 1300 if (mode_res->encoders[e] == connector->encoder_id) 1301 continue; 1302 1303 drmModeEncoderPtr other_encoder = 1304 drmModeGetEncoder(wsi->fd, mode_res->encoders[e]); 1305 1306 if (other_encoder) { 1307 bool match = (other_encoder->crtc_id == crtc_id); 1308 drmModeFreeEncoder(other_encoder); 1309 if (match) 1310 return false; 1311 } 1312 } 1313 return true; 1314} 1315 1316/* 1317 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is 1318 * currently driving this connector and not any others. Settle for a CRTC 1319 * which is currently idle. 1320 */ 1321static uint32_t 1322wsi_display_select_crtc(const struct wsi_display_connector *connector, 1323 drmModeResPtr mode_res, 1324 drmModeConnectorPtr drm_connector) 1325{ 1326 struct wsi_display *wsi = connector->wsi; 1327 1328 /* See what CRTC is currently driving this connector */ 1329 if (drm_connector->encoder_id) { 1330 drmModeEncoderPtr encoder = 1331 drmModeGetEncoder(wsi->fd, drm_connector->encoder_id); 1332 1333 if (encoder) { 1334 uint32_t crtc_id = encoder->crtc_id; 1335 drmModeFreeEncoder(encoder); 1336 if (crtc_id) { 1337 if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id)) 1338 return crtc_id; 1339 } 1340 } 1341 } 1342 uint32_t crtc_id = 0; 1343 for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) { 1344 drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]); 1345 if (crtc && crtc->buffer_id == 0) 1346 crtc_id = crtc->crtc_id; 1347 drmModeFreeCrtc(crtc); 1348 } 1349 return crtc_id; 1350} 1351 1352static VkResult 1353wsi_display_setup_connector(wsi_display_connector *connector, 1354 wsi_display_mode *display_mode) 1355{ 1356 struct wsi_display *wsi = connector->wsi; 1357 1358 if (connector->current_mode == display_mode && connector->crtc_id) 1359 return VK_SUCCESS; 1360 1361 VkResult result = VK_SUCCESS; 1362 1363 drmModeResPtr mode_res = drmModeGetResources(wsi->fd); 1364 if (!mode_res) { 1365 if (errno == ENOMEM) 1366 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1367 else 1368 result = VK_ERROR_SURFACE_LOST_KHR; 1369 goto bail; 1370 } 1371 1372 drmModeConnectorPtr drm_connector = 1373 drmModeGetConnectorCurrent(wsi->fd, connector->id); 1374 1375 if (!drm_connector) { 1376 if (errno == ENOMEM) 1377 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1378 else 1379 result = VK_ERROR_SURFACE_LOST_KHR; 1380 goto bail_mode_res; 1381 } 1382 1383 /* Pick a CRTC if we don't have one */ 1384 if (!connector->crtc_id) { 1385 connector->crtc_id = wsi_display_select_crtc(connector, 1386 mode_res, drm_connector); 1387 if (!connector->crtc_id) { 1388 result = VK_ERROR_SURFACE_LOST_KHR; 1389 goto bail_connector; 1390 } 1391 } 1392 1393 if (connector->current_mode != display_mode) { 1394 1395 /* Find the drm mode corresponding to the requested VkDisplayMode */ 1396 drmModeModeInfoPtr drm_mode = NULL; 1397 1398 for (int m = 0; m < drm_connector->count_modes; m++) { 1399 drm_mode = &drm_connector->modes[m]; 1400 if (wsi_display_mode_matches_drm(display_mode, drm_mode)) 1401 break; 1402 drm_mode = NULL; 1403 } 1404 1405 if (!drm_mode) { 1406 result = VK_ERROR_SURFACE_LOST_KHR; 1407 goto bail_connector; 1408 } 1409 1410 connector->current_mode = display_mode; 1411 connector->current_drm_mode = *drm_mode; 1412 } 1413 1414bail_connector: 1415 drmModeFreeConnector(drm_connector); 1416bail_mode_res: 1417 drmModeFreeResources(mode_res); 1418bail: 1419 return result; 1420 1421} 1422 1423static VkResult 1424wsi_display_fence_wait(struct wsi_fence *fence_wsi, uint64_t timeout) 1425{ 1426 const struct wsi_device *wsi_device = fence_wsi->wsi_device; 1427 struct wsi_display *wsi = 1428 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1429 struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi; 1430 1431 wsi_display_debug("%9lu wait fence %lu %ld\n", 1432 pthread_self(), fence->sequence, 1433 (int64_t) (timeout - wsi_get_current_monotonic())); 1434 wsi_display_debug_code(uint64_t start_ns = wsi_get_current_monotonic()); 1435 pthread_mutex_lock(&wsi->wait_mutex); 1436 1437 VkResult result; 1438 int ret = 0; 1439 for (;;) { 1440 if (fence->event_received) { 1441 wsi_display_debug("%9lu fence %lu passed\n", 1442 pthread_self(), fence->sequence); 1443 result = VK_SUCCESS; 1444 break; 1445 } 1446 1447 if (ret == ETIMEDOUT) { 1448 wsi_display_debug("%9lu fence %lu timeout\n", 1449 pthread_self(), fence->sequence); 1450 result = VK_TIMEOUT; 1451 break; 1452 } 1453 1454 ret = wsi_display_wait_for_event(wsi, timeout); 1455 1456 if (ret && ret != ETIMEDOUT) { 1457 wsi_display_debug("%9lu fence %lu error\n", 1458 pthread_self(), fence->sequence); 1459 result = VK_ERROR_DEVICE_LOST; 1460 break; 1461 } 1462 } 1463 pthread_mutex_unlock(&wsi->wait_mutex); 1464 wsi_display_debug("%9lu fence wait %f ms\n", 1465 pthread_self(), 1466 ((int64_t) (wsi_get_current_monotonic() - start_ns)) / 1467 1.0e6); 1468 return result; 1469} 1470 1471static void 1472wsi_display_fence_check_free(struct wsi_display_fence *fence) 1473{ 1474 if (fence->event_received && fence->destroyed) 1475 vk_free(fence->base.alloc, fence); 1476} 1477 1478static void wsi_display_fence_event_handler(struct wsi_display_fence *fence) 1479{ 1480 fence->event_received = true; 1481 wsi_display_fence_check_free(fence); 1482} 1483 1484static void 1485wsi_display_fence_destroy(struct wsi_fence *fence_wsi) 1486{ 1487 struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi; 1488 1489 assert(!fence->destroyed); 1490 fence->destroyed = true; 1491 wsi_display_fence_check_free(fence); 1492} 1493 1494static struct wsi_display_fence * 1495wsi_display_fence_alloc(VkDevice device, 1496 const struct wsi_device *wsi_device, 1497 VkDisplayKHR display, 1498 const VkAllocationCallbacks *allocator) 1499{ 1500 struct wsi_display *wsi = 1501 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1502 struct wsi_display_fence *fence = 1503 vk_zalloc2(wsi->alloc, allocator, sizeof (*fence), 1504 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 1505 1506 if (!fence) 1507 return NULL; 1508 1509 fence->base.device = device; 1510 fence->base.display = display; 1511 fence->base.wsi_device = wsi_device; 1512 fence->base.alloc = allocator ? allocator : wsi->alloc; 1513 fence->base.wait = wsi_display_fence_wait; 1514 fence->base.destroy = wsi_display_fence_destroy; 1515 fence->event_received = false; 1516 fence->destroyed = false; 1517 fence->sequence = ++fence_sequence; 1518 return fence; 1519} 1520 1521static VkResult 1522wsi_register_vblank_event(struct wsi_display_fence *fence, 1523 const struct wsi_device *wsi_device, 1524 VkDisplayKHR display, 1525 uint32_t flags, 1526 uint64_t frame_requested, 1527 uint64_t *frame_queued) 1528{ 1529 struct wsi_display *wsi = 1530 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1531 struct wsi_display_connector *connector = 1532 wsi_display_connector_from_handle(display); 1533 1534 if (wsi->fd < 0) 1535 return VK_ERROR_INITIALIZATION_FAILED; 1536 1537 for (;;) { 1538 int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id, 1539 flags, 1540 frame_requested, 1541 frame_queued, 1542 (uintptr_t) fence); 1543 1544 if (!ret) 1545 return VK_SUCCESS; 1546 1547 if (errno != ENOMEM) { 1548 1549 /* Something unexpected happened. Pause for a moment so the 1550 * application doesn't just spin and then return a failure indication 1551 */ 1552 1553 wsi_display_debug("queue vblank event %lu failed\n", fence->sequence); 1554 struct timespec delay = { 1555 .tv_sec = 0, 1556 .tv_nsec = 100000000ull, 1557 }; 1558 nanosleep(&delay, NULL); 1559 return VK_ERROR_OUT_OF_HOST_MEMORY; 1560 } 1561 1562 /* The kernel event queue is full. Wait for some events to be 1563 * processed and try again 1564 */ 1565 1566 pthread_mutex_lock(&wsi->wait_mutex); 1567 ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull)); 1568 pthread_mutex_unlock(&wsi->wait_mutex); 1569 1570 if (ret) { 1571 wsi_display_debug("vblank queue full, event wait failed\n"); 1572 return VK_ERROR_OUT_OF_HOST_MEMORY; 1573 } 1574 } 1575} 1576 1577/* 1578 * Check to see if the kernel has no flip queued and if there's an image 1579 * waiting to be displayed. 1580 */ 1581static VkResult 1582_wsi_display_queue_next(struct wsi_swapchain *drv_chain) 1583{ 1584 struct wsi_display_swapchain *chain = 1585 (struct wsi_display_swapchain *) drv_chain; 1586 struct wsi_display *wsi = chain->wsi; 1587 VkIcdSurfaceDisplay *surface = chain->surface; 1588 wsi_display_mode *display_mode = 1589 wsi_display_mode_from_handle(surface->displayMode); 1590 wsi_display_connector *connector = display_mode->connector; 1591 1592 if (wsi->fd < 0) 1593 return VK_ERROR_SURFACE_LOST_KHR; 1594 1595 if (display_mode != connector->current_mode) 1596 connector->active = false; 1597 1598 for (;;) { 1599 1600 /* Check to see if there is an image to display, or if some image is 1601 * already queued */ 1602 1603 struct wsi_display_image *image = NULL; 1604 1605 for (uint32_t i = 0; i < chain->base.image_count; i++) { 1606 struct wsi_display_image *tmp_image = &chain->images[i]; 1607 1608 switch (tmp_image->state) { 1609 case WSI_IMAGE_FLIPPING: 1610 /* already flipping, don't send another to the kernel yet */ 1611 return VK_SUCCESS; 1612 case WSI_IMAGE_QUEUED: 1613 /* find the oldest queued */ 1614 if (!image || tmp_image->flip_sequence < image->flip_sequence) 1615 image = tmp_image; 1616 break; 1617 default: 1618 break; 1619 } 1620 } 1621 1622 if (!image) 1623 return VK_SUCCESS; 1624 1625 int ret; 1626 if (connector->active) { 1627 ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id, 1628 DRM_MODE_PAGE_FLIP_EVENT, image); 1629 if (ret == 0) { 1630 image->state = WSI_IMAGE_FLIPPING; 1631 return VK_SUCCESS; 1632 } 1633 wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret)); 1634 } else { 1635 ret = -EINVAL; 1636 } 1637 1638 if (ret == -EINVAL) { 1639 VkResult result = wsi_display_setup_connector(connector, display_mode); 1640 1641 if (result != VK_SUCCESS) { 1642 image->state = WSI_IMAGE_IDLE; 1643 return result; 1644 } 1645 1646 /* XXX allow setting of position */ 1647 ret = drmModeSetCrtc(wsi->fd, connector->crtc_id, 1648 image->fb_id, 0, 0, 1649 &connector->id, 1, 1650 &connector->current_drm_mode); 1651 if (ret == 0) { 1652 /* Assume that the mode set is synchronous and that any 1653 * previous image is now idle. 1654 */ 1655 image->state = WSI_IMAGE_DISPLAYING; 1656 wsi_display_idle_old_displaying(image); 1657 connector->active = true; 1658 return VK_SUCCESS; 1659 } 1660 } 1661 1662 if (ret != -EACCES) { 1663 connector->active = false; 1664 image->state = WSI_IMAGE_IDLE; 1665 return VK_ERROR_SURFACE_LOST_KHR; 1666 } 1667 1668 /* Some other VT is currently active. Sit here waiting for 1669 * our VT to become active again by polling once a second 1670 */ 1671 usleep(1000 * 1000); 1672 connector->active = false; 1673 } 1674} 1675 1676static VkResult 1677wsi_display_queue_present(struct wsi_swapchain *drv_chain, 1678 uint32_t image_index, 1679 const VkPresentRegionKHR *damage) 1680{ 1681 struct wsi_display_swapchain *chain = 1682 (struct wsi_display_swapchain *) drv_chain; 1683 struct wsi_display *wsi = chain->wsi; 1684 struct wsi_display_image *image = &chain->images[image_index]; 1685 VkResult result; 1686 1687 /* Bail early if the swapchain is broken */ 1688 if (chain->status != VK_SUCCESS) 1689 return chain->status; 1690 1691 assert(image->state == WSI_IMAGE_DRAWING); 1692 wsi_display_debug("present %d\n", image_index); 1693 1694 pthread_mutex_lock(&wsi->wait_mutex); 1695 1696 image->flip_sequence = ++chain->flip_sequence; 1697 image->state = WSI_IMAGE_QUEUED; 1698 1699 result = _wsi_display_queue_next(drv_chain); 1700 if (result != VK_SUCCESS) 1701 chain->status = result; 1702 1703 pthread_mutex_unlock(&wsi->wait_mutex); 1704 1705 if (result != VK_SUCCESS) 1706 return result; 1707 1708 return chain->status; 1709} 1710 1711static VkResult 1712wsi_display_surface_create_swapchain( 1713 VkIcdSurfaceBase *icd_surface, 1714 VkDevice device, 1715 struct wsi_device *wsi_device, 1716 const VkSwapchainCreateInfoKHR *create_info, 1717 const VkAllocationCallbacks *allocator, 1718 struct wsi_swapchain **swapchain_out) 1719{ 1720 struct wsi_display *wsi = 1721 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1722 1723 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); 1724 1725 const unsigned num_images = create_info->minImageCount; 1726 struct wsi_display_swapchain *chain = 1727 vk_zalloc(allocator, 1728 sizeof(*chain) + num_images * sizeof(chain->images[0]), 1729 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 1730 1731 if (chain == NULL) 1732 return VK_ERROR_OUT_OF_HOST_MEMORY; 1733 1734 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device, 1735 create_info, allocator); 1736 if (result != VK_SUCCESS) { 1737 vk_free(allocator, chain); 1738 return result; 1739 } 1740 1741 chain->base.destroy = wsi_display_swapchain_destroy; 1742 chain->base.get_wsi_image = wsi_display_get_wsi_image; 1743 chain->base.acquire_next_image = wsi_display_acquire_next_image; 1744 chain->base.queue_present = wsi_display_queue_present; 1745 chain->base.present_mode = create_info->presentMode; 1746 chain->base.image_count = num_images; 1747 1748 chain->wsi = wsi; 1749 chain->status = VK_SUCCESS; 1750 1751 chain->surface = (VkIcdSurfaceDisplay *) icd_surface; 1752 1753 for (uint32_t image = 0; image < chain->base.image_count; image++) { 1754 result = wsi_display_image_init(device, &chain->base, 1755 create_info, allocator, 1756 &chain->images[image]); 1757 if (result != VK_SUCCESS) { 1758 while (image > 0) { 1759 --image; 1760 wsi_display_image_finish(&chain->base, allocator, 1761 &chain->images[image]); 1762 } 1763 vk_free(allocator, chain); 1764 goto fail_init_images; 1765 } 1766 } 1767 1768 *swapchain_out = &chain->base; 1769 1770 return VK_SUCCESS; 1771 1772fail_init_images: 1773 return result; 1774} 1775 1776static bool 1777wsi_init_pthread_cond_monotonic(pthread_cond_t *cond) 1778{ 1779 pthread_condattr_t condattr; 1780 bool ret = false; 1781 1782 if (pthread_condattr_init(&condattr) != 0) 1783 goto fail_attr_init; 1784 1785 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0) 1786 goto fail_attr_set; 1787 1788 if (pthread_cond_init(cond, &condattr) != 0) 1789 goto fail_cond_init; 1790 1791 ret = true; 1792 1793fail_cond_init: 1794fail_attr_set: 1795 pthread_condattr_destroy(&condattr); 1796fail_attr_init: 1797 return ret; 1798} 1799 1800VkResult 1801wsi_display_init_wsi(struct wsi_device *wsi_device, 1802 const VkAllocationCallbacks *alloc, 1803 int display_fd) 1804{ 1805 struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8, 1806 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 1807 VkResult result; 1808 1809 if (!wsi) { 1810 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1811 goto fail; 1812 } 1813 1814 wsi->fd = display_fd; 1815 wsi->alloc = alloc; 1816 1817 list_inithead(&wsi->connectors); 1818 1819 int ret = pthread_mutex_init(&wsi->wait_mutex, NULL); 1820 if (ret) { 1821 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1822 goto fail_mutex; 1823 } 1824 1825 if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) { 1826 result = VK_ERROR_OUT_OF_HOST_MEMORY; 1827 goto fail_cond; 1828 } 1829 1830 wsi->base.get_support = wsi_display_surface_get_support; 1831 wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2; 1832 wsi->base.get_formats = wsi_display_surface_get_formats; 1833 wsi->base.get_formats2 = wsi_display_surface_get_formats2; 1834 wsi->base.get_present_modes = wsi_display_surface_get_present_modes; 1835 wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles; 1836 wsi->base.create_swapchain = wsi_display_surface_create_swapchain; 1837 1838 wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base; 1839 1840 return VK_SUCCESS; 1841 1842fail_cond: 1843 pthread_mutex_destroy(&wsi->wait_mutex); 1844fail_mutex: 1845 vk_free(alloc, wsi); 1846fail: 1847 return result; 1848} 1849 1850void 1851wsi_display_finish_wsi(struct wsi_device *wsi_device, 1852 const VkAllocationCallbacks *alloc) 1853{ 1854 struct wsi_display *wsi = 1855 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1856 1857 if (wsi) { 1858 wsi_for_each_connector(connector, wsi) { 1859 wsi_for_each_display_mode(mode, connector) { 1860 vk_free(wsi->alloc, mode); 1861 } 1862 vk_free(wsi->alloc, connector); 1863 } 1864 1865 pthread_mutex_lock(&wsi->wait_mutex); 1866 if (wsi->wait_thread) { 1867 pthread_cancel(wsi->wait_thread); 1868 pthread_join(wsi->wait_thread, NULL); 1869 } 1870 pthread_mutex_unlock(&wsi->wait_mutex); 1871 pthread_mutex_destroy(&wsi->wait_mutex); 1872 pthread_cond_destroy(&wsi->wait_cond); 1873 1874 vk_free(alloc, wsi); 1875 } 1876} 1877 1878/* 1879 * Implement vkReleaseDisplay 1880 */ 1881VkResult 1882wsi_release_display(VkPhysicalDevice physical_device, 1883 struct wsi_device *wsi_device, 1884 VkDisplayKHR display) 1885{ 1886 struct wsi_display *wsi = 1887 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1888 1889 if (wsi->fd >= 0) { 1890 close(wsi->fd); 1891 wsi->fd = -1; 1892 } 1893#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 1894 wsi_display_connector_from_handle(display)->output = None; 1895#endif 1896 1897 return VK_SUCCESS; 1898} 1899 1900#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT 1901 1902static struct wsi_display_connector * 1903wsi_display_find_output(struct wsi_device *wsi_device, 1904 xcb_randr_output_t output) 1905{ 1906 struct wsi_display *wsi = 1907 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 1908 1909 wsi_for_each_connector(connector, wsi) { 1910 if (connector->output == output) 1911 return connector; 1912 } 1913 1914 return NULL; 1915} 1916 1917/* 1918 * Given a RandR output, find the associated kernel connector_id by 1919 * looking at the CONNECTOR_ID property provided by the X server 1920 */ 1921 1922static uint32_t 1923wsi_display_output_to_connector_id(xcb_connection_t *connection, 1924 xcb_atom_t *connector_id_atom_p, 1925 xcb_randr_output_t output) 1926{ 1927 uint32_t connector_id = 0; 1928 xcb_atom_t connector_id_atom = *connector_id_atom_p; 1929 1930 if (connector_id_atom == 0) { 1931 /* Go dig out the CONNECTOR_ID property */ 1932 xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection, 1933 true, 1934 12, 1935 "CONNECTOR_ID"); 1936 xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection, 1937 ia_c, 1938 NULL); 1939 if (ia_r) { 1940 *connector_id_atom_p = connector_id_atom = ia_r->atom; 1941 free(ia_r); 1942 } 1943 } 1944 1945 /* If there's an CONNECTOR_ID atom in the server, then there may be a 1946 * CONNECTOR_ID property. Otherwise, there will not be and we don't even 1947 * need to bother. 1948 */ 1949 if (connector_id_atom) { 1950 1951 xcb_randr_query_version_cookie_t qv_c = 1952 xcb_randr_query_version(connection, 1, 6); 1953 xcb_randr_get_output_property_cookie_t gop_c = 1954 xcb_randr_get_output_property(connection, 1955 output, 1956 connector_id_atom, 1957 0, 1958 0, 1959 0xffffffffUL, 1960 0, 1961 0); 1962 xcb_randr_query_version_reply_t *qv_r = 1963 xcb_randr_query_version_reply(connection, qv_c, NULL); 1964 free(qv_r); 1965 xcb_randr_get_output_property_reply_t *gop_r = 1966 xcb_randr_get_output_property_reply(connection, gop_c, NULL); 1967 if (gop_r) { 1968 if (gop_r->num_items == 1 && gop_r->format == 32) 1969 memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4); 1970 free(gop_r); 1971 } 1972 } 1973 return connector_id; 1974} 1975 1976static bool 1977wsi_display_check_randr_version(xcb_connection_t *connection) 1978{ 1979 xcb_randr_query_version_cookie_t qv_c = 1980 xcb_randr_query_version(connection, 1, 6); 1981 xcb_randr_query_version_reply_t *qv_r = 1982 xcb_randr_query_version_reply(connection, qv_c, NULL); 1983 bool ret = false; 1984 1985 if (!qv_r) 1986 return false; 1987 1988 /* Check for version 1.6 or newer */ 1989 ret = (qv_r->major_version > 1 || 1990 (qv_r->major_version == 1 && qv_r->minor_version >= 6)); 1991 1992 free(qv_r); 1993 return ret; 1994} 1995 1996/* 1997 * Given a kernel connector id, find the associated RandR output using the 1998 * CONNECTOR_ID property 1999 */ 2000 2001static xcb_randr_output_t 2002wsi_display_connector_id_to_output(xcb_connection_t *connection, 2003 uint32_t connector_id) 2004{ 2005 if (!wsi_display_check_randr_version(connection)) 2006 return 0; 2007 2008 const xcb_setup_t *setup = xcb_get_setup(connection); 2009 2010 xcb_atom_t connector_id_atom = 0; 2011 xcb_randr_output_t output = 0; 2012 2013 /* Search all of the screens for the provided output */ 2014 xcb_screen_iterator_t iter; 2015 for (iter = xcb_setup_roots_iterator(setup); 2016 output == 0 && iter.rem; 2017 xcb_screen_next(&iter)) 2018 { 2019 xcb_randr_get_screen_resources_cookie_t gsr_c = 2020 xcb_randr_get_screen_resources(connection, iter.data->root); 2021 xcb_randr_get_screen_resources_reply_t *gsr_r = 2022 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 2023 2024 if (!gsr_r) 2025 return 0; 2026 2027 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); 2028 int o; 2029 2030 for (o = 0; o < gsr_r->num_outputs; o++) { 2031 if (wsi_display_output_to_connector_id(connection, 2032 &connector_id_atom, ro[o]) 2033 == connector_id) 2034 { 2035 output = ro[o]; 2036 break; 2037 } 2038 } 2039 free(gsr_r); 2040 } 2041 return output; 2042} 2043 2044/* 2045 * Given a RandR output, find out which screen it's associated with 2046 */ 2047static xcb_window_t 2048wsi_display_output_to_root(xcb_connection_t *connection, 2049 xcb_randr_output_t output) 2050{ 2051 if (!wsi_display_check_randr_version(connection)) 2052 return 0; 2053 2054 const xcb_setup_t *setup = xcb_get_setup(connection); 2055 xcb_window_t root = 0; 2056 2057 /* Search all of the screens for the provided output */ 2058 for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); 2059 root == 0 && iter.rem; 2060 xcb_screen_next(&iter)) 2061 { 2062 xcb_randr_get_screen_resources_cookie_t gsr_c = 2063 xcb_randr_get_screen_resources(connection, iter.data->root); 2064 xcb_randr_get_screen_resources_reply_t *gsr_r = 2065 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 2066 2067 if (!gsr_r) 2068 return 0; 2069 2070 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r); 2071 2072 for (int o = 0; o < gsr_r->num_outputs; o++) { 2073 if (ro[o] == output) { 2074 root = iter.data->root; 2075 break; 2076 } 2077 } 2078 free(gsr_r); 2079 } 2080 return root; 2081} 2082 2083static bool 2084wsi_display_mode_matches_x(struct wsi_display_mode *wsi, 2085 xcb_randr_mode_info_t *xcb) 2086{ 2087 return wsi->clock == (xcb->dot_clock + 500) / 1000 && 2088 wsi->hdisplay == xcb->width && 2089 wsi->hsync_start == xcb->hsync_start && 2090 wsi->hsync_end == xcb->hsync_end && 2091 wsi->htotal == xcb->htotal && 2092 wsi->hskew == xcb->hskew && 2093 wsi->vdisplay == xcb->height && 2094 wsi->vsync_start == xcb->vsync_start && 2095 wsi->vsync_end == xcb->vsync_end && 2096 wsi->vtotal == xcb->vtotal && 2097 wsi->vscan <= 1 && 2098 wsi->flags == xcb->mode_flags; 2099} 2100 2101static struct wsi_display_mode * 2102wsi_display_find_x_mode(struct wsi_device *wsi_device, 2103 struct wsi_display_connector *connector, 2104 xcb_randr_mode_info_t *mode) 2105{ 2106 wsi_for_each_display_mode(display_mode, connector) { 2107 if (wsi_display_mode_matches_x(display_mode, mode)) 2108 return display_mode; 2109 } 2110 return NULL; 2111} 2112 2113static VkResult 2114wsi_display_register_x_mode(struct wsi_device *wsi_device, 2115 struct wsi_display_connector *connector, 2116 xcb_randr_mode_info_t *x_mode, 2117 bool preferred) 2118{ 2119 struct wsi_display *wsi = 2120 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2121 struct wsi_display_mode *display_mode = 2122 wsi_display_find_x_mode(wsi_device, connector, x_mode); 2123 2124 if (display_mode) { 2125 display_mode->valid = true; 2126 return VK_SUCCESS; 2127 } 2128 2129 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode), 2130 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); 2131 if (!display_mode) 2132 return VK_ERROR_OUT_OF_HOST_MEMORY; 2133 2134 display_mode->connector = connector; 2135 display_mode->valid = true; 2136 display_mode->preferred = preferred; 2137 display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */ 2138 display_mode->hdisplay = x_mode->width; 2139 display_mode->hsync_start = x_mode->hsync_start; 2140 display_mode->hsync_end = x_mode->hsync_end; 2141 display_mode->htotal = x_mode->htotal; 2142 display_mode->hskew = x_mode->hskew; 2143 display_mode->vdisplay = x_mode->height; 2144 display_mode->vsync_start = x_mode->vsync_start; 2145 display_mode->vsync_end = x_mode->vsync_end; 2146 display_mode->vtotal = x_mode->vtotal; 2147 display_mode->vscan = 0; 2148 display_mode->flags = x_mode->mode_flags; 2149 2150 list_addtail(&display_mode->list, &connector->display_modes); 2151 return VK_SUCCESS; 2152} 2153 2154static struct wsi_display_connector * 2155wsi_display_get_output(struct wsi_device *wsi_device, 2156 xcb_connection_t *connection, 2157 xcb_randr_output_t output) 2158{ 2159 struct wsi_display *wsi = 2160 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2161 struct wsi_display_connector *connector; 2162 uint32_t connector_id; 2163 2164 xcb_window_t root = wsi_display_output_to_root(connection, output); 2165 if (!root) 2166 return NULL; 2167 2168 /* See if we already have a connector for this output */ 2169 connector = wsi_display_find_output(wsi_device, output); 2170 2171 if (!connector) { 2172 xcb_atom_t connector_id_atom = 0; 2173 2174 /* 2175 * Go get the kernel connector ID for this X output 2176 */ 2177 connector_id = wsi_display_output_to_connector_id(connection, 2178 &connector_id_atom, 2179 output); 2180 2181 /* Any X server with lease support will have this atom */ 2182 if (!connector_id) { 2183 return NULL; 2184 } 2185 2186 /* See if we already have a connector for this id */ 2187 connector = wsi_display_find_connector(wsi_device, connector_id); 2188 2189 if (connector == NULL) { 2190 connector = wsi_display_alloc_connector(wsi, connector_id); 2191 if (!connector) { 2192 return NULL; 2193 } 2194 list_addtail(&connector->list, &wsi->connectors); 2195 } 2196 connector->output = output; 2197 } 2198 2199 xcb_randr_get_screen_resources_cookie_t src = 2200 xcb_randr_get_screen_resources(connection, root); 2201 xcb_randr_get_output_info_cookie_t oic = 2202 xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME); 2203 xcb_randr_get_screen_resources_reply_t *srr = 2204 xcb_randr_get_screen_resources_reply(connection, src, NULL); 2205 xcb_randr_get_output_info_reply_t *oir = 2206 xcb_randr_get_output_info_reply(connection, oic, NULL); 2207 2208 if (oir && srr) { 2209 /* Get X modes and add them */ 2210 2211 connector->connected = 2212 oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED; 2213 2214 wsi_display_invalidate_connector_modes(wsi_device, connector); 2215 2216 xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir); 2217 for (int m = 0; m < oir->num_modes; m++) { 2218 xcb_randr_mode_info_iterator_t i = 2219 xcb_randr_get_screen_resources_modes_iterator(srr); 2220 while (i.rem) { 2221 xcb_randr_mode_info_t *mi = i.data; 2222 if (mi->id == x_modes[m]) { 2223 VkResult result = wsi_display_register_x_mode( 2224 wsi_device, connector, mi, m < oir->num_preferred); 2225 if (result != VK_SUCCESS) { 2226 free(oir); 2227 free(srr); 2228 return NULL; 2229 } 2230 break; 2231 } 2232 xcb_randr_mode_info_next(&i); 2233 } 2234 } 2235 } 2236 2237 free(oir); 2238 free(srr); 2239 return connector; 2240} 2241 2242static xcb_randr_crtc_t 2243wsi_display_find_crtc_for_output(xcb_connection_t *connection, 2244 xcb_window_t root, 2245 xcb_randr_output_t output) 2246{ 2247 xcb_randr_get_screen_resources_cookie_t gsr_c = 2248 xcb_randr_get_screen_resources(connection, root); 2249 xcb_randr_get_screen_resources_reply_t *gsr_r = 2250 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL); 2251 2252 if (!gsr_r) 2253 return 0; 2254 2255 xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r); 2256 xcb_randr_crtc_t idle_crtc = 0; 2257 xcb_randr_crtc_t active_crtc = 0; 2258 2259 /* Find either a crtc already connected to the desired output or idle */ 2260 for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) { 2261 xcb_randr_get_crtc_info_cookie_t gci_c = 2262 xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp); 2263 xcb_randr_get_crtc_info_reply_t *gci_r = 2264 xcb_randr_get_crtc_info_reply(connection, gci_c, NULL); 2265 2266 if (gci_r) { 2267 if (gci_r->mode) { 2268 int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r); 2269 xcb_randr_output_t *outputs = 2270 xcb_randr_get_crtc_info_outputs(gci_r); 2271 2272 if (num_outputs == 1 && outputs[0] == output) 2273 active_crtc = rc[c]; 2274 2275 } else if (idle_crtc == 0) { 2276 int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r); 2277 xcb_randr_output_t *possible = 2278 xcb_randr_get_crtc_info_possible(gci_r); 2279 2280 for (int p = 0; p < num_possible; p++) 2281 if (possible[p] == output) { 2282 idle_crtc = rc[c]; 2283 break; 2284 } 2285 } 2286 free(gci_r); 2287 } 2288 } 2289 free(gsr_r); 2290 2291 if (active_crtc) 2292 return active_crtc; 2293 return idle_crtc; 2294} 2295 2296VkResult 2297wsi_acquire_xlib_display(VkPhysicalDevice physical_device, 2298 struct wsi_device *wsi_device, 2299 Display *dpy, 2300 VkDisplayKHR display) 2301{ 2302 struct wsi_display *wsi = 2303 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2304 xcb_connection_t *connection = XGetXCBConnection(dpy); 2305 struct wsi_display_connector *connector = 2306 wsi_display_connector_from_handle(display); 2307 xcb_window_t root; 2308 2309 /* XXX no support for multiple leases yet */ 2310 if (wsi->fd >= 0) 2311 return VK_ERROR_INITIALIZATION_FAILED; 2312 2313 if (!connector->output) { 2314 connector->output = wsi_display_connector_id_to_output(connection, 2315 connector->id); 2316 2317 /* Check and see if we found the output */ 2318 if (!connector->output) 2319 return VK_ERROR_INITIALIZATION_FAILED; 2320 } 2321 2322 root = wsi_display_output_to_root(connection, connector->output); 2323 if (!root) 2324 return VK_ERROR_INITIALIZATION_FAILED; 2325 2326 xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection, 2327 root, 2328 connector->output); 2329 2330 if (!crtc) 2331 return VK_ERROR_INITIALIZATION_FAILED; 2332 2333#ifdef HAVE_DRI3_MODIFIERS 2334 xcb_randr_lease_t lease = xcb_generate_id(connection); 2335 xcb_randr_create_lease_cookie_t cl_c = 2336 xcb_randr_create_lease(connection, root, lease, 1, 1, 2337 &crtc, &connector->output); 2338 xcb_randr_create_lease_reply_t *cl_r = 2339 xcb_randr_create_lease_reply(connection, cl_c, NULL); 2340 if (!cl_r) 2341 return VK_ERROR_INITIALIZATION_FAILED; 2342 2343 int fd = -1; 2344 if (cl_r->nfd > 0) { 2345 int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r); 2346 2347 fd = rcl_f[0]; 2348 } 2349 free (cl_r); 2350 if (fd < 0) 2351 return VK_ERROR_INITIALIZATION_FAILED; 2352 2353 wsi->fd = fd; 2354#endif 2355 2356 return VK_SUCCESS; 2357} 2358 2359VkResult 2360wsi_get_randr_output_display(VkPhysicalDevice physical_device, 2361 struct wsi_device *wsi_device, 2362 Display *dpy, 2363 RROutput output, 2364 VkDisplayKHR *display) 2365{ 2366 xcb_connection_t *connection = XGetXCBConnection(dpy); 2367 struct wsi_display_connector *connector = 2368 wsi_display_get_output(wsi_device, connection, (xcb_randr_output_t) output); 2369 2370 if (connector) 2371 *display = wsi_display_connector_to_handle(connector); 2372 else 2373 *display = VK_NULL_HANDLE; 2374 return VK_SUCCESS; 2375} 2376 2377#endif 2378 2379/* VK_EXT_display_control */ 2380VkResult 2381wsi_display_power_control(VkDevice device, 2382 struct wsi_device *wsi_device, 2383 VkDisplayKHR display, 2384 const VkDisplayPowerInfoEXT *display_power_info) 2385{ 2386 struct wsi_display *wsi = 2387 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2388 struct wsi_display_connector *connector = 2389 wsi_display_connector_from_handle(display); 2390 int mode; 2391 2392 if (wsi->fd < 0) 2393 return VK_ERROR_INITIALIZATION_FAILED; 2394 2395 switch (display_power_info->powerState) { 2396 case VK_DISPLAY_POWER_STATE_OFF_EXT: 2397 mode = DRM_MODE_DPMS_OFF; 2398 break; 2399 case VK_DISPLAY_POWER_STATE_SUSPEND_EXT: 2400 mode = DRM_MODE_DPMS_SUSPEND; 2401 break; 2402 default: 2403 mode = DRM_MODE_DPMS_ON; 2404 break; 2405 } 2406 drmModeConnectorSetProperty(wsi->fd, 2407 connector->id, 2408 connector->dpms_property, 2409 mode); 2410 return VK_SUCCESS; 2411} 2412 2413VkResult 2414wsi_register_device_event(VkDevice device, 2415 struct wsi_device *wsi_device, 2416 const VkDeviceEventInfoEXT *device_event_info, 2417 const VkAllocationCallbacks *allocator, 2418 struct wsi_fence **fence_p) 2419{ 2420 return VK_ERROR_FEATURE_NOT_PRESENT; 2421} 2422 2423VkResult 2424wsi_register_display_event(VkDevice device, 2425 struct wsi_device *wsi_device, 2426 VkDisplayKHR display, 2427 const VkDisplayEventInfoEXT *display_event_info, 2428 const VkAllocationCallbacks *allocator, 2429 struct wsi_fence **fence_p) 2430{ 2431 struct wsi_display *wsi = 2432 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2433 struct wsi_display_fence *fence; 2434 VkResult ret; 2435 2436 switch (display_event_info->displayEvent) { 2437 case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT: 2438 2439 fence = wsi_display_fence_alloc(device, wsi_device, display, allocator); 2440 2441 if (!fence) 2442 return VK_ERROR_OUT_OF_HOST_MEMORY; 2443 2444 ret = wsi_register_vblank_event(fence, wsi_device, display, 2445 DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL); 2446 2447 if (ret == VK_SUCCESS) 2448 *fence_p = &fence->base; 2449 else if (fence != NULL) 2450 vk_free2(wsi->alloc, allocator, fence); 2451 2452 break; 2453 default: 2454 ret = VK_ERROR_FEATURE_NOT_PRESENT; 2455 break; 2456 } 2457 2458 return ret; 2459} 2460 2461 2462VkResult 2463wsi_get_swapchain_counter(VkDevice device, 2464 struct wsi_device *wsi_device, 2465 VkSwapchainKHR _swapchain, 2466 VkSurfaceCounterFlagBitsEXT flag_bits, 2467 uint64_t *value) 2468{ 2469 struct wsi_display *wsi = 2470 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; 2471 struct wsi_display_swapchain *swapchain = 2472 (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain); 2473 struct wsi_display_connector *connector = 2474 wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector; 2475 2476 if (wsi->fd < 0) 2477 return VK_ERROR_INITIALIZATION_FAILED; 2478 2479 if (!connector->active) { 2480 *value = 0; 2481 return VK_SUCCESS; 2482 } 2483 2484 int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, value, NULL); 2485 if (ret) 2486 *value = 0; 2487 2488 return VK_SUCCESS; 2489} 2490 2491