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