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