vulkan: Add KHR_display extension using DRM [v10]
[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 #include "util/hash_table.h"
37 #include "util/list.h"
38
39 #include "vk_util.h"
40 #include "wsi_common_private.h"
41 #include "wsi_common_display.h"
42 #include "wsi_common_queue.h"
43
44 #if 0
45 #define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
46 #define wsi_display_debug_code(...) __VA_ARGS__
47 #else
48 #define wsi_display_debug(...)
49 #define wsi_display_debug_code(...)
50 #endif
51
52 /* These have lifetime equal to the instance, so they effectively
53 * never go away. This means we must keep track of them separately
54 * from all other resources.
55 */
56 typedef struct wsi_display_mode {
57 struct list_head list;
58 struct wsi_display_connector *connector;
59 bool valid; /* was found in most recent poll */
60 bool preferred;
61 uint32_t clock; /* in kHz */
62 uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
63 uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
64 uint32_t flags;
65 } wsi_display_mode;
66
67 typedef struct wsi_display_connector {
68 struct list_head list;
69 struct wsi_display *wsi;
70 uint32_t id;
71 uint32_t crtc_id;
72 char *name;
73 bool connected;
74 bool active;
75 struct list_head display_modes;
76 wsi_display_mode *current_mode;
77 drmModeModeInfo current_drm_mode;
78 } wsi_display_connector;
79
80 struct wsi_display {
81 struct wsi_interface base;
82
83 const VkAllocationCallbacks *alloc;
84
85 int fd;
86
87 pthread_mutex_t wait_mutex;
88 pthread_cond_t wait_cond;
89 pthread_t wait_thread;
90
91 struct list_head connectors;
92 };
93
94 #define wsi_for_each_display_mode(_mode, _conn) \
95 list_for_each_entry_safe(struct wsi_display_mode, _mode, \
96 &(_conn)->display_modes, list)
97
98 #define wsi_for_each_connector(_conn, _dev) \
99 list_for_each_entry_safe(struct wsi_display_connector, _conn, \
100 &(_dev)->connectors, list)
101
102 enum wsi_image_state {
103 WSI_IMAGE_IDLE,
104 WSI_IMAGE_DRAWING,
105 WSI_IMAGE_QUEUED,
106 WSI_IMAGE_FLIPPING,
107 WSI_IMAGE_DISPLAYING
108 };
109
110 struct wsi_display_image {
111 struct wsi_image base;
112 struct wsi_display_swapchain *chain;
113 enum wsi_image_state state;
114 uint32_t fb_id;
115 uint32_t buffer[4];
116 uint64_t flip_sequence;
117 };
118
119 struct wsi_display_swapchain {
120 struct wsi_swapchain base;
121 struct wsi_display *wsi;
122 VkIcdSurfaceDisplay *surface;
123 uint64_t flip_sequence;
124 VkResult status;
125 struct wsi_display_image images[0];
126 };
127
128 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
129 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
130
131 static bool
132 wsi_display_mode_matches_drm(wsi_display_mode *wsi,
133 drmModeModeInfoPtr drm)
134 {
135 return wsi->clock == drm->clock &&
136 wsi->hdisplay == drm->hdisplay &&
137 wsi->hsync_start == drm->hsync_start &&
138 wsi->hsync_end == drm->hsync_end &&
139 wsi->htotal == drm->htotal &&
140 wsi->hskew == drm->hskew &&
141 wsi->vdisplay == drm->vdisplay &&
142 wsi->vsync_start == drm->vsync_start &&
143 wsi->vsync_end == drm->vsync_end &&
144 wsi->vtotal == drm->vtotal &&
145 MAX2(wsi->vscan, 1) == MAX2(drm->vscan, 1) &&
146 wsi->flags == drm->flags;
147 }
148
149 static double
150 wsi_display_mode_refresh(struct wsi_display_mode *wsi)
151 {
152 return (double) wsi->clock * 1000.0 / ((double) wsi->htotal *
153 (double) wsi->vtotal *
154 (double) MAX2(wsi->vscan, 1));
155 }
156
157 static uint64_t wsi_get_current_monotonic(void)
158 {
159 struct timespec tv;
160
161 clock_gettime(CLOCK_MONOTONIC, &tv);
162 return tv.tv_nsec + tv.tv_sec*1000000000ull;
163 }
164
165 static uint64_t wsi_rel_to_abs_time(uint64_t rel_time)
166 {
167 uint64_t current_time = wsi_get_current_monotonic();
168
169 /* check for overflow */
170 if (rel_time > UINT64_MAX - current_time)
171 return UINT64_MAX;
172
173 return current_time + rel_time;
174 }
175
176 static struct wsi_display_mode *
177 wsi_display_find_drm_mode(struct wsi_device *wsi_device,
178 struct wsi_display_connector *connector,
179 drmModeModeInfoPtr mode)
180 {
181 wsi_for_each_display_mode(display_mode, connector) {
182 if (wsi_display_mode_matches_drm(display_mode, mode))
183 return display_mode;
184 }
185 return NULL;
186 }
187
188 static void
189 wsi_display_invalidate_connector_modes(struct wsi_device *wsi_device,
190 struct wsi_display_connector *connector)
191 {
192 wsi_for_each_display_mode(display_mode, connector) {
193 display_mode->valid = false;
194 }
195 }
196
197 static VkResult
198 wsi_display_register_drm_mode(struct wsi_device *wsi_device,
199 struct wsi_display_connector *connector,
200 drmModeModeInfoPtr drm_mode)
201 {
202 struct wsi_display *wsi =
203 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
204 struct wsi_display_mode *display_mode =
205 wsi_display_find_drm_mode(wsi_device, connector, drm_mode);
206
207 if (display_mode) {
208 display_mode->valid = true;
209 return VK_SUCCESS;
210 }
211
212 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
213 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
214 if (!display_mode)
215 return VK_ERROR_OUT_OF_HOST_MEMORY;
216
217 display_mode->connector = connector;
218 display_mode->valid = true;
219 display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0;
220 display_mode->clock = drm_mode->clock; /* kHz */
221 display_mode->hdisplay = drm_mode->hdisplay;
222 display_mode->hsync_start = drm_mode->hsync_start;
223 display_mode->hsync_end = drm_mode->hsync_end;
224 display_mode->htotal = drm_mode->htotal;
225 display_mode->hskew = drm_mode->hskew;
226 display_mode->vdisplay = drm_mode->vdisplay;
227 display_mode->vsync_start = drm_mode->vsync_start;
228 display_mode->vsync_end = drm_mode->vsync_end;
229 display_mode->vtotal = drm_mode->vtotal;
230 display_mode->vscan = drm_mode->vscan;
231 display_mode->flags = drm_mode->flags;
232
233 list_addtail(&display_mode->list, &connector->display_modes);
234 return VK_SUCCESS;
235 }
236
237 /*
238 * Update our information about a specific connector
239 */
240
241 static struct wsi_display_connector *
242 wsi_display_find_connector(struct wsi_device *wsi_device,
243 uint32_t connector_id)
244 {
245 struct wsi_display *wsi =
246 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
247
248 wsi_for_each_connector(connector, wsi) {
249 if (connector->id == connector_id)
250 return connector;
251 }
252
253 return NULL;
254 }
255
256 static struct wsi_display_connector *
257 wsi_display_alloc_connector(struct wsi_display *wsi,
258 uint32_t connector_id)
259 {
260 struct wsi_display_connector *connector =
261 vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector),
262 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
263
264 connector->id = connector_id;
265 connector->wsi = wsi;
266 connector->active = false;
267 /* XXX use EDID name */
268 connector->name = "monitor";
269 list_inithead(&connector->display_modes);
270 return connector;
271 }
272
273 static struct wsi_display_connector *
274 wsi_display_get_connector(struct wsi_device *wsi_device,
275 uint32_t connector_id)
276 {
277 struct wsi_display *wsi =
278 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
279
280 if (wsi->fd < 0)
281 return NULL;
282
283 drmModeConnectorPtr drm_connector =
284 drmModeGetConnector(wsi->fd, connector_id);
285
286 if (!drm_connector)
287 return NULL;
288
289 struct wsi_display_connector *connector =
290 wsi_display_find_connector(wsi_device, connector_id);
291
292 if (!connector) {
293 connector = wsi_display_alloc_connector(wsi, connector_id);
294 if (!connector) {
295 drmModeFreeConnector(drm_connector);
296 return NULL;
297 }
298 list_addtail(&connector->list, &wsi->connectors);
299 }
300
301 connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED;
302
303 /* Mark all connector modes as invalid */
304 wsi_display_invalidate_connector_modes(wsi_device, connector);
305
306 /*
307 * List current modes, adding new ones and marking existing ones as
308 * valid
309 */
310 for (int m = 0; m < drm_connector->count_modes; m++) {
311 VkResult result = wsi_display_register_drm_mode(wsi_device,
312 connector,
313 &drm_connector->modes[m]);
314 if (result != VK_SUCCESS) {
315 drmModeFreeConnector(drm_connector);
316 return NULL;
317 }
318 }
319
320 drmModeFreeConnector(drm_connector);
321
322 return connector;
323 }
324
325 #define MM_PER_PIXEL (1.0/96.0 * 25.4)
326
327 static uint32_t
328 mode_size(struct wsi_display_mode *mode)
329 {
330 /* fortunately, these are both uint16_t, so this is easy */
331 return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay;
332 }
333
334 static void
335 wsi_display_fill_in_display_properties(struct wsi_device *wsi_device,
336 struct wsi_display_connector *connector,
337 VkDisplayPropertiesKHR *properties)
338 {
339 properties->display = wsi_display_connector_to_handle(connector);
340 properties->displayName = connector->name;
341
342 /* Find the first preferred mode and assume that's the physical
343 * resolution. If there isn't a preferred mode, find the largest mode and
344 * use that.
345 */
346
347 struct wsi_display_mode *preferred_mode = NULL, *largest_mode = NULL;
348 wsi_for_each_display_mode(display_mode, connector) {
349 if (!display_mode->valid)
350 continue;
351 if (display_mode->preferred) {
352 preferred_mode = display_mode;
353 break;
354 }
355 if (largest_mode == NULL ||
356 mode_size(display_mode) > mode_size(largest_mode))
357 {
358 largest_mode = display_mode;
359 }
360 }
361
362 if (preferred_mode) {
363 properties->physicalResolution.width = preferred_mode->hdisplay;
364 properties->physicalResolution.height = preferred_mode->vdisplay;
365 } else if (largest_mode) {
366 properties->physicalResolution.width = largest_mode->hdisplay;
367 properties->physicalResolution.height = largest_mode->vdisplay;
368 } else {
369 properties->physicalResolution.width = 1024;
370 properties->physicalResolution.height = 768;
371 }
372
373 /* Make up physical size based on 96dpi */
374 properties->physicalDimensions.width =
375 floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5);
376 properties->physicalDimensions.height =
377 floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5);
378
379 properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
380 properties->planeReorderPossible = VK_FALSE;
381 properties->persistentContent = VK_FALSE;
382 }
383
384 /*
385 * Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display)
386 */
387 VkResult
388 wsi_display_get_physical_device_display_properties(
389 VkPhysicalDevice physical_device,
390 struct wsi_device *wsi_device,
391 uint32_t *property_count,
392 VkDisplayPropertiesKHR *properties)
393 {
394 struct wsi_display *wsi =
395 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
396
397 if (wsi->fd < 0)
398 goto bail;
399
400 drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
401
402 if (!mode_res)
403 goto bail;
404
405 VK_OUTARRAY_MAKE(conn, properties, property_count);
406
407 /* Get current information */
408
409 for (int c = 0; c < mode_res->count_connectors; c++) {
410 struct wsi_display_connector *connector =
411 wsi_display_get_connector(wsi_device, mode_res->connectors[c]);
412
413 if (!connector) {
414 drmModeFreeResources(mode_res);
415 return VK_ERROR_OUT_OF_HOST_MEMORY;
416 }
417
418 if (connector->connected) {
419 vk_outarray_append(&conn, prop) {
420 wsi_display_fill_in_display_properties(wsi_device,
421 connector,
422 prop);
423 }
424 }
425 }
426
427 drmModeFreeResources(mode_res);
428
429 return vk_outarray_status(&conn);
430
431 bail:
432 *property_count = 0;
433 return VK_SUCCESS;
434 }
435
436 /*
437 * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
438 */
439 VkResult
440 wsi_display_get_physical_device_display_plane_properties(
441 VkPhysicalDevice physical_device,
442 struct wsi_device *wsi_device,
443 uint32_t *property_count,
444 VkDisplayPlanePropertiesKHR *properties)
445 {
446 struct wsi_display *wsi =
447 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
448
449 VK_OUTARRAY_MAKE(conn, properties, property_count);
450
451 wsi_for_each_connector(connector, wsi) {
452 vk_outarray_append(&conn, prop) {
453 if (connector && connector->active) {
454 prop->currentDisplay = wsi_display_connector_to_handle(connector);
455 prop->currentStackIndex = 0;
456 } else {
457 prop->currentDisplay = VK_NULL_HANDLE;
458 prop->currentStackIndex = 0;
459 }
460 }
461 }
462 return vk_outarray_status(&conn);
463 }
464
465 /*
466 * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display)
467 */
468
469 VkResult
470 wsi_display_get_display_plane_supported_displays(
471 VkPhysicalDevice physical_device,
472 struct wsi_device *wsi_device,
473 uint32_t plane_index,
474 uint32_t *display_count,
475 VkDisplayKHR *displays)
476 {
477 struct wsi_display *wsi =
478 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
479
480 VK_OUTARRAY_MAKE(conn, displays, display_count);
481
482 int c = 0;
483
484 wsi_for_each_connector(connector, wsi) {
485 if (c == plane_index && connector->connected) {
486 vk_outarray_append(&conn, display) {
487 *display = wsi_display_connector_to_handle(connector);
488 }
489 }
490 c++;
491 }
492 return vk_outarray_status(&conn);
493 }
494
495 /*
496 * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
497 */
498
499 VkResult
500 wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device,
501 struct wsi_device *wsi_device,
502 VkDisplayKHR display,
503 uint32_t *property_count,
504 VkDisplayModePropertiesKHR *properties)
505 {
506 struct wsi_display_connector *connector =
507 wsi_display_connector_from_handle(display);
508
509 VK_OUTARRAY_MAKE(conn, properties, property_count);
510
511 wsi_for_each_display_mode(display_mode, connector) {
512 if (display_mode->valid) {
513 vk_outarray_append(&conn, prop) {
514 prop->displayMode = wsi_display_mode_to_handle(display_mode);
515 prop->parameters.visibleRegion.width = display_mode->hdisplay;
516 prop->parameters.visibleRegion.height = display_mode->vdisplay;
517 prop->parameters.refreshRate =
518 (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
519 }
520 }
521 }
522 return vk_outarray_status(&conn);
523 }
524
525 static bool
526 wsi_display_mode_matches_vk(wsi_display_mode *wsi,
527 const VkDisplayModeParametersKHR *vk)
528 {
529 return (vk->visibleRegion.width == wsi->hdisplay &&
530 vk->visibleRegion.height == wsi->vdisplay &&
531 fabs(wsi_display_mode_refresh(wsi) * 1000.0 - vk->refreshRate) < 10);
532 }
533
534 /*
535 * Implement vkCreateDisplayModeKHR (VK_KHR_display)
536 */
537 VkResult
538 wsi_display_create_display_mode(VkPhysicalDevice physical_device,
539 struct wsi_device *wsi_device,
540 VkDisplayKHR display,
541 const VkDisplayModeCreateInfoKHR *create_info,
542 const VkAllocationCallbacks *allocator,
543 VkDisplayModeKHR *mode)
544 {
545 struct wsi_display_connector *connector =
546 wsi_display_connector_from_handle(display);
547
548 if (create_info->flags != 0)
549 return VK_ERROR_INITIALIZATION_FAILED;
550
551 /* Check and see if the requested mode happens to match an existing one and
552 * return that. This makes the conformance suite happy. Doing more than
553 * this would involve embedding the CVT function into the driver, which seems
554 * excessive.
555 */
556 wsi_for_each_display_mode(display_mode, connector) {
557 if (display_mode->valid) {
558 if (wsi_display_mode_matches_vk(display_mode, &create_info->parameters)) {
559 *mode = wsi_display_mode_to_handle(display_mode);
560 return VK_SUCCESS;
561 }
562 }
563 }
564 return VK_ERROR_INITIALIZATION_FAILED;
565 }
566
567 /*
568 * Implement vkGetDisplayPlaneCapabilities
569 */
570 VkResult
571 wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device,
572 struct wsi_device *wsi_device,
573 VkDisplayModeKHR mode_khr,
574 uint32_t plane_index,
575 VkDisplayPlaneCapabilitiesKHR *capabilities)
576 {
577 struct wsi_display_mode *mode = wsi_display_mode_from_handle(mode_khr);
578
579 /* XXX use actual values */
580 capabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
581 capabilities->minSrcPosition.x = 0;
582 capabilities->minSrcPosition.y = 0;
583 capabilities->maxSrcPosition.x = 0;
584 capabilities->maxSrcPosition.y = 0;
585 capabilities->minSrcExtent.width = mode->hdisplay;
586 capabilities->minSrcExtent.height = mode->vdisplay;
587 capabilities->maxSrcExtent.width = mode->hdisplay;
588 capabilities->maxSrcExtent.height = mode->vdisplay;
589 capabilities->minDstPosition.x = 0;
590 capabilities->minDstPosition.y = 0;
591 capabilities->maxDstPosition.x = 0;
592 capabilities->maxDstPosition.y = 0;
593 capabilities->minDstExtent.width = mode->hdisplay;
594 capabilities->minDstExtent.height = mode->vdisplay;
595 capabilities->maxDstExtent.width = mode->hdisplay;
596 capabilities->maxDstExtent.height = mode->vdisplay;
597 return VK_SUCCESS;
598 }
599
600 VkResult
601 wsi_create_display_surface(VkInstance instance,
602 const VkAllocationCallbacks *allocator,
603 const VkDisplaySurfaceCreateInfoKHR *create_info,
604 VkSurfaceKHR *surface_khr)
605 {
606 VkIcdSurfaceDisplay *surface = vk_zalloc(allocator, sizeof *surface, 8,
607 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
608
609 if (surface == NULL)
610 return VK_ERROR_OUT_OF_HOST_MEMORY;
611
612 surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY;
613
614 surface->displayMode = create_info->displayMode;
615 surface->planeIndex = create_info->planeIndex;
616 surface->planeStackIndex = create_info->planeStackIndex;
617 surface->transform = create_info->transform;
618 surface->globalAlpha = create_info->globalAlpha;
619 surface->alphaMode = create_info->alphaMode;
620 surface->imageExtent = create_info->imageExtent;
621
622 *surface_khr = VkIcdSurfaceBase_to_handle(&surface->base);
623 return VK_SUCCESS;
624 }
625
626
627 static VkResult
628 wsi_display_surface_get_support(VkIcdSurfaceBase *surface,
629 struct wsi_device *wsi_device,
630 const VkAllocationCallbacks *allocator,
631 uint32_t queueFamilyIndex,
632 int local_fd,
633 VkBool32* pSupported)
634 {
635 *pSupported = VK_TRUE;
636 return VK_SUCCESS;
637 }
638
639 static VkResult
640 wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base,
641 VkSurfaceCapabilitiesKHR* caps)
642 {
643 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
644 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
645
646 caps->currentExtent.width = mode->hdisplay;
647 caps->currentExtent.height = mode->vdisplay;
648
649 /* XXX Figure out extents based on driver capabilities */
650 caps->maxImageExtent = caps->minImageExtent = caps->currentExtent;
651
652 caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
653
654 caps->minImageCount = 2;
655 caps->maxImageCount = 0;
656
657 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
658 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
659 caps->maxImageArrayLayers = 1;
660 caps->supportedUsageFlags =
661 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
662 VK_IMAGE_USAGE_SAMPLED_BIT |
663 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
664 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
665
666 return VK_SUCCESS;
667 }
668
669 static VkResult
670 wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
671 const void *info_next,
672 VkSurfaceCapabilities2KHR *caps)
673 {
674 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
675
676 return wsi_display_surface_get_capabilities(icd_surface,
677 &caps->surfaceCapabilities);
678 }
679
680 static const struct {
681 VkFormat format;
682 uint32_t drm_format;
683 } available_surface_formats[] = {
684 { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 },
685 { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 },
686 };
687
688 static VkResult
689 wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
690 struct wsi_device *wsi_device,
691 uint32_t *surface_format_count,
692 VkSurfaceFormatKHR *surface_formats)
693 {
694 VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
695
696 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
697 vk_outarray_append(&out, f) {
698 f->format = available_surface_formats[i].format;
699 f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
700 }
701 }
702
703 return vk_outarray_status(&out);
704 }
705
706 static VkResult
707 wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
708 struct wsi_device *wsi_device,
709 const void *info_next,
710 uint32_t *surface_format_count,
711 VkSurfaceFormat2KHR *surface_formats)
712 {
713 VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
714
715 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
716 vk_outarray_append(&out, f) {
717 assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
718 f->surfaceFormat.format = available_surface_formats[i].format;
719 f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
720 }
721 }
722
723 return vk_outarray_status(&out);
724 }
725
726 static VkResult
727 wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface,
728 uint32_t *present_mode_count,
729 VkPresentModeKHR *present_modes)
730 {
731 VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count);
732
733 vk_outarray_append(&conn, present) {
734 *present = VK_PRESENT_MODE_FIFO_KHR;
735 }
736
737 return vk_outarray_status(&conn);
738 }
739
740 static void
741 wsi_display_destroy_buffer(struct wsi_display *wsi,
742 uint32_t buffer)
743 {
744 (void) drmIoctl(wsi->fd, DRM_IOCTL_MODE_DESTROY_DUMB,
745 &((struct drm_mode_destroy_dumb) { .handle = buffer }));
746 }
747
748 static VkResult
749 wsi_display_image_init(VkDevice device_h,
750 struct wsi_swapchain *drv_chain,
751 const VkSwapchainCreateInfoKHR *create_info,
752 const VkAllocationCallbacks *allocator,
753 struct wsi_display_image *image)
754 {
755 struct wsi_display_swapchain *chain =
756 (struct wsi_display_swapchain *) drv_chain;
757 struct wsi_display *wsi = chain->wsi;
758 uint32_t drm_format = 0;
759
760 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
761 if (create_info->imageFormat == available_surface_formats[i].format) {
762 drm_format = available_surface_formats[i].drm_format;
763 break;
764 }
765 }
766
767 /* the application provided an invalid format, bail */
768 if (drm_format == 0)
769 return VK_ERROR_DEVICE_LOST;
770
771 VkResult result = wsi_create_native_image(&chain->base, create_info,
772 0, NULL, NULL,
773 &image->base);
774 if (result != VK_SUCCESS)
775 return result;
776
777 memset(image->buffer, 0, sizeof (image->buffer));
778
779 for (unsigned int i = 0; i < image->base.num_planes; i++) {
780 int ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i],
781 &image->buffer[i]);
782
783 close(image->base.fds[i]);
784 image->base.fds[i] = -1;
785 if (ret < 0)
786 goto fail_handle;
787 }
788
789 image->chain = chain;
790 image->state = WSI_IMAGE_IDLE;
791 image->fb_id = 0;
792
793 int ret = drmModeAddFB2(wsi->fd,
794 create_info->imageExtent.width,
795 create_info->imageExtent.height,
796 drm_format,
797 image->buffer,
798 image->base.row_pitches,
799 image->base.offsets,
800 &image->fb_id, 0);
801
802 if (ret)
803 goto fail_fb;
804
805 return VK_SUCCESS;
806
807 fail_fb:
808 fail_handle:
809 for (unsigned int i = 0; i < image->base.num_planes; i++) {
810 if (image->buffer[i])
811 wsi_display_destroy_buffer(wsi, image->buffer[i]);
812 if (image->base.fds[i] != -1) {
813 close(image->base.fds[i]);
814 image->base.fds[i] = -1;
815 }
816 }
817
818 wsi_destroy_image(&chain->base, &image->base);
819
820 return VK_ERROR_OUT_OF_HOST_MEMORY;
821 }
822
823 static void
824 wsi_display_image_finish(struct wsi_swapchain *drv_chain,
825 const VkAllocationCallbacks *allocator,
826 struct wsi_display_image *image)
827 {
828 struct wsi_display_swapchain *chain =
829 (struct wsi_display_swapchain *) drv_chain;
830 struct wsi_display *wsi = chain->wsi;
831
832 drmModeRmFB(wsi->fd, image->fb_id);
833 for (unsigned int i = 0; i < image->base.num_planes; i++)
834 wsi_display_destroy_buffer(wsi, image->buffer[i]);
835 wsi_destroy_image(&chain->base, &image->base);
836 }
837
838 static VkResult
839 wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain,
840 const VkAllocationCallbacks *allocator)
841 {
842 struct wsi_display_swapchain *chain =
843 (struct wsi_display_swapchain *) drv_chain;
844
845 for (uint32_t i = 0; i < chain->base.image_count; i++)
846 wsi_display_image_finish(drv_chain, allocator, &chain->images[i]);
847 vk_free(allocator, chain);
848 return VK_SUCCESS;
849 }
850
851 static struct wsi_image *
852 wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain,
853 uint32_t image_index)
854 {
855 struct wsi_display_swapchain *chain =
856 (struct wsi_display_swapchain *) drv_chain;
857
858 return &chain->images[image_index].base;
859 }
860
861 static void
862 wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
863 {
864 struct wsi_display_swapchain *chain = active_image->chain;
865
866 wsi_display_debug("idle everyone but %ld\n",
867 active_image - &(chain->images[0]));
868 for (uint32_t i = 0; i < chain->base.image_count; i++)
869 if (chain->images[i].state == WSI_IMAGE_DISPLAYING &&
870 &chain->images[i] != active_image)
871 {
872 wsi_display_debug("idle %d\n", i);
873 chain->images[i].state = WSI_IMAGE_IDLE;
874 }
875 }
876
877 static VkResult
878 _wsi_display_queue_next(struct wsi_swapchain *drv_chain);
879
880 static void
881 wsi_display_page_flip_handler2(int fd,
882 unsigned int frame,
883 unsigned int sec,
884 unsigned int usec,
885 uint32_t crtc_id,
886 void *data)
887 {
888 struct wsi_display_image *image = data;
889 struct wsi_display_swapchain *chain = image->chain;
890
891 wsi_display_debug("image %ld displayed at %d\n",
892 image - &(image->chain->images[0]), frame);
893 image->state = WSI_IMAGE_DISPLAYING;
894 wsi_display_idle_old_displaying(image);
895 VkResult result = _wsi_display_queue_next(&(chain->base));
896 if (result != VK_SUCCESS)
897 chain->status = result;
898 }
899
900 static void wsi_display_page_flip_handler(int fd,
901 unsigned int frame,
902 unsigned int sec,
903 unsigned int usec,
904 void *data)
905 {
906 wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
907 }
908
909 static drmEventContext event_context = {
910 .version = DRM_EVENT_CONTEXT_VERSION,
911 .page_flip_handler = wsi_display_page_flip_handler,
912 #if DRM_EVENT_CONTEXT_VERSION >= 3
913 .page_flip_handler2 = wsi_display_page_flip_handler2,
914 #endif
915 };
916
917 static void *
918 wsi_display_wait_thread(void *data)
919 {
920 struct wsi_display *wsi = data;
921 struct pollfd pollfd = {
922 .fd = wsi->fd,
923 .events = POLLIN
924 };
925
926 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
927 for (;;) {
928 int ret = poll(&pollfd, 1, -1);
929 if (ret > 0) {
930 pthread_mutex_lock(&wsi->wait_mutex);
931 (void) drmHandleEvent(wsi->fd, &event_context);
932 pthread_mutex_unlock(&wsi->wait_mutex);
933 pthread_cond_broadcast(&wsi->wait_cond);
934 }
935 }
936 return NULL;
937 }
938
939 static int
940 wsi_display_start_wait_thread(struct wsi_display *wsi)
941 {
942 if (!wsi->wait_thread) {
943 int ret = pthread_create(&wsi->wait_thread, NULL,
944 wsi_display_wait_thread, wsi);
945 if (ret)
946 return ret;
947 }
948 return 0;
949 }
950
951 /*
952 * Wait for at least one event from the kernel to be processed.
953 * Call with wait_mutex held
954 */
955 static int
956 wsi_display_wait_for_event(struct wsi_display *wsi,
957 uint64_t timeout_ns)
958 {
959 int ret;
960
961 ret = wsi_display_start_wait_thread(wsi);
962
963 if (ret)
964 return ret;
965
966 struct timespec abs_timeout = {
967 .tv_sec = timeout_ns / 1000000000ULL,
968 .tv_nsec = timeout_ns % 1000000000ULL,
969 };
970
971 ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex,
972 &abs_timeout);
973
974 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);
975 return ret;
976 }
977
978 static VkResult
979 wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
980 uint64_t timeout,
981 VkSemaphore semaphore,
982 uint32_t *image_index)
983 {
984 struct wsi_display_swapchain *chain =
985 (struct wsi_display_swapchain *)drv_chain;
986 struct wsi_display *wsi = chain->wsi;
987 int ret = 0;
988 VkResult result = VK_SUCCESS;
989
990 /* Bail early if the swapchain is broken */
991 if (chain->status != VK_SUCCESS)
992 return chain->status;
993
994 if (timeout != 0 && timeout != UINT64_MAX)
995 timeout = wsi_rel_to_abs_time(timeout);
996
997 pthread_mutex_lock(&wsi->wait_mutex);
998 for (;;) {
999 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1000 if (chain->images[i].state == WSI_IMAGE_IDLE) {
1001 *image_index = i;
1002 wsi_display_debug("image %d available\n", i);
1003 chain->images[i].state = WSI_IMAGE_DRAWING;
1004 result = VK_SUCCESS;
1005 goto done;
1006 }
1007 wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
1008 }
1009
1010 if (ret == ETIMEDOUT) {
1011 result = VK_TIMEOUT;
1012 goto done;
1013 }
1014
1015 ret = wsi_display_wait_for_event(wsi, timeout);
1016
1017 if (ret && ret != ETIMEDOUT) {
1018 result = VK_ERROR_OUT_OF_DATE_KHR;
1019 goto done;
1020 }
1021 }
1022 done:
1023 pthread_mutex_unlock(&wsi->wait_mutex);
1024
1025 if (result != VK_SUCCESS)
1026 return result;
1027
1028 return chain->status;
1029 }
1030
1031 /*
1032 * Check whether there are any other connectors driven by this crtc
1033 */
1034 static bool
1035 wsi_display_crtc_solo(struct wsi_display *wsi,
1036 drmModeResPtr mode_res,
1037 drmModeConnectorPtr connector,
1038 uint32_t crtc_id)
1039 {
1040 /* See if any other connectors share the same encoder */
1041 for (int c = 0; c < mode_res->count_connectors; c++) {
1042 if (mode_res->connectors[c] == connector->connector_id)
1043 continue;
1044
1045 drmModeConnectorPtr other_connector =
1046 drmModeGetConnector(wsi->fd, mode_res->connectors[c]);
1047
1048 if (other_connector) {
1049 bool match = (other_connector->encoder_id == connector->encoder_id);
1050 drmModeFreeConnector(other_connector);
1051 if (match)
1052 return false;
1053 }
1054 }
1055
1056 /* See if any other encoders share the same crtc */
1057 for (int e = 0; e < mode_res->count_encoders; e++) {
1058 if (mode_res->encoders[e] == connector->encoder_id)
1059 continue;
1060
1061 drmModeEncoderPtr other_encoder =
1062 drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);
1063
1064 if (other_encoder) {
1065 bool match = (other_encoder->crtc_id == crtc_id);
1066 drmModeFreeEncoder(other_encoder);
1067 if (match)
1068 return false;
1069 }
1070 }
1071 return true;
1072 }
1073
1074 /*
1075 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1076 * currently driving this connector and not any others. Settle for a CRTC
1077 * which is currently idle.
1078 */
1079 static uint32_t
1080 wsi_display_select_crtc(struct wsi_display_connector *connector,
1081 drmModeResPtr mode_res,
1082 drmModeConnectorPtr drm_connector)
1083 {
1084 struct wsi_display *wsi = connector->wsi;
1085
1086 /* See what CRTC is currently driving this connector */
1087 if (drm_connector->encoder_id) {
1088 drmModeEncoderPtr encoder =
1089 drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);
1090
1091 if (encoder) {
1092 uint32_t crtc_id = encoder->crtc_id;
1093 drmModeFreeEncoder(encoder);
1094 if (crtc_id) {
1095 if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))
1096 return crtc_id;
1097 }
1098 }
1099 }
1100 uint32_t crtc_id = 0;
1101 for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
1102 drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
1103 if (crtc && crtc->buffer_id == 0)
1104 crtc_id = crtc->crtc_id;
1105 drmModeFreeCrtc(crtc);
1106 }
1107 return crtc_id;
1108 }
1109
1110 static VkResult
1111 wsi_display_setup_connector(wsi_display_connector *connector,
1112 wsi_display_mode *display_mode)
1113 {
1114 struct wsi_display *wsi = connector->wsi;
1115
1116 if (connector->current_mode == display_mode && connector->crtc_id)
1117 return VK_SUCCESS;
1118
1119 VkResult result = VK_SUCCESS;
1120
1121 drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
1122 if (!mode_res) {
1123 if (errno == ENOMEM)
1124 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1125 else
1126 result = VK_ERROR_OUT_OF_DATE_KHR;
1127 goto bail;
1128 }
1129
1130 drmModeConnectorPtr drm_connector =
1131 drmModeGetConnectorCurrent(wsi->fd, connector->id);
1132
1133 if (!drm_connector) {
1134 if (errno == ENOMEM)
1135 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1136 else
1137 result = VK_ERROR_OUT_OF_DATE_KHR;
1138 goto bail_mode_res;
1139 }
1140
1141 /* Pick a CRTC if we don't have one */
1142 if (!connector->crtc_id) {
1143 connector->crtc_id = wsi_display_select_crtc(connector,
1144 mode_res, drm_connector);
1145 if (!connector->crtc_id) {
1146 result = VK_ERROR_OUT_OF_DATE_KHR;
1147 goto bail_connector;
1148 }
1149 }
1150
1151 if (connector->current_mode != display_mode) {
1152
1153 /* Find the drm mode corresponding to the requested VkDisplayMode */
1154 drmModeModeInfoPtr drm_mode = NULL;
1155
1156 for (int m = 0; m < drm_connector->count_modes; m++) {
1157 drm_mode = &drm_connector->modes[m];
1158 if (wsi_display_mode_matches_drm(display_mode, drm_mode))
1159 break;
1160 drm_mode = NULL;
1161 }
1162
1163 if (!drm_mode) {
1164 result = VK_ERROR_OUT_OF_DATE_KHR;
1165 goto bail_connector;
1166 }
1167
1168 connector->current_mode = display_mode;
1169 connector->current_drm_mode = *drm_mode;
1170 }
1171
1172 bail_connector:
1173 drmModeFreeConnector(drm_connector);
1174 bail_mode_res:
1175 drmModeFreeResources(mode_res);
1176 bail:
1177 return result;
1178
1179 }
1180
1181 /*
1182 * Check to see if the kernel has no flip queued and if there's an image
1183 * waiting to be displayed.
1184 */
1185 static VkResult
1186 _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
1187 {
1188 struct wsi_display_swapchain *chain =
1189 (struct wsi_display_swapchain *) drv_chain;
1190 struct wsi_display *wsi = chain->wsi;
1191 VkIcdSurfaceDisplay *surface = chain->surface;
1192 wsi_display_mode *display_mode =
1193 wsi_display_mode_from_handle(surface->displayMode);
1194 wsi_display_connector *connector = display_mode->connector;
1195
1196 if (wsi->fd < 0)
1197 return VK_ERROR_OUT_OF_DATE_KHR;
1198
1199 if (display_mode != connector->current_mode)
1200 connector->active = false;
1201
1202 for (;;) {
1203
1204 /* Check to see if there is an image to display, or if some image is
1205 * already queued */
1206
1207 struct wsi_display_image *image = NULL;
1208
1209 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1210 struct wsi_display_image *tmp_image = &chain->images[i];
1211
1212 switch (tmp_image->state) {
1213 case WSI_IMAGE_FLIPPING:
1214 /* already flipping, don't send another to the kernel yet */
1215 return VK_SUCCESS;
1216 case WSI_IMAGE_QUEUED:
1217 /* find the oldest queued */
1218 if (!image || tmp_image->flip_sequence < image->flip_sequence)
1219 image = tmp_image;
1220 break;
1221 default:
1222 break;
1223 }
1224 }
1225
1226 if (!image)
1227 return VK_SUCCESS;
1228
1229 int ret;
1230 if (connector->active) {
1231 ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
1232 DRM_MODE_PAGE_FLIP_EVENT, image);
1233 if (ret == 0) {
1234 image->state = WSI_IMAGE_FLIPPING;
1235 return VK_SUCCESS;
1236 }
1237 wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
1238 } else {
1239 ret = -EINVAL;
1240 }
1241
1242 if (ret == -EINVAL) {
1243 VkResult result = wsi_display_setup_connector(connector, display_mode);
1244
1245 if (result != VK_SUCCESS) {
1246 image->state = WSI_IMAGE_IDLE;
1247 return result;
1248 }
1249
1250 /* XXX allow setting of position */
1251 ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
1252 image->fb_id, 0, 0,
1253 &connector->id, 1,
1254 &connector->current_drm_mode);
1255 if (ret == 0) {
1256 /* Assume that the mode set is synchronous and that any
1257 * previous image is now idle.
1258 */
1259 image->state = WSI_IMAGE_DISPLAYING;
1260 wsi_display_idle_old_displaying(image);
1261 connector->active = true;
1262 return VK_SUCCESS;
1263 }
1264 }
1265
1266 if (ret != -EACCES) {
1267 connector->active = false;
1268 image->state = WSI_IMAGE_IDLE;
1269 return VK_ERROR_OUT_OF_DATE_KHR;
1270 }
1271
1272 /* Some other VT is currently active. Sit here waiting for
1273 * our VT to become active again by polling once a second
1274 */
1275 usleep(1000 * 1000);
1276 connector->active = false;
1277 }
1278 }
1279
1280 static VkResult
1281 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
1282 uint32_t image_index,
1283 const VkPresentRegionKHR *damage)
1284 {
1285 struct wsi_display_swapchain *chain =
1286 (struct wsi_display_swapchain *) drv_chain;
1287 struct wsi_display *wsi = chain->wsi;
1288 struct wsi_display_image *image = &chain->images[image_index];
1289 VkResult result;
1290
1291 /* Bail early if the swapchain is broken */
1292 if (chain->status != VK_SUCCESS)
1293 return chain->status;
1294
1295 assert(image->state == WSI_IMAGE_DRAWING);
1296 wsi_display_debug("present %d\n", image_index);
1297
1298 pthread_mutex_lock(&wsi->wait_mutex);
1299
1300 image->flip_sequence = ++chain->flip_sequence;
1301 image->state = WSI_IMAGE_QUEUED;
1302
1303 result = _wsi_display_queue_next(drv_chain);
1304 if (result != VK_SUCCESS)
1305 chain->status = result;
1306
1307 pthread_mutex_unlock(&wsi->wait_mutex);
1308
1309 if (result != VK_SUCCESS)
1310 return result;
1311
1312 return chain->status;
1313 }
1314
1315 static VkResult
1316 wsi_display_surface_create_swapchain(
1317 VkIcdSurfaceBase *icd_surface,
1318 VkDevice device,
1319 struct wsi_device *wsi_device,
1320 int local_fd,
1321 const VkSwapchainCreateInfoKHR *create_info,
1322 const VkAllocationCallbacks *allocator,
1323 struct wsi_swapchain **swapchain_out)
1324 {
1325 struct wsi_display *wsi =
1326 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1327
1328 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1329
1330 const unsigned num_images = create_info->minImageCount;
1331 struct wsi_display_swapchain *chain =
1332 vk_zalloc(allocator,
1333 sizeof(*chain) + num_images * sizeof(chain->images[0]),
1334 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1335
1336 if (chain == NULL)
1337 return VK_ERROR_OUT_OF_HOST_MEMORY;
1338
1339 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
1340 create_info, allocator);
1341
1342 chain->base.destroy = wsi_display_swapchain_destroy;
1343 chain->base.get_wsi_image = wsi_display_get_wsi_image;
1344 chain->base.acquire_next_image = wsi_display_acquire_next_image;
1345 chain->base.queue_present = wsi_display_queue_present;
1346 chain->base.present_mode = create_info->presentMode;
1347 chain->base.image_count = num_images;
1348
1349 chain->wsi = wsi;
1350 chain->status = VK_SUCCESS;
1351
1352 chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
1353
1354 for (uint32_t image = 0; image < chain->base.image_count; image++) {
1355 result = wsi_display_image_init(device, &chain->base,
1356 create_info, allocator,
1357 &chain->images[image]);
1358 if (result != VK_SUCCESS) {
1359 while (image > 0) {
1360 --image;
1361 wsi_display_image_finish(&chain->base, allocator,
1362 &chain->images[image]);
1363 }
1364 vk_free(allocator, chain);
1365 goto fail_init_images;
1366 }
1367 }
1368
1369 *swapchain_out = &chain->base;
1370
1371 return VK_SUCCESS;
1372
1373 fail_init_images:
1374 return result;
1375 }
1376
1377 static bool
1378 wsi_init_pthread_cond_monotonic(pthread_cond_t *cond)
1379 {
1380 pthread_condattr_t condattr;
1381 bool ret = false;
1382
1383 if (pthread_condattr_init(&condattr) != 0)
1384 goto fail_attr_init;
1385
1386 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0)
1387 goto fail_attr_set;
1388
1389 if (pthread_cond_init(cond, &condattr) != 0)
1390 goto fail_cond_init;
1391
1392 ret = true;
1393
1394 fail_cond_init:
1395 fail_attr_set:
1396 pthread_condattr_destroy(&condattr);
1397 fail_attr_init:
1398 return ret;
1399 }
1400
1401 VkResult
1402 wsi_display_init_wsi(struct wsi_device *wsi_device,
1403 const VkAllocationCallbacks *alloc,
1404 int display_fd)
1405 {
1406 struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
1407 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1408 VkResult result;
1409
1410 if (!wsi) {
1411 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1412 goto fail;
1413 }
1414
1415 wsi->fd = display_fd;
1416 wsi->alloc = alloc;
1417
1418 list_inithead(&wsi->connectors);
1419
1420 int ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
1421 if (ret) {
1422 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1423 goto fail_mutex;
1424 }
1425
1426 if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) {
1427 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1428 goto fail_cond;
1429 }
1430
1431 wsi->base.get_support = wsi_display_surface_get_support;
1432 wsi->base.get_capabilities = wsi_display_surface_get_capabilities;
1433 wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
1434 wsi->base.get_formats = wsi_display_surface_get_formats;
1435 wsi->base.get_formats2 = wsi_display_surface_get_formats2;
1436 wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
1437 wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
1438
1439 wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
1440
1441 return VK_SUCCESS;
1442
1443 fail_cond:
1444 pthread_mutex_destroy(&wsi->wait_mutex);
1445 fail_mutex:
1446 vk_free(alloc, wsi);
1447 fail:
1448 return result;
1449 }
1450
1451 void
1452 wsi_display_finish_wsi(struct wsi_device *wsi_device,
1453 const VkAllocationCallbacks *alloc)
1454 {
1455 struct wsi_display *wsi =
1456 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1457
1458 if (wsi) {
1459 wsi_for_each_connector(connector, wsi) {
1460 wsi_for_each_display_mode(mode, connector) {
1461 vk_free(wsi->alloc, mode);
1462 }
1463 vk_free(wsi->alloc, connector);
1464 }
1465
1466 pthread_mutex_lock(&wsi->wait_mutex);
1467 if (wsi->wait_thread) {
1468 pthread_cancel(wsi->wait_thread);
1469 pthread_join(wsi->wait_thread, NULL);
1470 }
1471 pthread_mutex_unlock(&wsi->wait_mutex);
1472 pthread_mutex_destroy(&wsi->wait_mutex);
1473 pthread_cond_destroy(&wsi->wait_cond);
1474
1475 vk_free(alloc, wsi);
1476 }
1477 }