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 <sys/stat.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <stdbool.h>
33 #include <math.h>
34 #include <xf86drm.h>
35 #include <xf86drmMode.h>
36 #ifdef HAVE_LIBUDEV
37 #include <libudev.h>
38 #endif
39 #include "drm-uapi/drm_fourcc.h"
40 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
41 #include <xcb/randr.h>
42 #include <X11/Xlib-xcb.h>
43 #endif
44 #include "util/cnd_monotonic.h"
45 #include "util/hash_table.h"
46 #include "util/list.h"
47 #include "util/os_time.h"
48 #include "util/timespec.h"
49
50 #include "vk_device.h"
51 #include "vk_fence.h"
52 #include "vk_instance.h"
53 #include "vk_physical_device.h"
54 #include "vk_sync.h"
55 #include "vk_util.h"
56 #include "wsi_common_entrypoints.h"
57 #include "wsi_common_private.h"
58 #include "wsi_common_display.h"
59 #include "wsi_common_queue.h"
60
61 #if 0
62 #define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
63 #define wsi_display_debug_code(...) __VA_ARGS__
64 #else
65 #define wsi_display_debug(...)
66 #define wsi_display_debug_code(...)
67 #endif
68
69 /* These have lifetime equal to the instance, so they effectively
70 * never go away. This means we must keep track of them separately
71 * from all other resources.
72 */
73 typedef struct wsi_display_mode {
74 struct list_head list;
75 struct wsi_display_connector *connector;
76 bool valid; /* was found in most recent poll */
77 bool preferred;
78 uint32_t clock; /* in kHz */
79 uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
80 uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
81 uint32_t flags;
82 } wsi_display_mode;
83
84 typedef struct wsi_display_connector {
85 struct list_head list;
86 struct wsi_display *wsi;
87 uint32_t id;
88 uint32_t crtc_id;
89 char *name;
90 bool connected;
91 bool active;
92 struct list_head display_modes;
93 wsi_display_mode *current_mode;
94 drmModeModeInfo current_drm_mode;
95 uint32_t dpms_property;
96 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
97 xcb_randr_output_t output;
98 #endif
99 } wsi_display_connector;
100
101 struct wsi_display {
102 struct wsi_interface base;
103
104 const VkAllocationCallbacks *alloc;
105
106 int fd;
107
108 /* Used with syncobj imported from driver side. */
109 int syncobj_fd;
110
111 mtx_t wait_mutex;
112 struct u_cnd_monotonic wait_cond;
113 pthread_t wait_thread;
114
115 struct u_cnd_monotonic hotplug_cond;
116 pthread_t hotplug_thread;
117
118 struct list_head connectors; /* list of all discovered connectors */
119 };
120
121 #define wsi_for_each_display_mode(_mode, _conn) \
122 list_for_each_entry_safe(struct wsi_display_mode, _mode, \
123 &(_conn)->display_modes, list)
124
125 #define wsi_for_each_connector(_conn, _dev) \
126 list_for_each_entry_safe(struct wsi_display_connector, _conn, \
127 &(_dev)->connectors, list)
128
129 enum wsi_image_state {
130 WSI_IMAGE_IDLE,
131 WSI_IMAGE_DRAWING,
132 WSI_IMAGE_QUEUED,
133 WSI_IMAGE_FLIPPING,
134 WSI_IMAGE_DISPLAYING
135 };
136
137 struct wsi_display_image {
138 struct wsi_image base;
139 struct wsi_display_swapchain *chain;
140 enum wsi_image_state state;
141 uint32_t fb_id;
142 uint32_t buffer[4];
143 uint64_t flip_sequence;
144 uint64_t present_id;
145 };
146
147 struct wsi_display_swapchain {
148 struct wsi_swapchain base;
149 struct wsi_display *wsi;
150 VkIcdSurfaceDisplay *surface;
151 uint64_t flip_sequence;
152 VkResult status;
153
154 mtx_t present_id_mutex;
155 struct u_cnd_monotonic present_id_cond;
156 uint64_t present_id;
157 VkResult present_id_error;
158
159 struct wsi_display_image images[0];
160 };
161
162 struct wsi_display_fence {
163 struct list_head link;
164 struct wsi_display *wsi;
165 bool event_received;
166 bool destroyed;
167 uint32_t syncobj; /* syncobj to signal on event */
168 uint64_t sequence;
169 bool device_event; /* fence is used for device events */
170 };
171
172 struct wsi_display_sync {
173 struct vk_sync sync;
174 struct wsi_display_fence *fence;
175 };
176
177 static uint64_t fence_sequence;
178
ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode,VkDisplayModeKHR)179 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
180 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
181
182 static bool
183 wsi_display_mode_matches_drm(wsi_display_mode *wsi,
184 drmModeModeInfoPtr drm)
185 {
186 return wsi->clock == drm->clock &&
187 wsi->hdisplay == drm->hdisplay &&
188 wsi->hsync_start == drm->hsync_start &&
189 wsi->hsync_end == drm->hsync_end &&
190 wsi->htotal == drm->htotal &&
191 wsi->hskew == drm->hskew &&
192 wsi->vdisplay == drm->vdisplay &&
193 wsi->vsync_start == drm->vsync_start &&
194 wsi->vsync_end == drm->vsync_end &&
195 wsi->vtotal == drm->vtotal &&
196 MAX2(wsi->vscan, 1) == MAX2(drm->vscan, 1) &&
197 wsi->flags == drm->flags;
198 }
199
200 static double
wsi_display_mode_refresh(struct wsi_display_mode * wsi)201 wsi_display_mode_refresh(struct wsi_display_mode *wsi)
202 {
203 return (double) wsi->clock * 1000.0 / ((double) wsi->htotal *
204 (double) wsi->vtotal *
205 (double) MAX2(wsi->vscan, 1));
206 }
207
wsi_rel_to_abs_time(uint64_t rel_time)208 static uint64_t wsi_rel_to_abs_time(uint64_t rel_time)
209 {
210 uint64_t current_time = os_time_get_nano();
211
212 /* check for overflow */
213 if (rel_time > UINT64_MAX - current_time)
214 return UINT64_MAX;
215
216 return current_time + rel_time;
217 }
218
219 static struct wsi_display_mode *
wsi_display_find_drm_mode(struct wsi_display_connector * connector,drmModeModeInfoPtr mode)220 wsi_display_find_drm_mode(struct wsi_display_connector *connector,
221 drmModeModeInfoPtr mode)
222 {
223 wsi_for_each_display_mode(display_mode, connector) {
224 if (wsi_display_mode_matches_drm(display_mode, mode))
225 return display_mode;
226 }
227 return NULL;
228 }
229
230 static void
wsi_display_invalidate_connector_modes(struct wsi_display_connector * connector)231 wsi_display_invalidate_connector_modes(struct wsi_display_connector *connector)
232 {
233 wsi_for_each_display_mode(display_mode, connector) {
234 display_mode->valid = false;
235 }
236 }
237
238 static VkResult
wsi_display_register_drm_mode(struct wsi_device * wsi_device,struct wsi_display_connector * connector,drmModeModeInfoPtr drm_mode)239 wsi_display_register_drm_mode(struct wsi_device *wsi_device,
240 struct wsi_display_connector *connector,
241 drmModeModeInfoPtr drm_mode)
242 {
243 struct wsi_display *wsi =
244 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
245 struct wsi_display_mode *display_mode =
246 wsi_display_find_drm_mode(connector, drm_mode);
247
248 if (display_mode) {
249 display_mode->valid = true;
250 return VK_SUCCESS;
251 }
252
253 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
254 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
255 if (!display_mode)
256 return VK_ERROR_OUT_OF_HOST_MEMORY;
257
258 display_mode->connector = connector;
259 display_mode->valid = true;
260 display_mode->preferred = (drm_mode->type & DRM_MODE_TYPE_PREFERRED) != 0;
261 display_mode->clock = drm_mode->clock; /* kHz */
262 display_mode->hdisplay = drm_mode->hdisplay;
263 display_mode->hsync_start = drm_mode->hsync_start;
264 display_mode->hsync_end = drm_mode->hsync_end;
265 display_mode->htotal = drm_mode->htotal;
266 display_mode->hskew = drm_mode->hskew;
267 display_mode->vdisplay = drm_mode->vdisplay;
268 display_mode->vsync_start = drm_mode->vsync_start;
269 display_mode->vsync_end = drm_mode->vsync_end;
270 display_mode->vtotal = drm_mode->vtotal;
271 display_mode->vscan = drm_mode->vscan;
272 display_mode->flags = drm_mode->flags;
273
274 list_addtail(&display_mode->list, &connector->display_modes);
275 return VK_SUCCESS;
276 }
277
278 /*
279 * Update our information about a specific connector
280 */
281
282 static struct wsi_display_connector *
wsi_display_find_connector(struct wsi_device * wsi_device,uint32_t connector_id)283 wsi_display_find_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 wsi_for_each_connector(connector, wsi) {
290 if (connector->id == connector_id)
291 return connector;
292 }
293
294 return NULL;
295 }
296
297 static struct wsi_display_connector *
wsi_display_alloc_connector(struct wsi_display * wsi,uint32_t connector_id)298 wsi_display_alloc_connector(struct wsi_display *wsi,
299 uint32_t connector_id)
300 {
301 struct wsi_display_connector *connector =
302 vk_zalloc(wsi->alloc, sizeof (struct wsi_display_connector),
303 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
304 if (!connector)
305 return NULL;
306
307 connector->id = connector_id;
308 connector->wsi = wsi;
309 connector->active = false;
310 /* XXX use EDID name */
311 connector->name = "monitor";
312 list_inithead(&connector->display_modes);
313 return connector;
314 }
315
316 static struct wsi_display_connector *
wsi_display_get_connector(struct wsi_device * wsi_device,int drm_fd,uint32_t connector_id)317 wsi_display_get_connector(struct wsi_device *wsi_device,
318 int drm_fd,
319 uint32_t connector_id)
320 {
321 struct wsi_display *wsi =
322 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
323
324 if (drm_fd < 0)
325 return NULL;
326
327 drmModeConnectorPtr drm_connector =
328 drmModeGetConnector(drm_fd, connector_id);
329
330 if (!drm_connector)
331 return NULL;
332
333 struct wsi_display_connector *connector =
334 wsi_display_find_connector(wsi_device, connector_id);
335
336 if (!connector) {
337 connector = wsi_display_alloc_connector(wsi, connector_id);
338 if (!connector) {
339 drmModeFreeConnector(drm_connector);
340 return NULL;
341 }
342 list_addtail(&connector->list, &wsi->connectors);
343 }
344
345 connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED;
346
347 /* Look for a DPMS property if we haven't already found one */
348 for (int p = 0; connector->dpms_property == 0 &&
349 p < drm_connector->count_props; p++)
350 {
351 drmModePropertyPtr prop = drmModeGetProperty(drm_fd,
352 drm_connector->props[p]);
353 if (!prop)
354 continue;
355 if (prop->flags & DRM_MODE_PROP_ENUM) {
356 if (!strcmp(prop->name, "DPMS"))
357 connector->dpms_property = drm_connector->props[p];
358 }
359 drmModeFreeProperty(prop);
360 }
361
362 /* Mark all connector modes as invalid */
363 wsi_display_invalidate_connector_modes(connector);
364
365 /*
366 * List current modes, adding new ones and marking existing ones as
367 * valid
368 */
369 for (int m = 0; m < drm_connector->count_modes; m++) {
370 VkResult result = wsi_display_register_drm_mode(wsi_device,
371 connector,
372 &drm_connector->modes[m]);
373 if (result != VK_SUCCESS) {
374 drmModeFreeConnector(drm_connector);
375 return NULL;
376 }
377 }
378
379 drmModeFreeConnector(drm_connector);
380
381 return connector;
382 }
383
384 #define MM_PER_PIXEL (1.0/96.0 * 25.4)
385
386 static uint32_t
mode_size(struct wsi_display_mode * mode)387 mode_size(struct wsi_display_mode *mode)
388 {
389 /* fortunately, these are both uint16_t, so this is easy */
390 return (uint32_t) mode->hdisplay * (uint32_t) mode->vdisplay;
391 }
392
393 static void
wsi_display_fill_in_display_properties(struct wsi_display_connector * connector,VkDisplayProperties2KHR * properties2)394 wsi_display_fill_in_display_properties(struct wsi_display_connector *connector,
395 VkDisplayProperties2KHR *properties2)
396 {
397 assert(properties2->sType == VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR);
398 VkDisplayPropertiesKHR *properties = &properties2->displayProperties;
399
400 properties->display = wsi_display_connector_to_handle(connector);
401 properties->displayName = connector->name;
402
403 /* Find the first preferred mode and assume that's the physical
404 * resolution. If there isn't a preferred mode, find the largest mode and
405 * use that.
406 */
407
408 struct wsi_display_mode *preferred_mode = NULL, *largest_mode = NULL;
409 wsi_for_each_display_mode(display_mode, connector) {
410 if (!display_mode->valid)
411 continue;
412 if (display_mode->preferred) {
413 preferred_mode = display_mode;
414 break;
415 }
416 if (largest_mode == NULL ||
417 mode_size(display_mode) > mode_size(largest_mode))
418 {
419 largest_mode = display_mode;
420 }
421 }
422
423 if (preferred_mode) {
424 properties->physicalResolution.width = preferred_mode->hdisplay;
425 properties->physicalResolution.height = preferred_mode->vdisplay;
426 } else if (largest_mode) {
427 properties->physicalResolution.width = largest_mode->hdisplay;
428 properties->physicalResolution.height = largest_mode->vdisplay;
429 } else {
430 properties->physicalResolution.width = 1024;
431 properties->physicalResolution.height = 768;
432 }
433
434 /* Make up physical size based on 96dpi */
435 properties->physicalDimensions.width =
436 floor(properties->physicalResolution.width * MM_PER_PIXEL + 0.5);
437 properties->physicalDimensions.height =
438 floor(properties->physicalResolution.height * MM_PER_PIXEL + 0.5);
439
440 properties->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
441 properties->planeReorderPossible = VK_FALSE;
442 properties->persistentContent = VK_FALSE;
443 }
444
445 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice,uint32_t * pPropertyCount,VkDisplayPropertiesKHR * pProperties)446 wsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice,
447 uint32_t *pPropertyCount,
448 VkDisplayPropertiesKHR *pProperties)
449 {
450 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
451 struct wsi_device *wsi_device = pdevice->wsi_device;
452 struct wsi_display *wsi =
453 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
454
455 if (pProperties == NULL) {
456 return wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice,
457 pPropertyCount,
458 NULL);
459 } else {
460 /* If we're actually returning properties, allocate a temporary array of
461 * VkDisplayProperties2KHR structs, call properties2 to fill them out,
462 * and then copy them to the client. This seems a bit expensive but
463 * wsi_display_get_physical_device_display_properties2() calls
464 * drmModeGetResources() which does an ioctl and then a bunch of
465 * allocations so this should get lost in the noise.
466 */
467 VkDisplayProperties2KHR *props2 =
468 vk_zalloc(wsi->alloc, sizeof(*props2) * *pPropertyCount, 8,
469 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
470 if (props2 == NULL)
471 return VK_ERROR_OUT_OF_HOST_MEMORY;
472
473 for (uint32_t i = 0; i < *pPropertyCount; i++)
474 props2[i].sType = VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR;
475
476 VkResult result =
477 wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice,
478 pPropertyCount, props2);
479
480 if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
481 for (uint32_t i = 0; i < *pPropertyCount; i++)
482 pProperties[i] = props2[i].displayProperties;
483 }
484
485 vk_free(wsi->alloc, props2);
486
487 return result;
488 }
489 }
490
491 static VkResult
wsi_get_connectors(VkPhysicalDevice physicalDevice)492 wsi_get_connectors(VkPhysicalDevice physicalDevice)
493 {
494 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
495 struct wsi_device *wsi_device = pdevice->wsi_device;
496 struct wsi_display *wsi =
497 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
498
499 if (wsi->fd < 0)
500 return VK_SUCCESS;
501
502 drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
503
504 if (!mode_res)
505 return VK_ERROR_OUT_OF_HOST_MEMORY;
506
507 /* Get current information */
508 for (int c = 0; c < mode_res->count_connectors; c++) {
509 struct wsi_display_connector *connector =
510 wsi_display_get_connector(wsi_device, wsi->fd,
511 mode_res->connectors[c]);
512 if (!connector) {
513 drmModeFreeResources(mode_res);
514 return VK_ERROR_OUT_OF_HOST_MEMORY;
515 }
516 }
517
518 drmModeFreeResources(mode_res);
519 return VK_SUCCESS;
520 }
521
522 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice,uint32_t * pPropertyCount,VkDisplayProperties2KHR * pProperties)523 wsi_GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice,
524 uint32_t *pPropertyCount,
525 VkDisplayProperties2KHR *pProperties)
526 {
527 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
528 struct wsi_device *wsi_device = pdevice->wsi_device;
529 struct wsi_display *wsi =
530 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
531
532 /* Get current information */
533 VkResult result = wsi_get_connectors(physicalDevice);
534 if (result != VK_SUCCESS)
535 goto bail;
536
537 VK_OUTARRAY_MAKE_TYPED(VkDisplayProperties2KHR, conn,
538 pProperties, pPropertyCount);
539
540 wsi_for_each_connector(connector, wsi) {
541 if (connector->connected) {
542 vk_outarray_append_typed(VkDisplayProperties2KHR, &conn, prop) {
543 wsi_display_fill_in_display_properties(connector, prop);
544 }
545 }
546 }
547
548 return vk_outarray_status(&conn);
549
550 bail:
551 *pPropertyCount = 0;
552 return result;
553 }
554
555 /*
556 * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
557 */
558 static void
wsi_display_fill_in_display_plane_properties(struct wsi_display_connector * connector,VkDisplayPlaneProperties2KHR * properties)559 wsi_display_fill_in_display_plane_properties(
560 struct wsi_display_connector *connector,
561 VkDisplayPlaneProperties2KHR *properties)
562 {
563 assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR);
564 VkDisplayPlanePropertiesKHR *prop = &properties->displayPlaneProperties;
565
566 if (connector && connector->active) {
567 prop->currentDisplay = wsi_display_connector_to_handle(connector);
568 prop->currentStackIndex = 0;
569 } else {
570 prop->currentDisplay = VK_NULL_HANDLE;
571 prop->currentStackIndex = 0;
572 }
573 }
574
575 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice,uint32_t * pPropertyCount,VkDisplayPlanePropertiesKHR * pProperties)576 wsi_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice,
577 uint32_t *pPropertyCount,
578 VkDisplayPlanePropertiesKHR *pProperties)
579 {
580 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
581 struct wsi_device *wsi_device = pdevice->wsi_device;
582 struct wsi_display *wsi =
583 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
584
585 VkResult result = wsi_get_connectors(physicalDevice);
586 if (result != VK_SUCCESS)
587 goto bail;
588
589 VK_OUTARRAY_MAKE_TYPED(VkDisplayPlanePropertiesKHR, conn,
590 pProperties, pPropertyCount);
591
592 wsi_for_each_connector(connector, wsi) {
593 vk_outarray_append_typed(VkDisplayPlanePropertiesKHR, &conn, prop) {
594 VkDisplayPlaneProperties2KHR prop2 = {
595 .sType = VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR,
596 };
597 wsi_display_fill_in_display_plane_properties(connector, &prop2);
598 *prop = prop2.displayPlaneProperties;
599 }
600 }
601 return vk_outarray_status(&conn);
602
603 bail:
604 *pPropertyCount = 0;
605 return result;
606 }
607
608 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice,uint32_t * pPropertyCount,VkDisplayPlaneProperties2KHR * pProperties)609 wsi_GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice,
610 uint32_t *pPropertyCount,
611 VkDisplayPlaneProperties2KHR *pProperties)
612 {
613 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
614 struct wsi_device *wsi_device = pdevice->wsi_device;
615 struct wsi_display *wsi =
616 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
617
618 /* Get current information */
619 VkResult result = wsi_get_connectors(physicalDevice);
620 if (result != VK_SUCCESS)
621 goto bail;
622
623 VK_OUTARRAY_MAKE_TYPED(VkDisplayPlaneProperties2KHR, conn,
624 pProperties, pPropertyCount);
625
626 wsi_for_each_connector(connector, wsi) {
627 vk_outarray_append_typed(VkDisplayPlaneProperties2KHR, &conn, prop) {
628 wsi_display_fill_in_display_plane_properties(connector, prop);
629 }
630 }
631 return vk_outarray_status(&conn);
632
633 bail:
634 *pPropertyCount = 0;
635 return result;
636 }
637
638 /*
639 * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display)
640 */
641
642 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice,uint32_t planeIndex,uint32_t * pDisplayCount,VkDisplayKHR * pDisplays)643 wsi_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice,
644 uint32_t planeIndex,
645 uint32_t *pDisplayCount,
646 VkDisplayKHR *pDisplays)
647 {
648 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
649 struct wsi_device *wsi_device = pdevice->wsi_device;
650 struct wsi_display *wsi =
651 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
652
653 VK_OUTARRAY_MAKE_TYPED(VkDisplayKHR, conn, pDisplays, pDisplayCount);
654
655 int c = 0;
656
657 wsi_for_each_connector(connector, wsi) {
658 if (c == planeIndex && connector->connected) {
659 vk_outarray_append_typed(VkDisplayKHR, &conn, display) {
660 *display = wsi_display_connector_to_handle(connector);
661 }
662 }
663 c++;
664 }
665 return vk_outarray_status(&conn);
666 }
667
668 /*
669 * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
670 */
671
672 static void
wsi_display_fill_in_display_mode_properties(struct wsi_display_mode * display_mode,VkDisplayModeProperties2KHR * properties)673 wsi_display_fill_in_display_mode_properties(
674 struct wsi_display_mode *display_mode,
675 VkDisplayModeProperties2KHR *properties)
676 {
677 assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR);
678 VkDisplayModePropertiesKHR *prop = &properties->displayModeProperties;
679
680 prop->displayMode = wsi_display_mode_to_handle(display_mode);
681 prop->parameters.visibleRegion.width = display_mode->hdisplay;
682 prop->parameters.visibleRegion.height = display_mode->vdisplay;
683 prop->parameters.refreshRate =
684 (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
685 }
686
687 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice,VkDisplayKHR display,uint32_t * pPropertyCount,VkDisplayModePropertiesKHR * pProperties)688 wsi_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice,
689 VkDisplayKHR display,
690 uint32_t *pPropertyCount,
691 VkDisplayModePropertiesKHR *pProperties)
692 {
693 struct wsi_display_connector *connector =
694 wsi_display_connector_from_handle(display);
695
696 VK_OUTARRAY_MAKE_TYPED(VkDisplayModePropertiesKHR, conn,
697 pProperties, pPropertyCount);
698
699 wsi_for_each_display_mode(display_mode, connector) {
700 if (!display_mode->valid)
701 continue;
702
703 vk_outarray_append_typed(VkDisplayModePropertiesKHR, &conn, prop) {
704 VkDisplayModeProperties2KHR prop2 = {
705 .sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR,
706 };
707 wsi_display_fill_in_display_mode_properties(display_mode, &prop2);
708 *prop = prop2.displayModeProperties;
709 }
710 }
711 return vk_outarray_status(&conn);
712 }
713
714 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice,VkDisplayKHR display,uint32_t * pPropertyCount,VkDisplayModeProperties2KHR * pProperties)715 wsi_GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice,
716 VkDisplayKHR display,
717 uint32_t *pPropertyCount,
718 VkDisplayModeProperties2KHR *pProperties)
719 {
720 struct wsi_display_connector *connector =
721 wsi_display_connector_from_handle(display);
722
723 VK_OUTARRAY_MAKE_TYPED(VkDisplayModeProperties2KHR, conn,
724 pProperties, pPropertyCount);
725
726 wsi_for_each_display_mode(display_mode, connector) {
727 if (!display_mode->valid)
728 continue;
729
730 vk_outarray_append_typed(VkDisplayModeProperties2KHR, &conn, prop) {
731 wsi_display_fill_in_display_mode_properties(display_mode, prop);
732 }
733 }
734 return vk_outarray_status(&conn);
735 }
736
737 static bool
wsi_display_mode_matches_vk(wsi_display_mode * wsi,const VkDisplayModeParametersKHR * vk)738 wsi_display_mode_matches_vk(wsi_display_mode *wsi,
739 const VkDisplayModeParametersKHR *vk)
740 {
741 return (vk->visibleRegion.width == wsi->hdisplay &&
742 vk->visibleRegion.height == wsi->vdisplay &&
743 fabs(wsi_display_mode_refresh(wsi) * 1000.0 - vk->refreshRate) < 10);
744 }
745
746 /*
747 * Implement vkCreateDisplayModeKHR (VK_KHR_display)
748 */
749 VKAPI_ATTR VkResult VKAPI_CALL
wsi_CreateDisplayModeKHR(VkPhysicalDevice physicalDevice,VkDisplayKHR display,const VkDisplayModeCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDisplayModeKHR * pMode)750 wsi_CreateDisplayModeKHR(VkPhysicalDevice physicalDevice,
751 VkDisplayKHR display,
752 const VkDisplayModeCreateInfoKHR *pCreateInfo,
753 const VkAllocationCallbacks *pAllocator,
754 VkDisplayModeKHR *pMode)
755 {
756 struct wsi_display_connector *connector =
757 wsi_display_connector_from_handle(display);
758
759 if (pCreateInfo->flags != 0)
760 return VK_ERROR_INITIALIZATION_FAILED;
761
762 /* Check and see if the requested mode happens to match an existing one and
763 * return that. This makes the conformance suite happy. Doing more than
764 * this would involve embedding the CVT function into the driver, which seems
765 * excessive.
766 */
767 wsi_for_each_display_mode(display_mode, connector) {
768 if (display_mode->valid) {
769 if (wsi_display_mode_matches_vk(display_mode, &pCreateInfo->parameters)) {
770 *pMode = wsi_display_mode_to_handle(display_mode);
771 return VK_SUCCESS;
772 }
773 }
774 }
775 return VK_ERROR_INITIALIZATION_FAILED;
776 }
777
778 /*
779 * Implement vkGetDisplayPlaneCapabilities
780 */
781 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice,VkDisplayModeKHR _mode,uint32_t planeIndex,VkDisplayPlaneCapabilitiesKHR * pCapabilities)782 wsi_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice,
783 VkDisplayModeKHR _mode,
784 uint32_t planeIndex,
785 VkDisplayPlaneCapabilitiesKHR *pCapabilities)
786 {
787 struct wsi_display_mode *mode = wsi_display_mode_from_handle(_mode);
788
789 /* XXX use actual values */
790 pCapabilities->supportedAlpha = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
791 pCapabilities->minSrcPosition.x = 0;
792 pCapabilities->minSrcPosition.y = 0;
793 pCapabilities->maxSrcPosition.x = 0;
794 pCapabilities->maxSrcPosition.y = 0;
795 pCapabilities->minSrcExtent.width = mode->hdisplay;
796 pCapabilities->minSrcExtent.height = mode->vdisplay;
797 pCapabilities->maxSrcExtent.width = mode->hdisplay;
798 pCapabilities->maxSrcExtent.height = mode->vdisplay;
799 pCapabilities->minDstPosition.x = 0;
800 pCapabilities->minDstPosition.y = 0;
801 pCapabilities->maxDstPosition.x = 0;
802 pCapabilities->maxDstPosition.y = 0;
803 pCapabilities->minDstExtent.width = mode->hdisplay;
804 pCapabilities->minDstExtent.height = mode->vdisplay;
805 pCapabilities->maxDstExtent.width = mode->hdisplay;
806 pCapabilities->maxDstExtent.height = mode->vdisplay;
807 return VK_SUCCESS;
808 }
809
810 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,const VkDisplayPlaneInfo2KHR * pDisplayPlaneInfo,VkDisplayPlaneCapabilities2KHR * pCapabilities)811 wsi_GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice,
812 const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
813 VkDisplayPlaneCapabilities2KHR *pCapabilities)
814 {
815 assert(pCapabilities->sType ==
816 VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR);
817
818 VkResult result =
819 wsi_GetDisplayPlaneCapabilitiesKHR(physicalDevice,
820 pDisplayPlaneInfo->mode,
821 pDisplayPlaneInfo->planeIndex,
822 &pCapabilities->capabilities);
823
824 vk_foreach_struct(ext, pCapabilities->pNext) {
825 switch (ext->sType) {
826 case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
827 VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
828 protected->supportsProtected = VK_FALSE;
829 break;
830 }
831
832 default:
833 /* Ignored */
834 break;
835 }
836 }
837
838 return result;
839 }
840
841 VKAPI_ATTR VkResult VKAPI_CALL
wsi_CreateDisplayPlaneSurfaceKHR(VkInstance _instance,const VkDisplaySurfaceCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface)842 wsi_CreateDisplayPlaneSurfaceKHR(VkInstance _instance,
843 const VkDisplaySurfaceCreateInfoKHR *pCreateInfo,
844 const VkAllocationCallbacks *pAllocator,
845 VkSurfaceKHR *pSurface)
846 {
847 VK_FROM_HANDLE(vk_instance, instance, _instance);
848 VkIcdSurfaceDisplay *surface;
849
850 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR);
851
852 surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8,
853 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
854 if (surface == NULL)
855 return VK_ERROR_OUT_OF_HOST_MEMORY;
856
857 surface->base.platform = VK_ICD_WSI_PLATFORM_DISPLAY;
858
859 surface->displayMode = pCreateInfo->displayMode;
860 surface->planeIndex = pCreateInfo->planeIndex;
861 surface->planeStackIndex = pCreateInfo->planeStackIndex;
862 surface->transform = pCreateInfo->transform;
863 surface->globalAlpha = pCreateInfo->globalAlpha;
864 surface->alphaMode = pCreateInfo->alphaMode;
865 surface->imageExtent = pCreateInfo->imageExtent;
866
867 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
868
869 return VK_SUCCESS;
870 }
871
872 static VkResult
wsi_display_surface_get_support(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t queueFamilyIndex,VkBool32 * pSupported)873 wsi_display_surface_get_support(VkIcdSurfaceBase *surface,
874 struct wsi_device *wsi_device,
875 uint32_t queueFamilyIndex,
876 VkBool32* pSupported)
877 {
878 struct wsi_display *wsi =
879 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
880
881 *pSupported = wsi->fd != -1;
882 return VK_SUCCESS;
883 }
884
885 static VkResult
wsi_display_surface_get_capabilities(VkIcdSurfaceBase * surface_base,struct wsi_device * wsi_device,VkSurfaceCapabilitiesKHR * caps)886 wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base,
887 struct wsi_device *wsi_device,
888 VkSurfaceCapabilitiesKHR* caps)
889 {
890 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
891 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
892
893 caps->currentExtent.width = mode->hdisplay;
894 caps->currentExtent.height = mode->vdisplay;
895
896 caps->minImageExtent = (VkExtent2D) { 1, 1 };
897 caps->maxImageExtent = (VkExtent2D) {
898 wsi_device->maxImageDimension2D,
899 wsi_device->maxImageDimension2D,
900 };
901
902 caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
903
904 caps->minImageCount = 2;
905 caps->maxImageCount = 0;
906
907 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
908 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
909 caps->maxImageArrayLayers = 1;
910 caps->supportedUsageFlags = wsi_caps_get_image_usage();
911
912 VK_FROM_HANDLE(vk_physical_device, pdevice, wsi_device->pdevice);
913 if (pdevice->supported_extensions.EXT_attachment_feedback_loop_layout)
914 caps->supportedUsageFlags |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT;
915
916 return VK_SUCCESS;
917 }
918
919 static VkResult
wsi_display_surface_get_surface_counters(VkSurfaceCounterFlagsEXT * counters)920 wsi_display_surface_get_surface_counters(VkSurfaceCounterFlagsEXT *counters)
921 {
922 *counters = VK_SURFACE_COUNTER_VBLANK_BIT_EXT;
923 return VK_SUCCESS;
924 }
925
926 static VkResult
wsi_display_surface_get_capabilities2(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,const void * info_next,VkSurfaceCapabilities2KHR * caps)927 wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
928 struct wsi_device *wsi_device,
929 const void *info_next,
930 VkSurfaceCapabilities2KHR *caps)
931 {
932 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
933 VkResult result;
934
935 result = wsi_display_surface_get_capabilities(icd_surface, wsi_device,
936 &caps->surfaceCapabilities);
937 if (result != VK_SUCCESS)
938 return result;
939
940 struct wsi_surface_supported_counters *counters =
941 vk_find_struct( caps->pNext, WSI_SURFACE_SUPPORTED_COUNTERS_MESA);
942 const VkSurfacePresentModeEXT *present_mode =
943 vk_find_struct_const(info_next, SURFACE_PRESENT_MODE_EXT);
944
945 if (counters) {
946 result = wsi_display_surface_get_surface_counters(&counters->supported_surface_counters);
947 }
948
949 vk_foreach_struct(ext, caps->pNext) {
950 switch (ext->sType) {
951 case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
952 VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
953 protected->supportsProtected = VK_FALSE;
954 break;
955 }
956
957 case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: {
958 /* Unsupported. */
959 VkSurfacePresentScalingCapabilitiesEXT *scaling = (void *)ext;
960 scaling->supportedPresentScaling = 0;
961 scaling->supportedPresentGravityX = 0;
962 scaling->supportedPresentGravityY = 0;
963 scaling->minScaledImageExtent = caps->surfaceCapabilities.minImageExtent;
964 scaling->maxScaledImageExtent = caps->surfaceCapabilities.maxImageExtent;
965 break;
966 }
967
968 case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: {
969 /* We only support FIFO. */
970 VkSurfacePresentModeCompatibilityEXT *compat = (void *)ext;
971 if (compat->pPresentModes) {
972 if (compat->presentModeCount) {
973 assert(present_mode);
974 compat->pPresentModes[0] = present_mode->presentMode;
975 compat->presentModeCount = 1;
976 }
977 } else {
978 compat->presentModeCount = 1;
979 }
980 break;
981 }
982
983 default:
984 /* Ignored */
985 break;
986 }
987 }
988
989 return result;
990 }
991
992 struct wsi_display_surface_format {
993 VkSurfaceFormatKHR surface_format;
994 uint32_t drm_format;
995 };
996
997 static const struct wsi_display_surface_format
998 available_surface_formats[] = {
999 {
1000 .surface_format = {
1001 .format = VK_FORMAT_B8G8R8A8_SRGB,
1002 .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
1003 },
1004 .drm_format = DRM_FORMAT_XRGB8888
1005 },
1006 {
1007 .surface_format = {
1008 .format = VK_FORMAT_B8G8R8A8_UNORM,
1009 .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
1010 },
1011 .drm_format = DRM_FORMAT_XRGB8888
1012 },
1013 };
1014
1015 static void
get_sorted_vk_formats(struct wsi_device * wsi_device,VkSurfaceFormatKHR * sorted_formats)1016 get_sorted_vk_formats(struct wsi_device *wsi_device, VkSurfaceFormatKHR *sorted_formats)
1017 {
1018 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)
1019 sorted_formats[i] = available_surface_formats[i].surface_format;
1020
1021 if (wsi_device->force_bgra8_unorm_first) {
1022 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
1023 if (sorted_formats[i].format == VK_FORMAT_B8G8R8A8_UNORM) {
1024 VkSurfaceFormatKHR tmp = sorted_formats[i];
1025 sorted_formats[i] = sorted_formats[0];
1026 sorted_formats[0] = tmp;
1027 break;
1028 }
1029 }
1030 }
1031 }
1032
1033 static VkResult
wsi_display_surface_get_formats(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,uint32_t * surface_format_count,VkSurfaceFormatKHR * surface_formats)1034 wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
1035 struct wsi_device *wsi_device,
1036 uint32_t *surface_format_count,
1037 VkSurfaceFormatKHR *surface_formats)
1038 {
1039 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out,
1040 surface_formats, surface_format_count);
1041
1042 VkSurfaceFormatKHR sorted_formats[ARRAY_SIZE(available_surface_formats)];
1043 get_sorted_vk_formats(wsi_device, sorted_formats);
1044
1045 for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
1046 vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) {
1047 *f = sorted_formats[i];
1048 }
1049 }
1050
1051 return vk_outarray_status(&out);
1052 }
1053
1054 static VkResult
wsi_display_surface_get_formats2(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,const void * info_next,uint32_t * surface_format_count,VkSurfaceFormat2KHR * surface_formats)1055 wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
1056 struct wsi_device *wsi_device,
1057 const void *info_next,
1058 uint32_t *surface_format_count,
1059 VkSurfaceFormat2KHR *surface_formats)
1060 {
1061 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out,
1062 surface_formats, surface_format_count);
1063
1064 VkSurfaceFormatKHR sorted_formats[ARRAY_SIZE(available_surface_formats)];
1065 get_sorted_vk_formats(wsi_device, sorted_formats);
1066
1067 for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
1068 vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) {
1069 assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
1070 f->surfaceFormat = sorted_formats[i];
1071 }
1072 }
1073
1074 return vk_outarray_status(&out);
1075 }
1076
1077 static VkResult
wsi_display_surface_get_present_modes(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t * present_mode_count,VkPresentModeKHR * present_modes)1078 wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface,
1079 struct wsi_device *wsi_device,
1080 uint32_t *present_mode_count,
1081 VkPresentModeKHR *present_modes)
1082 {
1083 VK_OUTARRAY_MAKE_TYPED(VkPresentModeKHR, conn,
1084 present_modes, present_mode_count);
1085
1086 vk_outarray_append_typed(VkPresentModeKHR, &conn, present) {
1087 *present = VK_PRESENT_MODE_FIFO_KHR;
1088 }
1089
1090 return vk_outarray_status(&conn);
1091 }
1092
1093 static VkResult
wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase * surface_base,struct wsi_device * wsi_device,uint32_t * pRectCount,VkRect2D * pRects)1094 wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base,
1095 struct wsi_device *wsi_device,
1096 uint32_t* pRectCount,
1097 VkRect2D* pRects)
1098 {
1099 VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
1100 wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
1101 VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount);
1102
1103 if (wsi_device->can_present_on_device(wsi_device->pdevice, mode->connector->wsi->fd)) {
1104 vk_outarray_append_typed(VkRect2D, &out, rect) {
1105 *rect = (VkRect2D) {
1106 .offset = { 0, 0 },
1107 .extent = { mode->hdisplay, mode->vdisplay },
1108 };
1109 }
1110 }
1111
1112 return vk_outarray_status(&out);
1113 }
1114
1115 static void
wsi_display_destroy_buffer(struct wsi_display * wsi,uint32_t buffer)1116 wsi_display_destroy_buffer(struct wsi_display *wsi,
1117 uint32_t buffer)
1118 {
1119 (void) drmIoctl(wsi->fd, DRM_IOCTL_GEM_CLOSE,
1120 &((struct drm_gem_close) { .handle = buffer }));
1121 }
1122
1123 static VkResult
wsi_display_image_init(struct wsi_swapchain * drv_chain,const VkSwapchainCreateInfoKHR * create_info,struct wsi_display_image * image)1124 wsi_display_image_init(struct wsi_swapchain *drv_chain,
1125 const VkSwapchainCreateInfoKHR *create_info,
1126 struct wsi_display_image *image)
1127 {
1128 struct wsi_display_swapchain *chain =
1129 (struct wsi_display_swapchain *) drv_chain;
1130 struct wsi_display *wsi = chain->wsi;
1131 uint32_t drm_format = 0;
1132
1133 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
1134 if (create_info->imageFormat == available_surface_formats[i].surface_format.format &&
1135 create_info->imageColorSpace == available_surface_formats[i].surface_format.colorSpace) {
1136 drm_format = available_surface_formats[i].drm_format;
1137 break;
1138 }
1139 }
1140
1141 /* the application provided an invalid format, bail */
1142 if (drm_format == 0)
1143 return VK_ERROR_DEVICE_LOST;
1144
1145 VkResult result = wsi_create_image(&chain->base, &chain->base.image_info,
1146 &image->base);
1147 if (result != VK_SUCCESS)
1148 return result;
1149
1150 memset(image->buffer, 0, sizeof (image->buffer));
1151
1152 for (unsigned int i = 0; i < image->base.num_planes; i++) {
1153 int ret = drmPrimeFDToHandle(wsi->fd, image->base.dma_buf_fd,
1154 &image->buffer[i]);
1155 if (ret < 0)
1156 goto fail_handle;
1157 }
1158
1159 image->chain = chain;
1160 image->state = WSI_IMAGE_IDLE;
1161 image->fb_id = 0;
1162
1163 int ret = drmModeAddFB2(wsi->fd,
1164 create_info->imageExtent.width,
1165 create_info->imageExtent.height,
1166 drm_format,
1167 image->buffer,
1168 image->base.row_pitches,
1169 image->base.offsets,
1170 &image->fb_id, 0);
1171
1172 if (ret)
1173 goto fail_fb;
1174
1175 return VK_SUCCESS;
1176
1177 fail_fb:
1178 fail_handle:
1179 for (unsigned int i = 0; i < image->base.num_planes; i++) {
1180 if (image->buffer[i])
1181 wsi_display_destroy_buffer(wsi, image->buffer[i]);
1182 }
1183
1184 wsi_destroy_image(&chain->base, &image->base);
1185
1186 return VK_ERROR_OUT_OF_HOST_MEMORY;
1187 }
1188
1189 static void
wsi_display_image_finish(struct wsi_swapchain * drv_chain,struct wsi_display_image * image)1190 wsi_display_image_finish(struct wsi_swapchain *drv_chain,
1191 struct wsi_display_image *image)
1192 {
1193 struct wsi_display_swapchain *chain =
1194 (struct wsi_display_swapchain *) drv_chain;
1195 struct wsi_display *wsi = chain->wsi;
1196
1197 drmModeRmFB(wsi->fd, image->fb_id);
1198 for (unsigned int i = 0; i < image->base.num_planes; i++)
1199 wsi_display_destroy_buffer(wsi, image->buffer[i]);
1200 wsi_destroy_image(&chain->base, &image->base);
1201 }
1202
1203 static VkResult
wsi_display_swapchain_destroy(struct wsi_swapchain * drv_chain,const VkAllocationCallbacks * allocator)1204 wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain,
1205 const VkAllocationCallbacks *allocator)
1206 {
1207 struct wsi_display_swapchain *chain =
1208 (struct wsi_display_swapchain *) drv_chain;
1209
1210 for (uint32_t i = 0; i < chain->base.image_count; i++)
1211 wsi_display_image_finish(drv_chain, &chain->images[i]);
1212
1213 mtx_destroy(&chain->present_id_mutex);
1214 u_cnd_monotonic_destroy(&chain->present_id_cond);
1215
1216 wsi_swapchain_finish(&chain->base);
1217 vk_free(allocator, chain);
1218 return VK_SUCCESS;
1219 }
1220
1221 static struct wsi_image *
wsi_display_get_wsi_image(struct wsi_swapchain * drv_chain,uint32_t image_index)1222 wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain,
1223 uint32_t image_index)
1224 {
1225 struct wsi_display_swapchain *chain =
1226 (struct wsi_display_swapchain *) drv_chain;
1227
1228 return &chain->images[image_index].base;
1229 }
1230
1231 static void
wsi_display_idle_old_displaying(struct wsi_display_image * active_image)1232 wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
1233 {
1234 struct wsi_display_swapchain *chain = active_image->chain;
1235
1236 wsi_display_debug("idle everyone but %ld\n",
1237 active_image - &(chain->images[0]));
1238 for (uint32_t i = 0; i < chain->base.image_count; i++)
1239 if (chain->images[i].state == WSI_IMAGE_DISPLAYING &&
1240 &chain->images[i] != active_image)
1241 {
1242 wsi_display_debug("idle %d\n", i);
1243 chain->images[i].state = WSI_IMAGE_IDLE;
1244 }
1245 }
1246
1247 static VkResult
1248 _wsi_display_queue_next(struct wsi_swapchain *drv_chain);
1249
1250 static void
wsi_display_present_complete(struct wsi_display_swapchain * swapchain,struct wsi_display_image * image)1251 wsi_display_present_complete(struct wsi_display_swapchain *swapchain,
1252 struct wsi_display_image *image)
1253 {
1254 if (image->present_id) {
1255 mtx_lock(&swapchain->present_id_mutex);
1256 if (image->present_id > swapchain->present_id) {
1257 swapchain->present_id = image->present_id;
1258 u_cnd_monotonic_broadcast(&swapchain->present_id_cond);
1259 }
1260 mtx_unlock(&swapchain->present_id_mutex);
1261 }
1262 }
1263
1264 static void
wsi_display_surface_error(struct wsi_display_swapchain * swapchain,VkResult result)1265 wsi_display_surface_error(struct wsi_display_swapchain *swapchain, VkResult result)
1266 {
1267 mtx_lock(&swapchain->present_id_mutex);
1268 swapchain->present_id = UINT64_MAX;
1269 swapchain->present_id_error = result;
1270 u_cnd_monotonic_broadcast(&swapchain->present_id_cond);
1271 mtx_unlock(&swapchain->present_id_mutex);
1272 }
1273
1274 static void
wsi_display_page_flip_handler2(int fd,unsigned int frame,unsigned int sec,unsigned int usec,uint32_t crtc_id,void * data)1275 wsi_display_page_flip_handler2(int fd,
1276 unsigned int frame,
1277 unsigned int sec,
1278 unsigned int usec,
1279 uint32_t crtc_id,
1280 void *data)
1281 {
1282 struct wsi_display_image *image = data;
1283 struct wsi_display_swapchain *chain = image->chain;
1284
1285 wsi_display_debug("image %ld displayed at %d\n",
1286 image - &(image->chain->images[0]), frame);
1287 image->state = WSI_IMAGE_DISPLAYING;
1288 wsi_display_present_complete(chain, image);
1289
1290 wsi_display_idle_old_displaying(image);
1291 VkResult result = _wsi_display_queue_next(&(chain->base));
1292 if (result != VK_SUCCESS)
1293 chain->status = result;
1294 }
1295
1296 static void wsi_display_fence_event_handler(struct wsi_display_fence *fence);
1297
wsi_display_page_flip_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)1298 static void wsi_display_page_flip_handler(int fd,
1299 unsigned int frame,
1300 unsigned int sec,
1301 unsigned int usec,
1302 void *data)
1303 {
1304 wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
1305 }
1306
wsi_display_vblank_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)1307 static void wsi_display_vblank_handler(int fd, unsigned int frame,
1308 unsigned int sec, unsigned int usec,
1309 void *data)
1310 {
1311 struct wsi_display_fence *fence = data;
1312
1313 wsi_display_fence_event_handler(fence);
1314 }
1315
wsi_display_sequence_handler(int fd,uint64_t frame,uint64_t nsec,uint64_t user_data)1316 static void wsi_display_sequence_handler(int fd, uint64_t frame,
1317 uint64_t nsec, uint64_t user_data)
1318 {
1319 struct wsi_display_fence *fence =
1320 (struct wsi_display_fence *) (uintptr_t) user_data;
1321
1322 wsi_display_fence_event_handler(fence);
1323 }
1324
1325 static drmEventContext event_context = {
1326 .version = DRM_EVENT_CONTEXT_VERSION,
1327 .page_flip_handler = wsi_display_page_flip_handler,
1328 #if DRM_EVENT_CONTEXT_VERSION >= 3
1329 .page_flip_handler2 = wsi_display_page_flip_handler2,
1330 #endif
1331 .vblank_handler = wsi_display_vblank_handler,
1332 .sequence_handler = wsi_display_sequence_handler,
1333 };
1334
1335 static void *
wsi_display_wait_thread(void * data)1336 wsi_display_wait_thread(void *data)
1337 {
1338 struct wsi_display *wsi = data;
1339 struct pollfd pollfd = {
1340 .fd = wsi->fd,
1341 .events = POLLIN
1342 };
1343
1344 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1345 for (;;) {
1346 int ret = poll(&pollfd, 1, -1);
1347 if (ret > 0) {
1348 mtx_lock(&wsi->wait_mutex);
1349 (void) drmHandleEvent(wsi->fd, &event_context);
1350 u_cnd_monotonic_broadcast(&wsi->wait_cond);
1351 mtx_unlock(&wsi->wait_mutex);
1352 }
1353 }
1354 return NULL;
1355 }
1356
1357 static int
wsi_display_start_wait_thread(struct wsi_display * wsi)1358 wsi_display_start_wait_thread(struct wsi_display *wsi)
1359 {
1360 if (!wsi->wait_thread) {
1361 int ret = pthread_create(&wsi->wait_thread, NULL,
1362 wsi_display_wait_thread, wsi);
1363 if (ret)
1364 return ret;
1365 }
1366 return 0;
1367 }
1368
1369 static void
wsi_display_stop_wait_thread(struct wsi_display * wsi)1370 wsi_display_stop_wait_thread(struct wsi_display *wsi)
1371 {
1372 mtx_lock(&wsi->wait_mutex);
1373 if (wsi->wait_thread) {
1374 pthread_cancel(wsi->wait_thread);
1375 pthread_join(wsi->wait_thread, NULL);
1376 wsi->wait_thread = 0;
1377 }
1378 mtx_unlock(&wsi->wait_mutex);
1379 }
1380
1381 static int
cond_timedwait_ns(struct u_cnd_monotonic * cond,mtx_t * mutex,uint64_t timeout_ns)1382 cond_timedwait_ns(struct u_cnd_monotonic *cond,
1383 mtx_t *mutex,
1384 uint64_t timeout_ns)
1385 {
1386 struct timespec abs_timeout = {
1387 .tv_sec = timeout_ns / 1000000000ULL,
1388 .tv_nsec = timeout_ns % 1000000000ULL,
1389 };
1390
1391 int ret = u_cnd_monotonic_timedwait(cond, mutex, &abs_timeout);
1392 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);
1393 return ret;
1394 }
1395
1396 /*
1397 * Wait for at least one event from the kernel to be processed.
1398 * Call with wait_mutex held
1399 */
1400 static int
wsi_display_wait_for_event(struct wsi_display * wsi,uint64_t timeout_ns)1401 wsi_display_wait_for_event(struct wsi_display *wsi,
1402 uint64_t timeout_ns)
1403 {
1404 int ret = wsi_display_start_wait_thread(wsi);
1405
1406 if (ret)
1407 return ret;
1408
1409 return cond_timedwait_ns(&wsi->wait_cond, &wsi->wait_mutex, timeout_ns);
1410 }
1411
1412 /* Wait for device event to be processed.
1413 * Call with wait_mutex held
1414 */
1415 static int
wsi_device_wait_for_event(struct wsi_display * wsi,uint64_t timeout_ns)1416 wsi_device_wait_for_event(struct wsi_display *wsi,
1417 uint64_t timeout_ns)
1418 {
1419 return cond_timedwait_ns(&wsi->hotplug_cond, &wsi->wait_mutex, timeout_ns);
1420 }
1421
1422 static VkResult
wsi_display_release_images(struct wsi_swapchain * drv_chain,uint32_t count,const uint32_t * indices)1423 wsi_display_release_images(struct wsi_swapchain *drv_chain,
1424 uint32_t count, const uint32_t *indices)
1425 {
1426 struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)drv_chain;
1427 if (chain->status == VK_ERROR_SURFACE_LOST_KHR)
1428 return chain->status;
1429
1430 for (uint32_t i = 0; i < count; i++) {
1431 uint32_t index = indices[i];
1432 assert(index < chain->base.image_count);
1433 assert(chain->images[index].state == WSI_IMAGE_DRAWING);
1434 chain->images[index].state = WSI_IMAGE_IDLE;
1435 }
1436
1437 return VK_SUCCESS;
1438 }
1439
1440 static VkResult
wsi_display_acquire_next_image(struct wsi_swapchain * drv_chain,const VkAcquireNextImageInfoKHR * info,uint32_t * image_index)1441 wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
1442 const VkAcquireNextImageInfoKHR *info,
1443 uint32_t *image_index)
1444 {
1445 struct wsi_display_swapchain *chain =
1446 (struct wsi_display_swapchain *)drv_chain;
1447 struct wsi_display *wsi = chain->wsi;
1448 int ret = 0;
1449 VkResult result = VK_SUCCESS;
1450
1451 /* Bail early if the swapchain is broken */
1452 if (chain->status != VK_SUCCESS)
1453 return chain->status;
1454
1455 uint64_t timeout = info->timeout;
1456 if (timeout != 0 && timeout != UINT64_MAX)
1457 timeout = wsi_rel_to_abs_time(timeout);
1458
1459 mtx_lock(&wsi->wait_mutex);
1460 for (;;) {
1461 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1462 if (chain->images[i].state == WSI_IMAGE_IDLE) {
1463 *image_index = i;
1464 wsi_display_debug("image %d available\n", i);
1465 chain->images[i].state = WSI_IMAGE_DRAWING;
1466 result = VK_SUCCESS;
1467 goto done;
1468 }
1469 wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
1470 }
1471
1472 if (ret == ETIMEDOUT) {
1473 result = VK_TIMEOUT;
1474 goto done;
1475 }
1476
1477 ret = wsi_display_wait_for_event(wsi, timeout);
1478
1479 if (ret && ret != ETIMEDOUT) {
1480 result = VK_ERROR_SURFACE_LOST_KHR;
1481 wsi_display_surface_error(chain, result);
1482 goto done;
1483 }
1484 }
1485 done:
1486 mtx_unlock(&wsi->wait_mutex);
1487
1488 if (result != VK_SUCCESS)
1489 return result;
1490
1491 return chain->status;
1492 }
1493
1494 /*
1495 * Check whether there are any other connectors driven by this crtc
1496 */
1497 static bool
wsi_display_crtc_solo(struct wsi_display * wsi,drmModeResPtr mode_res,drmModeConnectorPtr connector,uint32_t crtc_id)1498 wsi_display_crtc_solo(struct wsi_display *wsi,
1499 drmModeResPtr mode_res,
1500 drmModeConnectorPtr connector,
1501 uint32_t crtc_id)
1502 {
1503 /* See if any other connectors share the same encoder */
1504 for (int c = 0; c < mode_res->count_connectors; c++) {
1505 if (mode_res->connectors[c] == connector->connector_id)
1506 continue;
1507
1508 drmModeConnectorPtr other_connector =
1509 drmModeGetConnector(wsi->fd, mode_res->connectors[c]);
1510
1511 if (other_connector) {
1512 bool match = (other_connector->encoder_id == connector->encoder_id);
1513 drmModeFreeConnector(other_connector);
1514 if (match)
1515 return false;
1516 }
1517 }
1518
1519 /* See if any other encoders share the same crtc */
1520 for (int e = 0; e < mode_res->count_encoders; e++) {
1521 if (mode_res->encoders[e] == connector->encoder_id)
1522 continue;
1523
1524 drmModeEncoderPtr other_encoder =
1525 drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);
1526
1527 if (other_encoder) {
1528 bool match = (other_encoder->crtc_id == crtc_id);
1529 drmModeFreeEncoder(other_encoder);
1530 if (match)
1531 return false;
1532 }
1533 }
1534 return true;
1535 }
1536
1537 /*
1538 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1539 * currently driving this connector and not any others. Settle for a CRTC
1540 * which is currently idle.
1541 */
1542 static uint32_t
wsi_display_select_crtc(const struct wsi_display_connector * connector,drmModeResPtr mode_res,drmModeConnectorPtr drm_connector)1543 wsi_display_select_crtc(const struct wsi_display_connector *connector,
1544 drmModeResPtr mode_res,
1545 drmModeConnectorPtr drm_connector)
1546 {
1547 struct wsi_display *wsi = connector->wsi;
1548
1549 /* See what CRTC is currently driving this connector */
1550 if (drm_connector->encoder_id) {
1551 drmModeEncoderPtr encoder =
1552 drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);
1553
1554 if (encoder) {
1555 uint32_t crtc_id = encoder->crtc_id;
1556 drmModeFreeEncoder(encoder);
1557 if (crtc_id) {
1558 if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))
1559 return crtc_id;
1560 }
1561 }
1562 }
1563 uint32_t crtc_id = 0;
1564 for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
1565 drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
1566 if (crtc && crtc->buffer_id == 0)
1567 crtc_id = crtc->crtc_id;
1568 drmModeFreeCrtc(crtc);
1569 }
1570 return crtc_id;
1571 }
1572
1573 static VkResult
wsi_display_setup_connector(wsi_display_connector * connector,wsi_display_mode * display_mode)1574 wsi_display_setup_connector(wsi_display_connector *connector,
1575 wsi_display_mode *display_mode)
1576 {
1577 struct wsi_display *wsi = connector->wsi;
1578
1579 if (connector->current_mode == display_mode && connector->crtc_id)
1580 return VK_SUCCESS;
1581
1582 VkResult result = VK_SUCCESS;
1583
1584 drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
1585 if (!mode_res) {
1586 if (errno == ENOMEM)
1587 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1588 else
1589 result = VK_ERROR_SURFACE_LOST_KHR;
1590 goto bail;
1591 }
1592
1593 drmModeConnectorPtr drm_connector =
1594 drmModeGetConnectorCurrent(wsi->fd, connector->id);
1595
1596 if (!drm_connector) {
1597 if (errno == ENOMEM)
1598 result = VK_ERROR_OUT_OF_HOST_MEMORY;
1599 else
1600 result = VK_ERROR_SURFACE_LOST_KHR;
1601 goto bail_mode_res;
1602 }
1603
1604 /* Pick a CRTC if we don't have one */
1605 if (!connector->crtc_id) {
1606 connector->crtc_id = wsi_display_select_crtc(connector,
1607 mode_res, drm_connector);
1608 if (!connector->crtc_id) {
1609 result = VK_ERROR_SURFACE_LOST_KHR;
1610 goto bail_connector;
1611 }
1612 }
1613
1614 if (connector->current_mode != display_mode) {
1615
1616 /* Find the drm mode corresponding to the requested VkDisplayMode */
1617 drmModeModeInfoPtr drm_mode = NULL;
1618
1619 for (int m = 0; m < drm_connector->count_modes; m++) {
1620 drm_mode = &drm_connector->modes[m];
1621 if (wsi_display_mode_matches_drm(display_mode, drm_mode))
1622 break;
1623 drm_mode = NULL;
1624 }
1625
1626 if (!drm_mode) {
1627 result = VK_ERROR_SURFACE_LOST_KHR;
1628 goto bail_connector;
1629 }
1630
1631 connector->current_mode = display_mode;
1632 connector->current_drm_mode = *drm_mode;
1633 }
1634
1635 bail_connector:
1636 drmModeFreeConnector(drm_connector);
1637 bail_mode_res:
1638 drmModeFreeResources(mode_res);
1639 bail:
1640 return result;
1641
1642 }
1643
1644 static VkResult
wsi_display_fence_wait(struct wsi_display_fence * fence,uint64_t timeout)1645 wsi_display_fence_wait(struct wsi_display_fence *fence, uint64_t timeout)
1646 {
1647 wsi_display_debug("%9lu wait fence %lu %ld\n",
1648 pthread_self(), fence->sequence,
1649 (int64_t) (timeout - os_time_get_nano()));
1650 wsi_display_debug_code(uint64_t start_ns = os_time_get_nano());
1651 mtx_lock(&fence->wsi->wait_mutex);
1652
1653 VkResult result;
1654 int ret = 0;
1655 for (;;) {
1656 if (fence->event_received) {
1657 wsi_display_debug("%9lu fence %lu passed\n",
1658 pthread_self(), fence->sequence);
1659 result = VK_SUCCESS;
1660 break;
1661 }
1662
1663 if (ret == ETIMEDOUT) {
1664 wsi_display_debug("%9lu fence %lu timeout\n",
1665 pthread_self(), fence->sequence);
1666 result = VK_TIMEOUT;
1667 break;
1668 }
1669
1670 if (fence->device_event)
1671 ret = wsi_device_wait_for_event(fence->wsi, timeout);
1672 else
1673 ret = wsi_display_wait_for_event(fence->wsi, timeout);
1674
1675 if (ret && ret != ETIMEDOUT) {
1676 wsi_display_debug("%9lu fence %lu error\n",
1677 pthread_self(), fence->sequence);
1678 result = VK_ERROR_DEVICE_LOST;
1679 break;
1680 }
1681 }
1682 mtx_unlock(&fence->wsi->wait_mutex);
1683 wsi_display_debug("%9lu fence wait %f ms\n",
1684 pthread_self(),
1685 ((int64_t) (os_time_get_nano() - start_ns)) /
1686 1.0e6);
1687 return result;
1688 }
1689
1690 static void
wsi_display_fence_check_free(struct wsi_display_fence * fence)1691 wsi_display_fence_check_free(struct wsi_display_fence *fence)
1692 {
1693 if (fence->event_received && fence->destroyed)
1694 vk_free(fence->wsi->alloc, fence);
1695 }
1696
wsi_display_fence_event_handler(struct wsi_display_fence * fence)1697 static void wsi_display_fence_event_handler(struct wsi_display_fence *fence)
1698 {
1699 if (fence->syncobj) {
1700 (void) drmSyncobjSignal(fence->wsi->syncobj_fd, &fence->syncobj, 1);
1701 (void) drmSyncobjDestroy(fence->wsi->syncobj_fd, fence->syncobj);
1702 }
1703
1704 fence->event_received = true;
1705 wsi_display_fence_check_free(fence);
1706 }
1707
1708 static void
wsi_display_fence_destroy(struct wsi_display_fence * fence)1709 wsi_display_fence_destroy(struct wsi_display_fence *fence)
1710 {
1711 /* Destroy hotplug fence list. */
1712 if (fence->device_event) {
1713 mtx_lock(&fence->wsi->wait_mutex);
1714 list_del(&fence->link);
1715 mtx_unlock(&fence->wsi->wait_mutex);
1716 fence->event_received = true;
1717 }
1718
1719 assert(!fence->destroyed);
1720 fence->destroyed = true;
1721 wsi_display_fence_check_free(fence);
1722 }
1723
1724 static struct wsi_display_fence *
wsi_display_fence_alloc(struct wsi_display * wsi,int sync_fd)1725 wsi_display_fence_alloc(struct wsi_display *wsi, int sync_fd)
1726 {
1727 struct wsi_display_fence *fence =
1728 vk_zalloc(wsi->alloc, sizeof (*fence),
1729 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1730
1731 if (!fence)
1732 return NULL;
1733
1734 if (sync_fd >= 0) {
1735 int ret = drmSyncobjFDToHandle(wsi->syncobj_fd, sync_fd, &fence->syncobj);
1736
1737 if (ret) {
1738 vk_free(wsi->alloc, fence);
1739 return NULL;
1740 }
1741 }
1742
1743 fence->wsi = wsi;
1744 fence->event_received = false;
1745 fence->destroyed = false;
1746 fence->sequence = ++fence_sequence;
1747 return fence;
1748 }
1749
1750 static VkResult
wsi_display_sync_init(struct vk_device * device,struct vk_sync * sync,uint64_t initial_value)1751 wsi_display_sync_init(struct vk_device *device,
1752 struct vk_sync *sync,
1753 uint64_t initial_value)
1754 {
1755 assert(initial_value == 0);
1756 return VK_SUCCESS;
1757 }
1758
1759 static void
wsi_display_sync_finish(struct vk_device * device,struct vk_sync * sync)1760 wsi_display_sync_finish(struct vk_device *device,
1761 struct vk_sync *sync)
1762 {
1763 struct wsi_display_sync *wsi_sync =
1764 container_of(sync, struct wsi_display_sync, sync);
1765 if (wsi_sync->fence)
1766 wsi_display_fence_destroy(wsi_sync->fence);
1767 }
1768
1769 static VkResult
wsi_display_sync_wait(struct vk_device * device,struct vk_sync * sync,uint64_t wait_value,enum vk_sync_wait_flags wait_flags,uint64_t abs_timeout_ns)1770 wsi_display_sync_wait(struct vk_device *device,
1771 struct vk_sync *sync,
1772 uint64_t wait_value,
1773 enum vk_sync_wait_flags wait_flags,
1774 uint64_t abs_timeout_ns)
1775 {
1776 struct wsi_display_sync *wsi_sync =
1777 container_of(sync, struct wsi_display_sync, sync);
1778
1779 assert(wait_value == 0);
1780 assert(wait_flags == VK_SYNC_WAIT_COMPLETE);
1781
1782 return wsi_display_fence_wait(wsi_sync->fence, abs_timeout_ns);
1783 }
1784
1785 static const struct vk_sync_type wsi_display_sync_type = {
1786 .size = sizeof(struct wsi_display_sync),
1787 .features = VK_SYNC_FEATURE_BINARY |
1788 VK_SYNC_FEATURE_CPU_WAIT,
1789 .init = wsi_display_sync_init,
1790 .finish = wsi_display_sync_finish,
1791 .wait = wsi_display_sync_wait,
1792 };
1793
1794 static VkResult
wsi_display_sync_create(struct vk_device * device,struct wsi_display_fence * fence,struct vk_sync ** sync_out)1795 wsi_display_sync_create(struct vk_device *device,
1796 struct wsi_display_fence *fence,
1797 struct vk_sync **sync_out)
1798 {
1799 VkResult result = vk_sync_create(device, &wsi_display_sync_type,
1800 0 /* flags */,
1801 0 /* initial_value */, sync_out);
1802 if (result != VK_SUCCESS)
1803 return result;
1804
1805 struct wsi_display_sync *sync =
1806 container_of(*sync_out, struct wsi_display_sync, sync);
1807
1808 sync->fence = fence;
1809
1810 return VK_SUCCESS;
1811 }
1812
1813 static VkResult
wsi_register_vblank_event(struct wsi_display_fence * fence,const struct wsi_device * wsi_device,VkDisplayKHR display,uint32_t flags,uint64_t frame_requested,uint64_t * frame_queued)1814 wsi_register_vblank_event(struct wsi_display_fence *fence,
1815 const struct wsi_device *wsi_device,
1816 VkDisplayKHR display,
1817 uint32_t flags,
1818 uint64_t frame_requested,
1819 uint64_t *frame_queued)
1820 {
1821 struct wsi_display *wsi =
1822 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1823 struct wsi_display_connector *connector =
1824 wsi_display_connector_from_handle(display);
1825
1826 if (wsi->fd < 0)
1827 return VK_ERROR_INITIALIZATION_FAILED;
1828
1829 /* A display event may be registered before the first page flip at which
1830 * point crtc_id will be 0. If this is the case we setup the connector
1831 * here to allow drmCrtcQueueSequence to succeed.
1832 */
1833 if (!connector->crtc_id) {
1834 VkResult ret = wsi_display_setup_connector(connector,
1835 connector->current_mode);
1836 if (ret != VK_SUCCESS)
1837 return VK_ERROR_INITIALIZATION_FAILED;
1838 }
1839
1840 for (;;) {
1841 int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id,
1842 flags,
1843 frame_requested,
1844 frame_queued,
1845 (uintptr_t) fence);
1846
1847 if (!ret)
1848 return VK_SUCCESS;
1849
1850 if (errno != ENOMEM) {
1851
1852 /* Something unexpected happened. Pause for a moment so the
1853 * application doesn't just spin and then return a failure indication
1854 */
1855
1856 wsi_display_debug("queue vblank event %lu failed\n", fence->sequence);
1857 struct timespec delay = {
1858 .tv_sec = 0,
1859 .tv_nsec = 100000000ull,
1860 };
1861 nanosleep(&delay, NULL);
1862 return VK_ERROR_OUT_OF_HOST_MEMORY;
1863 }
1864
1865 /* The kernel event queue is full. Wait for some events to be
1866 * processed and try again
1867 */
1868
1869 mtx_lock(&wsi->wait_mutex);
1870 ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull));
1871 mtx_unlock(&wsi->wait_mutex);
1872
1873 if (ret) {
1874 wsi_display_debug("vblank queue full, event wait failed\n");
1875 return VK_ERROR_OUT_OF_HOST_MEMORY;
1876 }
1877 }
1878 }
1879
1880 /*
1881 * Check to see if the kernel has no flip queued and if there's an image
1882 * waiting to be displayed.
1883 */
1884 static VkResult
_wsi_display_queue_next(struct wsi_swapchain * drv_chain)1885 _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
1886 {
1887 struct wsi_display_swapchain *chain =
1888 (struct wsi_display_swapchain *) drv_chain;
1889 struct wsi_display *wsi = chain->wsi;
1890 VkIcdSurfaceDisplay *surface = chain->surface;
1891 wsi_display_mode *display_mode =
1892 wsi_display_mode_from_handle(surface->displayMode);
1893 wsi_display_connector *connector = display_mode->connector;
1894
1895 if (wsi->fd < 0) {
1896 wsi_display_surface_error(chain, VK_ERROR_SURFACE_LOST_KHR);
1897 return VK_ERROR_SURFACE_LOST_KHR;
1898 }
1899
1900 if (display_mode != connector->current_mode)
1901 connector->active = false;
1902
1903 for (;;) {
1904
1905 /* Check to see if there is an image to display, or if some image is
1906 * already queued */
1907
1908 struct wsi_display_image *image = NULL;
1909
1910 for (uint32_t i = 0; i < chain->base.image_count; i++) {
1911 struct wsi_display_image *tmp_image = &chain->images[i];
1912
1913 switch (tmp_image->state) {
1914 case WSI_IMAGE_FLIPPING:
1915 /* already flipping, don't send another to the kernel yet */
1916 return VK_SUCCESS;
1917 case WSI_IMAGE_QUEUED:
1918 /* find the oldest queued */
1919 if (!image || tmp_image->flip_sequence < image->flip_sequence)
1920 image = tmp_image;
1921 break;
1922 default:
1923 break;
1924 }
1925 }
1926
1927 if (!image)
1928 return VK_SUCCESS;
1929
1930 int ret;
1931 if (connector->active) {
1932 ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
1933 DRM_MODE_PAGE_FLIP_EVENT, image);
1934 if (ret == 0) {
1935 image->state = WSI_IMAGE_FLIPPING;
1936 return VK_SUCCESS;
1937 }
1938 wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
1939 } else {
1940 ret = -EINVAL;
1941 }
1942
1943 if (ret == -EINVAL) {
1944 VkResult result = wsi_display_setup_connector(connector, display_mode);
1945
1946 if (result != VK_SUCCESS) {
1947 image->state = WSI_IMAGE_IDLE;
1948 return result;
1949 }
1950
1951 /* XXX allow setting of position */
1952 ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
1953 image->fb_id, 0, 0,
1954 &connector->id, 1,
1955 &connector->current_drm_mode);
1956 if (ret == 0) {
1957 /* Disable the HW cursor as the app doesn't have a mechanism
1958 * to control it.
1959 * Refer to question 12 of the VK_KHR_display spec.
1960 */
1961 ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 );
1962 if (ret != 0) {
1963 wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret));
1964 }
1965
1966 /* unset some properties another drm master might've set
1967 * which can mess up the image
1968 */
1969 drmModeObjectPropertiesPtr properties =
1970 drmModeObjectGetProperties(wsi->fd,
1971 connector->crtc_id,
1972 DRM_MODE_OBJECT_CRTC);
1973 for (uint32_t i = 0; i < properties->count_props; i++) {
1974 drmModePropertyPtr prop =
1975 drmModeGetProperty(wsi->fd, properties->props[i]);
1976 if (strcmp(prop->name, "GAMMA_LUT") == 0 ||
1977 strcmp(prop->name, "CTM") == 0 ||
1978 strcmp(prop->name, "DEGAMMA_LUT") == 0) {
1979 drmModeObjectSetProperty(wsi->fd, connector->crtc_id,
1980 DRM_MODE_OBJECT_CRTC,
1981 properties->props[i], 0);
1982 }
1983 drmModeFreeProperty(prop);
1984 }
1985 drmModeFreeObjectProperties(properties);
1986
1987 /* Assume that the mode set is synchronous and that any
1988 * previous image is now idle.
1989 */
1990 image->state = WSI_IMAGE_DISPLAYING;
1991 wsi_display_present_complete(chain, image);
1992 wsi_display_idle_old_displaying(image);
1993 connector->active = true;
1994 return VK_SUCCESS;
1995 }
1996 }
1997
1998 if (ret != -EACCES) {
1999 connector->active = false;
2000 image->state = WSI_IMAGE_IDLE;
2001 wsi_display_surface_error(chain, VK_ERROR_SURFACE_LOST_KHR);
2002 return VK_ERROR_SURFACE_LOST_KHR;
2003 }
2004
2005 /* Some other VT is currently active. Sit here waiting for
2006 * our VT to become active again by polling once a second
2007 */
2008 usleep(1000 * 1000);
2009 connector->active = false;
2010 }
2011 }
2012
2013 static VkResult
wsi_display_queue_present(struct wsi_swapchain * drv_chain,uint32_t image_index,uint64_t present_id,const VkPresentRegionKHR * damage)2014 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
2015 uint32_t image_index,
2016 uint64_t present_id,
2017 const VkPresentRegionKHR *damage)
2018 {
2019 struct wsi_display_swapchain *chain =
2020 (struct wsi_display_swapchain *) drv_chain;
2021 struct wsi_display *wsi = chain->wsi;
2022 struct wsi_display_image *image = &chain->images[image_index];
2023 VkResult result;
2024
2025 /* Bail early if the swapchain is broken */
2026 if (chain->status != VK_SUCCESS)
2027 return chain->status;
2028
2029 image->present_id = present_id;
2030
2031 assert(image->state == WSI_IMAGE_DRAWING);
2032 wsi_display_debug("present %d\n", image_index);
2033
2034 mtx_lock(&wsi->wait_mutex);
2035
2036 /* Make sure that the page flip handler is processed in finite time if using present wait. */
2037 if (present_id)
2038 wsi_display_start_wait_thread(wsi);
2039
2040 image->flip_sequence = ++chain->flip_sequence;
2041 image->state = WSI_IMAGE_QUEUED;
2042
2043 result = _wsi_display_queue_next(drv_chain);
2044 if (result != VK_SUCCESS)
2045 chain->status = result;
2046
2047 mtx_unlock(&wsi->wait_mutex);
2048
2049 if (result != VK_SUCCESS)
2050 return result;
2051
2052 return chain->status;
2053 }
2054
2055 static VkResult
wsi_display_wait_for_present(struct wsi_swapchain * wsi_chain,uint64_t waitValue,uint64_t timeout)2056 wsi_display_wait_for_present(struct wsi_swapchain *wsi_chain,
2057 uint64_t waitValue,
2058 uint64_t timeout)
2059 {
2060 struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)wsi_chain;
2061 struct timespec abs_timespec;
2062 uint64_t abs_timeout = 0;
2063
2064 if (timeout != 0)
2065 abs_timeout = os_time_get_absolute_timeout(timeout);
2066
2067 /* Need to observe that the swapchain semaphore has been unsignalled,
2068 * as this is guaranteed when a present is complete. */
2069 VkResult result = wsi_swapchain_wait_for_present_semaphore(
2070 &chain->base, waitValue, timeout);
2071 if (result != VK_SUCCESS)
2072 return result;
2073
2074 timespec_from_nsec(&abs_timespec, abs_timeout);
2075
2076 mtx_lock(&chain->present_id_mutex);
2077 while (chain->present_id < waitValue) {
2078 int ret = u_cnd_monotonic_timedwait(&chain->present_id_cond,
2079 &chain->present_id_mutex,
2080 &abs_timespec);
2081 if (ret == thrd_timedout) {
2082 result = VK_TIMEOUT;
2083 break;
2084 }
2085 if (ret != thrd_success) {
2086 result = VK_ERROR_DEVICE_LOST;
2087 break;
2088 }
2089 }
2090
2091 if (result == VK_SUCCESS && chain->present_id_error)
2092 result = chain->present_id_error;
2093 mtx_unlock(&chain->present_id_mutex);
2094 return result;
2095 }
2096
2097 static VkResult
wsi_display_surface_create_swapchain(VkIcdSurfaceBase * icd_surface,VkDevice device,struct wsi_device * wsi_device,const VkSwapchainCreateInfoKHR * create_info,const VkAllocationCallbacks * allocator,struct wsi_swapchain ** swapchain_out)2098 wsi_display_surface_create_swapchain(
2099 VkIcdSurfaceBase *icd_surface,
2100 VkDevice device,
2101 struct wsi_device *wsi_device,
2102 const VkSwapchainCreateInfoKHR *create_info,
2103 const VkAllocationCallbacks *allocator,
2104 struct wsi_swapchain **swapchain_out)
2105 {
2106 struct wsi_display *wsi =
2107 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2108
2109 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
2110
2111 const unsigned num_images = create_info->minImageCount;
2112 struct wsi_display_swapchain *chain =
2113 vk_zalloc(allocator,
2114 sizeof(*chain) + num_images * sizeof(chain->images[0]),
2115 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2116
2117 if (chain == NULL)
2118 return VK_ERROR_OUT_OF_HOST_MEMORY;
2119
2120 struct wsi_drm_image_params image_params = {
2121 .base.image_type = WSI_IMAGE_TYPE_DRM,
2122 .same_gpu = true,
2123 };
2124
2125 int ret = mtx_init(&chain->present_id_mutex, mtx_plain);
2126 if (ret != thrd_success) {
2127 vk_free(allocator, chain);
2128 return VK_ERROR_OUT_OF_HOST_MEMORY;
2129 }
2130
2131 ret = u_cnd_monotonic_init(&chain->present_id_cond);
2132 if (ret != thrd_success) {
2133 mtx_destroy(&chain->present_id_mutex);
2134 vk_free(allocator, chain);
2135 return VK_ERROR_OUT_OF_HOST_MEMORY;
2136 }
2137
2138 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
2139 create_info, &image_params.base,
2140 allocator);
2141 if (result != VK_SUCCESS) {
2142 u_cnd_monotonic_destroy(&chain->present_id_cond);
2143 mtx_destroy(&chain->present_id_mutex);
2144 vk_free(allocator, chain);
2145 return result;
2146 }
2147
2148 chain->base.destroy = wsi_display_swapchain_destroy;
2149 chain->base.get_wsi_image = wsi_display_get_wsi_image;
2150 chain->base.acquire_next_image = wsi_display_acquire_next_image;
2151 chain->base.release_images = wsi_display_release_images;
2152 chain->base.queue_present = wsi_display_queue_present;
2153 chain->base.wait_for_present = wsi_display_wait_for_present;
2154 chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
2155 chain->base.image_count = num_images;
2156
2157 chain->wsi = wsi;
2158 chain->status = VK_SUCCESS;
2159
2160 chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
2161
2162 for (uint32_t image = 0; image < chain->base.image_count; image++) {
2163 result = wsi_display_image_init(&chain->base,
2164 create_info,
2165 &chain->images[image]);
2166 if (result != VK_SUCCESS) {
2167 while (image > 0) {
2168 --image;
2169 wsi_display_image_finish(&chain->base,
2170 &chain->images[image]);
2171 }
2172 u_cnd_monotonic_destroy(&chain->present_id_cond);
2173 mtx_destroy(&chain->present_id_mutex);
2174 wsi_swapchain_finish(&chain->base);
2175 vk_free(allocator, chain);
2176 goto fail_init_images;
2177 }
2178 }
2179
2180 *swapchain_out = &chain->base;
2181
2182 return VK_SUCCESS;
2183
2184 fail_init_images:
2185 return result;
2186 }
2187
2188 /*
2189 * Local version fo the libdrm helper. Added to avoid depending on bleeding
2190 * edge version of the library.
2191 */
2192 static int
local_drmIsMaster(int fd)2193 local_drmIsMaster(int fd)
2194 {
2195 /* Detect master by attempting something that requires master.
2196 *
2197 * Authenticating magic tokens requires master and 0 is an
2198 * internal kernel detail which we could use. Attempting this on
2199 * a master fd would fail therefore fail with EINVAL because 0
2200 * is invalid.
2201 *
2202 * A non-master fd will fail with EACCES, as the kernel checks
2203 * for master before attempting to do anything else.
2204 *
2205 * Since we don't want to leak implementation details, use
2206 * EACCES.
2207 */
2208 return drmAuthMagic(fd, 0) != -EACCES;
2209 }
2210
2211 #ifdef HAVE_LIBUDEV
2212 static void *
udev_event_listener_thread(void * data)2213 udev_event_listener_thread(void *data)
2214 {
2215 struct wsi_device *wsi_device = data;
2216 struct wsi_display *wsi =
2217 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2218
2219 struct udev *u = udev_new();
2220 if (!u)
2221 goto fail;
2222
2223 struct udev_monitor *mon =
2224 udev_monitor_new_from_netlink(u, "udev");
2225 if (!mon)
2226 goto fail_udev;
2227
2228 int ret =
2229 udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor");
2230 if (ret < 0)
2231 goto fail_udev_monitor;
2232
2233 ret = udev_monitor_enable_receiving(mon);
2234 if (ret < 0)
2235 goto fail_udev_monitor;
2236
2237 int udev_fd = udev_monitor_get_fd(mon);
2238
2239 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
2240
2241 for (;;) {
2242 nfds_t nfds = 1;
2243 struct pollfd fds[1] = {
2244 {
2245 .fd = udev_fd,
2246 .events = POLLIN,
2247 },
2248 };
2249
2250 int ret = poll(fds, nfds, -1);
2251 if (ret > 0) {
2252 if (fds[0].revents & POLLIN) {
2253 struct udev_device *dev = udev_monitor_receive_device(mon);
2254
2255 /* Ignore event if it is not a hotplug event */
2256 if (!atoi(udev_device_get_property_value(dev, "HOTPLUG")))
2257 continue;
2258
2259 /* Note, this supports both drmSyncobjWait for fence->syncobj
2260 * and wsi_display_wait_for_event.
2261 */
2262 mtx_lock(&wsi->wait_mutex);
2263 u_cnd_monotonic_broadcast(&wsi->hotplug_cond);
2264 list_for_each_entry(struct wsi_display_fence, fence,
2265 &wsi_device->hotplug_fences, link) {
2266 if (fence->syncobj)
2267 drmSyncobjSignal(wsi->syncobj_fd, &fence->syncobj, 1);
2268 fence->event_received = true;
2269 }
2270 mtx_unlock(&wsi->wait_mutex);
2271 udev_device_unref(dev);
2272 }
2273 } else if (ret < 0) {
2274 goto fail;
2275 }
2276 }
2277
2278 udev_monitor_unref(mon);
2279 udev_unref(u);
2280
2281 return 0;
2282
2283 fail_udev_monitor:
2284 udev_monitor_unref(mon);
2285 fail_udev:
2286 udev_unref(u);
2287 fail:
2288 wsi_display_debug("critical hotplug thread error\n");
2289 return 0;
2290 }
2291 #endif
2292
2293 VkResult
wsi_display_init_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc,int display_fd)2294 wsi_display_init_wsi(struct wsi_device *wsi_device,
2295 const VkAllocationCallbacks *alloc,
2296 int display_fd)
2297 {
2298 struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
2299 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2300 VkResult result;
2301
2302 if (!wsi) {
2303 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2304 goto fail;
2305 }
2306
2307 wsi->fd = display_fd;
2308 if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
2309 wsi->fd = -1;
2310
2311 wsi->syncobj_fd = wsi->fd;
2312
2313 wsi->alloc = alloc;
2314
2315 list_inithead(&wsi->connectors);
2316
2317 int ret = mtx_init(&wsi->wait_mutex, mtx_plain);
2318 if (ret != thrd_success) {
2319 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2320 goto fail_mutex;
2321 }
2322
2323 ret = u_cnd_monotonic_init(&wsi->wait_cond);
2324 if (ret != thrd_success) {
2325 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2326 goto fail_cond;
2327 }
2328
2329 ret = u_cnd_monotonic_init(&wsi->hotplug_cond);
2330 if (ret != thrd_success) {
2331 result = VK_ERROR_OUT_OF_HOST_MEMORY;
2332 goto fail_hotplug_cond;
2333 }
2334
2335 wsi->base.get_support = wsi_display_surface_get_support;
2336 wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
2337 wsi->base.get_formats = wsi_display_surface_get_formats;
2338 wsi->base.get_formats2 = wsi_display_surface_get_formats2;
2339 wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
2340 wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
2341 wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
2342
2343 wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
2344
2345 return VK_SUCCESS;
2346
2347 fail_hotplug_cond:
2348 u_cnd_monotonic_destroy(&wsi->wait_cond);
2349 fail_cond:
2350 mtx_destroy(&wsi->wait_mutex);
2351 fail_mutex:
2352 vk_free(alloc, wsi);
2353 fail:
2354 return result;
2355 }
2356
2357 void
wsi_display_finish_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc)2358 wsi_display_finish_wsi(struct wsi_device *wsi_device,
2359 const VkAllocationCallbacks *alloc)
2360 {
2361 struct wsi_display *wsi =
2362 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2363
2364 if (wsi) {
2365 wsi_for_each_connector(connector, wsi) {
2366 wsi_for_each_display_mode(mode, connector) {
2367 vk_free(wsi->alloc, mode);
2368 }
2369 vk_free(wsi->alloc, connector);
2370 }
2371
2372 wsi_display_stop_wait_thread(wsi);
2373
2374 if (wsi->hotplug_thread) {
2375 pthread_cancel(wsi->hotplug_thread);
2376 pthread_join(wsi->hotplug_thread, NULL);
2377 }
2378
2379 mtx_destroy(&wsi->wait_mutex);
2380 u_cnd_monotonic_destroy(&wsi->wait_cond);
2381 u_cnd_monotonic_destroy(&wsi->hotplug_cond);
2382
2383 vk_free(alloc, wsi);
2384 }
2385 }
2386
2387 /*
2388 * Implement vkReleaseDisplay
2389 */
2390 VKAPI_ATTR VkResult VKAPI_CALL
wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice,VkDisplayKHR display)2391 wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice,
2392 VkDisplayKHR display)
2393 {
2394 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2395 struct wsi_device *wsi_device = pdevice->wsi_device;
2396 struct wsi_display *wsi =
2397 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2398
2399 if (wsi->fd >= 0) {
2400 wsi_display_stop_wait_thread(wsi);
2401
2402 close(wsi->fd);
2403 wsi->fd = -1;
2404 }
2405
2406 wsi_display_connector_from_handle(display)->active = false;
2407
2408 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2409 wsi_display_connector_from_handle(display)->output = None;
2410 #endif
2411
2412 return VK_SUCCESS;
2413 }
2414
2415 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2416
2417 static struct wsi_display_connector *
wsi_display_find_output(struct wsi_device * wsi_device,xcb_randr_output_t output)2418 wsi_display_find_output(struct wsi_device *wsi_device,
2419 xcb_randr_output_t output)
2420 {
2421 struct wsi_display *wsi =
2422 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2423
2424 wsi_for_each_connector(connector, wsi) {
2425 if (connector->output == output)
2426 return connector;
2427 }
2428
2429 return NULL;
2430 }
2431
2432 /*
2433 * Given a RandR output, find the associated kernel connector_id by
2434 * looking at the CONNECTOR_ID property provided by the X server
2435 */
2436
2437 static uint32_t
wsi_display_output_to_connector_id(xcb_connection_t * connection,xcb_atom_t * connector_id_atom_p,xcb_randr_output_t output)2438 wsi_display_output_to_connector_id(xcb_connection_t *connection,
2439 xcb_atom_t *connector_id_atom_p,
2440 xcb_randr_output_t output)
2441 {
2442 uint32_t connector_id = 0;
2443 xcb_atom_t connector_id_atom = *connector_id_atom_p;
2444
2445 if (connector_id_atom == 0) {
2446 /* Go dig out the CONNECTOR_ID property */
2447 xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
2448 true,
2449 12,
2450 "CONNECTOR_ID");
2451 xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
2452 ia_c,
2453 NULL);
2454 if (ia_r) {
2455 *connector_id_atom_p = connector_id_atom = ia_r->atom;
2456 free(ia_r);
2457 }
2458 }
2459
2460 /* If there's an CONNECTOR_ID atom in the server, then there may be a
2461 * CONNECTOR_ID property. Otherwise, there will not be and we don't even
2462 * need to bother.
2463 */
2464 if (connector_id_atom) {
2465
2466 xcb_randr_query_version_cookie_t qv_c =
2467 xcb_randr_query_version(connection, 1, 6);
2468 xcb_randr_get_output_property_cookie_t gop_c =
2469 xcb_randr_get_output_property(connection,
2470 output,
2471 connector_id_atom,
2472 0,
2473 0,
2474 0xffffffffUL,
2475 0,
2476 0);
2477 xcb_randr_query_version_reply_t *qv_r =
2478 xcb_randr_query_version_reply(connection, qv_c, NULL);
2479 free(qv_r);
2480 xcb_randr_get_output_property_reply_t *gop_r =
2481 xcb_randr_get_output_property_reply(connection, gop_c, NULL);
2482 if (gop_r) {
2483 if (gop_r->num_items == 1 && gop_r->format == 32)
2484 memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
2485 free(gop_r);
2486 }
2487 }
2488 return connector_id;
2489 }
2490
2491 static bool
wsi_display_check_randr_version(xcb_connection_t * connection)2492 wsi_display_check_randr_version(xcb_connection_t *connection)
2493 {
2494 xcb_randr_query_version_cookie_t qv_c =
2495 xcb_randr_query_version(connection, 1, 6);
2496 xcb_randr_query_version_reply_t *qv_r =
2497 xcb_randr_query_version_reply(connection, qv_c, NULL);
2498 bool ret = false;
2499
2500 if (!qv_r)
2501 return false;
2502
2503 /* Check for version 1.6 or newer */
2504 ret = (qv_r->major_version > 1 ||
2505 (qv_r->major_version == 1 && qv_r->minor_version >= 6));
2506
2507 free(qv_r);
2508 return ret;
2509 }
2510
2511 /*
2512 * Given a kernel connector id, find the associated RandR output using the
2513 * CONNECTOR_ID property
2514 */
2515
2516 static xcb_randr_output_t
wsi_display_connector_id_to_output(xcb_connection_t * connection,uint32_t connector_id)2517 wsi_display_connector_id_to_output(xcb_connection_t *connection,
2518 uint32_t connector_id)
2519 {
2520 if (!wsi_display_check_randr_version(connection))
2521 return 0;
2522
2523 const xcb_setup_t *setup = xcb_get_setup(connection);
2524
2525 xcb_atom_t connector_id_atom = 0;
2526 xcb_randr_output_t output = 0;
2527
2528 /* Search all of the screens for the provided output */
2529 xcb_screen_iterator_t iter;
2530 for (iter = xcb_setup_roots_iterator(setup);
2531 output == 0 && iter.rem;
2532 xcb_screen_next(&iter))
2533 {
2534 xcb_randr_get_screen_resources_cookie_t gsr_c =
2535 xcb_randr_get_screen_resources(connection, iter.data->root);
2536 xcb_randr_get_screen_resources_reply_t *gsr_r =
2537 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2538
2539 if (!gsr_r)
2540 return 0;
2541
2542 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2543 int o;
2544
2545 for (o = 0; o < gsr_r->num_outputs; o++) {
2546 if (wsi_display_output_to_connector_id(connection,
2547 &connector_id_atom, ro[o])
2548 == connector_id)
2549 {
2550 output = ro[o];
2551 break;
2552 }
2553 }
2554 free(gsr_r);
2555 }
2556 return output;
2557 }
2558
2559 /*
2560 * Given a RandR output, find out which screen it's associated with
2561 */
2562 static xcb_window_t
wsi_display_output_to_root(xcb_connection_t * connection,xcb_randr_output_t output)2563 wsi_display_output_to_root(xcb_connection_t *connection,
2564 xcb_randr_output_t output)
2565 {
2566 if (!wsi_display_check_randr_version(connection))
2567 return 0;
2568
2569 const xcb_setup_t *setup = xcb_get_setup(connection);
2570 xcb_window_t root = 0;
2571
2572 /* Search all of the screens for the provided output */
2573 for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
2574 root == 0 && iter.rem;
2575 xcb_screen_next(&iter))
2576 {
2577 xcb_randr_get_screen_resources_cookie_t gsr_c =
2578 xcb_randr_get_screen_resources(connection, iter.data->root);
2579 xcb_randr_get_screen_resources_reply_t *gsr_r =
2580 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2581
2582 if (!gsr_r)
2583 return 0;
2584
2585 xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2586
2587 for (int o = 0; o < gsr_r->num_outputs; o++) {
2588 if (ro[o] == output) {
2589 root = iter.data->root;
2590 break;
2591 }
2592 }
2593 free(gsr_r);
2594 }
2595 return root;
2596 }
2597
2598 static bool
wsi_display_mode_matches_x(struct wsi_display_mode * wsi,xcb_randr_mode_info_t * xcb)2599 wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
2600 xcb_randr_mode_info_t *xcb)
2601 {
2602 return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
2603 wsi->hdisplay == xcb->width &&
2604 wsi->hsync_start == xcb->hsync_start &&
2605 wsi->hsync_end == xcb->hsync_end &&
2606 wsi->htotal == xcb->htotal &&
2607 wsi->hskew == xcb->hskew &&
2608 wsi->vdisplay == xcb->height &&
2609 wsi->vsync_start == xcb->vsync_start &&
2610 wsi->vsync_end == xcb->vsync_end &&
2611 wsi->vtotal == xcb->vtotal &&
2612 wsi->vscan <= 1 &&
2613 wsi->flags == xcb->mode_flags;
2614 }
2615
2616 static struct wsi_display_mode *
wsi_display_find_x_mode(struct wsi_device * wsi_device,struct wsi_display_connector * connector,xcb_randr_mode_info_t * mode)2617 wsi_display_find_x_mode(struct wsi_device *wsi_device,
2618 struct wsi_display_connector *connector,
2619 xcb_randr_mode_info_t *mode)
2620 {
2621 wsi_for_each_display_mode(display_mode, connector) {
2622 if (wsi_display_mode_matches_x(display_mode, mode))
2623 return display_mode;
2624 }
2625 return NULL;
2626 }
2627
2628 static VkResult
wsi_display_register_x_mode(struct wsi_device * wsi_device,struct wsi_display_connector * connector,xcb_randr_mode_info_t * x_mode,bool preferred)2629 wsi_display_register_x_mode(struct wsi_device *wsi_device,
2630 struct wsi_display_connector *connector,
2631 xcb_randr_mode_info_t *x_mode,
2632 bool preferred)
2633 {
2634 struct wsi_display *wsi =
2635 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2636 struct wsi_display_mode *display_mode =
2637 wsi_display_find_x_mode(wsi_device, connector, x_mode);
2638
2639 if (display_mode) {
2640 display_mode->valid = true;
2641 return VK_SUCCESS;
2642 }
2643
2644 display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
2645 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2646 if (!display_mode)
2647 return VK_ERROR_OUT_OF_HOST_MEMORY;
2648
2649 display_mode->connector = connector;
2650 display_mode->valid = true;
2651 display_mode->preferred = preferred;
2652 display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
2653 display_mode->hdisplay = x_mode->width;
2654 display_mode->hsync_start = x_mode->hsync_start;
2655 display_mode->hsync_end = x_mode->hsync_end;
2656 display_mode->htotal = x_mode->htotal;
2657 display_mode->hskew = x_mode->hskew;
2658 display_mode->vdisplay = x_mode->height;
2659 display_mode->vsync_start = x_mode->vsync_start;
2660 display_mode->vsync_end = x_mode->vsync_end;
2661 display_mode->vtotal = x_mode->vtotal;
2662 display_mode->vscan = 0;
2663 display_mode->flags = x_mode->mode_flags;
2664
2665 list_addtail(&display_mode->list, &connector->display_modes);
2666 return VK_SUCCESS;
2667 }
2668
2669 static struct wsi_display_connector *
wsi_display_get_output(struct wsi_device * wsi_device,xcb_connection_t * connection,xcb_randr_output_t output)2670 wsi_display_get_output(struct wsi_device *wsi_device,
2671 xcb_connection_t *connection,
2672 xcb_randr_output_t output)
2673 {
2674 struct wsi_display *wsi =
2675 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2676 struct wsi_display_connector *connector;
2677 uint32_t connector_id;
2678
2679 xcb_window_t root = wsi_display_output_to_root(connection, output);
2680 if (!root)
2681 return NULL;
2682
2683 /* See if we already have a connector for this output */
2684 connector = wsi_display_find_output(wsi_device, output);
2685
2686 if (!connector) {
2687 xcb_atom_t connector_id_atom = 0;
2688
2689 /*
2690 * Go get the kernel connector ID for this X output
2691 */
2692 connector_id = wsi_display_output_to_connector_id(connection,
2693 &connector_id_atom,
2694 output);
2695
2696 /* Any X server with lease support will have this atom */
2697 if (!connector_id) {
2698 return NULL;
2699 }
2700
2701 /* See if we already have a connector for this id */
2702 connector = wsi_display_find_connector(wsi_device, connector_id);
2703
2704 if (connector == NULL) {
2705 connector = wsi_display_alloc_connector(wsi, connector_id);
2706 if (!connector) {
2707 return NULL;
2708 }
2709 list_addtail(&connector->list, &wsi->connectors);
2710 }
2711 connector->output = output;
2712 }
2713
2714 xcb_randr_get_screen_resources_cookie_t src =
2715 xcb_randr_get_screen_resources(connection, root);
2716 xcb_randr_get_output_info_cookie_t oic =
2717 xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
2718 xcb_randr_get_screen_resources_reply_t *srr =
2719 xcb_randr_get_screen_resources_reply(connection, src, NULL);
2720 xcb_randr_get_output_info_reply_t *oir =
2721 xcb_randr_get_output_info_reply(connection, oic, NULL);
2722
2723 if (oir && srr) {
2724 /* Get X modes and add them */
2725
2726 connector->connected =
2727 oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
2728
2729 wsi_display_invalidate_connector_modes(connector);
2730
2731 xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
2732 for (int m = 0; m < oir->num_modes; m++) {
2733 xcb_randr_mode_info_iterator_t i =
2734 xcb_randr_get_screen_resources_modes_iterator(srr);
2735 while (i.rem) {
2736 xcb_randr_mode_info_t *mi = i.data;
2737 if (mi->id == x_modes[m]) {
2738 VkResult result = wsi_display_register_x_mode(
2739 wsi_device, connector, mi, m < oir->num_preferred);
2740 if (result != VK_SUCCESS) {
2741 free(oir);
2742 free(srr);
2743 return NULL;
2744 }
2745 break;
2746 }
2747 xcb_randr_mode_info_next(&i);
2748 }
2749 }
2750 }
2751
2752 free(oir);
2753 free(srr);
2754 return connector;
2755 }
2756
2757 static xcb_randr_crtc_t
wsi_display_find_crtc_for_output(xcb_connection_t * connection,xcb_window_t root,xcb_randr_output_t output)2758 wsi_display_find_crtc_for_output(xcb_connection_t *connection,
2759 xcb_window_t root,
2760 xcb_randr_output_t output)
2761 {
2762 xcb_randr_get_screen_resources_cookie_t gsr_c =
2763 xcb_randr_get_screen_resources(connection, root);
2764 xcb_randr_get_screen_resources_reply_t *gsr_r =
2765 xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2766
2767 if (!gsr_r)
2768 return 0;
2769
2770 xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
2771 xcb_randr_crtc_t idle_crtc = 0;
2772 xcb_randr_crtc_t active_crtc = 0;
2773
2774 /* Find either a crtc already connected to the desired output or idle */
2775 for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
2776 xcb_randr_get_crtc_info_cookie_t gci_c =
2777 xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
2778 xcb_randr_get_crtc_info_reply_t *gci_r =
2779 xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
2780
2781 if (gci_r) {
2782 if (gci_r->mode) {
2783 int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
2784 xcb_randr_output_t *outputs =
2785 xcb_randr_get_crtc_info_outputs(gci_r);
2786
2787 if (num_outputs == 1 && outputs[0] == output)
2788 active_crtc = rc[c];
2789
2790 } else if (idle_crtc == 0) {
2791 int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
2792 xcb_randr_output_t *possible =
2793 xcb_randr_get_crtc_info_possible(gci_r);
2794
2795 for (int p = 0; p < num_possible; p++)
2796 if (possible[p] == output) {
2797 idle_crtc = rc[c];
2798 break;
2799 }
2800 }
2801 free(gci_r);
2802 }
2803 }
2804 free(gsr_r);
2805
2806 if (active_crtc)
2807 return active_crtc;
2808 return idle_crtc;
2809 }
2810
2811 VKAPI_ATTR VkResult VKAPI_CALL
wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice,Display * dpy,VkDisplayKHR display)2812 wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice,
2813 Display *dpy,
2814 VkDisplayKHR display)
2815 {
2816 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2817 struct wsi_device *wsi_device = pdevice->wsi_device;
2818 struct wsi_display *wsi =
2819 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2820 xcb_connection_t *connection = XGetXCBConnection(dpy);
2821 struct wsi_display_connector *connector =
2822 wsi_display_connector_from_handle(display);
2823 xcb_window_t root;
2824
2825 /* XXX no support for multiple leases yet */
2826 if (wsi->fd >= 0)
2827 return VK_ERROR_INITIALIZATION_FAILED;
2828
2829 if (!connector->output) {
2830 connector->output = wsi_display_connector_id_to_output(connection,
2831 connector->id);
2832
2833 /* Check and see if we found the output */
2834 if (!connector->output)
2835 return VK_ERROR_INITIALIZATION_FAILED;
2836 }
2837
2838 root = wsi_display_output_to_root(connection, connector->output);
2839 if (!root)
2840 return VK_ERROR_INITIALIZATION_FAILED;
2841
2842 xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
2843 root,
2844 connector->output);
2845
2846 if (!crtc)
2847 return VK_ERROR_INITIALIZATION_FAILED;
2848
2849 #ifdef HAVE_X11_DRM
2850 xcb_randr_lease_t lease = xcb_generate_id(connection);
2851 xcb_randr_create_lease_cookie_t cl_c =
2852 xcb_randr_create_lease(connection, root, lease, 1, 1,
2853 &crtc, &connector->output);
2854 xcb_randr_create_lease_reply_t *cl_r =
2855 xcb_randr_create_lease_reply(connection, cl_c, NULL);
2856 if (!cl_r)
2857 return VK_ERROR_INITIALIZATION_FAILED;
2858
2859 int fd = -1;
2860 if (cl_r->nfd > 0) {
2861 int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
2862
2863 fd = rcl_f[0];
2864 }
2865 free (cl_r);
2866 if (fd < 0)
2867 return VK_ERROR_INITIALIZATION_FAILED;
2868
2869 wsi->fd = fd;
2870 #endif
2871
2872 return VK_SUCCESS;
2873 }
2874
2875 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice,Display * dpy,RROutput rrOutput,VkDisplayKHR * pDisplay)2876 wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice,
2877 Display *dpy,
2878 RROutput rrOutput,
2879 VkDisplayKHR *pDisplay)
2880 {
2881 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2882 struct wsi_device *wsi_device = pdevice->wsi_device;
2883 xcb_connection_t *connection = XGetXCBConnection(dpy);
2884 struct wsi_display_connector *connector =
2885 wsi_display_get_output(wsi_device, connection,
2886 (xcb_randr_output_t) rrOutput);
2887
2888 if (connector)
2889 *pDisplay = wsi_display_connector_to_handle(connector);
2890 else
2891 *pDisplay = VK_NULL_HANDLE;
2892 return VK_SUCCESS;
2893 }
2894
2895 #endif
2896
2897 /* VK_EXT_display_control */
2898 VKAPI_ATTR VkResult VKAPI_CALL
wsi_DisplayPowerControlEXT(VkDevice _device,VkDisplayKHR display,const VkDisplayPowerInfoEXT * pDisplayPowerInfo)2899 wsi_DisplayPowerControlEXT(VkDevice _device,
2900 VkDisplayKHR display,
2901 const VkDisplayPowerInfoEXT *pDisplayPowerInfo)
2902 {
2903 VK_FROM_HANDLE(vk_device, device, _device);
2904 struct wsi_device *wsi_device = device->physical->wsi_device;
2905 struct wsi_display *wsi =
2906 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2907 struct wsi_display_connector *connector =
2908 wsi_display_connector_from_handle(display);
2909 int mode;
2910
2911 if (wsi->fd < 0)
2912 return VK_ERROR_INITIALIZATION_FAILED;
2913
2914 switch (pDisplayPowerInfo->powerState) {
2915 case VK_DISPLAY_POWER_STATE_OFF_EXT:
2916 mode = DRM_MODE_DPMS_OFF;
2917 break;
2918 case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
2919 mode = DRM_MODE_DPMS_SUSPEND;
2920 break;
2921 default:
2922 mode = DRM_MODE_DPMS_ON;
2923 break;
2924 }
2925 drmModeConnectorSetProperty(wsi->fd,
2926 connector->id,
2927 connector->dpms_property,
2928 mode);
2929 return VK_SUCCESS;
2930 }
2931
2932 VkResult
wsi_register_device_event(VkDevice _device,struct wsi_device * wsi_device,const VkDeviceEventInfoEXT * device_event_info,const VkAllocationCallbacks * allocator,struct vk_sync ** sync_out,int sync_fd)2933 wsi_register_device_event(VkDevice _device,
2934 struct wsi_device *wsi_device,
2935 const VkDeviceEventInfoEXT *device_event_info,
2936 const VkAllocationCallbacks *allocator,
2937 struct vk_sync **sync_out,
2938 int sync_fd)
2939 {
2940 VK_FROM_HANDLE(vk_device, device, _device);
2941 struct wsi_display *wsi =
2942 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2943 VkResult ret = VK_SUCCESS;
2944
2945 #ifdef HAVE_LIBUDEV
2946 /* Start listening for output change notifications. */
2947 mtx_lock(&wsi->wait_mutex);
2948 if (!wsi->hotplug_thread) {
2949 if (pthread_create(&wsi->hotplug_thread, NULL, udev_event_listener_thread,
2950 wsi_device)) {
2951 mtx_unlock(&wsi->wait_mutex);
2952 return VK_ERROR_OUT_OF_HOST_MEMORY;
2953 }
2954 }
2955 mtx_unlock(&wsi->wait_mutex);
2956 #endif
2957
2958 struct wsi_display_fence *fence;
2959 assert(device_event_info->deviceEvent ==
2960 VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT);
2961
2962 fence = wsi_display_fence_alloc(wsi, sync_fd);
2963
2964 if (!fence)
2965 return VK_ERROR_OUT_OF_HOST_MEMORY;
2966
2967 fence->device_event = true;
2968
2969 mtx_lock(&wsi->wait_mutex);
2970 list_addtail(&fence->link, &wsi_device->hotplug_fences);
2971 mtx_unlock(&wsi->wait_mutex);
2972
2973 if (sync_out) {
2974 ret = wsi_display_sync_create(device, fence, sync_out);
2975 if (ret != VK_SUCCESS)
2976 wsi_display_fence_destroy(fence);
2977 } else {
2978 wsi_display_fence_destroy(fence);
2979 }
2980
2981 return ret;
2982 }
2983
2984 VKAPI_ATTR VkResult VKAPI_CALL
wsi_RegisterDeviceEventEXT(VkDevice _device,const VkDeviceEventInfoEXT * device_event_info,const VkAllocationCallbacks * allocator,VkFence * _fence)2985 wsi_RegisterDeviceEventEXT(VkDevice _device, const VkDeviceEventInfoEXT *device_event_info,
2986 const VkAllocationCallbacks *allocator, VkFence *_fence)
2987 {
2988 VK_FROM_HANDLE(vk_device, device, _device);
2989 struct vk_fence *fence;
2990 VkResult ret;
2991
2992 const VkFenceCreateInfo info = {
2993 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
2994 .flags = 0,
2995 };
2996 ret = vk_fence_create(device, &info, allocator, &fence);
2997 if (ret != VK_SUCCESS)
2998 return ret;
2999
3000 ret = wsi_register_device_event(_device,
3001 device->physical->wsi_device,
3002 device_event_info,
3003 allocator,
3004 &fence->temporary,
3005 -1);
3006 if (ret == VK_SUCCESS)
3007 *_fence = vk_fence_to_handle(fence);
3008 else
3009 vk_fence_destroy(device, fence, allocator);
3010 return ret;
3011 }
3012
3013 VkResult
wsi_register_display_event(VkDevice _device,struct wsi_device * wsi_device,VkDisplayKHR display,const VkDisplayEventInfoEXT * display_event_info,const VkAllocationCallbacks * allocator,struct vk_sync ** sync_out,int sync_fd)3014 wsi_register_display_event(VkDevice _device,
3015 struct wsi_device *wsi_device,
3016 VkDisplayKHR display,
3017 const VkDisplayEventInfoEXT *display_event_info,
3018 const VkAllocationCallbacks *allocator,
3019 struct vk_sync **sync_out,
3020 int sync_fd)
3021 {
3022 VK_FROM_HANDLE(vk_device, device, _device);
3023 struct wsi_display *wsi =
3024 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3025 struct wsi_display_fence *fence;
3026 VkResult ret;
3027
3028 switch (display_event_info->displayEvent) {
3029 case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
3030
3031 fence = wsi_display_fence_alloc(wsi, sync_fd);
3032
3033 if (!fence)
3034 return VK_ERROR_OUT_OF_HOST_MEMORY;
3035
3036 ret = wsi_register_vblank_event(fence, wsi_device, display,
3037 DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
3038
3039 if (ret == VK_SUCCESS) {
3040 if (sync_out) {
3041 ret = wsi_display_sync_create(device, fence, sync_out);
3042 if (ret != VK_SUCCESS)
3043 wsi_display_fence_destroy(fence);
3044 } else {
3045 wsi_display_fence_destroy(fence);
3046 }
3047 } else if (fence != NULL) {
3048 if (fence->syncobj)
3049 drmSyncobjDestroy(wsi->syncobj_fd, fence->syncobj);
3050 vk_free2(wsi->alloc, allocator, fence);
3051 }
3052
3053 break;
3054 default:
3055 ret = VK_ERROR_FEATURE_NOT_PRESENT;
3056 break;
3057 }
3058
3059 return ret;
3060 }
3061
3062 VKAPI_ATTR VkResult VKAPI_CALL
wsi_RegisterDisplayEventEXT(VkDevice _device,VkDisplayKHR display,const VkDisplayEventInfoEXT * display_event_info,const VkAllocationCallbacks * allocator,VkFence * _fence)3063 wsi_RegisterDisplayEventEXT(VkDevice _device, VkDisplayKHR display,
3064 const VkDisplayEventInfoEXT *display_event_info,
3065 const VkAllocationCallbacks *allocator, VkFence *_fence)
3066 {
3067 VK_FROM_HANDLE(vk_device, device, _device);
3068 struct vk_fence *fence;
3069 VkResult ret;
3070
3071 const VkFenceCreateInfo info = {
3072 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
3073 .flags = 0,
3074 };
3075 ret = vk_fence_create(device, &info, allocator, &fence);
3076 if (ret != VK_SUCCESS)
3077 return ret;
3078
3079 ret = wsi_register_display_event(
3080 _device, device->physical->wsi_device,
3081 display, display_event_info, allocator, &fence->temporary, -1);
3082
3083 if (ret == VK_SUCCESS)
3084 *_fence = vk_fence_to_handle(fence);
3085 else
3086 vk_fence_destroy(device, fence, allocator);
3087 return ret;
3088 }
3089
3090 void
wsi_display_setup_syncobj_fd(struct wsi_device * wsi_device,int fd)3091 wsi_display_setup_syncobj_fd(struct wsi_device *wsi_device,
3092 int fd)
3093 {
3094 struct wsi_display *wsi =
3095 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3096 wsi->syncobj_fd = fd;
3097 }
3098
3099 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetSwapchainCounterEXT(VkDevice _device,VkSwapchainKHR _swapchain,VkSurfaceCounterFlagBitsEXT counter,uint64_t * pCounterValue)3100 wsi_GetSwapchainCounterEXT(VkDevice _device,
3101 VkSwapchainKHR _swapchain,
3102 VkSurfaceCounterFlagBitsEXT counter,
3103 uint64_t *pCounterValue)
3104 {
3105 VK_FROM_HANDLE(vk_device, device, _device);
3106 struct wsi_device *wsi_device = device->physical->wsi_device;
3107 struct wsi_display *wsi =
3108 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3109 struct wsi_display_swapchain *swapchain =
3110 (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
3111 struct wsi_display_connector *connector =
3112 wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
3113
3114 if (wsi->fd < 0)
3115 return VK_ERROR_INITIALIZATION_FAILED;
3116
3117 if (!connector->active) {
3118 *pCounterValue = 0;
3119 return VK_SUCCESS;
3120 }
3121
3122 int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id,
3123 pCounterValue, NULL);
3124 if (ret)
3125 *pCounterValue = 0;
3126
3127 return VK_SUCCESS;
3128 }
3129
3130 VKAPI_ATTR VkResult VKAPI_CALL
wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice,int32_t drmFd,VkDisplayKHR display)3131 wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice,
3132 int32_t drmFd,
3133 VkDisplayKHR display)
3134 {
3135 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
3136 struct wsi_device *wsi_device = pdevice->wsi_device;
3137
3138 if (!wsi_device->can_present_on_device(wsi_device->pdevice, drmFd))
3139 return VK_ERROR_UNKNOWN;
3140
3141 struct wsi_display *wsi =
3142 (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3143
3144 /* XXX no support for mulitple leases yet */
3145 if (wsi->fd >= 0 || !local_drmIsMaster(drmFd))
3146 return VK_ERROR_INITIALIZATION_FAILED;
3147
3148 struct wsi_display_connector *connector =
3149 wsi_display_connector_from_handle(display);
3150
3151 drmModeConnectorPtr drm_connector =
3152 drmModeGetConnectorCurrent(drmFd, connector->id);
3153
3154 if (!drm_connector)
3155 return VK_ERROR_INITIALIZATION_FAILED;
3156
3157 drmModeFreeConnector(drm_connector);
3158
3159 wsi->fd = drmFd;
3160 return VK_SUCCESS;
3161 }
3162
3163 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice,int32_t drmFd,uint32_t connectorId,VkDisplayKHR * pDisplay)3164 wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice,
3165 int32_t drmFd,
3166 uint32_t connectorId,
3167 VkDisplayKHR *pDisplay)
3168 {
3169 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
3170 struct wsi_device *wsi_device = pdevice->wsi_device;
3171
3172 if (!wsi_device->can_present_on_device(wsi_device->pdevice, drmFd)) {
3173 *pDisplay = VK_NULL_HANDLE;
3174 return VK_ERROR_UNKNOWN;
3175 }
3176
3177 struct wsi_display_connector *connector =
3178 wsi_display_get_connector(wsi_device, drmFd, connectorId);
3179
3180 if (!connector) {
3181 *pDisplay = VK_NULL_HANDLE;
3182 return VK_ERROR_UNKNOWN;
3183 }
3184
3185 *pDisplay = wsi_display_connector_to_handle(connector);
3186 return VK_SUCCESS;
3187 }
3188