04c77162df423ffea5f585e59e0e21e4bdb6ee34
[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 /* Assume that the mode set is synchronous and that any
1691 * previous image is now idle.
1692 */
1693 image->state = WSI_IMAGE_DISPLAYING;
1694 wsi_display_idle_old_displaying(image);
1695 connector->active = true;
1696 return VK_SUCCESS;
1697 }
1698 }
1699
1700 if (ret != -EACCES) {
1701 connector->active = false;
1702 image->state = WSI_IMAGE_IDLE;
1703 return VK_ERROR_SURFACE_LOST_KHR;
1704 }
1705
1706 /* Some other VT is currently active. Sit here waiting for
1707 * our VT to become active again by polling once a second
1708 */
1709 usleep(1000 * 1000);
1710 connector->active = false;
1711 }
1712 }
1713
1714 static VkResult
1715 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
1716 uint32_t image_index,
1717 const VkPresentRegionKHR *damage)
1718 {
1719 struct wsi_display_swapchain *chain =
1720 (struct wsi_display_swapchain *) drv_chain;
1721 struct wsi_display *wsi = chain->wsi;
1722 struct wsi_display_image *image = &chain->images[image_index];
1723 VkResult result;
1724
1725 /* Bail early if the swapchain is broken */
1726 if (chain->status != VK_SUCCESS)
1727 return chain->status;
1728
1729 assert(image->state == WSI_IMAGE_DRAWING);
1730 wsi_display_debug("present %d\n", image_index);
1731
1732 pthread_mutex_lock(&wsi->wait_mutex);
1733
1734 image->flip_sequence = ++chain->flip_sequence;
1735 image->state = WSI_IMAGE_QUEUED;
1736
1737 result = _wsi_display_queue_next(drv_chain);
1738 if (result != VK_SUCCESS)
1739 chain->status = result;
1740
1741 pthread_mutex_unlock(&wsi->wait_mutex);
1742
1743 if (result != VK_SUCCESS)
1744 return result;
1745
1746 return chain->status;
1747 }
1748
1749 static VkResult
1750 wsi_display_surface_create_swapchain(
1751 VkIcdSurfaceBase *icd_surface,
1752 VkDevice device,
1753 struct wsi_device *wsi_device,
1754 const VkSwapchainCreateInfoKHR *create_info,
1755 const VkAllocationCallbacks *allocator,
1756 struct wsi_swapchain **swapchain_out)
1757 {
1758 struct wsi_display *wsi =
1759 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1760
1761 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1762
1763 const unsigned num_images = create_info->minImageCount;
1764 struct wsi_display_swapchain *chain =
1765 vk_zalloc(allocator,
1766 sizeof(*chain) + num_images * sizeof(chain->images[0]),
1767 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1768
1769 if (chain == NULL)
1770 return VK_ERROR_OUT_OF_HOST_MEMORY;
1771
1772 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
1773 create_info, allocator);
1774 if (result != VK_SUCCESS) {
1775 vk_free(allocator, chain);
1776 return result;
1777 }
1778
1779 chain->base.destroy = wsi_display_swapchain_destroy;
1780 chain->base.get_wsi_image = wsi_display_get_wsi_image;
1781 chain->base.acquire_next_image = wsi_display_acquire_next_image;
1782 chain->base.queue_present = wsi_display_queue_present;
1783 chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
1784 chain->base.image_count = num_images;
1785
1786 chain->wsi = wsi;
1787 chain->status = VK_SUCCESS;
1788
1789 chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
1790
1791 for (uint32_t image = 0; image < chain->base.image_count; image++) {
1792 result = wsi_display_image_init(device, &chain->base,
1793 create_info, allocator,
1794 &chain->images[image]);
1795 if (result != VK_SUCCESS) {
1796 while (image > 0) {
1797 --image;
1798 wsi_display_image_finish(&chain->base, allocator,
1799 &chain->images[image]);
1800 }
1801 vk_free(allocator, chain);
1802 goto fail_init_images;
1803 }
1804 }
1805
1806 *swapchain_out = &chain->base;
1807
1808 return VK_SUCCESS;
1809
1810 fail_init_images:
1811 return result;
1812 }
1813
1814 static bool
1815 wsi_init_pthread_cond_monotonic(pthread_cond_t *cond)
1816 {
1817 pthread_condattr_t condattr;
1818 bool ret = false;
1819
1820 if (pthread_condattr_init(&condattr) != 0)
1821 goto fail_attr_init;
1822
1823 if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0)
1824 goto fail_attr_set;
1825
1826 if (pthread_cond_init(cond, &condattr) != 0)
1827 goto fail_cond_init;
1828
1829 ret = true;
1830
1831 fail_cond_init:
1832 fail_attr_set:
1833 pthread_condattr_destroy(&condattr);
1834 fail_attr_init:
1835 return ret;
1836 }
1837
1838
1839 /*
1840 * Local version fo the libdrm helper. Added to avoid depending on bleeding
1841 * edge version of the library.
1842 */
1843 static int
1844 local_drmIsMaster(int fd)
1845 {
1846 /* Detect master by attempting something that requires master.
1847 *
1848 * Authenticating magic tokens requires master and 0 is an
1849 * internal kernel detail which we could use. Attempting this on
1850 * a master fd would fail therefore fail with EINVAL because 0
1851 * is invalid.
1852 *
1853 * A non-master fd will fail with EACCES, as the kernel checks
1854 * for master before attempting to do anything else.
1855 *
1856 * Since we don't want to leak implementation details, use
1857 * EACCES.
1858 */
1859 return drmAuthMagic(fd, 0) != -EACCES;
1860 }
1861
1862 VkResult
1863 wsi_display_init_wsi(struct wsi_device *wsi_device,
1864 const VkAllocationCallbacks *alloc,
1865 int display_fd)
1866 {
1867 struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
1868 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1869 VkResult result;
1870
1871 if (!wsi) {
1872 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1873 goto fail;
1874 }
1875
1876 wsi->fd = display_fd;
1877 if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
1878 wsi->fd = -1;
1879
1880 wsi->alloc = alloc;
1881
1882 list_inithead(&wsi->connectors);
1883
1884 int ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
1885 if (ret) {
1886 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1887 goto fail_mutex;
1888 }
1889
1890 if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) {
1891 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1892 goto fail_cond;
1893 }
1894
1895 wsi->base.get_support = wsi_display_surface_get_support;
1896 wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
1897 wsi->base.get_formats = wsi_display_surface_get_formats;
1898 wsi->base.get_formats2 = wsi_display_surface_get_formats2;
1899 wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
1900 wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
1901 wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
1902
1903 wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
1904
1905 return VK_SUCCESS;
1906
1907 fail_cond:
1908 pthread_mutex_destroy(&wsi->wait_mutex);
1909 fail_mutex:
1910 vk_free(alloc, wsi);
1911 fail:
1912 return result;
1913 }
1914
1915 void
1916 wsi_display_finish_wsi(struct wsi_device *wsi_device,
1917 const VkAllocationCallbacks *alloc)
1918 {
1919 struct wsi_display *wsi =
1920 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1921
1922 if (wsi) {
1923 wsi_for_each_connector(connector, wsi) {
1924 wsi_for_each_display_mode(mode, connector) {
1925 vk_free(wsi->alloc, mode);
1926 }
1927 vk_free(wsi->alloc, connector);
1928 }
1929
1930 pthread_mutex_lock(&wsi->wait_mutex);
1931 if (wsi->wait_thread) {
1932 pthread_cancel(wsi->wait_thread);
1933 pthread_join(wsi->wait_thread, NULL);
1934 }
1935 pthread_mutex_unlock(&wsi->wait_mutex);
1936 pthread_mutex_destroy(&wsi->wait_mutex);
1937 pthread_cond_destroy(&wsi->wait_cond);
1938
1939 vk_free(alloc, wsi);
1940 }
1941 }
1942
1943 /*
1944 * Implement vkReleaseDisplay
1945 */
1946 VkResult
1947 wsi_release_display(VkPhysicalDevice physical_device,
1948 struct wsi_device *wsi_device,
1949 VkDisplayKHR display)
1950 {
1951 struct wsi_display *wsi =
1952 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1953
1954 if (wsi->fd >= 0) {
1955 close(wsi->fd);
1956 wsi->fd = -1;
1957 }
1958 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1959 wsi_display_connector_from_handle(display)->output = None;
1960 #endif
1961
1962 return VK_SUCCESS;
1963 }
1964
1965 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1966
1967 static struct wsi_display_connector *
1968 wsi_display_find_output(struct wsi_device *wsi_device,
1969 xcb_randr_output_t output)
1970 {
1971 struct wsi_display *wsi =
1972 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1973
1974 wsi_for_each_connector(connector, wsi) {
1975 if (connector->output == output)
1976 return connector;
1977 }
1978
1979 return NULL;
1980 }
1981
1982 /*
1983 * Given a RandR output, find the associated kernel connector_id by
1984 * looking at the CONNECTOR_ID property provided by the X server
1985 */
1986
1987 static uint32_t
1988 wsi_display_output_to_connector_id(xcb_connection_t *connection,
1989 xcb_atom_t *connector_id_atom_p,
1990 xcb_randr_output_t output)
1991 {
1992 uint32_t connector_id = 0;
1993 xcb_atom_t connector_id_atom = *connector_id_atom_p;
1994
1995 if (connector_id_atom == 0) {
1996 /* Go dig out the CONNECTOR_ID property */
1997 xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
1998 true,
1999 12,
2000 "CONNECTOR_ID");
2001 xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
2002 ia_c,
2003 NULL);
2004 if (ia_r) {
2005 *connector_id_atom_p = connector_id_atom = ia_r->atom;
2006 free(ia_r);
2007 }
2008 }
2009
2010 /* If there's an CONNECTOR_ID atom in the server, then there may be a
2011 * CONNECTOR_ID property. Otherwise, there will not be and we don't even
2012 * need to bother.
2013 */
2014 if (connector_id_atom) {
2015
2016 xcb_randr_query_version_cookie_t qv_c =
2017 xcb_randr_query_version(connection, 1, 6);
2018 xcb_randr_get_output_property_cookie_t gop_c =
2019 xcb_randr_get_output_property(connection,
2020 output,
2021 connector_id_atom,
2022 0,
2023 0,
2024 0xffffffffUL,
2025 0,
2026 0);
2027 xcb_randr_query_version_reply_t *qv_r =
2028 xcb_randr_query_version_reply(connection, qv_c, NULL);
2029 free(qv_r);
2030 xcb_randr_get_output_property_reply_t *gop_r =
2031 xcb_randr_get_output_property_reply(connection, gop_c, NULL);
2032 if (gop_r) {
2033 if (gop_r->num_items == 1 && gop_r->format == 32)
2034 memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
2035 free(gop_r);
2036 }
2037 }
2038 return connector_id;
2039 }
2040
2041 static bool
2042 wsi_display_check_randr_version(xcb_connection_t *connection)
2043 {
2044 xcb_randr_query_version_cookie_t qv_c =
2045 xcb_randr_query_version(connection, 1, 6);
2046 xcb_randr_query_version_reply_t *qv_r =
2047 xcb_randr_query_version_reply(connection, qv_c, NULL);
2048 bool ret = false;
2049
2050 if (!qv_r)
2051 return false;
2052
2053 /* Check for version 1.6 or newer */
2054 ret = (qv_r->major_version > 1 ||
2055 (qv_r->major_version == 1 && qv_r->minor_version >= 6));
2056
2057 free(qv_r);
2058 return ret;
2059 }
2060
2061 /*
2062 * Given a kernel connector id, find the associated RandR output using the
2063 * CONNECTOR_ID property
2064 */
2065
2066 static xcb_randr_output_t
2067 wsi_display_connector_id_to_output(xcb_connection_t *connection,
2068 uint32_t connector_id)
2069 {
2070 if (!wsi_display_check_randr_version(connection))
2071 return 0;
2072
2073 const xcb_setup_t *setup = xcb_get_setup(connection);
2074
2075 xcb_atom_t connector_id_atom = 0;
2076 xcb_randr_output_t output = 0;
2077
2078 /* Search all of the screens for the provided output */
2079 xcb_screen_iterator_t iter;
2080 for (iter = xcb_setup_roots_iterator(setup);
2081 output == 0 && iter.rem;
2082 xcb_screen_next(&iter))
2083 {
2084 xcb_randr_get_screen_resources_cookie_t gsr_c =
2085 xcb_randr_get_screen_resources(connection, iter.data->root);
2086 xcb_randr_get_screen_resources_reply_t *gsr_r =
2087 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2088
2089 if (!gsr_r)
2090 return 0;
2091
2092 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2093 int o;
2094
2095 for (o = 0; o < gsr_r->num_outputs; o++) {
2096 if (wsi_display_output_to_connector_id(connection,
2097 &connector_id_atom, ro[o])
2098 == connector_id)
2099 {
2100 output = ro[o];
2101 break;
2102 }
2103 }
2104 free(gsr_r);
2105 }
2106 return output;
2107 }
2108
2109 /*
2110 * Given a RandR output, find out which screen it's associated with
2111 */
2112 static xcb_window_t
2113 wsi_display_output_to_root(xcb_connection_t *connection,
2114 xcb_randr_output_t output)
2115 {
2116 if (!wsi_display_check_randr_version(connection))
2117 return 0;
2118
2119 const xcb_setup_t *setup = xcb_get_setup(connection);
2120 xcb_window_t root = 0;
2121
2122 /* Search all of the screens for the provided output */
2123 for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
2124 root == 0 && iter.rem;
2125 xcb_screen_next(&iter))
2126 {
2127 xcb_randr_get_screen_resources_cookie_t gsr_c =
2128 xcb_randr_get_screen_resources(connection, iter.data->root);
2129 xcb_randr_get_screen_resources_reply_t *gsr_r =
2130 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2131
2132 if (!gsr_r)
2133 return 0;
2134
2135 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2136
2137 for (int o = 0; o < gsr_r->num_outputs; o++) {
2138 if (ro[o] == output) {
2139 root = iter.data->root;
2140 break;
2141 }
2142 }
2143 free(gsr_r);
2144 }
2145 return root;
2146 }
2147
2148 static bool
2149 wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
2150 xcb_randr_mode_info_t *xcb)
2151 {
2152 return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
2153 wsi->hdisplay == xcb->width &&
2154 wsi->hsync_start == xcb->hsync_start &&
2155 wsi->hsync_end == xcb->hsync_end &&
2156 wsi->htotal == xcb->htotal &&
2157 wsi->hskew == xcb->hskew &&
2158 wsi->vdisplay == xcb->height &&
2159 wsi->vsync_start == xcb->vsync_start &&
2160 wsi->vsync_end == xcb->vsync_end &&
2161 wsi->vtotal == xcb->vtotal &&
2162 wsi->vscan <= 1 &&
2163 wsi->flags == xcb->mode_flags;
2164 }
2165
2166 static struct wsi_display_mode *
2167 wsi_display_find_x_mode(struct wsi_device *wsi_device,
2168 struct wsi_display_connector *connector,
2169 xcb_randr_mode_info_t *mode)
2170 {
2171 wsi_for_each_display_mode(display_mode, connector) {
2172 if (wsi_display_mode_matches_x(display_mode, mode))
2173 return display_mode;
2174 }
2175 return NULL;
2176 }
2177
2178 static VkResult
2179 wsi_display_register_x_mode(struct wsi_device *wsi_device,
2180 struct wsi_display_connector *connector,
2181 xcb_randr_mode_info_t *x_mode,
2182 bool preferred)
2183 {
2184 struct wsi_display *wsi =
2185 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2186 struct wsi_display_mode *display_mode =
2187 wsi_display_find_x_mode(wsi_device, connector, x_mode);
2188
2189 if (display_mode) {
2190 display_mode->valid = true;
2191 return VK_SUCCESS;
2192 }
2193
2194 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
2195 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2196 if (!display_mode)
2197 return VK_ERROR_OUT_OF_HOST_MEMORY;
2198
2199 display_mode->connector = connector;
2200 display_mode->valid = true;
2201 display_mode->preferred = preferred;
2202 display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
2203 display_mode->hdisplay = x_mode->width;
2204 display_mode->hsync_start = x_mode->hsync_start;
2205 display_mode->hsync_end = x_mode->hsync_end;
2206 display_mode->htotal = x_mode->htotal;
2207 display_mode->hskew = x_mode->hskew;
2208 display_mode->vdisplay = x_mode->height;
2209 display_mode->vsync_start = x_mode->vsync_start;
2210 display_mode->vsync_end = x_mode->vsync_end;
2211 display_mode->vtotal = x_mode->vtotal;
2212 display_mode->vscan = 0;
2213 display_mode->flags = x_mode->mode_flags;
2214
2215 list_addtail(&display_mode->list, &connector->display_modes);
2216 return VK_SUCCESS;
2217 }
2218
2219 static struct wsi_display_connector *
2220 wsi_display_get_output(struct wsi_device *wsi_device,
2221 xcb_connection_t *connection,
2222 xcb_randr_output_t output)
2223 {
2224 struct wsi_display *wsi =
2225 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2226 struct wsi_display_connector *connector;
2227 uint32_t connector_id;
2228
2229 xcb_window_t root = wsi_display_output_to_root(connection, output);
2230 if (!root)
2231 return NULL;
2232
2233 /* See if we already have a connector for this output */
2234 connector = wsi_display_find_output(wsi_device, output);
2235
2236 if (!connector) {
2237 xcb_atom_t connector_id_atom = 0;
2238
2239 /*
2240 * Go get the kernel connector ID for this X output
2241 */
2242 connector_id = wsi_display_output_to_connector_id(connection,
2243 &connector_id_atom,
2244 output);
2245
2246 /* Any X server with lease support will have this atom */
2247 if (!connector_id) {
2248 return NULL;
2249 }
2250
2251 /* See if we already have a connector for this id */
2252 connector = wsi_display_find_connector(wsi_device, connector_id);
2253
2254 if (connector == NULL) {
2255 connector = wsi_display_alloc_connector(wsi, connector_id);
2256 if (!connector) {
2257 return NULL;
2258 }
2259 list_addtail(&connector->list, &wsi->connectors);
2260 }
2261 connector->output = output;
2262 }
2263
2264 xcb_randr_get_screen_resources_cookie_t src =
2265 xcb_randr_get_screen_resources(connection, root);
2266 xcb_randr_get_output_info_cookie_t oic =
2267 xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
2268 xcb_randr_get_screen_resources_reply_t *srr =
2269 xcb_randr_get_screen_resources_reply(connection, src, NULL);
2270 xcb_randr_get_output_info_reply_t *oir =
2271 xcb_randr_get_output_info_reply(connection, oic, NULL);
2272
2273 if (oir && srr) {
2274 /* Get X modes and add them */
2275
2276 connector->connected =
2277 oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
2278
2279 wsi_display_invalidate_connector_modes(wsi_device, connector);
2280
2281 xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
2282 for (int m = 0; m < oir->num_modes; m++) {
2283 xcb_randr_mode_info_iterator_t i =
2284 xcb_randr_get_screen_resources_modes_iterator(srr);
2285 while (i.rem) {
2286 xcb_randr_mode_info_t *mi = i.data;
2287 if (mi->id == x_modes[m]) {
2288 VkResult result = wsi_display_register_x_mode(
2289 wsi_device, connector, mi, m < oir->num_preferred);
2290 if (result != VK_SUCCESS) {
2291 free(oir);
2292 free(srr);
2293 return NULL;
2294 }
2295 break;
2296 }
2297 xcb_randr_mode_info_next(&i);
2298 }
2299 }
2300 }
2301
2302 free(oir);
2303 free(srr);
2304 return connector;
2305 }
2306
2307 static xcb_randr_crtc_t
2308 wsi_display_find_crtc_for_output(xcb_connection_t *connection,
2309 xcb_window_t root,
2310 xcb_randr_output_t output)
2311 {
2312 xcb_randr_get_screen_resources_cookie_t gsr_c =
2313 xcb_randr_get_screen_resources(connection, root);
2314 xcb_randr_get_screen_resources_reply_t *gsr_r =
2315 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2316
2317 if (!gsr_r)
2318 return 0;
2319
2320 xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
2321 xcb_randr_crtc_t idle_crtc = 0;
2322 xcb_randr_crtc_t active_crtc = 0;
2323
2324 /* Find either a crtc already connected to the desired output or idle */
2325 for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
2326 xcb_randr_get_crtc_info_cookie_t gci_c =
2327 xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
2328 xcb_randr_get_crtc_info_reply_t *gci_r =
2329 xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
2330
2331 if (gci_r) {
2332 if (gci_r->mode) {
2333 int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
2334 xcb_randr_output_t *outputs =
2335 xcb_randr_get_crtc_info_outputs(gci_r);
2336
2337 if (num_outputs == 1 && outputs[0] == output)
2338 active_crtc = rc[c];
2339
2340 } else if (idle_crtc == 0) {
2341 int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
2342 xcb_randr_output_t *possible =
2343 xcb_randr_get_crtc_info_possible(gci_r);
2344
2345 for (int p = 0; p < num_possible; p++)
2346 if (possible[p] == output) {
2347 idle_crtc = rc[c];
2348 break;
2349 }
2350 }
2351 free(gci_r);
2352 }
2353 }
2354 free(gsr_r);
2355
2356 if (active_crtc)
2357 return active_crtc;
2358 return idle_crtc;
2359 }
2360
2361 VkResult
2362 wsi_acquire_xlib_display(VkPhysicalDevice physical_device,
2363 struct wsi_device *wsi_device,
2364 Display *dpy,
2365 VkDisplayKHR display)
2366 {
2367 struct wsi_display *wsi =
2368 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2369 xcb_connection_t *connection = XGetXCBConnection(dpy);
2370 struct wsi_display_connector *connector =
2371 wsi_display_connector_from_handle(display);
2372 xcb_window_t root;
2373
2374 /* XXX no support for multiple leases yet */
2375 if (wsi->fd >= 0)
2376 return VK_ERROR_INITIALIZATION_FAILED;
2377
2378 if (!connector->output) {
2379 connector->output = wsi_display_connector_id_to_output(connection,
2380 connector->id);
2381
2382 /* Check and see if we found the output */
2383 if (!connector->output)
2384 return VK_ERROR_INITIALIZATION_FAILED;
2385 }
2386
2387 root = wsi_display_output_to_root(connection, connector->output);
2388 if (!root)
2389 return VK_ERROR_INITIALIZATION_FAILED;
2390
2391 xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
2392 root,
2393 connector->output);
2394
2395 if (!crtc)
2396 return VK_ERROR_INITIALIZATION_FAILED;
2397
2398 #ifdef HAVE_DRI3_MODIFIERS
2399 xcb_randr_lease_t lease = xcb_generate_id(connection);
2400 xcb_randr_create_lease_cookie_t cl_c =
2401 xcb_randr_create_lease(connection, root, lease, 1, 1,
2402 &crtc, &connector->output);
2403 xcb_randr_create_lease_reply_t *cl_r =
2404 xcb_randr_create_lease_reply(connection, cl_c, NULL);
2405 if (!cl_r)
2406 return VK_ERROR_INITIALIZATION_FAILED;
2407
2408 int fd = -1;
2409 if (cl_r->nfd > 0) {
2410 int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
2411
2412 fd = rcl_f[0];
2413 }
2414 free (cl_r);
2415 if (fd < 0)
2416 return VK_ERROR_INITIALIZATION_FAILED;
2417
2418 wsi->fd = fd;
2419 #endif
2420
2421 return VK_SUCCESS;
2422 }
2423
2424 VkResult
2425 wsi_get_randr_output_display(VkPhysicalDevice physical_device,
2426 struct wsi_device *wsi_device,
2427 Display *dpy,
2428 RROutput output,
2429 VkDisplayKHR *display)
2430 {
2431 xcb_connection_t *connection = XGetXCBConnection(dpy);
2432 struct wsi_display_connector *connector =
2433 wsi_display_get_output(wsi_device, connection, (xcb_randr_output_t) output);
2434
2435 if (connector)
2436 *display = wsi_display_connector_to_handle(connector);
2437 else
2438 *display = VK_NULL_HANDLE;
2439 return VK_SUCCESS;
2440 }
2441
2442 #endif
2443
2444 /* VK_EXT_display_control */
2445 VkResult
2446 wsi_display_power_control(VkDevice device,
2447 struct wsi_device *wsi_device,
2448 VkDisplayKHR display,
2449 const VkDisplayPowerInfoEXT *display_power_info)
2450 {
2451 struct wsi_display *wsi =
2452 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2453 struct wsi_display_connector *connector =
2454 wsi_display_connector_from_handle(display);
2455 int mode;
2456
2457 if (wsi->fd < 0)
2458 return VK_ERROR_INITIALIZATION_FAILED;
2459
2460 switch (display_power_info->powerState) {
2461 case VK_DISPLAY_POWER_STATE_OFF_EXT:
2462 mode = DRM_MODE_DPMS_OFF;
2463 break;
2464 case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
2465 mode = DRM_MODE_DPMS_SUSPEND;
2466 break;
2467 default:
2468 mode = DRM_MODE_DPMS_ON;
2469 break;
2470 }
2471 drmModeConnectorSetProperty(wsi->fd,
2472 connector->id,
2473 connector->dpms_property,
2474 mode);
2475 return VK_SUCCESS;
2476 }
2477
2478 VkResult
2479 wsi_register_device_event(VkDevice device,
2480 struct wsi_device *wsi_device,
2481 const VkDeviceEventInfoEXT *device_event_info,
2482 const VkAllocationCallbacks *allocator,
2483 struct wsi_fence **fence_p)
2484 {
2485 return VK_ERROR_FEATURE_NOT_PRESENT;
2486 }
2487
2488 VkResult
2489 wsi_register_display_event(VkDevice device,
2490 struct wsi_device *wsi_device,
2491 VkDisplayKHR display,
2492 const VkDisplayEventInfoEXT *display_event_info,
2493 const VkAllocationCallbacks *allocator,
2494 struct wsi_fence **fence_p)
2495 {
2496 struct wsi_display *wsi =
2497 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2498 struct wsi_display_fence *fence;
2499 VkResult ret;
2500
2501 switch (display_event_info->displayEvent) {
2502 case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
2503
2504 fence = wsi_display_fence_alloc(device, wsi_device, display, allocator);
2505
2506 if (!fence)
2507 return VK_ERROR_OUT_OF_HOST_MEMORY;
2508
2509 ret = wsi_register_vblank_event(fence, wsi_device, display,
2510 DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
2511
2512 if (ret == VK_SUCCESS)
2513 *fence_p = &fence->base;
2514 else if (fence != NULL)
2515 vk_free2(wsi->alloc, allocator, fence);
2516
2517 break;
2518 default:
2519 ret = VK_ERROR_FEATURE_NOT_PRESENT;
2520 break;
2521 }
2522
2523 return ret;
2524 }
2525
2526
2527 VkResult
2528 wsi_get_swapchain_counter(VkDevice device,
2529 struct wsi_device *wsi_device,
2530 VkSwapchainKHR _swapchain,
2531 VkSurfaceCounterFlagBitsEXT flag_bits,
2532 uint64_t *value)
2533 {
2534 struct wsi_display *wsi =
2535 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2536 struct wsi_display_swapchain *swapchain =
2537 (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
2538 struct wsi_display_connector *connector =
2539 wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
2540
2541 if (wsi->fd < 0)
2542 return VK_ERROR_INITIALIZATION_FAILED;
2543
2544 if (!connector->active) {
2545 *value = 0;
2546 return VK_SUCCESS;
2547 }
2548
2549 int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, value, NULL);
2550 if (ret)
2551 *value = 0;
2552
2553 return VK_SUCCESS;
2554 }
2555