vulkan: Add EXT_acquire_xlib_display [v5]
[mesa.git] / src / vulkan / wsi / wsi_common_display.c
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 */
60 typedef 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
71 typedef 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 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
83 xcb_randr_output_t output;
84 #endif
85 } wsi_display_connector;
86
87 struct wsi_display {
88 struct wsi_interface base;
89
90 const VkAllocationCallbacks *alloc;
91
92 int fd;
93
94 pthread_mutex_t wait_mutex;
95 pthread_cond_t wait_cond;
96 pthread_t wait_thread;
97
98 struct list_head connectors;
99 };
100
101 #define wsi_for_each_display_mode(_mode, _conn) \
102 list_for_each_entry_safe(struct wsi_display_mode, _mode, \
103 &(_conn)->display_modes, list)
104
105 #define wsi_for_each_connector(_conn, _dev) \
106 list_for_each_entry_safe(struct wsi_display_connector, _conn, \
107 &(_dev)->connectors, list)
108
109 enum wsi_image_state {
110 WSI_IMAGE_IDLE,
111 WSI_IMAGE_DRAWING,
112 WSI_IMAGE_QUEUED,
113 WSI_IMAGE_FLIPPING,
114 WSI_IMAGE_DISPLAYING
115 };
116
117 struct wsi_display_image {
118 struct wsi_image base;
119 struct wsi_display_swapchain *chain;
120 enum wsi_image_state state;
121 uint32_t fb_id;
122 uint32_t buffer[4];
123 uint64_t flip_sequence;
124 };
125
126 struct wsi_display_swapchain {
127 struct wsi_swapchain base;
128 struct wsi_display *wsi;
129 VkIcdSurfaceDisplay *surface;
130 uint64_t flip_sequence;
131 VkResult status;
132 struct wsi_display_image images[0];
133 };
134
135 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
136 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
137
138 static bool
139 wsi_display_mode_matches_drm(wsi_display_mode *wsi,
140 drmModeModeInfoPtr drm)
141 {
142 return wsi->clock == drm->clock &&
143 wsi->hdisplay == drm->hdisplay &&
144 wsi->hsync_start == drm->hsync_start &&
145 wsi->hsync_end == drm->hsync_end &&
146 wsi->htotal == drm->htotal &&
147 wsi->hskew == drm->hskew &&
148 wsi->vdisplay == drm->vdisplay &&
149 wsi->vsync_start == drm->vsync_start &&
150 wsi->vsync_end == drm->vsync_end &&
151 wsi->vtotal == drm->vtotal &&
152 MAX2(wsi->vscan, 1) == MAX2(drm->vscan, 1) &&
153 wsi->flags == drm->flags;
154 }
155
156 static double
157 wsi_display_mode_refresh(struct wsi_display_mode *wsi)
158 {
159 return (double) wsi->clock * 1000.0 / ((double) wsi->htotal *
160 (double) wsi->vtotal *
161 (double) MAX2(wsi->vscan, 1));
162 }
163
164 static uint64_t wsi_get_current_monotonic(void)
165 {
166 struct timespec tv;
167
168 clock_gettime(CLOCK_MONOTONIC, &tv);
169 return tv.tv_nsec + tv.tv_sec*1000000000ull;
170 }
171
172 static uint64_t wsi_rel_to_abs_time(uint64_t rel_time)
173 {
174 uint64_t current_time = wsi_get_current_monotonic();
175
176 /* check for overflow */
177 if (rel_time > UINT64_MAX - current_time)
178 return UINT64_MAX;
179
180 return current_time + rel_time;
181 }
182
183 static struct wsi_display_mode *
184 wsi_display_find_drm_mode(struct wsi_device *wsi_device,
185 struct wsi_display_connector *connector,
186 drmModeModeInfoPtr mode)
187 {
188 wsi_for_each_display_mode(display_mode, connector) {
189 if (wsi_display_mode_matches_drm(display_mode, mode))
190 return display_mode;
191 }
192 return NULL;
193 }
194
195 static void
196 wsi_display_invalidate_connector_modes(struct wsi_device *wsi_device,
197 struct wsi_display_connector *connector)
198 {
199 wsi_for_each_display_mode(display_mode, connector) {
200 display_mode->valid = false;
201 }
202 }
203
204 static VkResult
205 wsi_display_register_drm_mode(struct wsi_device *wsi_device,
206 struct wsi_display_connector *connector,
207 drmModeModeInfoPtr drm_mode)
208 {
209 struct wsi_display *wsi =
210 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
211 struct wsi_display_mode *display_mode =
212 wsi_display_find_drm_mode(wsi_device, connector, drm_mode);
213
214 if (display_mode) {
215 display_mode->valid = true;
216 return VK_SUCCESS;
217 }
218
219 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
220 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
221 if (!display_mode)
222 return VK_ERROR_OUT_OF_HOST_MEMORY;
223
224 display_mode->connector = connector;
225 display_mode->valid = true;
226 display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0;
227 display_mode->clock = drm_mode->clock; /* kHz */
228 display_mode->hdisplay = drm_mode->hdisplay;
229 display_mode->hsync_start = drm_mode->hsync_start;
230 display_mode->hsync_end = drm_mode->hsync_end;
231 display_mode->htotal = drm_mode->htotal;
232 display_mode->hskew = drm_mode->hskew;
233 display_mode->vdisplay = drm_mode->vdisplay;
234 display_mode->vsync_start = drm_mode->vsync_start;
235 display_mode->vsync_end = drm_mode->vsync_end;
236 display_mode->vtotal = drm_mode->vtotal;
237 display_mode->vscan = drm_mode->vscan;
238 display_mode->flags = drm_mode->flags;
239
240 list_addtail(&display_mode->list, &connector->display_modes);
241 return VK_SUCCESS;
242 }
243
244 /*
245 * Update our information about a specific connector
246 */
247
248 static struct wsi_display_connector *
249 wsi_display_find_connector(struct wsi_device *wsi_device,
250 uint32_t connector_id)
251 {
252 struct wsi_display *wsi =
253 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
254
255 wsi_for_each_connector(connector, wsi) {
256 if (connector->id == connector_id)
257 return connector;
258 }
259
260 return NULL;
261 }
262
263 static struct wsi_display_connector *
264 wsi_display_alloc_connector(struct wsi_display *wsi,
265 uint32_t connector_id)
266 {
267 struct wsi_display_connector *connector =
268 vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector),
269 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
270
271 connector->id = connector_id;
272 connector->wsi = wsi;
273 connector->active = false;
274 /* XXX use EDID name */
275 connector->name = "monitor";
276 list_inithead(&connector->display_modes);
277 return connector;
278 }
279
280 static struct wsi_display_connector *
281 wsi_display_get_connector(struct wsi_device *wsi_device,
282 uint32_t connector_id)
283 {
284 struct wsi_display *wsi =
285 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
286
287 if (wsi->fd < 0)
288 return NULL;
289
290 drmModeConnectorPtr drm_connector =
291 drmModeGetConnector(wsi->fd, connector_id);
292
293 if (!drm_connector)
294 return NULL;
295
296 struct wsi_display_connector *connector =
297 wsi_display_find_connector(wsi_device, connector_id);
298
299 if (!connector) {
300 connector = wsi_display_alloc_connector(wsi, connector_id);
301 if (!connector) {
302 drmModeFreeConnector(drm_connector);
303 return NULL;
304 }
305 list_addtail(&connector->list, &wsi->connectors);
306 }
307
308 connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED;
309
310 /* Mark all connector modes as invalid */
311 wsi_display_invalidate_connector_modes(wsi_device, connector);
312
313 /*
314 * List current modes, adding new ones and marking existing ones as
315 * valid
316 */
317 for (int m = 0; m < drm_connector->count_modes; m++) {
318 VkResult result = wsi_display_register_drm_mode(wsi_device,
319 connector,
320 &drm_connector->modes[m]);
321 if (result != VK_SUCCESS) {
322 drmModeFreeConnector(drm_connector);
323 return NULL;
324 }
325 }
326
327 drmModeFreeConnector(drm_connector);
328
329 return connector;
330 }
331
332 #define MM_PER_PIXEL (1.0/96.0 * 25.4)
333
334 static uint32_t
335 mode_size(struct wsi_display_mode *mode)
336 {
337 /* fortunately, these are both uint16_t, so this is easy */
338 return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay;
339 }
340
341 static void
342 wsi_display_fill_in_display_properties(struct wsi_device *wsi_device,
343 struct wsi_display_connector *connector,
344 VkDisplayPropertiesKHR *properties)
345 {
346 properties->display = wsi_display_connector_to_handle(connector);
347 properties->displayName = connector->name;
348
349 /* Find the first preferred mode and assume that's the physical
350 * resolution. If there isn't a preferred mode, find the largest mode and
351 * use that.
352 */
353
354 struct wsi_display_mode *preferred_mode = NULL, *largest_mode = NULL;
355 wsi_for_each_display_mode(display_mode, connector) {
356 if (!display_mode->valid)
357 continue;
358 if (display_mode->preferred) {
359 preferred_mode = display_mode;
360 break;
361 }
362 if (largest_mode == NULL ||
363 mode_size(display_mode) > mode_size(largest_mode))
364 {
365 largest_mode = display_mode;
366 }
367 }
368
369 if (preferred_mode) {
370 properties->physicalResolution.width = preferred_mode->hdisplay;
371 properties->physicalResolution.height = preferred_mode->vdisplay;
372 } else if (largest_mode) {
373 properties->physicalResolution.width = largest_mode->hdisplay;
374 properties->physicalResolution.height = largest_mode->vdisplay;
375 } else {
376 properties->physicalResolution.width = 1024;
377 properties->physicalResolution.height = 768;
378 }
379
380 /* Make up physical size based on 96dpi */
381 properties->physicalDimensions.width =
382 floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5);
383 properties->physicalDimensions.height =
384 floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5);
385
386 properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
387 properties->planeReorderPossible = VK_FALSE;
388 properties->persistentContent = VK_FALSE;
389 }
390
391 /*
392 * Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display)
393 */
394 VkResult
395 wsi_display_get_physical_device_display_properties(
396 VkPhysicalDevice physical_device,
397 struct wsi_device *wsi_device,
398 uint32_t *property_count,
399 VkDisplayPropertiesKHR *properties)
400 {
401 struct wsi_display *wsi =
402 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
403
404 if (wsi->fd < 0)
405 goto bail;
406
407 drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
408
409 if (!mode_res)
410 goto bail;
411
412 VK_OUTARRAY_MAKE(conn, properties, property_count);
413
414 /* Get current information */
415
416 for (int c = 0; c < mode_res->count_connectors; c++) {
417 struct wsi_display_connector *connector =
418 wsi_display_get_connector(wsi_device, mode_res->connectors[c]);
419
420 if (!connector) {
421 drmModeFreeResources(mode_res);
422 return VK_ERROR_OUT_OF_HOST_MEMORY;
423 }
424
425 if (connector->connected) {
426 vk_outarray_append(&conn, prop) {
427 wsi_display_fill_in_display_properties(wsi_device,
428 connector,
429 prop);
430 }
431 }
432 }
433
434 drmModeFreeResources(mode_res);
435
436 return vk_outarray_status(&conn);
437
438 bail:
439 *property_count = 0;
440 return VK_SUCCESS;
441 }
442
443 /*
444 * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
445 */
446 VkResult
447 wsi_display_get_physical_device_display_plane_properties(
448 VkPhysicalDevice physical_device,
449 struct wsi_device *wsi_device,
450 uint32_t *property_count,
451 VkDisplayPlanePropertiesKHR *properties)
452 {
453 struct wsi_display *wsi =
454 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
455
456 VK_OUTARRAY_MAKE(conn, properties, property_count);
457
458 wsi_for_each_connector(connector, wsi) {
459 vk_outarray_append(&conn, prop) {
460 if (connector && connector->active) {
461 prop->currentDisplay = wsi_display_connector_to_handle(connector);
462 prop->currentStackIndex = 0;
463 } else {
464 prop->currentDisplay = VK_NULL_HANDLE;
465 prop->currentStackIndex = 0;
466 }
467 }
468 }
469 return vk_outarray_status(&conn);
470 }
471
472 /*
473 * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display)
474 */
475
476 VkResult
477 wsi_display_get_display_plane_supported_displays(
478 VkPhysicalDevice physical_device,
479 struct wsi_device *wsi_device,
480 uint32_t plane_index,
481 uint32_t *display_count,
482 VkDisplayKHR *displays)
483 {
484 struct wsi_display *wsi =
485 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
486
487 VK_OUTARRAY_MAKE(conn, displays, display_count);
488
489 int c = 0;
490
491 wsi_for_each_connector(connector, wsi) {
492 if (c == plane_index && connector->connected) {
493 vk_outarray_append(&conn, display) {
494 *display = wsi_display_connector_to_handle(connector);
495 }
496 }
497 c++;
498 }
499 return vk_outarray_status(&conn);
500 }
501
502 /*
503 * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
504 */
505
506 VkResult
507 wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device,
508 struct wsi_device *wsi_device,
509 VkDisplayKHR display,
510 uint32_t *property_count,
511 VkDisplayModePropertiesKHR *properties)
512 {
513 struct wsi_display_connector *connector =
514 wsi_display_connector_from_handle(display);
515
516 VK_OUTARRAY_MAKE(conn, properties, property_count);
517
518 wsi_for_each_display_mode(display_mode, connector) {
519 if (display_mode->valid) {
520 vk_outarray_append(&conn, prop) {
521 prop->displayMode = wsi_display_mode_to_handle(display_mode);
522 prop->parameters.visibleRegion.width = display_mode->hdisplay;
523 prop->parameters.visibleRegion.height = display_mode->vdisplay;
524 prop->parameters.refreshRate =
525 (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
526 }
527 }
528 }
529 return vk_outarray_status(&conn);
530 }
531
532 static bool
533 wsi_display_mode_matches_vk(wsi_display_mode *wsi,
534 const VkDisplayModeParametersKHR *vk)
535 {
536 return (vk->visibleRegion.width == wsi->hdisplay &&
537 vk->visibleRegion.height == wsi->vdisplay &&
538 fabs(wsi_display_mode_refresh(wsi) * 1000.0 - vk->refreshRate) < 10);
539 }
540
541 /*
542 * Implement vkCreateDisplayModeKHR (VK_KHR_display)
543 */
544 VkResult
545 wsi_display_create_display_mode(VkPhysicalDevice physical_device,
546 struct wsi_device *wsi_device,
547 VkDisplayKHR display,
548 const VkDisplayModeCreateInfoKHR *create_info,
549 const VkAllocationCallbacks *allocator,
550 VkDisplayModeKHR *mode)
551 {
552 struct wsi_display_connector *connector =
553 wsi_display_connector_from_handle(display);
554
555 if (create_info->flags != 0)
556 return VK_ERROR_INITIALIZATION_FAILED;
557
558 /* Check and see if the requested mode happens to match an existing one and
559 * return that. This makes the conformance suite happy. Doing more than
560 * this would involve embedding the CVT function into the driver, which seems
561 * excessive.
562 */
563 wsi_for_each_display_mode(display_mode, connector) {
564 if (display_mode->valid) {
565 if (wsi_display_mode_matches_vk(display_mode, &create_info->parameters)) {
566 *mode = wsi_display_mode_to_handle(display_mode);
567 return VK_SUCCESS;
568 }
569 }
570 }
571 return VK_ERROR_INITIALIZATION_FAILED;
572 }
573
574 /*
575 * Implement vkGetDisplayPlaneCapabilities
576 */
577 VkResult
578 wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device,
579 struct wsi_device *wsi_device,
580 VkDisplayModeKHR mode_khr,
581 uint32_t plane_index,
582 VkDisplayPlaneCapabilitiesKHR *capabilities)
583 {
584 struct wsi_display_mode *mode = wsi_display_mode_from_handle(mode_khr);
585
586 /* XXX use actual values */
587 capabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
588 capabilities->minSrcPosition.x = 0;
589 capabilities->minSrcPosition.y = 0;
590 capabilities->maxSrcPosition.x = 0;
591 capabilities->maxSrcPosition.y = 0;
592 capabilities->minSrcExtent.width = mode->hdisplay;
593 capabilities->minSrcExtent.height = mode->vdisplay;
594 capabilities->maxSrcExtent.width = mode->hdisplay;
595 capabilities->maxSrcExtent.height = mode->vdisplay;
596 capabilities->minDstPosition.x = 0;
597 capabilities->minDstPosition.y = 0;
598 capabilities->maxDstPosition.x = 0;
599 capabilities->maxDstPosition.y = 0;
600 capabilities->minDstExtent.width = mode->hdisplay;
601 capabilities->minDstExtent.height = mode->vdisplay;
602 capabilities->maxDstExtent.width = mode->hdisplay;
603 capabilities->maxDstExtent.height = mode->vdisplay;
604 return VK_SUCCESS;
605 }
606
607 VkResult
608 wsi_create_display_surface(VkInstance instance,
609 const VkAllocationCallbacks *allocator,
610 const VkDisplaySurfaceCreateInfoKHR *create_info,
611 VkSurfaceKHR *surface_khr)
612 {
613 VkIcdSurfaceDisplay *surface = vk_zalloc(allocator, sizeof *surface, 8,
614 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
615
616 if (surface == NULL)
617 return VK_ERROR_OUT_OF_HOST_MEMORY;
618
619 surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY;
620
621 surface->displayMode = create_info->displayMode;
622 surface->planeIndex = create_info->planeIndex;
623 surface->planeStackIndex = create_info->planeStackIndex;
624 surface->transform = create_info->transform;
625 surface->globalAlpha = create_info->globalAlpha;
626 surface->alphaMode = create_info->alphaMode;
627 surface->imageExtent = create_info->imageExtent;
628
629 *surface_khr = VkIcdSurfaceBase_to_handle(&surface->base);
630 return VK_SUCCESS;
631 }
632
633
634 static VkResult
635 wsi_display_surface_get_support(VkIcdSurfaceBase *surface,
636 struct wsi_device *wsi_device,
637 const VkAllocationCallbacks *allocator,
638 uint32_t queueFamilyIndex,
639 int local_fd,
640 VkBool32* pSupported)
641 {
642 *pSupported = VK_TRUE;
643 return VK_SUCCESS;
644 }
645
646 static VkResult
647 wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base,
648 VkSurfaceCapabilitiesKHR* caps)
649 {
650 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
651 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
652
653 caps->currentExtent.width = mode->hdisplay;
654 caps->currentExtent.height = mode->vdisplay;
655
656 /* XXX Figure out extents based on driver capabilities */
657 caps->maxImageExtent = caps->minImageExtent = caps->currentExtent;
658
659 caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
660
661 caps->minImageCount = 2;
662 caps->maxImageCount = 0;
663
664 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
665 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
666 caps->maxImageArrayLayers = 1;
667 caps->supportedUsageFlags =
668 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
669 VK_IMAGE_USAGE_SAMPLED_BIT |
670 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
671 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
672
673 return VK_SUCCESS;
674 }
675
676 static VkResult
677 wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
678 const void *info_next,
679 VkSurfaceCapabilities2KHR *caps)
680 {
681 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
682
683 return wsi_display_surface_get_capabilities(icd_surface,
684 &caps->surfaceCapabilities);
685 }
686
687 static const struct {
688 VkFormat format;
689 uint32_t drm_format;
690 } available_surface_formats[] = {
691 { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 },
692 { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 },
693 };
694
695 static VkResult
696 wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
697 struct wsi_device *wsi_device,
698 uint32_t *surface_format_count,
699 VkSurfaceFormatKHR *surface_formats)
700 {
701 VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
702
703 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
704 vk_outarray_append(&out, f) {
705 f->format = available_surface_formats[i].format;
706 f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
707 }
708 }
709
710 return vk_outarray_status(&out);
711 }
712
713 static VkResult
714 wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
715 struct wsi_device *wsi_device,
716 const void *info_next,
717 uint32_t *surface_format_count,
718 VkSurfaceFormat2KHR *surface_formats)
719 {
720 VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
721
722 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
723 vk_outarray_append(&out, f) {
724 assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
725 f->surfaceFormat.format = available_surface_formats[i].format;
726 f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
727 }
728 }
729
730 return vk_outarray_status(&out);
731 }
732
733 static VkResult
734 wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface,
735 uint32_t *present_mode_count,
736 VkPresentModeKHR *present_modes)
737 {
738 VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count);
739
740 vk_outarray_append(&conn, present) {
741 *present = VK_PRESENT_MODE_FIFO_KHR;
742 }
743
744 return vk_outarray_status(&conn);
745 }
746
747 static void
748 wsi_display_destroy_buffer(struct wsi_display *wsi,
749 uint32_t buffer)
750 {
751 (void) drmIoctl(wsi->fd, DRM_IOCTL_MODE_DESTROY_DUMB,
752 &((struct drm_mode_destroy_dumb) { .handle = buffer }));
753 }
754
755 static VkResult
756 wsi_display_image_init(VkDevice device_h,
757 struct wsi_swapchain *drv_chain,
758 const VkSwapchainCreateInfoKHR *create_info,
759 const VkAllocationCallbacks *allocator,
760 struct wsi_display_image *image)
761 {
762 struct wsi_display_swapchain *chain =
763 (struct wsi_display_swapchain *) drv_chain;
764 struct wsi_display *wsi = chain->wsi;
765 uint32_t drm_format = 0;
766
767 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
768 if (create_info->imageFormat == available_surface_formats[i].format) {
769 drm_format = available_surface_formats[i].drm_format;
770 break;
771 }
772 }
773
774 /* the application provided an invalid format, bail */
775 if (drm_format == 0)
776 return VK_ERROR_DEVICE_LOST;
777
778 VkResult result = wsi_create_native_image(&chain->base, create_info,
779 0, NULL, NULL,
780 &image->base);
781 if (result != VK_SUCCESS)
782 return result;
783
784 memset(image->buffer, 0, sizeof (image->buffer));
785
786 for (unsigned int i = 0; i < image->base.num_planes; i++) {
787 int ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i],
788 &image->buffer[i]);
789
790 close(image->base.fds[i]);
791 image->base.fds[i] = -1;
792 if (ret < 0)
793 goto fail_handle;
794 }
795
796 image->chain = chain;
797 image->state = WSI_IMAGE_IDLE;
798 image->fb_id = 0;
799
800 int ret = drmModeAddFB2(wsi->fd,
801 create_info->imageExtent.width,
802 create_info->imageExtent.height,
803 drm_format,
804 image->buffer,
805 image->base.row_pitches,
806 image->base.offsets,
807 &image->fb_id, 0);
808
809 if (ret)
810 goto fail_fb;
811
812 return VK_SUCCESS;
813
814 fail_fb:
815 fail_handle:
816 for (unsigned int i = 0; i < image->base.num_planes; i++) {
817 if (image->buffer[i])
818 wsi_display_destroy_buffer(wsi, image->buffer[i]);
819 if (image->base.fds[i] != -1) {
820 close(image->base.fds[i]);
821 image->base.fds[i] = -1;
822 }
823 }
824
825 wsi_destroy_image(&chain->base, &image->base);
826
827 return VK_ERROR_OUT_OF_HOST_MEMORY;
828 }
829
830 static void
831 wsi_display_image_finish(struct wsi_swapchain *drv_chain,
832 const VkAllocationCallbacks *allocator,
833 struct wsi_display_image *image)
834 {
835 struct wsi_display_swapchain *chain =
836 (struct wsi_display_swapchain *) drv_chain;
837 struct wsi_display *wsi = chain->wsi;
838
839 drmModeRmFB(wsi->fd, image->fb_id);
840 for (unsigned int i = 0; i < image->base.num_planes; i++)
841 wsi_display_destroy_buffer(wsi, image->buffer[i]);
842 wsi_destroy_image(&chain->base, &image->base);
843 }
844
845 static VkResult
846 wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain,
847 const VkAllocationCallbacks *allocator)
848 {
849 struct wsi_display_swapchain *chain =
850 (struct wsi_display_swapchain *) drv_chain;
851
852 for (uint32_t i = 0; i < chain->base.image_count; i++)
853 wsi_display_image_finish(drv_chain, allocator, &chain->images[i]);
854 vk_free(allocator, chain);
855 return VK_SUCCESS;
856 }
857
858 static struct wsi_image *
859 wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain,
860 uint32_t image_index)
861 {
862 struct wsi_display_swapchain *chain =
863 (struct wsi_display_swapchain *) drv_chain;
864
865 return &chain->images[image_index].base;
866 }
867
868 static void
869 wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
870 {
871 struct wsi_display_swapchain *chain = active_image->chain;
872
873 wsi_display_debug("idle everyone but %ld\n",
874 active_image - &(chain->images[0]));
875 for (uint32_t i = 0; i < chain->base.image_count; i++)
876 if (chain->images[i].state == WSI_IMAGE_DISPLAYING &&
877 &chain->images[i] != active_image)
878 {
879 wsi_display_debug("idle %d\n", i);
880 chain->images[i].state = WSI_IMAGE_IDLE;
881 }
882 }
883
884 static VkResult
885 _wsi_display_queue_next(struct wsi_swapchain *drv_chain);
886
887 static void
888 wsi_display_page_flip_handler2(int fd,
889 unsigned int frame,
890 unsigned int sec,
891 unsigned int usec,
892 uint32_t crtc_id,
893 void *data)
894 {
895 struct wsi_display_image *image = data;
896 struct wsi_display_swapchain *chain = image->chain;
897
898 wsi_display_debug("image %ld displayed at %d\n",
899 image - &(image->chain->images[0]), frame);
900 image->state = WSI_IMAGE_DISPLAYING;
901 wsi_display_idle_old_displaying(image);
902 VkResult result = _wsi_display_queue_next(&(chain->base));
903 if (result != VK_SUCCESS)
904 chain->status = result;
905 }
906
907 static void wsi_display_page_flip_handler(int fd,
908 unsigned int frame,
909 unsigned int sec,
910 unsigned int usec,
911 void *data)
912 {
913 wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
914 }
915
916 static drmEventContext event_context = {
917 .version = DRM_EVENT_CONTEXT_VERSION,
918 .page_flip_handler = wsi_display_page_flip_handler,
919 #if DRM_EVENT_CONTEXT_VERSION >= 3
920 .page_flip_handler2 = wsi_display_page_flip_handler2,
921 #endif
922 };
923
924 static void *
925 wsi_display_wait_thread(void *data)
926 {
927 struct wsi_display *wsi = data;
928 struct pollfd pollfd = {
929 .fd = wsi->fd,
930 .events = POLLIN
931 };
932
933 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
934 for (;;) {
935 int ret = poll(&pollfd, 1, -1);
936 if (ret > 0) {
937 pthread_mutex_lock(&wsi->wait_mutex);
938 (void) drmHandleEvent(wsi->fd, &event_context);
939 pthread_mutex_unlock(&wsi->wait_mutex);
940 pthread_cond_broadcast(&wsi->wait_cond);
941 }
942 }
943 return NULL;
944 }
945
946 static int
947 wsi_display_start_wait_thread(struct wsi_display *wsi)
948 {
949 if (!wsi->wait_thread) {
950 int ret = pthread_create(&wsi->wait_thread, NULL,
951 wsi_display_wait_thread, wsi);
952 if (ret)
953 return ret;
954 }
955 return 0;
956 }
957
958 /*
959 * Wait for at least one event from the kernel to be processed.
960 * Call with wait_mutex held
961 */
962 static int
963 wsi_display_wait_for_event(struct wsi_display *wsi,
964 uint64_t timeout_ns)
965 {
966 int ret;
967
968 ret = wsi_display_start_wait_thread(wsi);
969
970 if (ret)
971 return ret;
972
973 struct timespec abs_timeout = {
974 .tv_sec = timeout_ns / 1000000000ULL,
975 .tv_nsec = timeout_ns % 1000000000ULL,
976 };
977
978 ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex,
979 &abs_timeout);
980
981 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);
982 return ret;
983 }
984
985 static VkResult
986 wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
987 uint64_t timeout,
988 VkSemaphore semaphore,
989 uint32_t *image_index)
990 {
991 struct wsi_display_swapchain *chain =
992 (struct wsi_display_swapchain *)drv_chain;
993 struct wsi_display *wsi = chain->wsi;
994 int ret = 0;
995 VkResult result = VK_SUCCESS;
996
997 /* Bail early if the swapchain is broken */
998 if (chain->status != VK_SUCCESS)
999 return chain->status;
1000
1001 if (timeout != 0 && timeout != UINT64_MAX)
1002 timeout = wsi_rel_to_abs_time(timeout);
1003
1004 pthread_mutex_lock(&wsi->wait_mutex);
1005 for (;;) {
1006 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1007 if (chain->images[i].state == WSI_IMAGE_IDLE) {
1008 *image_index = i;
1009 wsi_display_debug("image %d available\n", i);
1010 chain->images[i].state = WSI_IMAGE_DRAWING;
1011 result = VK_SUCCESS;
1012 goto done;
1013 }
1014 wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
1015 }
1016
1017 if (ret == ETIMEDOUT) {
1018 result = VK_TIMEOUT;
1019 goto done;
1020 }
1021
1022 ret = wsi_display_wait_for_event(wsi, timeout);
1023
1024 if (ret && ret != ETIMEDOUT) {
1025 result = VK_ERROR_OUT_OF_DATE_KHR;
1026 goto done;
1027 }
1028 }
1029 done:
1030 pthread_mutex_unlock(&wsi->wait_mutex);
1031
1032 if (result != VK_SUCCESS)
1033 return result;
1034
1035 return chain->status;
1036 }
1037
1038 /*
1039 * Check whether there are any other connectors driven by this crtc
1040 */
1041 static bool
1042 wsi_display_crtc_solo(struct wsi_display *wsi,
1043 drmModeResPtr mode_res,
1044 drmModeConnectorPtr connector,
1045 uint32_t crtc_id)
1046 {
1047 /* See if any other connectors share the same encoder */
1048 for (int c = 0; c < mode_res->count_connectors; c++) {
1049 if (mode_res->connectors[c] == connector->connector_id)
1050 continue;
1051
1052 drmModeConnectorPtr other_connector =
1053 drmModeGetConnector(wsi->fd, mode_res->connectors[c]);
1054
1055 if (other_connector) {
1056 bool match = (other_connector->encoder_id == connector->encoder_id);
1057 drmModeFreeConnector(other_connector);
1058 if (match)
1059 return false;
1060 }
1061 }
1062
1063 /* See if any other encoders share the same crtc */
1064 for (int e = 0; e < mode_res->count_encoders; e++) {
1065 if (mode_res->encoders[e] == connector->encoder_id)
1066 continue;
1067
1068 drmModeEncoderPtr other_encoder =
1069 drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);
1070
1071 if (other_encoder) {
1072 bool match = (other_encoder->crtc_id == crtc_id);
1073 drmModeFreeEncoder(other_encoder);
1074 if (match)
1075 return false;
1076 }
1077 }
1078 return true;
1079 }
1080
1081 /*
1082 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1083 * currently driving this connector and not any others. Settle for a CRTC
1084 * which is currently idle.
1085 */
1086 static uint32_t
1087 wsi_display_select_crtc(struct wsi_display_connector *connector,
1088 drmModeResPtr mode_res,
1089 drmModeConnectorPtr drm_connector)
1090 {
1091 struct wsi_display *wsi = connector->wsi;
1092
1093 /* See what CRTC is currently driving this connector */
1094 if (drm_connector->encoder_id) {
1095 drmModeEncoderPtr encoder =
1096 drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);
1097
1098 if (encoder) {
1099 uint32_t crtc_id = encoder->crtc_id;
1100 drmModeFreeEncoder(encoder);
1101 if (crtc_id) {
1102 if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))
1103 return crtc_id;
1104 }
1105 }
1106 }
1107 uint32_t crtc_id = 0;
1108 for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
1109 drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
1110 if (crtc && crtc->buffer_id == 0)
1111 crtc_id = crtc->crtc_id;
1112 drmModeFreeCrtc(crtc);
1113 }
1114 return crtc_id;
1115 }
1116
1117 static VkResult
1118 wsi_display_setup_connector(wsi_display_connector *connector,
1119 wsi_display_mode *display_mode)
1120 {
1121 struct wsi_display *wsi = connector->wsi;
1122
1123 if (connector->current_mode == display_mode && connector->crtc_id)
1124 return VK_SUCCESS;
1125
1126 VkResult result = VK_SUCCESS;
1127
1128 drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
1129 if (!mode_res) {
1130 if (errno == ENOMEM)
1131 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1132 else
1133 result = VK_ERROR_OUT_OF_DATE_KHR;
1134 goto bail;
1135 }
1136
1137 drmModeConnectorPtr drm_connector =
1138 drmModeGetConnectorCurrent(wsi->fd, connector->id);
1139
1140 if (!drm_connector) {
1141 if (errno == ENOMEM)
1142 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1143 else
1144 result = VK_ERROR_OUT_OF_DATE_KHR;
1145 goto bail_mode_res;
1146 }
1147
1148 /* Pick a CRTC if we don't have one */
1149 if (!connector->crtc_id) {
1150 connector->crtc_id = wsi_display_select_crtc(connector,
1151 mode_res, drm_connector);
1152 if (!connector->crtc_id) {
1153 result = VK_ERROR_OUT_OF_DATE_KHR;
1154 goto bail_connector;
1155 }
1156 }
1157
1158 if (connector->current_mode != display_mode) {
1159
1160 /* Find the drm mode corresponding to the requested VkDisplayMode */
1161 drmModeModeInfoPtr drm_mode = NULL;
1162
1163 for (int m = 0; m < drm_connector->count_modes; m++) {
1164 drm_mode = &drm_connector->modes[m];
1165 if (wsi_display_mode_matches_drm(display_mode, drm_mode))
1166 break;
1167 drm_mode = NULL;
1168 }
1169
1170 if (!drm_mode) {
1171 result = VK_ERROR_OUT_OF_DATE_KHR;
1172 goto bail_connector;
1173 }
1174
1175 connector->current_mode = display_mode;
1176 connector->current_drm_mode = *drm_mode;
1177 }
1178
1179 bail_connector:
1180 drmModeFreeConnector(drm_connector);
1181 bail_mode_res:
1182 drmModeFreeResources(mode_res);
1183 bail:
1184 return result;
1185
1186 }
1187
1188 /*
1189 * Check to see if the kernel has no flip queued and if there's an image
1190 * waiting to be displayed.
1191 */
1192 static VkResult
1193 _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
1194 {
1195 struct wsi_display_swapchain *chain =
1196 (struct wsi_display_swapchain *) drv_chain;
1197 struct wsi_display *wsi = chain->wsi;
1198 VkIcdSurfaceDisplay *surface = chain->surface;
1199 wsi_display_mode *display_mode =
1200 wsi_display_mode_from_handle(surface->displayMode);
1201 wsi_display_connector *connector = display_mode->connector;
1202
1203 if (wsi->fd < 0)
1204 return VK_ERROR_OUT_OF_DATE_KHR;
1205
1206 if (display_mode != connector->current_mode)
1207 connector->active = false;
1208
1209 for (;;) {
1210
1211 /* Check to see if there is an image to display, or if some image is
1212 * already queued */
1213
1214 struct wsi_display_image *image = NULL;
1215
1216 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1217 struct wsi_display_image *tmp_image = &chain->images[i];
1218
1219 switch (tmp_image->state) {
1220 case WSI_IMAGE_FLIPPING:
1221 /* already flipping, don't send another to the kernel yet */
1222 return VK_SUCCESS;
1223 case WSI_IMAGE_QUEUED:
1224 /* find the oldest queued */
1225 if (!image || tmp_image->flip_sequence < image->flip_sequence)
1226 image = tmp_image;
1227 break;
1228 default:
1229 break;
1230 }
1231 }
1232
1233 if (!image)
1234 return VK_SUCCESS;
1235
1236 int ret;
1237 if (connector->active) {
1238 ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
1239 DRM_MODE_PAGE_FLIP_EVENT, image);
1240 if (ret == 0) {
1241 image->state = WSI_IMAGE_FLIPPING;
1242 return VK_SUCCESS;
1243 }
1244 wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
1245 } else {
1246 ret = -EINVAL;
1247 }
1248
1249 if (ret == -EINVAL) {
1250 VkResult result = wsi_display_setup_connector(connector, display_mode);
1251
1252 if (result != VK_SUCCESS) {
1253 image->state = WSI_IMAGE_IDLE;
1254 return result;
1255 }
1256
1257 /* XXX allow setting of position */
1258 ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
1259 image->fb_id, 0, 0,
1260 &connector->id, 1,
1261 &connector->current_drm_mode);
1262 if (ret == 0) {
1263 /* Assume that the mode set is synchronous and that any
1264 * previous image is now idle.
1265 */
1266 image->state = WSI_IMAGE_DISPLAYING;
1267 wsi_display_idle_old_displaying(image);
1268 connector->active = true;
1269 return VK_SUCCESS;
1270 }
1271 }
1272
1273 if (ret != -EACCES) {
1274 connector->active = false;
1275 image->state = WSI_IMAGE_IDLE;
1276 return VK_ERROR_OUT_OF_DATE_KHR;
1277 }
1278
1279 /* Some other VT is currently active. Sit here waiting for
1280 * our VT to become active again by polling once a second
1281 */
1282 usleep(1000 * 1000);
1283 connector->active = false;
1284 }
1285 }
1286
1287 static VkResult
1288 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
1289 uint32_t image_index,
1290 const VkPresentRegionKHR *damage)
1291 {
1292 struct wsi_display_swapchain *chain =
1293 (struct wsi_display_swapchain *) drv_chain;
1294 struct wsi_display *wsi = chain->wsi;
1295 struct wsi_display_image *image = &chain->images[image_index];
1296 VkResult result;
1297
1298 /* Bail early if the swapchain is broken */
1299 if (chain->status != VK_SUCCESS)
1300 return chain->status;
1301
1302 assert(image->state == WSI_IMAGE_DRAWING);
1303 wsi_display_debug("present %d\n", image_index);
1304
1305 pthread_mutex_lock(&wsi->wait_mutex);
1306
1307 image->flip_sequence = ++chain->flip_sequence;
1308 image->state = WSI_IMAGE_QUEUED;
1309
1310 result = _wsi_display_queue_next(drv_chain);
1311 if (result != VK_SUCCESS)
1312 chain->status = result;
1313
1314 pthread_mutex_unlock(&wsi->wait_mutex);
1315
1316 if (result != VK_SUCCESS)
1317 return result;
1318
1319 return chain->status;
1320 }
1321
1322 static VkResult
1323 wsi_display_surface_create_swapchain(
1324 VkIcdSurfaceBase *icd_surface,
1325 VkDevice device,
1326 struct wsi_device *wsi_device,
1327 int local_fd,
1328 const VkSwapchainCreateInfoKHR *create_info,
1329 const VkAllocationCallbacks *allocator,
1330 struct wsi_swapchain **swapchain_out)
1331 {
1332 struct wsi_display *wsi =
1333 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1334
1335 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1336
1337 const unsigned num_images = create_info->minImageCount;
1338 struct wsi_display_swapchain *chain =
1339 vk_zalloc(allocator,
1340 sizeof(*chain) + num_images * sizeof(chain->images[0]),
1341 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1342
1343 if (chain == NULL)
1344 return VK_ERROR_OUT_OF_HOST_MEMORY;
1345
1346 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
1347 create_info, allocator);
1348
1349 chain->base.destroy = wsi_display_swapchain_destroy;
1350 chain->base.get_wsi_image = wsi_display_get_wsi_image;
1351 chain->base.acquire_next_image = wsi_display_acquire_next_image;
1352 chain->base.queue_present = wsi_display_queue_present;
1353 chain->base.present_mode = create_info->presentMode;
1354 chain->base.image_count = num_images;
1355
1356 chain->wsi = wsi;
1357 chain->status = VK_SUCCESS;
1358
1359 chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
1360
1361 for (uint32_t image = 0; image < chain->base.image_count; image++) {
1362 result = wsi_display_image_init(device, &chain->base,
1363 create_info, allocator,
1364 &chain->images[image]);
1365 if (result != VK_SUCCESS) {
1366 while (image > 0) {
1367 --image;
1368 wsi_display_image_finish(&chain->base, allocator,
1369 &chain->images[image]);
1370 }
1371 vk_free(allocator, chain);
1372 goto fail_init_images;
1373 }
1374 }
1375
1376 *swapchain_out = &chain->base;
1377
1378 return VK_SUCCESS;
1379
1380 fail_init_images:
1381 return result;
1382 }
1383
1384 static bool
1385 wsi_init_pthread_cond_monotonic(pthread_cond_t *cond)
1386 {
1387 pthread_condattr_t condattr;
1388 bool ret = false;
1389
1390 if (pthread_condattr_init(&condattr) != 0)
1391 goto fail_attr_init;
1392
1393 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0)
1394 goto fail_attr_set;
1395
1396 if (pthread_cond_init(cond, &condattr) != 0)
1397 goto fail_cond_init;
1398
1399 ret = true;
1400
1401 fail_cond_init:
1402 fail_attr_set:
1403 pthread_condattr_destroy(&condattr);
1404 fail_attr_init:
1405 return ret;
1406 }
1407
1408 VkResult
1409 wsi_display_init_wsi(struct wsi_device *wsi_device,
1410 const VkAllocationCallbacks *alloc,
1411 int display_fd)
1412 {
1413 struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
1414 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1415 VkResult result;
1416
1417 if (!wsi) {
1418 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1419 goto fail;
1420 }
1421
1422 wsi->fd = display_fd;
1423 wsi->alloc = alloc;
1424
1425 list_inithead(&wsi->connectors);
1426
1427 int ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
1428 if (ret) {
1429 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1430 goto fail_mutex;
1431 }
1432
1433 if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) {
1434 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1435 goto fail_cond;
1436 }
1437
1438 wsi->base.get_support = wsi_display_surface_get_support;
1439 wsi->base.get_capabilities = wsi_display_surface_get_capabilities;
1440 wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
1441 wsi->base.get_formats = wsi_display_surface_get_formats;
1442 wsi->base.get_formats2 = wsi_display_surface_get_formats2;
1443 wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
1444 wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
1445
1446 wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
1447
1448 return VK_SUCCESS;
1449
1450 fail_cond:
1451 pthread_mutex_destroy(&wsi->wait_mutex);
1452 fail_mutex:
1453 vk_free(alloc, wsi);
1454 fail:
1455 return result;
1456 }
1457
1458 void
1459 wsi_display_finish_wsi(struct wsi_device *wsi_device,
1460 const VkAllocationCallbacks *alloc)
1461 {
1462 struct wsi_display *wsi =
1463 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1464
1465 if (wsi) {
1466 wsi_for_each_connector(connector, wsi) {
1467 wsi_for_each_display_mode(mode, connector) {
1468 vk_free(wsi->alloc, mode);
1469 }
1470 vk_free(wsi->alloc, connector);
1471 }
1472
1473 pthread_mutex_lock(&wsi->wait_mutex);
1474 if (wsi->wait_thread) {
1475 pthread_cancel(wsi->wait_thread);
1476 pthread_join(wsi->wait_thread, NULL);
1477 }
1478 pthread_mutex_unlock(&wsi->wait_mutex);
1479 pthread_mutex_destroy(&wsi->wait_mutex);
1480 pthread_cond_destroy(&wsi->wait_cond);
1481
1482 vk_free(alloc, wsi);
1483 }
1484 }
1485
1486 /*
1487 * Implement vkReleaseDisplay
1488 */
1489 VkResult
1490 wsi_release_display(VkPhysicalDevice physical_device,
1491 struct wsi_device *wsi_device,
1492 VkDisplayKHR display)
1493 {
1494 struct wsi_display *wsi =
1495 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1496
1497 if (wsi->fd >= 0) {
1498 close(wsi->fd);
1499 wsi->fd = -1;
1500 }
1501 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1502 wsi_display_connector_from_handle(display)->output = None;
1503 #endif
1504
1505 return VK_SUCCESS;
1506 }
1507
1508 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1509
1510 static struct wsi_display_connector *
1511 wsi_display_find_output(struct wsi_device *wsi_device,
1512 xcb_randr_output_t output)
1513 {
1514 struct wsi_display *wsi =
1515 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1516
1517 wsi_for_each_connector(connector, wsi) {
1518 if (connector->output == output)
1519 return connector;
1520 }
1521
1522 return NULL;
1523 }
1524
1525 /*
1526 * Given a RandR output, find the associated kernel connector_id by
1527 * looking at the CONNECTOR_ID property provided by the X server
1528 */
1529
1530 static uint32_t
1531 wsi_display_output_to_connector_id(xcb_connection_t *connection,
1532 xcb_atom_t *connector_id_atom_p,
1533 xcb_randr_output_t output)
1534 {
1535 uint32_t connector_id = 0;
1536 xcb_atom_t connector_id_atom = *connector_id_atom_p;
1537
1538 if (connector_id_atom == 0) {
1539 /* Go dig out the CONNECTOR_ID property */
1540 xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
1541 true,
1542 12,
1543 "CONNECTOR_ID");
1544 xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
1545 ia_c,
1546 NULL);
1547 if (ia_r) {
1548 *connector_id_atom_p = connector_id_atom = ia_r->atom;
1549 free(ia_r);
1550 }
1551 }
1552
1553 /* If there's an CONNECTOR_ID atom in the server, then there may be a
1554 * CONNECTOR_ID property. Otherwise, there will not be and we don't even
1555 * need to bother.
1556 */
1557 if (connector_id_atom) {
1558
1559 xcb_randr_query_version_cookie_t qv_c =
1560 xcb_randr_query_version(connection, 1, 6);
1561 xcb_randr_get_output_property_cookie_t gop_c =
1562 xcb_randr_get_output_property(connection,
1563 output,
1564 connector_id_atom,
1565 0,
1566 0,
1567 0xffffffffUL,
1568 0,
1569 0);
1570 xcb_randr_query_version_reply_t *qv_r =
1571 xcb_randr_query_version_reply(connection, qv_c, NULL);
1572 free(qv_r);
1573 xcb_randr_get_output_property_reply_t *gop_r =
1574 xcb_randr_get_output_property_reply(connection, gop_c, NULL);
1575 if (gop_r) {
1576 if (gop_r->num_items == 1 && gop_r->format == 32)
1577 memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
1578 free(gop_r);
1579 }
1580 }
1581 return connector_id;
1582 }
1583
1584 static bool
1585 wsi_display_check_randr_version(xcb_connection_t *connection)
1586 {
1587 xcb_randr_query_version_cookie_t qv_c =
1588 xcb_randr_query_version(connection, 1, 6);
1589 xcb_randr_query_version_reply_t *qv_r =
1590 xcb_randr_query_version_reply(connection, qv_c, NULL);
1591 bool ret = false;
1592
1593 if (!qv_r)
1594 return false;
1595
1596 /* Check for version 1.6 or newer */
1597 ret = (qv_r->major_version > 1 ||
1598 (qv_r->major_version == 1 && qv_r->minor_version >= 6));
1599
1600 free(qv_r);
1601 return ret;
1602 }
1603
1604 /*
1605 * Given a kernel connector id, find the associated RandR output using the
1606 * CONNECTOR_ID property
1607 */
1608
1609 static xcb_randr_output_t
1610 wsi_display_connector_id_to_output(xcb_connection_t *connection,
1611 uint32_t connector_id)
1612 {
1613 if (!wsi_display_check_randr_version(connection))
1614 return 0;
1615
1616 const xcb_setup_t *setup = xcb_get_setup(connection);
1617
1618 xcb_atom_t connector_id_atom = 0;
1619 xcb_randr_output_t output = 0;
1620
1621 /* Search all of the screens for the provided output */
1622 xcb_screen_iterator_t iter;
1623 for (iter = xcb_setup_roots_iterator(setup);
1624 output == 0 && iter.rem;
1625 xcb_screen_next(&iter))
1626 {
1627 xcb_randr_get_screen_resources_cookie_t gsr_c =
1628 xcb_randr_get_screen_resources(connection, iter.data->root);
1629 xcb_randr_get_screen_resources_reply_t *gsr_r =
1630 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
1631
1632 if (!gsr_r)
1633 return 0;
1634
1635 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
1636 int o;
1637
1638 for (o = 0; o < gsr_r->num_outputs; o++) {
1639 if (wsi_display_output_to_connector_id(connection,
1640 &connector_id_atom, ro[o])
1641 == connector_id)
1642 {
1643 output = ro[o];
1644 break;
1645 }
1646 }
1647 free(gsr_r);
1648 }
1649 return output;
1650 }
1651
1652 /*
1653 * Given a RandR output, find out which screen it's associated with
1654 */
1655 static xcb_window_t
1656 wsi_display_output_to_root(xcb_connection_t *connection,
1657 xcb_randr_output_t output)
1658 {
1659 if (!wsi_display_check_randr_version(connection))
1660 return 0;
1661
1662 const xcb_setup_t *setup = xcb_get_setup(connection);
1663 xcb_window_t root = 0;
1664
1665 /* Search all of the screens for the provided output */
1666 for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
1667 root == 0 && iter.rem;
1668 xcb_screen_next(&iter))
1669 {
1670 xcb_randr_get_screen_resources_cookie_t gsr_c =
1671 xcb_randr_get_screen_resources(connection, iter.data->root);
1672 xcb_randr_get_screen_resources_reply_t *gsr_r =
1673 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
1674
1675 if (!gsr_r)
1676 return 0;
1677
1678 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
1679
1680 for (int o = 0; o < gsr_r->num_outputs; o++) {
1681 if (ro[o] == output) {
1682 root = iter.data->root;
1683 break;
1684 }
1685 }
1686 free(gsr_r);
1687 }
1688 return root;
1689 }
1690
1691 static bool
1692 wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
1693 xcb_randr_mode_info_t *xcb)
1694 {
1695 return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
1696 wsi->hdisplay == xcb->width &&
1697 wsi->hsync_start == xcb->hsync_start &&
1698 wsi->hsync_end == xcb->hsync_end &&
1699 wsi->htotal == xcb->htotal &&
1700 wsi->hskew == xcb->hskew &&
1701 wsi->vdisplay == xcb->height &&
1702 wsi->vsync_start == xcb->vsync_start &&
1703 wsi->vsync_end == xcb->vsync_end &&
1704 wsi->vtotal == xcb->vtotal &&
1705 wsi->vscan <= 1 &&
1706 wsi->flags == xcb->mode_flags;
1707 }
1708
1709 static struct wsi_display_mode *
1710 wsi_display_find_x_mode(struct wsi_device *wsi_device,
1711 struct wsi_display_connector *connector,
1712 xcb_randr_mode_info_t *mode)
1713 {
1714 wsi_for_each_display_mode(display_mode, connector) {
1715 if (wsi_display_mode_matches_x(display_mode, mode))
1716 return display_mode;
1717 }
1718 return NULL;
1719 }
1720
1721 static VkResult
1722 wsi_display_register_x_mode(struct wsi_device *wsi_device,
1723 struct wsi_display_connector *connector,
1724 xcb_randr_mode_info_t *x_mode,
1725 bool preferred)
1726 {
1727 struct wsi_display *wsi =
1728 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1729 struct wsi_display_mode *display_mode =
1730 wsi_display_find_x_mode(wsi_device, connector, x_mode);
1731
1732 if (display_mode) {
1733 display_mode->valid = true;
1734 return VK_SUCCESS;
1735 }
1736
1737 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
1738 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1739 if (!display_mode)
1740 return VK_ERROR_OUT_OF_HOST_MEMORY;
1741
1742 display_mode->connector = connector;
1743 display_mode->valid = true;
1744 display_mode->preferred = preferred;
1745 display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
1746 display_mode->hdisplay = x_mode->width;
1747 display_mode->hsync_start = x_mode->hsync_start;
1748 display_mode->hsync_end = x_mode->hsync_end;
1749 display_mode->htotal = x_mode->htotal;
1750 display_mode->hskew = x_mode->hskew;
1751 display_mode->vdisplay = x_mode->height;
1752 display_mode->vsync_start = x_mode->vsync_start;
1753 display_mode->vsync_end = x_mode->vsync_end;
1754 display_mode->vtotal = x_mode->vtotal;
1755 display_mode->vscan = 0;
1756 display_mode->flags = x_mode->mode_flags;
1757
1758 list_addtail(&display_mode->list, &connector->display_modes);
1759 return VK_SUCCESS;
1760 }
1761
1762 static struct wsi_display_connector *
1763 wsi_display_get_output(struct wsi_device *wsi_device,
1764 xcb_connection_t *connection,
1765 xcb_randr_output_t output)
1766 {
1767 struct wsi_display *wsi =
1768 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1769 struct wsi_display_connector *connector;
1770 uint32_t connector_id;
1771
1772 xcb_window_t root = wsi_display_output_to_root(connection, output);
1773 if (!root)
1774 return NULL;
1775
1776 /* See if we already have a connector for this output */
1777 connector = wsi_display_find_output(wsi_device, output);
1778
1779 if (!connector) {
1780 xcb_atom_t connector_id_atom = 0;
1781
1782 /*
1783 * Go get the kernel connector ID for this X output
1784 */
1785 connector_id = wsi_display_output_to_connector_id(connection,
1786 &connector_id_atom,
1787 output);
1788
1789 /* Any X server with lease support will have this atom */
1790 if (!connector_id) {
1791 return NULL;
1792 }
1793
1794 /* See if we already have a connector for this id */
1795 connector = wsi_display_find_connector(wsi_device, connector_id);
1796
1797 if (connector == NULL) {
1798 connector = wsi_display_alloc_connector(wsi, connector_id);
1799 if (!connector) {
1800 return NULL;
1801 }
1802 list_addtail(&connector->list, &wsi->connectors);
1803 }
1804 connector->output = output;
1805 }
1806
1807 xcb_randr_get_screen_resources_cookie_t src =
1808 xcb_randr_get_screen_resources(connection, root);
1809 xcb_randr_get_output_info_cookie_t oic =
1810 xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
1811 xcb_randr_get_screen_resources_reply_t *srr =
1812 xcb_randr_get_screen_resources_reply(connection, src, NULL);
1813 xcb_randr_get_output_info_reply_t *oir =
1814 xcb_randr_get_output_info_reply(connection, oic, NULL);
1815
1816 if (oir && srr) {
1817 /* Get X modes and add them */
1818
1819 connector->connected =
1820 oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
1821
1822 wsi_display_invalidate_connector_modes(wsi_device, connector);
1823
1824 xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
1825 for (int m = 0; m < oir->num_modes; m++) {
1826 xcb_randr_mode_info_iterator_t i =
1827 xcb_randr_get_screen_resources_modes_iterator(srr);
1828 while (i.rem) {
1829 xcb_randr_mode_info_t *mi = i.data;
1830 if (mi->id == x_modes[m]) {
1831 VkResult result = wsi_display_register_x_mode(
1832 wsi_device, connector, mi, m < oir->num_preferred);
1833 if (result != VK_SUCCESS) {
1834 free(oir);
1835 free(srr);
1836 return NULL;
1837 }
1838 break;
1839 }
1840 xcb_randr_mode_info_next(&i);
1841 }
1842 }
1843 }
1844
1845 free(oir);
1846 free(srr);
1847 return connector;
1848 }
1849
1850 static xcb_randr_crtc_t
1851 wsi_display_find_crtc_for_output(xcb_connection_t *connection,
1852 xcb_window_t root,
1853 xcb_randr_output_t output)
1854 {
1855 xcb_randr_get_screen_resources_cookie_t gsr_c =
1856 xcb_randr_get_screen_resources(connection, root);
1857 xcb_randr_get_screen_resources_reply_t *gsr_r =
1858 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
1859
1860 if (!gsr_r)
1861 return 0;
1862
1863 xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
1864 xcb_randr_crtc_t idle_crtc = 0;
1865 xcb_randr_crtc_t active_crtc = 0;
1866
1867 /* Find either a crtc already connected to the desired output or idle */
1868 for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
1869 xcb_randr_get_crtc_info_cookie_t gci_c =
1870 xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
1871 xcb_randr_get_crtc_info_reply_t *gci_r =
1872 xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
1873
1874 if (gci_r) {
1875 if (gci_r->mode) {
1876 int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
1877 xcb_randr_output_t *outputs =
1878 xcb_randr_get_crtc_info_outputs(gci_r);
1879
1880 if (num_outputs == 1 && outputs[0] == output)
1881 active_crtc = rc[c];
1882
1883 } else if (idle_crtc == 0) {
1884 int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
1885 xcb_randr_output_t *possible =
1886 xcb_randr_get_crtc_info_possible(gci_r);
1887
1888 for (int p = 0; p < num_possible; p++)
1889 if (possible[p] == output) {
1890 idle_crtc = rc[c];
1891 break;
1892 }
1893 }
1894 free(gci_r);
1895 }
1896 }
1897 free(gsr_r);
1898
1899 if (active_crtc)
1900 return active_crtc;
1901 return idle_crtc;
1902 }
1903
1904 VkResult
1905 wsi_acquire_xlib_display(VkPhysicalDevice physical_device,
1906 struct wsi_device *wsi_device,
1907 Display *dpy,
1908 VkDisplayKHR display)
1909 {
1910 struct wsi_display *wsi =
1911 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1912 xcb_connection_t *connection = XGetXCBConnection(dpy);
1913 struct wsi_display_connector *connector =
1914 wsi_display_connector_from_handle(display);
1915 xcb_window_t root;
1916
1917 /* XXX no support for multiple leases yet */
1918 if (wsi->fd >= 0)
1919 return VK_ERROR_INITIALIZATION_FAILED;
1920
1921 if (!connector->output) {
1922 connector->output = wsi_display_connector_id_to_output(connection,
1923 connector->id);
1924
1925 /* Check and see if we found the output */
1926 if (!connector->output)
1927 return VK_ERROR_INITIALIZATION_FAILED;
1928 }
1929
1930 root = wsi_display_output_to_root(connection, connector->output);
1931 if (!root)
1932 return VK_ERROR_INITIALIZATION_FAILED;
1933
1934 xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
1935 root,
1936 connector->output);
1937
1938 if (!crtc)
1939 return VK_ERROR_INITIALIZATION_FAILED;
1940
1941 xcb_randr_lease_t lease = xcb_generate_id(connection);
1942 xcb_randr_create_lease_cookie_t cl_c =
1943 xcb_randr_create_lease(connection, root, lease, 1, 1,
1944 &crtc, &connector->output);
1945 xcb_randr_create_lease_reply_t *cl_r =
1946 xcb_randr_create_lease_reply(connection, cl_c, NULL);
1947 if (!cl_r)
1948 return VK_ERROR_INITIALIZATION_FAILED;
1949
1950 int fd = -1;
1951 if (cl_r->nfd > 0) {
1952 int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
1953
1954 fd = rcl_f[0];
1955 }
1956 free (cl_r);
1957 if (fd < 0)
1958 return VK_ERROR_INITIALIZATION_FAILED;
1959
1960 wsi->fd = fd;
1961
1962 return VK_SUCCESS;
1963 }
1964
1965 VkResult
1966 wsi_get_randr_output_display(VkPhysicalDevice physical_device,
1967 struct wsi_device *wsi_device,
1968 Display *dpy,
1969 RROutput output,
1970 VkDisplayKHR *display)
1971 {
1972 xcb_connection_t *connection = XGetXCBConnection(dpy);
1973 struct wsi_display_connector *connector =
1974 wsi_display_get_output(wsi_device, connection, (xcb_randr_output_t) output);
1975
1976 if (connector)
1977 *display = wsi_display_connector_to_handle(connector);
1978 else
1979 *display = NULL;
1980 return VK_SUCCESS;
1981 }
1982
1983 #endif