0f9a1ffe8d3af271f0ee5848e1c6090b75efc6b1
[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 /*
1232 * Wait for at least one event from the kernel to be processed.
1233 * Call with wait_mutex held
1234 */
1235 static int
1236 wsi_display_wait_for_event(struct wsi_display *wsi,
1237 uint64_t timeout_ns)
1238 {
1239 int ret;
1240
1241 ret = wsi_display_start_wait_thread(wsi);
1242
1243 if (ret)
1244 return ret;
1245
1246 struct timespec abs_timeout = {
1247 .tv_sec = timeout_ns / 1000000000ULL,
1248 .tv_nsec = timeout_ns % 1000000000ULL,
1249 };
1250
1251 ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex,
1252 &abs_timeout);
1253
1254 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);
1255 return ret;
1256 }
1257
1258 static VkResult
1259 wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
1260 const VkAcquireNextImageInfoKHR *info,
1261 uint32_t *image_index)
1262 {
1263 struct wsi_display_swapchain *chain =
1264 (struct wsi_display_swapchain *)drv_chain;
1265 struct wsi_display *wsi = chain->wsi;
1266 int ret = 0;
1267 VkResult result = VK_SUCCESS;
1268
1269 /* Bail early if the swapchain is broken */
1270 if (chain->status != VK_SUCCESS)
1271 return chain->status;
1272
1273 uint64_t timeout = info->timeout;
1274 if (timeout != 0 && timeout != UINT64_MAX)
1275 timeout = wsi_rel_to_abs_time(timeout);
1276
1277 pthread_mutex_lock(&wsi->wait_mutex);
1278 for (;;) {
1279 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1280 if (chain->images[i].state == WSI_IMAGE_IDLE) {
1281 *image_index = i;
1282 wsi_display_debug("image %d available\n", i);
1283 chain->images[i].state = WSI_IMAGE_DRAWING;
1284 result = VK_SUCCESS;
1285 goto done;
1286 }
1287 wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
1288 }
1289
1290 if (ret == ETIMEDOUT) {
1291 result = VK_TIMEOUT;
1292 goto done;
1293 }
1294
1295 ret = wsi_display_wait_for_event(wsi, timeout);
1296
1297 if (ret && ret != ETIMEDOUT) {
1298 result = VK_ERROR_SURFACE_LOST_KHR;
1299 goto done;
1300 }
1301 }
1302 done:
1303 pthread_mutex_unlock(&wsi->wait_mutex);
1304
1305 if (result != VK_SUCCESS)
1306 return result;
1307
1308 return chain->status;
1309 }
1310
1311 /*
1312 * Check whether there are any other connectors driven by this crtc
1313 */
1314 static bool
1315 wsi_display_crtc_solo(struct wsi_display *wsi,
1316 drmModeResPtr mode_res,
1317 drmModeConnectorPtr connector,
1318 uint32_t crtc_id)
1319 {
1320 /* See if any other connectors share the same encoder */
1321 for (int c = 0; c < mode_res->count_connectors; c++) {
1322 if (mode_res->connectors[c] == connector->connector_id)
1323 continue;
1324
1325 drmModeConnectorPtr other_connector =
1326 drmModeGetConnector(wsi->fd, mode_res->connectors[c]);
1327
1328 if (other_connector) {
1329 bool match = (other_connector->encoder_id == connector->encoder_id);
1330 drmModeFreeConnector(other_connector);
1331 if (match)
1332 return false;
1333 }
1334 }
1335
1336 /* See if any other encoders share the same crtc */
1337 for (int e = 0; e < mode_res->count_encoders; e++) {
1338 if (mode_res->encoders[e] == connector->encoder_id)
1339 continue;
1340
1341 drmModeEncoderPtr other_encoder =
1342 drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);
1343
1344 if (other_encoder) {
1345 bool match = (other_encoder->crtc_id == crtc_id);
1346 drmModeFreeEncoder(other_encoder);
1347 if (match)
1348 return false;
1349 }
1350 }
1351 return true;
1352 }
1353
1354 /*
1355 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1356 * currently driving this connector and not any others. Settle for a CRTC
1357 * which is currently idle.
1358 */
1359 static uint32_t
1360 wsi_display_select_crtc(const struct wsi_display_connector *connector,
1361 drmModeResPtr mode_res,
1362 drmModeConnectorPtr drm_connector)
1363 {
1364 struct wsi_display *wsi = connector->wsi;
1365
1366 /* See what CRTC is currently driving this connector */
1367 if (drm_connector->encoder_id) {
1368 drmModeEncoderPtr encoder =
1369 drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);
1370
1371 if (encoder) {
1372 uint32_t crtc_id = encoder->crtc_id;
1373 drmModeFreeEncoder(encoder);
1374 if (crtc_id) {
1375 if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))
1376 return crtc_id;
1377 }
1378 }
1379 }
1380 uint32_t crtc_id = 0;
1381 for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
1382 drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
1383 if (crtc && crtc->buffer_id == 0)
1384 crtc_id = crtc->crtc_id;
1385 drmModeFreeCrtc(crtc);
1386 }
1387 return crtc_id;
1388 }
1389
1390 static VkResult
1391 wsi_display_setup_connector(wsi_display_connector *connector,
1392 wsi_display_mode *display_mode)
1393 {
1394 struct wsi_display *wsi = connector->wsi;
1395
1396 if (connector->current_mode == display_mode && connector->crtc_id)
1397 return VK_SUCCESS;
1398
1399 VkResult result = VK_SUCCESS;
1400
1401 drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
1402 if (!mode_res) {
1403 if (errno == ENOMEM)
1404 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1405 else
1406 result = VK_ERROR_SURFACE_LOST_KHR;
1407 goto bail;
1408 }
1409
1410 drmModeConnectorPtr drm_connector =
1411 drmModeGetConnectorCurrent(wsi->fd, connector->id);
1412
1413 if (!drm_connector) {
1414 if (errno == ENOMEM)
1415 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1416 else
1417 result = VK_ERROR_SURFACE_LOST_KHR;
1418 goto bail_mode_res;
1419 }
1420
1421 /* Pick a CRTC if we don't have one */
1422 if (!connector->crtc_id) {
1423 connector->crtc_id = wsi_display_select_crtc(connector,
1424 mode_res, drm_connector);
1425 if (!connector->crtc_id) {
1426 result = VK_ERROR_SURFACE_LOST_KHR;
1427 goto bail_connector;
1428 }
1429 }
1430
1431 if (connector->current_mode != display_mode) {
1432
1433 /* Find the drm mode corresponding to the requested VkDisplayMode */
1434 drmModeModeInfoPtr drm_mode = NULL;
1435
1436 for (int m = 0; m < drm_connector->count_modes; m++) {
1437 drm_mode = &drm_connector->modes[m];
1438 if (wsi_display_mode_matches_drm(display_mode, drm_mode))
1439 break;
1440 drm_mode = NULL;
1441 }
1442
1443 if (!drm_mode) {
1444 result = VK_ERROR_SURFACE_LOST_KHR;
1445 goto bail_connector;
1446 }
1447
1448 connector->current_mode = display_mode;
1449 connector->current_drm_mode = *drm_mode;
1450 }
1451
1452 bail_connector:
1453 drmModeFreeConnector(drm_connector);
1454 bail_mode_res:
1455 drmModeFreeResources(mode_res);
1456 bail:
1457 return result;
1458
1459 }
1460
1461 static VkResult
1462 wsi_display_fence_wait(struct wsi_fence *fence_wsi, uint64_t timeout)
1463 {
1464 const struct wsi_device *wsi_device = fence_wsi->wsi_device;
1465 struct wsi_display *wsi =
1466 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1467 struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
1468
1469 wsi_display_debug("%9lu wait fence %lu %ld\n",
1470 pthread_self(), fence->sequence,
1471 (int64_t) (timeout - wsi_common_get_current_time()));
1472 wsi_display_debug_code(uint64_t start_ns = wsi_common_get_current_time());
1473 pthread_mutex_lock(&wsi->wait_mutex);
1474
1475 VkResult result;
1476 int ret = 0;
1477 for (;;) {
1478 if (fence->event_received) {
1479 wsi_display_debug("%9lu fence %lu passed\n",
1480 pthread_self(), fence->sequence);
1481 result = VK_SUCCESS;
1482 break;
1483 }
1484
1485 if (ret == ETIMEDOUT) {
1486 wsi_display_debug("%9lu fence %lu timeout\n",
1487 pthread_self(), fence->sequence);
1488 result = VK_TIMEOUT;
1489 break;
1490 }
1491
1492 ret = wsi_display_wait_for_event(wsi, timeout);
1493
1494 if (ret && ret != ETIMEDOUT) {
1495 wsi_display_debug("%9lu fence %lu error\n",
1496 pthread_self(), fence->sequence);
1497 result = VK_ERROR_DEVICE_LOST;
1498 break;
1499 }
1500 }
1501 pthread_mutex_unlock(&wsi->wait_mutex);
1502 wsi_display_debug("%9lu fence wait %f ms\n",
1503 pthread_self(),
1504 ((int64_t) (wsi_common_get_current_time() - start_ns)) /
1505 1.0e6);
1506 return result;
1507 }
1508
1509 static void
1510 wsi_display_fence_check_free(struct wsi_display_fence *fence)
1511 {
1512 if (fence->event_received && fence->destroyed)
1513 vk_free(fence->base.alloc, fence);
1514 }
1515
1516 static void wsi_display_fence_event_handler(struct wsi_display_fence *fence)
1517 {
1518 fence->event_received = true;
1519 wsi_display_fence_check_free(fence);
1520 }
1521
1522 static void
1523 wsi_display_fence_destroy(struct wsi_fence *fence_wsi)
1524 {
1525 struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
1526
1527 assert(!fence->destroyed);
1528 fence->destroyed = true;
1529 wsi_display_fence_check_free(fence);
1530 }
1531
1532 static struct wsi_display_fence *
1533 wsi_display_fence_alloc(VkDevice device,
1534 const struct wsi_device *wsi_device,
1535 VkDisplayKHR display,
1536 const VkAllocationCallbacks *allocator)
1537 {
1538 struct wsi_display *wsi =
1539 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1540 struct wsi_display_fence *fence =
1541 vk_zalloc2(wsi->alloc, allocator, sizeof (*fence),
1542 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1543
1544 if (!fence)
1545 return NULL;
1546
1547 fence->base.device = device;
1548 fence->base.display = display;
1549 fence->base.wsi_device = wsi_device;
1550 fence->base.alloc = allocator ? allocator : wsi->alloc;
1551 fence->base.wait = wsi_display_fence_wait;
1552 fence->base.destroy = wsi_display_fence_destroy;
1553 fence->event_received = false;
1554 fence->destroyed = false;
1555 fence->sequence = ++fence_sequence;
1556 return fence;
1557 }
1558
1559 static VkResult
1560 wsi_register_vblank_event(struct wsi_display_fence *fence,
1561 const struct wsi_device *wsi_device,
1562 VkDisplayKHR display,
1563 uint32_t flags,
1564 uint64_t frame_requested,
1565 uint64_t *frame_queued)
1566 {
1567 struct wsi_display *wsi =
1568 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1569 struct wsi_display_connector *connector =
1570 wsi_display_connector_from_handle(display);
1571
1572 if (wsi->fd < 0)
1573 return VK_ERROR_INITIALIZATION_FAILED;
1574
1575 for (;;) {
1576 int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id,
1577 flags,
1578 frame_requested,
1579 frame_queued,
1580 (uintptr_t) fence);
1581
1582 if (!ret)
1583 return VK_SUCCESS;
1584
1585 if (errno != ENOMEM) {
1586
1587 /* Something unexpected happened. Pause for a moment so the
1588 * application doesn't just spin and then return a failure indication
1589 */
1590
1591 wsi_display_debug("queue vblank event %lu failed\n", fence->sequence);
1592 struct timespec delay = {
1593 .tv_sec = 0,
1594 .tv_nsec = 100000000ull,
1595 };
1596 nanosleep(&delay, NULL);
1597 return VK_ERROR_OUT_OF_HOST_MEMORY;
1598 }
1599
1600 /* The kernel event queue is full. Wait for some events to be
1601 * processed and try again
1602 */
1603
1604 pthread_mutex_lock(&wsi->wait_mutex);
1605 ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull));
1606 pthread_mutex_unlock(&wsi->wait_mutex);
1607
1608 if (ret) {
1609 wsi_display_debug("vblank queue full, event wait failed\n");
1610 return VK_ERROR_OUT_OF_HOST_MEMORY;
1611 }
1612 }
1613 }
1614
1615 /*
1616 * Check to see if the kernel has no flip queued and if there's an image
1617 * waiting to be displayed.
1618 */
1619 static VkResult
1620 _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
1621 {
1622 struct wsi_display_swapchain *chain =
1623 (struct wsi_display_swapchain *) drv_chain;
1624 struct wsi_display *wsi = chain->wsi;
1625 VkIcdSurfaceDisplay *surface = chain->surface;
1626 wsi_display_mode *display_mode =
1627 wsi_display_mode_from_handle(surface->displayMode);
1628 wsi_display_connector *connector = display_mode->connector;
1629
1630 if (wsi->fd < 0)
1631 return VK_ERROR_SURFACE_LOST_KHR;
1632
1633 if (display_mode != connector->current_mode)
1634 connector->active = false;
1635
1636 for (;;) {
1637
1638 /* Check to see if there is an image to display, or if some image is
1639 * already queued */
1640
1641 struct wsi_display_image *image = NULL;
1642
1643 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1644 struct wsi_display_image *tmp_image = &chain->images[i];
1645
1646 switch (tmp_image->state) {
1647 case WSI_IMAGE_FLIPPING:
1648 /* already flipping, don't send another to the kernel yet */
1649 return VK_SUCCESS;
1650 case WSI_IMAGE_QUEUED:
1651 /* find the oldest queued */
1652 if (!image || tmp_image->flip_sequence < image->flip_sequence)
1653 image = tmp_image;
1654 break;
1655 default:
1656 break;
1657 }
1658 }
1659
1660 if (!image)
1661 return VK_SUCCESS;
1662
1663 int ret;
1664 if (connector->active) {
1665 ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
1666 DRM_MODE_PAGE_FLIP_EVENT, image);
1667 if (ret == 0) {
1668 image->state = WSI_IMAGE_FLIPPING;
1669 return VK_SUCCESS;
1670 }
1671 wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
1672 } else {
1673 ret = -EINVAL;
1674 }
1675
1676 if (ret == -EINVAL) {
1677 VkResult result = wsi_display_setup_connector(connector, display_mode);
1678
1679 if (result != VK_SUCCESS) {
1680 image->state = WSI_IMAGE_IDLE;
1681 return result;
1682 }
1683
1684 /* XXX allow setting of position */
1685 ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
1686 image->fb_id, 0, 0,
1687 &connector->id, 1,
1688 &connector->current_drm_mode);
1689 if (ret == 0) {
1690 /* Disable the HW cursor as the app doesn't have a mechanism
1691 * to control it.
1692 * Refer to question 12 of the VK_KHR_display spec.
1693 */
1694 ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 );
1695 if (ret != 0) {
1696 wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret));
1697 }
1698
1699 /* Assume that the mode set is synchronous and that any
1700 * previous image is now idle.
1701 */
1702 image->state = WSI_IMAGE_DISPLAYING;
1703 wsi_display_idle_old_displaying(image);
1704 connector->active = true;
1705 return VK_SUCCESS;
1706 }
1707 }
1708
1709 if (ret != -EACCES) {
1710 connector->active = false;
1711 image->state = WSI_IMAGE_IDLE;
1712 return VK_ERROR_SURFACE_LOST_KHR;
1713 }
1714
1715 /* Some other VT is currently active. Sit here waiting for
1716 * our VT to become active again by polling once a second
1717 */
1718 usleep(1000 * 1000);
1719 connector->active = false;
1720 }
1721 }
1722
1723 static VkResult
1724 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
1725 uint32_t image_index,
1726 const VkPresentRegionKHR *damage)
1727 {
1728 struct wsi_display_swapchain *chain =
1729 (struct wsi_display_swapchain *) drv_chain;
1730 struct wsi_display *wsi = chain->wsi;
1731 struct wsi_display_image *image = &chain->images[image_index];
1732 VkResult result;
1733
1734 /* Bail early if the swapchain is broken */
1735 if (chain->status != VK_SUCCESS)
1736 return chain->status;
1737
1738 assert(image->state == WSI_IMAGE_DRAWING);
1739 wsi_display_debug("present %d\n", image_index);
1740
1741 pthread_mutex_lock(&wsi->wait_mutex);
1742
1743 image->flip_sequence = ++chain->flip_sequence;
1744 image->state = WSI_IMAGE_QUEUED;
1745
1746 result = _wsi_display_queue_next(drv_chain);
1747 if (result != VK_SUCCESS)
1748 chain->status = result;
1749
1750 pthread_mutex_unlock(&wsi->wait_mutex);
1751
1752 if (result != VK_SUCCESS)
1753 return result;
1754
1755 return chain->status;
1756 }
1757
1758 static VkResult
1759 wsi_display_surface_create_swapchain(
1760 VkIcdSurfaceBase *icd_surface,
1761 VkDevice device,
1762 struct wsi_device *wsi_device,
1763 const VkSwapchainCreateInfoKHR *create_info,
1764 const VkAllocationCallbacks *allocator,
1765 struct wsi_swapchain **swapchain_out)
1766 {
1767 struct wsi_display *wsi =
1768 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1769
1770 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1771
1772 const unsigned num_images = create_info->minImageCount;
1773 struct wsi_display_swapchain *chain =
1774 vk_zalloc(allocator,
1775 sizeof(*chain) + num_images * sizeof(chain->images[0]),
1776 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1777
1778 if (chain == NULL)
1779 return VK_ERROR_OUT_OF_HOST_MEMORY;
1780
1781 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
1782 create_info, allocator);
1783 if (result != VK_SUCCESS) {
1784 vk_free(allocator, chain);
1785 return result;
1786 }
1787
1788 chain->base.destroy = wsi_display_swapchain_destroy;
1789 chain->base.get_wsi_image = wsi_display_get_wsi_image;
1790 chain->base.acquire_next_image = wsi_display_acquire_next_image;
1791 chain->base.queue_present = wsi_display_queue_present;
1792 chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
1793 chain->base.image_count = num_images;
1794
1795 chain->wsi = wsi;
1796 chain->status = VK_SUCCESS;
1797
1798 chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
1799
1800 for (uint32_t image = 0; image < chain->base.image_count; image++) {
1801 result = wsi_display_image_init(device, &chain->base,
1802 create_info, allocator,
1803 &chain->images[image]);
1804 if (result != VK_SUCCESS) {
1805 while (image > 0) {
1806 --image;
1807 wsi_display_image_finish(&chain->base, allocator,
1808 &chain->images[image]);
1809 }
1810 vk_free(allocator, chain);
1811 goto fail_init_images;
1812 }
1813 }
1814
1815 *swapchain_out = &chain->base;
1816
1817 return VK_SUCCESS;
1818
1819 fail_init_images:
1820 return result;
1821 }
1822
1823 static bool
1824 wsi_init_pthread_cond_monotonic(pthread_cond_t *cond)
1825 {
1826 pthread_condattr_t condattr;
1827 bool ret = false;
1828
1829 if (pthread_condattr_init(&condattr) != 0)
1830 goto fail_attr_init;
1831
1832 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0)
1833 goto fail_attr_set;
1834
1835 if (pthread_cond_init(cond, &condattr) != 0)
1836 goto fail_cond_init;
1837
1838 ret = true;
1839
1840 fail_cond_init:
1841 fail_attr_set:
1842 pthread_condattr_destroy(&condattr);
1843 fail_attr_init:
1844 return ret;
1845 }
1846
1847
1848 /*
1849 * Local version fo the libdrm helper. Added to avoid depending on bleeding
1850 * edge version of the library.
1851 */
1852 static int
1853 local_drmIsMaster(int fd)
1854 {
1855 /* Detect master by attempting something that requires master.
1856 *
1857 * Authenticating magic tokens requires master and 0 is an
1858 * internal kernel detail which we could use. Attempting this on
1859 * a master fd would fail therefore fail with EINVAL because 0
1860 * is invalid.
1861 *
1862 * A non-master fd will fail with EACCES, as the kernel checks
1863 * for master before attempting to do anything else.
1864 *
1865 * Since we don't want to leak implementation details, use
1866 * EACCES.
1867 */
1868 return drmAuthMagic(fd, 0) != -EACCES;
1869 }
1870
1871 VkResult
1872 wsi_display_init_wsi(struct wsi_device *wsi_device,
1873 const VkAllocationCallbacks *alloc,
1874 int display_fd)
1875 {
1876 struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
1877 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1878 VkResult result;
1879
1880 if (!wsi) {
1881 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1882 goto fail;
1883 }
1884
1885 wsi->fd = display_fd;
1886 if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
1887 wsi->fd = -1;
1888
1889 wsi->alloc = alloc;
1890
1891 list_inithead(&wsi->connectors);
1892
1893 int ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
1894 if (ret) {
1895 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1896 goto fail_mutex;
1897 }
1898
1899 if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) {
1900 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1901 goto fail_cond;
1902 }
1903
1904 wsi->base.get_support = wsi_display_surface_get_support;
1905 wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
1906 wsi->base.get_formats = wsi_display_surface_get_formats;
1907 wsi->base.get_formats2 = wsi_display_surface_get_formats2;
1908 wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
1909 wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
1910 wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
1911
1912 wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
1913
1914 return VK_SUCCESS;
1915
1916 fail_cond:
1917 pthread_mutex_destroy(&wsi->wait_mutex);
1918 fail_mutex:
1919 vk_free(alloc, wsi);
1920 fail:
1921 return result;
1922 }
1923
1924 void
1925 wsi_display_finish_wsi(struct wsi_device *wsi_device,
1926 const VkAllocationCallbacks *alloc)
1927 {
1928 struct wsi_display *wsi =
1929 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1930
1931 if (wsi) {
1932 wsi_for_each_connector(connector, wsi) {
1933 wsi_for_each_display_mode(mode, connector) {
1934 vk_free(wsi->alloc, mode);
1935 }
1936 vk_free(wsi->alloc, connector);
1937 }
1938
1939 pthread_mutex_lock(&wsi->wait_mutex);
1940 if (wsi->wait_thread) {
1941 pthread_cancel(wsi->wait_thread);
1942 pthread_join(wsi->wait_thread, NULL);
1943 }
1944 pthread_mutex_unlock(&wsi->wait_mutex);
1945 pthread_mutex_destroy(&wsi->wait_mutex);
1946 pthread_cond_destroy(&wsi->wait_cond);
1947
1948 vk_free(alloc, wsi);
1949 }
1950 }
1951
1952 /*
1953 * Implement vkReleaseDisplay
1954 */
1955 VkResult
1956 wsi_release_display(VkPhysicalDevice physical_device,
1957 struct wsi_device *wsi_device,
1958 VkDisplayKHR display)
1959 {
1960 struct wsi_display *wsi =
1961 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1962
1963 if (wsi->fd >= 0) {
1964 close(wsi->fd);
1965 wsi->fd = -1;
1966 }
1967 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1968 wsi_display_connector_from_handle(display)->output = None;
1969 #endif
1970
1971 return VK_SUCCESS;
1972 }
1973
1974 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1975
1976 static struct wsi_display_connector *
1977 wsi_display_find_output(struct wsi_device *wsi_device,
1978 xcb_randr_output_t output)
1979 {
1980 struct wsi_display *wsi =
1981 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1982
1983 wsi_for_each_connector(connector, wsi) {
1984 if (connector->output == output)
1985 return connector;
1986 }
1987
1988 return NULL;
1989 }
1990
1991 /*
1992 * Given a RandR output, find the associated kernel connector_id by
1993 * looking at the CONNECTOR_ID property provided by the X server
1994 */
1995
1996 static uint32_t
1997 wsi_display_output_to_connector_id(xcb_connection_t *connection,
1998 xcb_atom_t *connector_id_atom_p,
1999 xcb_randr_output_t output)
2000 {
2001 uint32_t connector_id = 0;
2002 xcb_atom_t connector_id_atom = *connector_id_atom_p;
2003
2004 if (connector_id_atom == 0) {
2005 /* Go dig out the CONNECTOR_ID property */
2006 xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
2007 true,
2008 12,
2009 "CONNECTOR_ID");
2010 xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
2011 ia_c,
2012 NULL);
2013 if (ia_r) {
2014 *connector_id_atom_p = connector_id_atom = ia_r->atom;
2015 free(ia_r);
2016 }
2017 }
2018
2019 /* If there's an CONNECTOR_ID atom in the server, then there may be a
2020 * CONNECTOR_ID property. Otherwise, there will not be and we don't even
2021 * need to bother.
2022 */
2023 if (connector_id_atom) {
2024
2025 xcb_randr_query_version_cookie_t qv_c =
2026 xcb_randr_query_version(connection, 1, 6);
2027 xcb_randr_get_output_property_cookie_t gop_c =
2028 xcb_randr_get_output_property(connection,
2029 output,
2030 connector_id_atom,
2031 0,
2032 0,
2033 0xffffffffUL,
2034 0,
2035 0);
2036 xcb_randr_query_version_reply_t *qv_r =
2037 xcb_randr_query_version_reply(connection, qv_c, NULL);
2038 free(qv_r);
2039 xcb_randr_get_output_property_reply_t *gop_r =
2040 xcb_randr_get_output_property_reply(connection, gop_c, NULL);
2041 if (gop_r) {
2042 if (gop_r->num_items == 1 && gop_r->format == 32)
2043 memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
2044 free(gop_r);
2045 }
2046 }
2047 return connector_id;
2048 }
2049
2050 static bool
2051 wsi_display_check_randr_version(xcb_connection_t *connection)
2052 {
2053 xcb_randr_query_version_cookie_t qv_c =
2054 xcb_randr_query_version(connection, 1, 6);
2055 xcb_randr_query_version_reply_t *qv_r =
2056 xcb_randr_query_version_reply(connection, qv_c, NULL);
2057 bool ret = false;
2058
2059 if (!qv_r)
2060 return false;
2061
2062 /* Check for version 1.6 or newer */
2063 ret = (qv_r->major_version > 1 ||
2064 (qv_r->major_version == 1 && qv_r->minor_version >= 6));
2065
2066 free(qv_r);
2067 return ret;
2068 }
2069
2070 /*
2071 * Given a kernel connector id, find the associated RandR output using the
2072 * CONNECTOR_ID property
2073 */
2074
2075 static xcb_randr_output_t
2076 wsi_display_connector_id_to_output(xcb_connection_t *connection,
2077 uint32_t connector_id)
2078 {
2079 if (!wsi_display_check_randr_version(connection))
2080 return 0;
2081
2082 const xcb_setup_t *setup = xcb_get_setup(connection);
2083
2084 xcb_atom_t connector_id_atom = 0;
2085 xcb_randr_output_t output = 0;
2086
2087 /* Search all of the screens for the provided output */
2088 xcb_screen_iterator_t iter;
2089 for (iter = xcb_setup_roots_iterator(setup);
2090 output == 0 && iter.rem;
2091 xcb_screen_next(&iter))
2092 {
2093 xcb_randr_get_screen_resources_cookie_t gsr_c =
2094 xcb_randr_get_screen_resources(connection, iter.data->root);
2095 xcb_randr_get_screen_resources_reply_t *gsr_r =
2096 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2097
2098 if (!gsr_r)
2099 return 0;
2100
2101 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2102 int o;
2103
2104 for (o = 0; o < gsr_r->num_outputs; o++) {
2105 if (wsi_display_output_to_connector_id(connection,
2106 &connector_id_atom, ro[o])
2107 == connector_id)
2108 {
2109 output = ro[o];
2110 break;
2111 }
2112 }
2113 free(gsr_r);
2114 }
2115 return output;
2116 }
2117
2118 /*
2119 * Given a RandR output, find out which screen it's associated with
2120 */
2121 static xcb_window_t
2122 wsi_display_output_to_root(xcb_connection_t *connection,
2123 xcb_randr_output_t output)
2124 {
2125 if (!wsi_display_check_randr_version(connection))
2126 return 0;
2127
2128 const xcb_setup_t *setup = xcb_get_setup(connection);
2129 xcb_window_t root = 0;
2130
2131 /* Search all of the screens for the provided output */
2132 for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
2133 root == 0 && iter.rem;
2134 xcb_screen_next(&iter))
2135 {
2136 xcb_randr_get_screen_resources_cookie_t gsr_c =
2137 xcb_randr_get_screen_resources(connection, iter.data->root);
2138 xcb_randr_get_screen_resources_reply_t *gsr_r =
2139 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2140
2141 if (!gsr_r)
2142 return 0;
2143
2144 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2145
2146 for (int o = 0; o < gsr_r->num_outputs; o++) {
2147 if (ro[o] == output) {
2148 root = iter.data->root;
2149 break;
2150 }
2151 }
2152 free(gsr_r);
2153 }
2154 return root;
2155 }
2156
2157 static bool
2158 wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
2159 xcb_randr_mode_info_t *xcb)
2160 {
2161 return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
2162 wsi->hdisplay == xcb->width &&
2163 wsi->hsync_start == xcb->hsync_start &&
2164 wsi->hsync_end == xcb->hsync_end &&
2165 wsi->htotal == xcb->htotal &&
2166 wsi->hskew == xcb->hskew &&
2167 wsi->vdisplay == xcb->height &&
2168 wsi->vsync_start == xcb->vsync_start &&
2169 wsi->vsync_end == xcb->vsync_end &&
2170 wsi->vtotal == xcb->vtotal &&
2171 wsi->vscan <= 1 &&
2172 wsi->flags == xcb->mode_flags;
2173 }
2174
2175 static struct wsi_display_mode *
2176 wsi_display_find_x_mode(struct wsi_device *wsi_device,
2177 struct wsi_display_connector *connector,
2178 xcb_randr_mode_info_t *mode)
2179 {
2180 wsi_for_each_display_mode(display_mode, connector) {
2181 if (wsi_display_mode_matches_x(display_mode, mode))
2182 return display_mode;
2183 }
2184 return NULL;
2185 }
2186
2187 static VkResult
2188 wsi_display_register_x_mode(struct wsi_device *wsi_device,
2189 struct wsi_display_connector *connector,
2190 xcb_randr_mode_info_t *x_mode,
2191 bool preferred)
2192 {
2193 struct wsi_display *wsi =
2194 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2195 struct wsi_display_mode *display_mode =
2196 wsi_display_find_x_mode(wsi_device, connector, x_mode);
2197
2198 if (display_mode) {
2199 display_mode->valid = true;
2200 return VK_SUCCESS;
2201 }
2202
2203 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
2204 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2205 if (!display_mode)
2206 return VK_ERROR_OUT_OF_HOST_MEMORY;
2207
2208 display_mode->connector = connector;
2209 display_mode->valid = true;
2210 display_mode->preferred = preferred;
2211 display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
2212 display_mode->hdisplay = x_mode->width;
2213 display_mode->hsync_start = x_mode->hsync_start;
2214 display_mode->hsync_end = x_mode->hsync_end;
2215 display_mode->htotal = x_mode->htotal;
2216 display_mode->hskew = x_mode->hskew;
2217 display_mode->vdisplay = x_mode->height;
2218 display_mode->vsync_start = x_mode->vsync_start;
2219 display_mode->vsync_end = x_mode->vsync_end;
2220 display_mode->vtotal = x_mode->vtotal;
2221 display_mode->vscan = 0;
2222 display_mode->flags = x_mode->mode_flags;
2223
2224 list_addtail(&display_mode->list, &connector->display_modes);
2225 return VK_SUCCESS;
2226 }
2227
2228 static struct wsi_display_connector *
2229 wsi_display_get_output(struct wsi_device *wsi_device,
2230 xcb_connection_t *connection,
2231 xcb_randr_output_t output)
2232 {
2233 struct wsi_display *wsi =
2234 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2235 struct wsi_display_connector *connector;
2236 uint32_t connector_id;
2237
2238 xcb_window_t root = wsi_display_output_to_root(connection, output);
2239 if (!root)
2240 return NULL;
2241
2242 /* See if we already have a connector for this output */
2243 connector = wsi_display_find_output(wsi_device, output);
2244
2245 if (!connector) {
2246 xcb_atom_t connector_id_atom = 0;
2247
2248 /*
2249 * Go get the kernel connector ID for this X output
2250 */
2251 connector_id = wsi_display_output_to_connector_id(connection,
2252 &connector_id_atom,
2253 output);
2254
2255 /* Any X server with lease support will have this atom */
2256 if (!connector_id) {
2257 return NULL;
2258 }
2259
2260 /* See if we already have a connector for this id */
2261 connector = wsi_display_find_connector(wsi_device, connector_id);
2262
2263 if (connector == NULL) {
2264 connector = wsi_display_alloc_connector(wsi, connector_id);
2265 if (!connector) {
2266 return NULL;
2267 }
2268 list_addtail(&connector->list, &wsi->connectors);
2269 }
2270 connector->output = output;
2271 }
2272
2273 xcb_randr_get_screen_resources_cookie_t src =
2274 xcb_randr_get_screen_resources(connection, root);
2275 xcb_randr_get_output_info_cookie_t oic =
2276 xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
2277 xcb_randr_get_screen_resources_reply_t *srr =
2278 xcb_randr_get_screen_resources_reply(connection, src, NULL);
2279 xcb_randr_get_output_info_reply_t *oir =
2280 xcb_randr_get_output_info_reply(connection, oic, NULL);
2281
2282 if (oir && srr) {
2283 /* Get X modes and add them */
2284
2285 connector->connected =
2286 oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
2287
2288 wsi_display_invalidate_connector_modes(wsi_device, connector);
2289
2290 xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
2291 for (int m = 0; m < oir->num_modes; m++) {
2292 xcb_randr_mode_info_iterator_t i =
2293 xcb_randr_get_screen_resources_modes_iterator(srr);
2294 while (i.rem) {
2295 xcb_randr_mode_info_t *mi = i.data;
2296 if (mi->id == x_modes[m]) {
2297 VkResult result = wsi_display_register_x_mode(
2298 wsi_device, connector, mi, m < oir->num_preferred);
2299 if (result != VK_SUCCESS) {
2300 free(oir);
2301 free(srr);
2302 return NULL;
2303 }
2304 break;
2305 }
2306 xcb_randr_mode_info_next(&i);
2307 }
2308 }
2309 }
2310
2311 free(oir);
2312 free(srr);
2313 return connector;
2314 }
2315
2316 static xcb_randr_crtc_t
2317 wsi_display_find_crtc_for_output(xcb_connection_t *connection,
2318 xcb_window_t root,
2319 xcb_randr_output_t output)
2320 {
2321 xcb_randr_get_screen_resources_cookie_t gsr_c =
2322 xcb_randr_get_screen_resources(connection, root);
2323 xcb_randr_get_screen_resources_reply_t *gsr_r =
2324 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2325
2326 if (!gsr_r)
2327 return 0;
2328
2329 xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
2330 xcb_randr_crtc_t idle_crtc = 0;
2331 xcb_randr_crtc_t active_crtc = 0;
2332
2333 /* Find either a crtc already connected to the desired output or idle */
2334 for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
2335 xcb_randr_get_crtc_info_cookie_t gci_c =
2336 xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
2337 xcb_randr_get_crtc_info_reply_t *gci_r =
2338 xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
2339
2340 if (gci_r) {
2341 if (gci_r->mode) {
2342 int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
2343 xcb_randr_output_t *outputs =
2344 xcb_randr_get_crtc_info_outputs(gci_r);
2345
2346 if (num_outputs == 1 && outputs[0] == output)
2347 active_crtc = rc[c];
2348
2349 } else if (idle_crtc == 0) {
2350 int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
2351 xcb_randr_output_t *possible =
2352 xcb_randr_get_crtc_info_possible(gci_r);
2353
2354 for (int p = 0; p < num_possible; p++)
2355 if (possible[p] == output) {
2356 idle_crtc = rc[c];
2357 break;
2358 }
2359 }
2360 free(gci_r);
2361 }
2362 }
2363 free(gsr_r);
2364
2365 if (active_crtc)
2366 return active_crtc;
2367 return idle_crtc;
2368 }
2369
2370 VkResult
2371 wsi_acquire_xlib_display(VkPhysicalDevice physical_device,
2372 struct wsi_device *wsi_device,
2373 Display *dpy,
2374 VkDisplayKHR display)
2375 {
2376 struct wsi_display *wsi =
2377 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2378 xcb_connection_t *connection = XGetXCBConnection(dpy);
2379 struct wsi_display_connector *connector =
2380 wsi_display_connector_from_handle(display);
2381 xcb_window_t root;
2382
2383 /* XXX no support for multiple leases yet */
2384 if (wsi->fd >= 0)
2385 return VK_ERROR_INITIALIZATION_FAILED;
2386
2387 if (!connector->output) {
2388 connector->output = wsi_display_connector_id_to_output(connection,
2389 connector->id);
2390
2391 /* Check and see if we found the output */
2392 if (!connector->output)
2393 return VK_ERROR_INITIALIZATION_FAILED;
2394 }
2395
2396 root = wsi_display_output_to_root(connection, connector->output);
2397 if (!root)
2398 return VK_ERROR_INITIALIZATION_FAILED;
2399
2400 xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
2401 root,
2402 connector->output);
2403
2404 if (!crtc)
2405 return VK_ERROR_INITIALIZATION_FAILED;
2406
2407 #ifdef HAVE_DRI3_MODIFIERS
2408 xcb_randr_lease_t lease = xcb_generate_id(connection);
2409 xcb_randr_create_lease_cookie_t cl_c =
2410 xcb_randr_create_lease(connection, root, lease, 1, 1,
2411 &crtc, &connector->output);
2412 xcb_randr_create_lease_reply_t *cl_r =
2413 xcb_randr_create_lease_reply(connection, cl_c, NULL);
2414 if (!cl_r)
2415 return VK_ERROR_INITIALIZATION_FAILED;
2416
2417 int fd = -1;
2418 if (cl_r->nfd > 0) {
2419 int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
2420
2421 fd = rcl_f[0];
2422 }
2423 free (cl_r);
2424 if (fd < 0)
2425 return VK_ERROR_INITIALIZATION_FAILED;
2426
2427 wsi->fd = fd;
2428 #endif
2429
2430 return VK_SUCCESS;
2431 }
2432
2433 VkResult
2434 wsi_get_randr_output_display(VkPhysicalDevice physical_device,
2435 struct wsi_device *wsi_device,
2436 Display *dpy,
2437 RROutput output,
2438 VkDisplayKHR *display)
2439 {
2440 xcb_connection_t *connection = XGetXCBConnection(dpy);
2441 struct wsi_display_connector *connector =
2442 wsi_display_get_output(wsi_device, connection, (xcb_randr_output_t) output);
2443
2444 if (connector)
2445 *display = wsi_display_connector_to_handle(connector);
2446 else
2447 *display = VK_NULL_HANDLE;
2448 return VK_SUCCESS;
2449 }
2450
2451 #endif
2452
2453 /* VK_EXT_display_control */
2454 VkResult
2455 wsi_display_power_control(VkDevice device,
2456 struct wsi_device *wsi_device,
2457 VkDisplayKHR display,
2458 const VkDisplayPowerInfoEXT *display_power_info)
2459 {
2460 struct wsi_display *wsi =
2461 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2462 struct wsi_display_connector *connector =
2463 wsi_display_connector_from_handle(display);
2464 int mode;
2465
2466 if (wsi->fd < 0)
2467 return VK_ERROR_INITIALIZATION_FAILED;
2468
2469 switch (display_power_info->powerState) {
2470 case VK_DISPLAY_POWER_STATE_OFF_EXT:
2471 mode = DRM_MODE_DPMS_OFF;
2472 break;
2473 case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
2474 mode = DRM_MODE_DPMS_SUSPEND;
2475 break;
2476 default:
2477 mode = DRM_MODE_DPMS_ON;
2478 break;
2479 }
2480 drmModeConnectorSetProperty(wsi->fd,
2481 connector->id,
2482 connector->dpms_property,
2483 mode);
2484 return VK_SUCCESS;
2485 }
2486
2487 VkResult
2488 wsi_register_device_event(VkDevice device,
2489 struct wsi_device *wsi_device,
2490 const VkDeviceEventInfoEXT *device_event_info,
2491 const VkAllocationCallbacks *allocator,
2492 struct wsi_fence **fence_p)
2493 {
2494 return VK_ERROR_FEATURE_NOT_PRESENT;
2495 }
2496
2497 VkResult
2498 wsi_register_display_event(VkDevice device,
2499 struct wsi_device *wsi_device,
2500 VkDisplayKHR display,
2501 const VkDisplayEventInfoEXT *display_event_info,
2502 const VkAllocationCallbacks *allocator,
2503 struct wsi_fence **fence_p)
2504 {
2505 struct wsi_display *wsi =
2506 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2507 struct wsi_display_fence *fence;
2508 VkResult ret;
2509
2510 switch (display_event_info->displayEvent) {
2511 case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
2512
2513 fence = wsi_display_fence_alloc(device, wsi_device, display, allocator);
2514
2515 if (!fence)
2516 return VK_ERROR_OUT_OF_HOST_MEMORY;
2517
2518 ret = wsi_register_vblank_event(fence, wsi_device, display,
2519 DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
2520
2521 if (ret == VK_SUCCESS)
2522 *fence_p = &fence->base;
2523 else if (fence != NULL)
2524 vk_free2(wsi->alloc, allocator, fence);
2525
2526 break;
2527 default:
2528 ret = VK_ERROR_FEATURE_NOT_PRESENT;
2529 break;
2530 }
2531
2532 return ret;
2533 }
2534
2535
2536 VkResult
2537 wsi_get_swapchain_counter(VkDevice device,
2538 struct wsi_device *wsi_device,
2539 VkSwapchainKHR _swapchain,
2540 VkSurfaceCounterFlagBitsEXT flag_bits,
2541 uint64_t *value)
2542 {
2543 struct wsi_display *wsi =
2544 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2545 struct wsi_display_swapchain *swapchain =
2546 (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
2547 struct wsi_display_connector *connector =
2548 wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
2549
2550 if (wsi->fd < 0)
2551 return VK_ERROR_INITIALIZATION_FAILED;
2552
2553 if (!connector->active) {
2554 *value = 0;
2555 return VK_SUCCESS;
2556 }
2557
2558 int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, value, NULL);
2559 if (ret)
2560 *value = 0;
2561
2562 return VK_SUCCESS;
2563 }
2564