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