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