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