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