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