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