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