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