• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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             /* unset some properties another drm master might've set
1967              * which can mess up the image
1968              */
1969             drmModeObjectPropertiesPtr properties =
1970                drmModeObjectGetProperties(wsi->fd,
1971                                           connector->crtc_id,
1972                                           DRM_MODE_OBJECT_CRTC);
1973             for (uint32_t i = 0; i < properties->count_props; i++) {
1974                drmModePropertyPtr prop =
1975                   drmModeGetProperty(wsi->fd, properties->props[i]);
1976                if (strcmp(prop->name, "GAMMA_LUT") == 0 ||
1977                    strcmp(prop->name, "CTM") == 0 ||
1978                    strcmp(prop->name, "DEGAMMA_LUT") == 0) {
1979                   drmModeObjectSetProperty(wsi->fd, connector->crtc_id,
1980                                            DRM_MODE_OBJECT_CRTC,
1981                                            properties->props[i], 0);
1982                }
1983                drmModeFreeProperty(prop);
1984             }
1985             drmModeFreeObjectProperties(properties);
1986 
1987             /* Assume that the mode set is synchronous and that any
1988              * previous image is now idle.
1989              */
1990             image->state = WSI_IMAGE_DISPLAYING;
1991             wsi_display_present_complete(chain, image);
1992             wsi_display_idle_old_displaying(image);
1993             connector->active = true;
1994             return VK_SUCCESS;
1995          }
1996       }
1997 
1998       if (ret != -EACCES) {
1999          connector->active = false;
2000          image->state = WSI_IMAGE_IDLE;
2001          wsi_display_surface_error(chain, VK_ERROR_SURFACE_LOST_KHR);
2002          return VK_ERROR_SURFACE_LOST_KHR;
2003       }
2004 
2005       /* Some other VT is currently active. Sit here waiting for
2006        * our VT to become active again by polling once a second
2007        */
2008       usleep(1000 * 1000);
2009       connector->active = false;
2010    }
2011 }
2012 
2013 static VkResult
wsi_display_queue_present(struct wsi_swapchain * drv_chain,uint32_t image_index,uint64_t present_id,const VkPresentRegionKHR * damage)2014 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
2015                           uint32_t image_index,
2016                           uint64_t present_id,
2017                           const VkPresentRegionKHR *damage)
2018 {
2019    struct wsi_display_swapchain *chain =
2020       (struct wsi_display_swapchain *) drv_chain;
2021    struct wsi_display *wsi = chain->wsi;
2022    struct wsi_display_image *image = &chain->images[image_index];
2023    VkResult result;
2024 
2025    /* Bail early if the swapchain is broken */
2026    if (chain->status != VK_SUCCESS)
2027       return chain->status;
2028 
2029    image->present_id = present_id;
2030 
2031    assert(image->state == WSI_IMAGE_DRAWING);
2032    wsi_display_debug("present %d\n", image_index);
2033 
2034    mtx_lock(&wsi->wait_mutex);
2035 
2036    /* Make sure that the page flip handler is processed in finite time if using present wait. */
2037    if (present_id)
2038       wsi_display_start_wait_thread(wsi);
2039 
2040    image->flip_sequence = ++chain->flip_sequence;
2041    image->state = WSI_IMAGE_QUEUED;
2042 
2043    result = _wsi_display_queue_next(drv_chain);
2044    if (result != VK_SUCCESS)
2045       chain->status = result;
2046 
2047    mtx_unlock(&wsi->wait_mutex);
2048 
2049    if (result != VK_SUCCESS)
2050       return result;
2051 
2052    return chain->status;
2053 }
2054 
2055 static VkResult
wsi_display_wait_for_present(struct wsi_swapchain * wsi_chain,uint64_t waitValue,uint64_t timeout)2056 wsi_display_wait_for_present(struct wsi_swapchain *wsi_chain,
2057                              uint64_t waitValue,
2058                              uint64_t timeout)
2059 {
2060    struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)wsi_chain;
2061    struct timespec abs_timespec;
2062    uint64_t abs_timeout = 0;
2063 
2064    if (timeout != 0)
2065       abs_timeout = os_time_get_absolute_timeout(timeout);
2066 
2067    /* Need to observe that the swapchain semaphore has been unsignalled,
2068     * as this is guaranteed when a present is complete. */
2069    VkResult result = wsi_swapchain_wait_for_present_semaphore(
2070       &chain->base, waitValue, timeout);
2071    if (result != VK_SUCCESS)
2072       return result;
2073 
2074    timespec_from_nsec(&abs_timespec, abs_timeout);
2075 
2076    mtx_lock(&chain->present_id_mutex);
2077    while (chain->present_id < waitValue) {
2078       int ret = u_cnd_monotonic_timedwait(&chain->present_id_cond,
2079                                           &chain->present_id_mutex,
2080                                           &abs_timespec);
2081       if (ret == thrd_timedout) {
2082          result = VK_TIMEOUT;
2083          break;
2084       }
2085       if (ret != thrd_success) {
2086          result = VK_ERROR_DEVICE_LOST;
2087          break;
2088       }
2089    }
2090 
2091    if (result == VK_SUCCESS && chain->present_id_error)
2092       result = chain->present_id_error;
2093    mtx_unlock(&chain->present_id_mutex);
2094    return result;
2095 }
2096 
2097 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)2098 wsi_display_surface_create_swapchain(
2099    VkIcdSurfaceBase *icd_surface,
2100    VkDevice device,
2101    struct wsi_device *wsi_device,
2102    const VkSwapchainCreateInfoKHR *create_info,
2103    const VkAllocationCallbacks *allocator,
2104    struct wsi_swapchain **swapchain_out)
2105 {
2106    struct wsi_display *wsi =
2107       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2108 
2109    assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
2110 
2111    const unsigned num_images = create_info->minImageCount;
2112    struct wsi_display_swapchain *chain =
2113       vk_zalloc(allocator,
2114                 sizeof(*chain) + num_images * sizeof(chain->images[0]),
2115                 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2116 
2117    if (chain == NULL)
2118       return VK_ERROR_OUT_OF_HOST_MEMORY;
2119 
2120    struct wsi_drm_image_params image_params = {
2121       .base.image_type = WSI_IMAGE_TYPE_DRM,
2122       .same_gpu = true,
2123    };
2124 
2125    int ret = mtx_init(&chain->present_id_mutex, mtx_plain);
2126    if (ret != thrd_success) {
2127       vk_free(allocator, chain);
2128       return VK_ERROR_OUT_OF_HOST_MEMORY;
2129    }
2130 
2131    ret = u_cnd_monotonic_init(&chain->present_id_cond);
2132    if (ret != thrd_success) {
2133       mtx_destroy(&chain->present_id_mutex);
2134       vk_free(allocator, chain);
2135       return VK_ERROR_OUT_OF_HOST_MEMORY;
2136    }
2137 
2138    VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
2139                                         create_info, &image_params.base,
2140                                         allocator);
2141    if (result != VK_SUCCESS) {
2142       u_cnd_monotonic_destroy(&chain->present_id_cond);
2143       mtx_destroy(&chain->present_id_mutex);
2144       vk_free(allocator, chain);
2145       return result;
2146    }
2147 
2148    chain->base.destroy = wsi_display_swapchain_destroy;
2149    chain->base.get_wsi_image = wsi_display_get_wsi_image;
2150    chain->base.acquire_next_image = wsi_display_acquire_next_image;
2151    chain->base.release_images = wsi_display_release_images;
2152    chain->base.queue_present = wsi_display_queue_present;
2153    chain->base.wait_for_present = wsi_display_wait_for_present;
2154    chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
2155    chain->base.image_count = num_images;
2156 
2157    chain->wsi = wsi;
2158    chain->status = VK_SUCCESS;
2159 
2160    chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
2161 
2162    for (uint32_t image = 0; image < chain->base.image_count; image++) {
2163       result = wsi_display_image_init(&chain->base,
2164                                       create_info,
2165                                       &chain->images[image]);
2166       if (result != VK_SUCCESS) {
2167          while (image > 0) {
2168             --image;
2169             wsi_display_image_finish(&chain->base,
2170                                      &chain->images[image]);
2171          }
2172          u_cnd_monotonic_destroy(&chain->present_id_cond);
2173          mtx_destroy(&chain->present_id_mutex);
2174          wsi_swapchain_finish(&chain->base);
2175          vk_free(allocator, chain);
2176          goto fail_init_images;
2177       }
2178    }
2179 
2180    *swapchain_out = &chain->base;
2181 
2182    return VK_SUCCESS;
2183 
2184 fail_init_images:
2185    return result;
2186 }
2187 
2188 /*
2189  * Local version fo the libdrm helper. Added to avoid depending on bleeding
2190  * edge version of the library.
2191  */
2192 static int
local_drmIsMaster(int fd)2193 local_drmIsMaster(int fd)
2194 {
2195    /* Detect master by attempting something that requires master.
2196     *
2197     * Authenticating magic tokens requires master and 0 is an
2198     * internal kernel detail which we could use. Attempting this on
2199     * a master fd would fail therefore fail with EINVAL because 0
2200     * is invalid.
2201     *
2202     * A non-master fd will fail with EACCES, as the kernel checks
2203     * for master before attempting to do anything else.
2204     *
2205     * Since we don't want to leak implementation details, use
2206     * EACCES.
2207     */
2208    return drmAuthMagic(fd, 0) != -EACCES;
2209 }
2210 
2211 #ifdef HAVE_LIBUDEV
2212 static void *
udev_event_listener_thread(void * data)2213 udev_event_listener_thread(void *data)
2214 {
2215    struct wsi_device *wsi_device = data;
2216    struct wsi_display *wsi =
2217       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2218 
2219    struct udev *u = udev_new();
2220    if (!u)
2221       goto fail;
2222 
2223    struct udev_monitor *mon =
2224       udev_monitor_new_from_netlink(u, "udev");
2225    if (!mon)
2226       goto fail_udev;
2227 
2228    int ret =
2229       udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor");
2230    if (ret < 0)
2231       goto fail_udev_monitor;
2232 
2233    ret = udev_monitor_enable_receiving(mon);
2234    if (ret < 0)
2235       goto fail_udev_monitor;
2236 
2237    int udev_fd = udev_monitor_get_fd(mon);
2238 
2239    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
2240 
2241    for (;;) {
2242       nfds_t nfds = 1;
2243       struct pollfd fds[1] =  {
2244          {
2245             .fd = udev_fd,
2246             .events = POLLIN,
2247          },
2248       };
2249 
2250       int ret = poll(fds, nfds, -1);
2251       if (ret > 0) {
2252          if (fds[0].revents & POLLIN) {
2253             struct udev_device *dev = udev_monitor_receive_device(mon);
2254 
2255             /* Ignore event if it is not a hotplug event */
2256             if (!atoi(udev_device_get_property_value(dev, "HOTPLUG")))
2257                continue;
2258 
2259             /* Note, this supports both drmSyncobjWait for fence->syncobj
2260              * and wsi_display_wait_for_event.
2261              */
2262             mtx_lock(&wsi->wait_mutex);
2263             u_cnd_monotonic_broadcast(&wsi->hotplug_cond);
2264             list_for_each_entry(struct wsi_display_fence, fence,
2265                                 &wsi_device->hotplug_fences, link) {
2266                if (fence->syncobj)
2267                   drmSyncobjSignal(wsi->syncobj_fd, &fence->syncobj, 1);
2268                fence->event_received = true;
2269             }
2270             mtx_unlock(&wsi->wait_mutex);
2271             udev_device_unref(dev);
2272          }
2273       } else if (ret < 0) {
2274          goto fail;
2275       }
2276    }
2277 
2278    udev_monitor_unref(mon);
2279    udev_unref(u);
2280 
2281    return 0;
2282 
2283 fail_udev_monitor:
2284    udev_monitor_unref(mon);
2285 fail_udev:
2286    udev_unref(u);
2287 fail:
2288    wsi_display_debug("critical hotplug thread error\n");
2289    return 0;
2290 }
2291 #endif
2292 
2293 VkResult
wsi_display_init_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc,int display_fd)2294 wsi_display_init_wsi(struct wsi_device *wsi_device,
2295                      const VkAllocationCallbacks *alloc,
2296                      int display_fd)
2297 {
2298    struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
2299                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2300    VkResult result;
2301 
2302    if (!wsi) {
2303       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2304       goto fail;
2305    }
2306 
2307    wsi->fd = display_fd;
2308    if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
2309       wsi->fd = -1;
2310 
2311    wsi->syncobj_fd = wsi->fd;
2312 
2313    wsi->alloc = alloc;
2314 
2315    list_inithead(&wsi->connectors);
2316 
2317    int ret = mtx_init(&wsi->wait_mutex, mtx_plain);
2318    if (ret != thrd_success) {
2319       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2320       goto fail_mutex;
2321    }
2322 
2323    ret = u_cnd_monotonic_init(&wsi->wait_cond);
2324    if (ret != thrd_success) {
2325       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2326       goto fail_cond;
2327    }
2328 
2329    ret = u_cnd_monotonic_init(&wsi->hotplug_cond);
2330    if (ret != thrd_success) {
2331       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2332       goto fail_hotplug_cond;
2333    }
2334 
2335    wsi->base.get_support = wsi_display_surface_get_support;
2336    wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
2337    wsi->base.get_formats = wsi_display_surface_get_formats;
2338    wsi->base.get_formats2 = wsi_display_surface_get_formats2;
2339    wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
2340    wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
2341    wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
2342 
2343    wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
2344 
2345    return VK_SUCCESS;
2346 
2347 fail_hotplug_cond:
2348    u_cnd_monotonic_destroy(&wsi->wait_cond);
2349 fail_cond:
2350    mtx_destroy(&wsi->wait_mutex);
2351 fail_mutex:
2352    vk_free(alloc, wsi);
2353 fail:
2354    return result;
2355 }
2356 
2357 void
wsi_display_finish_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc)2358 wsi_display_finish_wsi(struct wsi_device *wsi_device,
2359                        const VkAllocationCallbacks *alloc)
2360 {
2361    struct wsi_display *wsi =
2362       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2363 
2364    if (wsi) {
2365       wsi_for_each_connector(connector, wsi) {
2366          wsi_for_each_display_mode(mode, connector) {
2367             vk_free(wsi->alloc, mode);
2368          }
2369          vk_free(wsi->alloc, connector);
2370       }
2371 
2372       wsi_display_stop_wait_thread(wsi);
2373 
2374       if (wsi->hotplug_thread) {
2375          pthread_cancel(wsi->hotplug_thread);
2376          pthread_join(wsi->hotplug_thread, NULL);
2377       }
2378 
2379       mtx_destroy(&wsi->wait_mutex);
2380       u_cnd_monotonic_destroy(&wsi->wait_cond);
2381       u_cnd_monotonic_destroy(&wsi->hotplug_cond);
2382 
2383       vk_free(alloc, wsi);
2384    }
2385 }
2386 
2387 /*
2388  * Implement vkReleaseDisplay
2389  */
2390 VKAPI_ATTR VkResult VKAPI_CALL
wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice,VkDisplayKHR display)2391 wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice,
2392                       VkDisplayKHR display)
2393 {
2394    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2395    struct wsi_device *wsi_device = pdevice->wsi_device;
2396    struct wsi_display *wsi =
2397       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2398 
2399    if (wsi->fd >= 0) {
2400       wsi_display_stop_wait_thread(wsi);
2401 
2402       close(wsi->fd);
2403       wsi->fd = -1;
2404    }
2405 
2406    wsi_display_connector_from_handle(display)->active = false;
2407 
2408 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2409    wsi_display_connector_from_handle(display)->output = None;
2410 #endif
2411 
2412    return VK_SUCCESS;
2413 }
2414 
2415 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2416 
2417 static struct wsi_display_connector *
wsi_display_find_output(struct wsi_device * wsi_device,xcb_randr_output_t output)2418 wsi_display_find_output(struct wsi_device *wsi_device,
2419                         xcb_randr_output_t output)
2420 {
2421    struct wsi_display *wsi =
2422       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2423 
2424    wsi_for_each_connector(connector, wsi) {
2425       if (connector->output == output)
2426          return connector;
2427    }
2428 
2429    return NULL;
2430 }
2431 
2432 /*
2433  * Given a RandR output, find the associated kernel connector_id by
2434  * looking at the CONNECTOR_ID property provided by the X server
2435  */
2436 
2437 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)2438 wsi_display_output_to_connector_id(xcb_connection_t *connection,
2439                                    xcb_atom_t *connector_id_atom_p,
2440                                    xcb_randr_output_t output)
2441 {
2442    uint32_t connector_id = 0;
2443    xcb_atom_t connector_id_atom = *connector_id_atom_p;
2444 
2445    if (connector_id_atom == 0) {
2446    /* Go dig out the CONNECTOR_ID property */
2447       xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
2448                                                           true,
2449                                                           12,
2450                                                           "CONNECTOR_ID");
2451       xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
2452                                                                  ia_c,
2453                                                                  NULL);
2454       if (ia_r) {
2455          *connector_id_atom_p = connector_id_atom = ia_r->atom;
2456          free(ia_r);
2457       }
2458    }
2459 
2460    /* If there's an CONNECTOR_ID atom in the server, then there may be a
2461     * CONNECTOR_ID property. Otherwise, there will not be and we don't even
2462     * need to bother.
2463     */
2464    if (connector_id_atom) {
2465 
2466       xcb_randr_query_version_cookie_t qv_c =
2467          xcb_randr_query_version(connection, 1, 6);
2468       xcb_randr_get_output_property_cookie_t gop_c =
2469          xcb_randr_get_output_property(connection,
2470                                        output,
2471                                        connector_id_atom,
2472                                        0,
2473                                        0,
2474                                        0xffffffffUL,
2475                                        0,
2476                                        0);
2477       xcb_randr_query_version_reply_t *qv_r =
2478          xcb_randr_query_version_reply(connection, qv_c, NULL);
2479       free(qv_r);
2480       xcb_randr_get_output_property_reply_t *gop_r =
2481          xcb_randr_get_output_property_reply(connection, gop_c, NULL);
2482       if (gop_r) {
2483          if (gop_r->num_items == 1 && gop_r->format == 32)
2484             memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
2485          free(gop_r);
2486       }
2487    }
2488    return connector_id;
2489 }
2490 
2491 static bool
wsi_display_check_randr_version(xcb_connection_t * connection)2492 wsi_display_check_randr_version(xcb_connection_t *connection)
2493 {
2494    xcb_randr_query_version_cookie_t qv_c =
2495       xcb_randr_query_version(connection, 1, 6);
2496    xcb_randr_query_version_reply_t *qv_r =
2497       xcb_randr_query_version_reply(connection, qv_c, NULL);
2498    bool ret = false;
2499 
2500    if (!qv_r)
2501       return false;
2502 
2503    /* Check for version 1.6 or newer */
2504    ret = (qv_r->major_version > 1 ||
2505           (qv_r->major_version == 1 && qv_r->minor_version >= 6));
2506 
2507    free(qv_r);
2508    return ret;
2509 }
2510 
2511 /*
2512  * Given a kernel connector id, find the associated RandR output using the
2513  * CONNECTOR_ID property
2514  */
2515 
2516 static xcb_randr_output_t
wsi_display_connector_id_to_output(xcb_connection_t * connection,uint32_t connector_id)2517 wsi_display_connector_id_to_output(xcb_connection_t *connection,
2518                                    uint32_t connector_id)
2519 {
2520    if (!wsi_display_check_randr_version(connection))
2521       return 0;
2522 
2523    const xcb_setup_t *setup = xcb_get_setup(connection);
2524 
2525    xcb_atom_t connector_id_atom = 0;
2526    xcb_randr_output_t output = 0;
2527 
2528    /* Search all of the screens for the provided output */
2529    xcb_screen_iterator_t iter;
2530    for (iter = xcb_setup_roots_iterator(setup);
2531         output == 0 && iter.rem;
2532         xcb_screen_next(&iter))
2533    {
2534       xcb_randr_get_screen_resources_cookie_t gsr_c =
2535          xcb_randr_get_screen_resources(connection, iter.data->root);
2536       xcb_randr_get_screen_resources_reply_t *gsr_r =
2537          xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2538 
2539       if (!gsr_r)
2540          return 0;
2541 
2542       xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2543       int o;
2544 
2545       for (o = 0; o < gsr_r->num_outputs; o++) {
2546          if (wsi_display_output_to_connector_id(connection,
2547                                                 &connector_id_atom, ro[o])
2548              == connector_id)
2549          {
2550             output = ro[o];
2551             break;
2552          }
2553       }
2554       free(gsr_r);
2555    }
2556    return output;
2557 }
2558 
2559 /*
2560  * Given a RandR output, find out which screen it's associated with
2561  */
2562 static xcb_window_t
wsi_display_output_to_root(xcb_connection_t * connection,xcb_randr_output_t output)2563 wsi_display_output_to_root(xcb_connection_t *connection,
2564                            xcb_randr_output_t output)
2565 {
2566    if (!wsi_display_check_randr_version(connection))
2567       return 0;
2568 
2569    const xcb_setup_t *setup = xcb_get_setup(connection);
2570    xcb_window_t root = 0;
2571 
2572    /* Search all of the screens for the provided output */
2573    for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
2574         root == 0 && iter.rem;
2575         xcb_screen_next(&iter))
2576    {
2577       xcb_randr_get_screen_resources_cookie_t gsr_c =
2578          xcb_randr_get_screen_resources(connection, iter.data->root);
2579       xcb_randr_get_screen_resources_reply_t *gsr_r =
2580          xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2581 
2582       if (!gsr_r)
2583          return 0;
2584 
2585       xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2586 
2587       for (int o = 0; o < gsr_r->num_outputs; o++) {
2588          if (ro[o] == output) {
2589             root = iter.data->root;
2590             break;
2591          }
2592       }
2593       free(gsr_r);
2594    }
2595    return root;
2596 }
2597 
2598 static bool
wsi_display_mode_matches_x(struct wsi_display_mode * wsi,xcb_randr_mode_info_t * xcb)2599 wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
2600                            xcb_randr_mode_info_t *xcb)
2601 {
2602    return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
2603       wsi->hdisplay == xcb->width &&
2604       wsi->hsync_start == xcb->hsync_start &&
2605       wsi->hsync_end == xcb->hsync_end &&
2606       wsi->htotal == xcb->htotal &&
2607       wsi->hskew == xcb->hskew &&
2608       wsi->vdisplay == xcb->height &&
2609       wsi->vsync_start == xcb->vsync_start &&
2610       wsi->vsync_end == xcb->vsync_end &&
2611       wsi->vtotal == xcb->vtotal &&
2612       wsi->vscan <= 1 &&
2613       wsi->flags == xcb->mode_flags;
2614 }
2615 
2616 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)2617 wsi_display_find_x_mode(struct wsi_device *wsi_device,
2618                         struct wsi_display_connector *connector,
2619                         xcb_randr_mode_info_t *mode)
2620 {
2621    wsi_for_each_display_mode(display_mode, connector) {
2622       if (wsi_display_mode_matches_x(display_mode, mode))
2623          return display_mode;
2624    }
2625    return NULL;
2626 }
2627 
2628 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)2629 wsi_display_register_x_mode(struct wsi_device *wsi_device,
2630                             struct wsi_display_connector *connector,
2631                             xcb_randr_mode_info_t *x_mode,
2632                             bool preferred)
2633 {
2634    struct wsi_display *wsi =
2635       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2636    struct wsi_display_mode *display_mode =
2637       wsi_display_find_x_mode(wsi_device, connector, x_mode);
2638 
2639    if (display_mode) {
2640       display_mode->valid = true;
2641       return VK_SUCCESS;
2642    }
2643 
2644    display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
2645                             8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2646    if (!display_mode)
2647       return VK_ERROR_OUT_OF_HOST_MEMORY;
2648 
2649    display_mode->connector = connector;
2650    display_mode->valid = true;
2651    display_mode->preferred = preferred;
2652    display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
2653    display_mode->hdisplay = x_mode->width;
2654    display_mode->hsync_start = x_mode->hsync_start;
2655    display_mode->hsync_end = x_mode->hsync_end;
2656    display_mode->htotal = x_mode->htotal;
2657    display_mode->hskew = x_mode->hskew;
2658    display_mode->vdisplay = x_mode->height;
2659    display_mode->vsync_start = x_mode->vsync_start;
2660    display_mode->vsync_end = x_mode->vsync_end;
2661    display_mode->vtotal = x_mode->vtotal;
2662    display_mode->vscan = 0;
2663    display_mode->flags = x_mode->mode_flags;
2664 
2665    list_addtail(&display_mode->list, &connector->display_modes);
2666    return VK_SUCCESS;
2667 }
2668 
2669 static struct wsi_display_connector *
wsi_display_get_output(struct wsi_device * wsi_device,xcb_connection_t * connection,xcb_randr_output_t output)2670 wsi_display_get_output(struct wsi_device *wsi_device,
2671                        xcb_connection_t *connection,
2672                        xcb_randr_output_t output)
2673 {
2674    struct wsi_display *wsi =
2675       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2676    struct wsi_display_connector *connector;
2677    uint32_t connector_id;
2678 
2679    xcb_window_t root = wsi_display_output_to_root(connection, output);
2680    if (!root)
2681       return NULL;
2682 
2683    /* See if we already have a connector for this output */
2684    connector = wsi_display_find_output(wsi_device, output);
2685 
2686    if (!connector) {
2687       xcb_atom_t connector_id_atom = 0;
2688 
2689       /*
2690        * Go get the kernel connector ID for this X output
2691        */
2692       connector_id = wsi_display_output_to_connector_id(connection,
2693                                                         &connector_id_atom,
2694                                                         output);
2695 
2696       /* Any X server with lease support will have this atom */
2697       if (!connector_id) {
2698          return NULL;
2699       }
2700 
2701       /* See if we already have a connector for this id */
2702       connector = wsi_display_find_connector(wsi_device, connector_id);
2703 
2704       if (connector == NULL) {
2705          connector = wsi_display_alloc_connector(wsi, connector_id);
2706          if (!connector) {
2707             return NULL;
2708          }
2709          list_addtail(&connector->list, &wsi->connectors);
2710       }
2711       connector->output = output;
2712    }
2713 
2714    xcb_randr_get_screen_resources_cookie_t src =
2715       xcb_randr_get_screen_resources(connection, root);
2716    xcb_randr_get_output_info_cookie_t oic =
2717       xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
2718    xcb_randr_get_screen_resources_reply_t *srr =
2719       xcb_randr_get_screen_resources_reply(connection, src, NULL);
2720    xcb_randr_get_output_info_reply_t *oir =
2721       xcb_randr_get_output_info_reply(connection, oic, NULL);
2722 
2723    if (oir && srr) {
2724       /* Get X modes and add them */
2725 
2726       connector->connected =
2727          oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
2728 
2729       wsi_display_invalidate_connector_modes(connector);
2730 
2731       xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
2732       for (int m = 0; m < oir->num_modes; m++) {
2733          xcb_randr_mode_info_iterator_t i =
2734             xcb_randr_get_screen_resources_modes_iterator(srr);
2735          while (i.rem) {
2736             xcb_randr_mode_info_t *mi = i.data;
2737             if (mi->id == x_modes[m]) {
2738                VkResult result = wsi_display_register_x_mode(
2739                   wsi_device, connector, mi, m < oir->num_preferred);
2740                if (result != VK_SUCCESS) {
2741                   free(oir);
2742                   free(srr);
2743                   return NULL;
2744                }
2745                break;
2746             }
2747             xcb_randr_mode_info_next(&i);
2748          }
2749       }
2750    }
2751 
2752    free(oir);
2753    free(srr);
2754    return connector;
2755 }
2756 
2757 static xcb_randr_crtc_t
wsi_display_find_crtc_for_output(xcb_connection_t * connection,xcb_window_t root,xcb_randr_output_t output)2758 wsi_display_find_crtc_for_output(xcb_connection_t *connection,
2759                                  xcb_window_t root,
2760                                  xcb_randr_output_t output)
2761 {
2762    xcb_randr_get_screen_resources_cookie_t gsr_c =
2763       xcb_randr_get_screen_resources(connection, root);
2764    xcb_randr_get_screen_resources_reply_t *gsr_r =
2765       xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2766 
2767    if (!gsr_r)
2768       return 0;
2769 
2770    xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
2771    xcb_randr_crtc_t idle_crtc = 0;
2772    xcb_randr_crtc_t active_crtc = 0;
2773 
2774    /* Find either a crtc already connected to the desired output or idle */
2775    for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
2776       xcb_randr_get_crtc_info_cookie_t gci_c =
2777          xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
2778       xcb_randr_get_crtc_info_reply_t *gci_r =
2779          xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
2780 
2781       if (gci_r) {
2782          if (gci_r->mode) {
2783             int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
2784             xcb_randr_output_t *outputs =
2785                xcb_randr_get_crtc_info_outputs(gci_r);
2786 
2787             if (num_outputs == 1 && outputs[0] == output)
2788                active_crtc = rc[c];
2789 
2790          } else if (idle_crtc == 0) {
2791             int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
2792             xcb_randr_output_t *possible =
2793                xcb_randr_get_crtc_info_possible(gci_r);
2794 
2795             for (int p = 0; p < num_possible; p++)
2796                if (possible[p] == output) {
2797                   idle_crtc = rc[c];
2798                   break;
2799                }
2800          }
2801          free(gci_r);
2802       }
2803    }
2804    free(gsr_r);
2805 
2806    if (active_crtc)
2807       return active_crtc;
2808    return idle_crtc;
2809 }
2810 
2811 VKAPI_ATTR VkResult VKAPI_CALL
wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice,Display * dpy,VkDisplayKHR display)2812 wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice,
2813                           Display *dpy,
2814                           VkDisplayKHR display)
2815 {
2816    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2817    struct wsi_device *wsi_device = pdevice->wsi_device;
2818    struct wsi_display *wsi =
2819       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2820    xcb_connection_t *connection = XGetXCBConnection(dpy);
2821    struct wsi_display_connector *connector =
2822       wsi_display_connector_from_handle(display);
2823    xcb_window_t root;
2824 
2825    /* XXX no support for multiple leases yet */
2826    if (wsi->fd >= 0)
2827       return VK_ERROR_INITIALIZATION_FAILED;
2828 
2829    if (!connector->output) {
2830       connector->output = wsi_display_connector_id_to_output(connection,
2831                                                              connector->id);
2832 
2833       /* Check and see if we found the output */
2834       if (!connector->output)
2835          return VK_ERROR_INITIALIZATION_FAILED;
2836    }
2837 
2838    root = wsi_display_output_to_root(connection, connector->output);
2839    if (!root)
2840       return VK_ERROR_INITIALIZATION_FAILED;
2841 
2842    xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
2843                                                             root,
2844                                                             connector->output);
2845 
2846    if (!crtc)
2847       return VK_ERROR_INITIALIZATION_FAILED;
2848 
2849 #ifdef HAVE_X11_DRM
2850    xcb_randr_lease_t lease = xcb_generate_id(connection);
2851    xcb_randr_create_lease_cookie_t cl_c =
2852       xcb_randr_create_lease(connection, root, lease, 1, 1,
2853                              &crtc, &connector->output);
2854    xcb_randr_create_lease_reply_t *cl_r =
2855       xcb_randr_create_lease_reply(connection, cl_c, NULL);
2856    if (!cl_r)
2857       return VK_ERROR_INITIALIZATION_FAILED;
2858 
2859    int fd = -1;
2860    if (cl_r->nfd > 0) {
2861       int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
2862 
2863       fd = rcl_f[0];
2864    }
2865    free (cl_r);
2866    if (fd < 0)
2867       return VK_ERROR_INITIALIZATION_FAILED;
2868 
2869    wsi->fd = fd;
2870 #endif
2871 
2872    return VK_SUCCESS;
2873 }
2874 
2875 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice,Display * dpy,RROutput rrOutput,VkDisplayKHR * pDisplay)2876 wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice,
2877                              Display *dpy,
2878                              RROutput rrOutput,
2879                              VkDisplayKHR *pDisplay)
2880 {
2881    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2882    struct wsi_device *wsi_device = pdevice->wsi_device;
2883    xcb_connection_t *connection = XGetXCBConnection(dpy);
2884    struct wsi_display_connector *connector =
2885       wsi_display_get_output(wsi_device, connection,
2886                              (xcb_randr_output_t) rrOutput);
2887 
2888    if (connector)
2889       *pDisplay = wsi_display_connector_to_handle(connector);
2890    else
2891       *pDisplay = VK_NULL_HANDLE;
2892    return VK_SUCCESS;
2893 }
2894 
2895 #endif
2896 
2897 /* VK_EXT_display_control */
2898 VKAPI_ATTR VkResult VKAPI_CALL
wsi_DisplayPowerControlEXT(VkDevice _device,VkDisplayKHR display,const VkDisplayPowerInfoEXT * pDisplayPowerInfo)2899 wsi_DisplayPowerControlEXT(VkDevice _device,
2900                            VkDisplayKHR display,
2901                            const VkDisplayPowerInfoEXT *pDisplayPowerInfo)
2902 {
2903    VK_FROM_HANDLE(vk_device, device, _device);
2904    struct wsi_device *wsi_device = device->physical->wsi_device;
2905    struct wsi_display *wsi =
2906       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2907    struct wsi_display_connector *connector =
2908       wsi_display_connector_from_handle(display);
2909    int mode;
2910 
2911    if (wsi->fd < 0)
2912       return VK_ERROR_INITIALIZATION_FAILED;
2913 
2914    switch (pDisplayPowerInfo->powerState) {
2915    case VK_DISPLAY_POWER_STATE_OFF_EXT:
2916       mode = DRM_MODE_DPMS_OFF;
2917       break;
2918    case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
2919       mode = DRM_MODE_DPMS_SUSPEND;
2920       break;
2921    default:
2922       mode = DRM_MODE_DPMS_ON;
2923       break;
2924    }
2925    drmModeConnectorSetProperty(wsi->fd,
2926                                connector->id,
2927                                connector->dpms_property,
2928                                mode);
2929    return VK_SUCCESS;
2930 }
2931 
2932 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)2933 wsi_register_device_event(VkDevice _device,
2934                           struct wsi_device *wsi_device,
2935                           const VkDeviceEventInfoEXT *device_event_info,
2936                           const VkAllocationCallbacks *allocator,
2937                           struct vk_sync **sync_out,
2938                           int sync_fd)
2939 {
2940    VK_FROM_HANDLE(vk_device, device, _device);
2941    struct wsi_display *wsi =
2942       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2943    VkResult ret = VK_SUCCESS;
2944 
2945 #ifdef HAVE_LIBUDEV
2946    /* Start listening for output change notifications. */
2947    mtx_lock(&wsi->wait_mutex);
2948    if (!wsi->hotplug_thread) {
2949       if (pthread_create(&wsi->hotplug_thread, NULL, udev_event_listener_thread,
2950                          wsi_device)) {
2951          mtx_unlock(&wsi->wait_mutex);
2952          return VK_ERROR_OUT_OF_HOST_MEMORY;
2953       }
2954    }
2955    mtx_unlock(&wsi->wait_mutex);
2956 #endif
2957 
2958    struct wsi_display_fence *fence;
2959    assert(device_event_info->deviceEvent ==
2960           VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT);
2961 
2962    fence = wsi_display_fence_alloc(wsi, sync_fd);
2963 
2964    if (!fence)
2965       return VK_ERROR_OUT_OF_HOST_MEMORY;
2966 
2967    fence->device_event = true;
2968 
2969    mtx_lock(&wsi->wait_mutex);
2970    list_addtail(&fence->link, &wsi_device->hotplug_fences);
2971    mtx_unlock(&wsi->wait_mutex);
2972 
2973    if (sync_out) {
2974       ret = wsi_display_sync_create(device, fence, sync_out);
2975       if (ret != VK_SUCCESS)
2976          wsi_display_fence_destroy(fence);
2977    } else {
2978       wsi_display_fence_destroy(fence);
2979    }
2980 
2981    return ret;
2982 }
2983 
2984 VKAPI_ATTR VkResult VKAPI_CALL
wsi_RegisterDeviceEventEXT(VkDevice _device,const VkDeviceEventInfoEXT * device_event_info,const VkAllocationCallbacks * allocator,VkFence * _fence)2985 wsi_RegisterDeviceEventEXT(VkDevice _device, const VkDeviceEventInfoEXT *device_event_info,
2986                             const VkAllocationCallbacks *allocator, VkFence *_fence)
2987 {
2988    VK_FROM_HANDLE(vk_device, device, _device);
2989    struct vk_fence *fence;
2990    VkResult ret;
2991 
2992    const VkFenceCreateInfo info = {
2993       .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
2994       .flags = 0,
2995    };
2996    ret = vk_fence_create(device, &info, allocator, &fence);
2997    if (ret != VK_SUCCESS)
2998       return ret;
2999 
3000    ret = wsi_register_device_event(_device,
3001                                    device->physical->wsi_device,
3002                                    device_event_info,
3003                                    allocator,
3004                                    &fence->temporary,
3005                                    -1);
3006    if (ret == VK_SUCCESS)
3007       *_fence = vk_fence_to_handle(fence);
3008    else
3009       vk_fence_destroy(device, fence, allocator);
3010    return ret;
3011 }
3012 
3013 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)3014 wsi_register_display_event(VkDevice _device,
3015                            struct wsi_device *wsi_device,
3016                            VkDisplayKHR display,
3017                            const VkDisplayEventInfoEXT *display_event_info,
3018                            const VkAllocationCallbacks *allocator,
3019                            struct vk_sync **sync_out,
3020                            int sync_fd)
3021 {
3022    VK_FROM_HANDLE(vk_device, device, _device);
3023    struct wsi_display *wsi =
3024       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3025    struct wsi_display_fence *fence;
3026    VkResult ret;
3027 
3028    switch (display_event_info->displayEvent) {
3029    case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
3030 
3031       fence = wsi_display_fence_alloc(wsi, sync_fd);
3032 
3033       if (!fence)
3034          return VK_ERROR_OUT_OF_HOST_MEMORY;
3035 
3036       ret = wsi_register_vblank_event(fence, wsi_device, display,
3037                                       DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
3038 
3039       if (ret == VK_SUCCESS) {
3040          if (sync_out) {
3041             ret = wsi_display_sync_create(device, fence, sync_out);
3042             if (ret != VK_SUCCESS)
3043                wsi_display_fence_destroy(fence);
3044          } else {
3045             wsi_display_fence_destroy(fence);
3046          }
3047       } else if (fence != NULL) {
3048          if (fence->syncobj)
3049             drmSyncobjDestroy(wsi->syncobj_fd, fence->syncobj);
3050          vk_free2(wsi->alloc, allocator, fence);
3051       }
3052 
3053       break;
3054    default:
3055       ret = VK_ERROR_FEATURE_NOT_PRESENT;
3056       break;
3057    }
3058 
3059    return ret;
3060 }
3061 
3062 VKAPI_ATTR VkResult VKAPI_CALL
wsi_RegisterDisplayEventEXT(VkDevice _device,VkDisplayKHR display,const VkDisplayEventInfoEXT * display_event_info,const VkAllocationCallbacks * allocator,VkFence * _fence)3063 wsi_RegisterDisplayEventEXT(VkDevice _device, VkDisplayKHR display,
3064                              const VkDisplayEventInfoEXT *display_event_info,
3065                              const VkAllocationCallbacks *allocator, VkFence *_fence)
3066 {
3067    VK_FROM_HANDLE(vk_device, device, _device);
3068    struct vk_fence *fence;
3069    VkResult ret;
3070 
3071    const VkFenceCreateInfo info = {
3072       .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
3073       .flags = 0,
3074    };
3075    ret = vk_fence_create(device, &info, allocator, &fence);
3076    if (ret != VK_SUCCESS)
3077       return ret;
3078 
3079    ret = wsi_register_display_event(
3080       _device, device->physical->wsi_device,
3081       display, display_event_info, allocator, &fence->temporary, -1);
3082 
3083    if (ret == VK_SUCCESS)
3084       *_fence = vk_fence_to_handle(fence);
3085    else
3086       vk_fence_destroy(device, fence, allocator);
3087    return ret;
3088 }
3089 
3090 void
wsi_display_setup_syncobj_fd(struct wsi_device * wsi_device,int fd)3091 wsi_display_setup_syncobj_fd(struct wsi_device *wsi_device,
3092                              int fd)
3093 {
3094    struct wsi_display *wsi =
3095       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3096    wsi->syncobj_fd = fd;
3097 }
3098 
3099 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetSwapchainCounterEXT(VkDevice _device,VkSwapchainKHR _swapchain,VkSurfaceCounterFlagBitsEXT counter,uint64_t * pCounterValue)3100 wsi_GetSwapchainCounterEXT(VkDevice _device,
3101                            VkSwapchainKHR _swapchain,
3102                            VkSurfaceCounterFlagBitsEXT counter,
3103                            uint64_t *pCounterValue)
3104 {
3105    VK_FROM_HANDLE(vk_device, device, _device);
3106    struct wsi_device *wsi_device = device->physical->wsi_device;
3107    struct wsi_display *wsi =
3108       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3109    struct wsi_display_swapchain *swapchain =
3110       (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
3111    struct wsi_display_connector *connector =
3112       wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
3113 
3114    if (wsi->fd < 0)
3115       return VK_ERROR_INITIALIZATION_FAILED;
3116 
3117    if (!connector->active) {
3118       *pCounterValue = 0;
3119       return VK_SUCCESS;
3120    }
3121 
3122    int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id,
3123                                 pCounterValue, NULL);
3124    if (ret)
3125       *pCounterValue = 0;
3126 
3127    return VK_SUCCESS;
3128 }
3129 
3130 VKAPI_ATTR VkResult VKAPI_CALL
wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice,int32_t drmFd,VkDisplayKHR display)3131 wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice,
3132                          int32_t drmFd,
3133                          VkDisplayKHR display)
3134 {
3135    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
3136    struct wsi_device *wsi_device = pdevice->wsi_device;
3137 
3138    if (!wsi_device->can_present_on_device(wsi_device->pdevice, drmFd))
3139       return VK_ERROR_UNKNOWN;
3140 
3141    struct wsi_display *wsi =
3142       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3143 
3144    /* XXX no support for mulitple leases yet */
3145    if (wsi->fd >= 0 || !local_drmIsMaster(drmFd))
3146       return VK_ERROR_INITIALIZATION_FAILED;
3147 
3148    struct wsi_display_connector *connector =
3149          wsi_display_connector_from_handle(display);
3150 
3151    drmModeConnectorPtr drm_connector =
3152          drmModeGetConnectorCurrent(drmFd, connector->id);
3153 
3154    if (!drm_connector)
3155       return VK_ERROR_INITIALIZATION_FAILED;
3156 
3157    drmModeFreeConnector(drm_connector);
3158 
3159    wsi->fd = drmFd;
3160    return VK_SUCCESS;
3161 }
3162 
3163 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice,int32_t drmFd,uint32_t connectorId,VkDisplayKHR * pDisplay)3164 wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice,
3165                      int32_t drmFd,
3166                      uint32_t connectorId,
3167                      VkDisplayKHR *pDisplay)
3168 {
3169    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
3170    struct wsi_device *wsi_device = pdevice->wsi_device;
3171 
3172    if (!wsi_device->can_present_on_device(wsi_device->pdevice, drmFd)) {
3173       *pDisplay = VK_NULL_HANDLE;
3174       return VK_ERROR_UNKNOWN;
3175    }
3176 
3177    struct wsi_display_connector *connector =
3178       wsi_display_get_connector(wsi_device, drmFd, connectorId);
3179 
3180    if (!connector) {
3181       *pDisplay = VK_NULL_HANDLE;
3182       return VK_ERROR_UNKNOWN;
3183    }
3184 
3185    *pDisplay = wsi_display_connector_to_handle(connector);
3186    return VK_SUCCESS;
3187 }
3188