• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2017 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 #include "util/macros.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <stdbool.h>
33 #include <math.h>
34 #include <xf86drm.h>
35 #include <xf86drmMode.h>
36 #ifdef HAVE_LIBUDEV
37 #include <libudev.h>
38 #endif
39 #include "drm-uapi/drm_fourcc.h"
40 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
41 #include <xcb/randr.h>
42 #include <X11/Xlib-xcb.h>
43 #endif
44 #include "util/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 = wsi_caps_get_image_usage();
910 
911    VK_FROM_HANDLE(vk_physical_device, pdevice, wsi_device->pdevice);
912    if (pdevice->supported_extensions.EXT_attachment_feedback_loop_layout)
913       caps->supportedUsageFlags |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT;
914 
915    return VK_SUCCESS;
916 }
917 
918 static VkResult
wsi_display_surface_get_surface_counters(VkSurfaceCounterFlagsEXT * counters)919 wsi_display_surface_get_surface_counters(VkSurfaceCounterFlagsEXT *counters)
920 {
921    *counters = VK_SURFACE_COUNTER_VBLANK_BIT_EXT;
922    return VK_SUCCESS;
923 }
924 
925 static VkResult
wsi_display_surface_get_capabilities2(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,const void * info_next,VkSurfaceCapabilities2KHR * caps)926 wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
927                                       struct wsi_device *wsi_device,
928                                       const void *info_next,
929                                       VkSurfaceCapabilities2KHR *caps)
930 {
931    assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
932    VkResult result;
933 
934    result = wsi_display_surface_get_capabilities(icd_surface, wsi_device,
935                                                  &caps->surfaceCapabilities);
936    if (result != VK_SUCCESS)
937       return result;
938 
939    struct wsi_surface_supported_counters *counters =
940       vk_find_struct( caps->pNext, WSI_SURFACE_SUPPORTED_COUNTERS_MESA);
941    const VkSurfacePresentModeEXT *present_mode =
942       vk_find_struct_const(info_next, SURFACE_PRESENT_MODE_EXT);
943 
944    if (counters) {
945       result = wsi_display_surface_get_surface_counters(&counters->supported_surface_counters);
946    }
947 
948    vk_foreach_struct(ext, caps->pNext) {
949       switch (ext->sType) {
950       case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
951          VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
952          protected->supportsProtected = VK_FALSE;
953          break;
954       }
955 
956       case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: {
957          /* Unsupported. */
958          VkSurfacePresentScalingCapabilitiesEXT *scaling = (void *)ext;
959          scaling->supportedPresentScaling = 0;
960          scaling->supportedPresentGravityX = 0;
961          scaling->supportedPresentGravityY = 0;
962          scaling->minScaledImageExtent = caps->surfaceCapabilities.minImageExtent;
963          scaling->maxScaledImageExtent = caps->surfaceCapabilities.maxImageExtent;
964          break;
965       }
966 
967       case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: {
968          /* We only support FIFO. */
969          VkSurfacePresentModeCompatibilityEXT *compat = (void *)ext;
970          if (compat->pPresentModes) {
971             if (compat->presentModeCount) {
972                assert(present_mode);
973                compat->pPresentModes[0] = present_mode->presentMode;
974                compat->presentModeCount = 1;
975             }
976          } else {
977             compat->presentModeCount = 1;
978          }
979          break;
980       }
981 
982       default:
983          /* Ignored */
984          break;
985       }
986    }
987 
988    return result;
989 }
990 
991 struct wsi_display_surface_format {
992    VkSurfaceFormatKHR surface_format;
993    uint32_t           drm_format;
994 };
995 
996 static const struct wsi_display_surface_format
997  available_surface_formats[] = {
998    {
999       .surface_format = {
1000          .format = VK_FORMAT_B8G8R8A8_SRGB,
1001          .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
1002       },
1003       .drm_format = DRM_FORMAT_XRGB8888
1004    },
1005    {
1006       .surface_format = {
1007          .format = VK_FORMAT_B8G8R8A8_UNORM,
1008          .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
1009       },
1010       .drm_format = DRM_FORMAT_XRGB8888
1011    },
1012 };
1013 
1014 static void
get_sorted_vk_formats(struct wsi_device * wsi_device,VkSurfaceFormatKHR * sorted_formats)1015 get_sorted_vk_formats(struct wsi_device *wsi_device, VkSurfaceFormatKHR *sorted_formats)
1016 {
1017    for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)
1018       sorted_formats[i] = available_surface_formats[i].surface_format;
1019 
1020    if (wsi_device->force_bgra8_unorm_first) {
1021       for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
1022          if (sorted_formats[i].format == VK_FORMAT_B8G8R8A8_UNORM) {
1023             VkSurfaceFormatKHR tmp = sorted_formats[i];
1024             sorted_formats[i] = sorted_formats[0];
1025             sorted_formats[0] = tmp;
1026             break;
1027          }
1028       }
1029    }
1030 }
1031 
1032 static VkResult
wsi_display_surface_get_formats(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,uint32_t * surface_format_count,VkSurfaceFormatKHR * surface_formats)1033 wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
1034                                 struct wsi_device *wsi_device,
1035                                 uint32_t *surface_format_count,
1036                                 VkSurfaceFormatKHR *surface_formats)
1037 {
1038    VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out,
1039                           surface_formats, surface_format_count);
1040 
1041    VkSurfaceFormatKHR sorted_formats[ARRAY_SIZE(available_surface_formats)];
1042    get_sorted_vk_formats(wsi_device, sorted_formats);
1043 
1044    for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
1045       vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) {
1046          *f = sorted_formats[i];
1047       }
1048    }
1049 
1050    return vk_outarray_status(&out);
1051 }
1052 
1053 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)1054 wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
1055                                  struct wsi_device *wsi_device,
1056                                  const void *info_next,
1057                                  uint32_t *surface_format_count,
1058                                  VkSurfaceFormat2KHR *surface_formats)
1059 {
1060    VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out,
1061                           surface_formats, surface_format_count);
1062 
1063    VkSurfaceFormatKHR sorted_formats[ARRAY_SIZE(available_surface_formats)];
1064    get_sorted_vk_formats(wsi_device, sorted_formats);
1065 
1066    for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
1067       vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) {
1068          assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
1069          f->surfaceFormat = sorted_formats[i];
1070       }
1071    }
1072 
1073    return vk_outarray_status(&out);
1074 }
1075 
1076 static VkResult
wsi_display_surface_get_present_modes(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t * present_mode_count,VkPresentModeKHR * present_modes)1077 wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface,
1078                                       struct wsi_device *wsi_device,
1079                                       uint32_t *present_mode_count,
1080                                       VkPresentModeKHR *present_modes)
1081 {
1082    VK_OUTARRAY_MAKE_TYPED(VkPresentModeKHR, conn,
1083                           present_modes, present_mode_count);
1084 
1085    vk_outarray_append_typed(VkPresentModeKHR, &conn, present) {
1086       *present = VK_PRESENT_MODE_FIFO_KHR;
1087    }
1088 
1089    return vk_outarray_status(&conn);
1090 }
1091 
1092 static VkResult
wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase * surface_base,struct wsi_device * wsi_device,uint32_t * pRectCount,VkRect2D * pRects)1093 wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base,
1094                                            struct wsi_device *wsi_device,
1095                                            uint32_t* pRectCount,
1096                                            VkRect2D* pRects)
1097 {
1098    VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
1099    wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
1100    VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount);
1101 
1102    if (wsi_device_matches_drm_fd(wsi_device, mode->connector->wsi->fd)) {
1103       vk_outarray_append_typed(VkRect2D, &out, rect) {
1104          *rect = (VkRect2D) {
1105             .offset = { 0, 0 },
1106             .extent = { mode->hdisplay, mode->vdisplay },
1107          };
1108       }
1109    }
1110 
1111    return vk_outarray_status(&out);
1112 }
1113 
1114 static void
wsi_display_destroy_buffer(struct wsi_display * wsi,uint32_t buffer)1115 wsi_display_destroy_buffer(struct wsi_display *wsi,
1116                            uint32_t buffer)
1117 {
1118    (void) drmIoctl(wsi->fd, DRM_IOCTL_GEM_CLOSE,
1119                    &((struct drm_gem_close) { .handle = buffer }));
1120 }
1121 
1122 static VkResult
wsi_display_image_init(struct wsi_swapchain * drv_chain,const VkSwapchainCreateInfoKHR * create_info,struct wsi_display_image * image)1123 wsi_display_image_init(struct wsi_swapchain *drv_chain,
1124                        const VkSwapchainCreateInfoKHR *create_info,
1125                        struct wsi_display_image *image)
1126 {
1127    struct wsi_display_swapchain *chain =
1128       (struct wsi_display_swapchain *) drv_chain;
1129    struct wsi_display *wsi = chain->wsi;
1130    uint32_t drm_format = 0;
1131 
1132    for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
1133       if (create_info->imageFormat == available_surface_formats[i].surface_format.format &&
1134           create_info->imageColorSpace == available_surface_formats[i].surface_format.colorSpace) {
1135          drm_format = available_surface_formats[i].drm_format;
1136          break;
1137       }
1138    }
1139 
1140    /* the application provided an invalid format, bail */
1141    if (drm_format == 0)
1142       return VK_ERROR_DEVICE_LOST;
1143 
1144    VkResult result = wsi_create_image(&chain->base, &chain->base.image_info,
1145                                       &image->base);
1146    if (result != VK_SUCCESS)
1147       return result;
1148 
1149    memset(image->buffer, 0, sizeof (image->buffer));
1150 
1151    for (unsigned int i = 0; i < image->base.num_planes; i++) {
1152       int ret = drmPrimeFDToHandle(wsi->fd, image->base.dma_buf_fd,
1153                                    &image->buffer[i]);
1154       if (ret < 0)
1155          goto fail_handle;
1156    }
1157 
1158    image->chain = chain;
1159    image->state = WSI_IMAGE_IDLE;
1160    image->fb_id = 0;
1161 
1162    int ret = drmModeAddFB2(wsi->fd,
1163                            create_info->imageExtent.width,
1164                            create_info->imageExtent.height,
1165                            drm_format,
1166                            image->buffer,
1167                            image->base.row_pitches,
1168                            image->base.offsets,
1169                            &image->fb_id, 0);
1170 
1171    if (ret)
1172       goto fail_fb;
1173 
1174    return VK_SUCCESS;
1175 
1176 fail_fb:
1177 fail_handle:
1178    for (unsigned int i = 0; i < image->base.num_planes; i++) {
1179       if (image->buffer[i])
1180          wsi_display_destroy_buffer(wsi, image->buffer[i]);
1181    }
1182 
1183    wsi_destroy_image(&chain->base, &image->base);
1184 
1185    return VK_ERROR_OUT_OF_HOST_MEMORY;
1186 }
1187 
1188 static void
wsi_display_image_finish(struct wsi_swapchain * drv_chain,struct wsi_display_image * image)1189 wsi_display_image_finish(struct wsi_swapchain *drv_chain,
1190                          struct wsi_display_image *image)
1191 {
1192    struct wsi_display_swapchain *chain =
1193       (struct wsi_display_swapchain *) drv_chain;
1194    struct wsi_display *wsi = chain->wsi;
1195 
1196    drmModeRmFB(wsi->fd, image->fb_id);
1197    for (unsigned int i = 0; i < image->base.num_planes; i++)
1198       wsi_display_destroy_buffer(wsi, image->buffer[i]);
1199    wsi_destroy_image(&chain->base, &image->base);
1200 }
1201 
1202 static VkResult
wsi_display_swapchain_destroy(struct wsi_swapchain * drv_chain,const VkAllocationCallbacks * allocator)1203 wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain,
1204                               const VkAllocationCallbacks *allocator)
1205 {
1206    struct wsi_display_swapchain *chain =
1207       (struct wsi_display_swapchain *) drv_chain;
1208 
1209    for (uint32_t i = 0; i < chain->base.image_count; i++)
1210       wsi_display_image_finish(drv_chain, &chain->images[i]);
1211 
1212    pthread_mutex_destroy(&chain->present_id_mutex);
1213    pthread_cond_destroy(&chain->present_id_cond);
1214 
1215    wsi_swapchain_finish(&chain->base);
1216    vk_free(allocator, chain);
1217    return VK_SUCCESS;
1218 }
1219 
1220 static struct wsi_image *
wsi_display_get_wsi_image(struct wsi_swapchain * drv_chain,uint32_t image_index)1221 wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain,
1222                           uint32_t image_index)
1223 {
1224    struct wsi_display_swapchain *chain =
1225       (struct wsi_display_swapchain *) drv_chain;
1226 
1227    return &chain->images[image_index].base;
1228 }
1229 
1230 static void
wsi_display_idle_old_displaying(struct wsi_display_image * active_image)1231 wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
1232 {
1233    struct wsi_display_swapchain *chain = active_image->chain;
1234 
1235    wsi_display_debug("idle everyone but %ld\n",
1236                      active_image - &(chain->images[0]));
1237    for (uint32_t i = 0; i < chain->base.image_count; i++)
1238       if (chain->images[i].state == WSI_IMAGE_DISPLAYING &&
1239           &chain->images[i] != active_image)
1240       {
1241          wsi_display_debug("idle %d\n", i);
1242          chain->images[i].state = WSI_IMAGE_IDLE;
1243       }
1244 }
1245 
1246 static VkResult
1247 _wsi_display_queue_next(struct wsi_swapchain *drv_chain);
1248 
1249 static void
wsi_display_present_complete(struct wsi_display_swapchain * swapchain,struct wsi_display_image * image)1250 wsi_display_present_complete(struct wsi_display_swapchain *swapchain,
1251                              struct wsi_display_image *image)
1252 {
1253    if (image->present_id) {
1254       pthread_mutex_lock(&swapchain->present_id_mutex);
1255       if (image->present_id > swapchain->present_id) {
1256          swapchain->present_id = image->present_id;
1257          pthread_cond_broadcast(&swapchain->present_id_cond);
1258       }
1259       pthread_mutex_unlock(&swapchain->present_id_mutex);
1260    }
1261 }
1262 
1263 static void
wsi_display_surface_error(struct wsi_display_swapchain * swapchain,VkResult result)1264 wsi_display_surface_error(struct wsi_display_swapchain *swapchain, VkResult result)
1265 {
1266    pthread_mutex_lock(&swapchain->present_id_mutex);
1267    swapchain->present_id = UINT64_MAX;
1268    swapchain->present_id_error = result;
1269    pthread_cond_broadcast(&swapchain->present_id_cond);
1270    pthread_mutex_unlock(&swapchain->present_id_mutex);
1271 }
1272 
1273 static void
wsi_display_page_flip_handler2(int fd,unsigned int frame,unsigned int sec,unsigned int usec,uint32_t crtc_id,void * data)1274 wsi_display_page_flip_handler2(int fd,
1275                                unsigned int frame,
1276                                unsigned int sec,
1277                                unsigned int usec,
1278                                uint32_t crtc_id,
1279                                void *data)
1280 {
1281    struct wsi_display_image *image = data;
1282    struct wsi_display_swapchain *chain = image->chain;
1283 
1284    wsi_display_debug("image %ld displayed at %d\n",
1285                      image - &(image->chain->images[0]), frame);
1286    image->state = WSI_IMAGE_DISPLAYING;
1287    wsi_display_present_complete(chain, image);
1288 
1289    wsi_display_idle_old_displaying(image);
1290    VkResult result = _wsi_display_queue_next(&(chain->base));
1291    if (result != VK_SUCCESS)
1292       chain->status = result;
1293 }
1294 
1295 static void wsi_display_fence_event_handler(struct wsi_display_fence *fence);
1296 
wsi_display_page_flip_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)1297 static void wsi_display_page_flip_handler(int fd,
1298                                           unsigned int frame,
1299                                           unsigned int sec,
1300                                           unsigned int usec,
1301                                           void *data)
1302 {
1303    wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
1304 }
1305 
wsi_display_vblank_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)1306 static void wsi_display_vblank_handler(int fd, unsigned int frame,
1307                                        unsigned int sec, unsigned int usec,
1308                                        void *data)
1309 {
1310    struct wsi_display_fence *fence = data;
1311 
1312    wsi_display_fence_event_handler(fence);
1313 }
1314 
wsi_display_sequence_handler(int fd,uint64_t frame,uint64_t nsec,uint64_t user_data)1315 static void wsi_display_sequence_handler(int fd, uint64_t frame,
1316                                          uint64_t nsec, uint64_t user_data)
1317 {
1318    struct wsi_display_fence *fence =
1319       (struct wsi_display_fence *) (uintptr_t) user_data;
1320 
1321    wsi_display_fence_event_handler(fence);
1322 }
1323 
1324 static drmEventContext event_context = {
1325    .version = DRM_EVENT_CONTEXT_VERSION,
1326    .page_flip_handler = wsi_display_page_flip_handler,
1327 #if DRM_EVENT_CONTEXT_VERSION >= 3
1328    .page_flip_handler2 = wsi_display_page_flip_handler2,
1329 #endif
1330    .vblank_handler = wsi_display_vblank_handler,
1331    .sequence_handler = wsi_display_sequence_handler,
1332 };
1333 
1334 static void *
wsi_display_wait_thread(void * data)1335 wsi_display_wait_thread(void *data)
1336 {
1337    struct wsi_display *wsi = data;
1338    struct pollfd pollfd = {
1339       .fd = wsi->fd,
1340       .events = POLLIN
1341    };
1342 
1343    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1344    for (;;) {
1345       int ret = poll(&pollfd, 1, -1);
1346       if (ret > 0) {
1347          pthread_mutex_lock(&wsi->wait_mutex);
1348          (void) drmHandleEvent(wsi->fd, &event_context);
1349          pthread_cond_broadcast(&wsi->wait_cond);
1350          pthread_mutex_unlock(&wsi->wait_mutex);
1351       }
1352    }
1353    return NULL;
1354 }
1355 
1356 static int
wsi_display_start_wait_thread(struct wsi_display * wsi)1357 wsi_display_start_wait_thread(struct wsi_display *wsi)
1358 {
1359    if (!wsi->wait_thread) {
1360       int ret = pthread_create(&wsi->wait_thread, NULL,
1361                                wsi_display_wait_thread, wsi);
1362       if (ret)
1363          return ret;
1364    }
1365    return 0;
1366 }
1367 
1368 static void
wsi_display_stop_wait_thread(struct wsi_display * wsi)1369 wsi_display_stop_wait_thread(struct wsi_display *wsi)
1370 {
1371    pthread_mutex_lock(&wsi->wait_mutex);
1372    if (wsi->wait_thread) {
1373       pthread_cancel(wsi->wait_thread);
1374       pthread_join(wsi->wait_thread, NULL);
1375       wsi->wait_thread = 0;
1376    }
1377    pthread_mutex_unlock(&wsi->wait_mutex);
1378 }
1379 
1380 static int
cond_timedwait_ns(pthread_cond_t * cond,pthread_mutex_t * mutex,uint64_t timeout_ns)1381 cond_timedwait_ns(pthread_cond_t *cond,
1382                   pthread_mutex_t *mutex,
1383                   uint64_t timeout_ns)
1384 {
1385    struct timespec abs_timeout = {
1386       .tv_sec = timeout_ns / 1000000000ULL,
1387       .tv_nsec = timeout_ns % 1000000000ULL,
1388    };
1389 
1390    int ret = pthread_cond_timedwait(cond, mutex, &abs_timeout);
1391    wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);
1392    return ret;
1393 }
1394 
1395 /*
1396  * Wait for at least one event from the kernel to be processed.
1397  * Call with wait_mutex held
1398  */
1399 static int
wsi_display_wait_for_event(struct wsi_display * wsi,uint64_t timeout_ns)1400 wsi_display_wait_for_event(struct wsi_display *wsi,
1401                            uint64_t timeout_ns)
1402 {
1403    int ret = wsi_display_start_wait_thread(wsi);
1404 
1405    if (ret)
1406       return ret;
1407 
1408    return cond_timedwait_ns(&wsi->wait_cond, &wsi->wait_mutex, timeout_ns);
1409 }
1410 
1411 /* Wait for device event to be processed.
1412  * Call with wait_mutex held
1413  */
1414 static int
wsi_device_wait_for_event(struct wsi_display * wsi,uint64_t timeout_ns)1415 wsi_device_wait_for_event(struct wsi_display *wsi,
1416                           uint64_t timeout_ns)
1417 {
1418    return cond_timedwait_ns(&wsi->hotplug_cond, &wsi->wait_mutex, timeout_ns);
1419 }
1420 
1421 static VkResult
wsi_display_release_images(struct wsi_swapchain * drv_chain,uint32_t count,const uint32_t * indices)1422 wsi_display_release_images(struct wsi_swapchain *drv_chain,
1423                            uint32_t count, const uint32_t *indices)
1424 {
1425    struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)drv_chain;
1426    if (chain->status == VK_ERROR_SURFACE_LOST_KHR)
1427       return chain->status;
1428 
1429    for (uint32_t i = 0; i < count; i++) {
1430       uint32_t index = indices[i];
1431       assert(index < chain->base.image_count);
1432       assert(chain->images[index].state == WSI_IMAGE_DRAWING);
1433       chain->images[index].state = WSI_IMAGE_IDLE;
1434    }
1435 
1436    return VK_SUCCESS;
1437 }
1438 
1439 static VkResult
wsi_display_acquire_next_image(struct wsi_swapchain * drv_chain,const VkAcquireNextImageInfoKHR * info,uint32_t * image_index)1440 wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
1441                                const VkAcquireNextImageInfoKHR *info,
1442                                uint32_t *image_index)
1443 {
1444    struct wsi_display_swapchain *chain =
1445       (struct wsi_display_swapchain *)drv_chain;
1446    struct wsi_display *wsi = chain->wsi;
1447    int ret = 0;
1448    VkResult result = VK_SUCCESS;
1449 
1450    /* Bail early if the swapchain is broken */
1451    if (chain->status != VK_SUCCESS)
1452       return chain->status;
1453 
1454    uint64_t timeout = info->timeout;
1455    if (timeout != 0 && timeout != UINT64_MAX)
1456       timeout = wsi_rel_to_abs_time(timeout);
1457 
1458    pthread_mutex_lock(&wsi->wait_mutex);
1459    for (;;) {
1460       for (uint32_t i = 0; i < chain->base.image_count; i++) {
1461          if (chain->images[i].state == WSI_IMAGE_IDLE) {
1462             *image_index = i;
1463             wsi_display_debug("image %d available\n", i);
1464             chain->images[i].state = WSI_IMAGE_DRAWING;
1465             result = VK_SUCCESS;
1466             goto done;
1467          }
1468          wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
1469       }
1470 
1471       if (ret == ETIMEDOUT) {
1472          result = VK_TIMEOUT;
1473          goto done;
1474       }
1475 
1476       ret = wsi_display_wait_for_event(wsi, timeout);
1477 
1478       if (ret && ret != ETIMEDOUT) {
1479          result = VK_ERROR_SURFACE_LOST_KHR;
1480          wsi_display_surface_error(chain, result);
1481          goto done;
1482       }
1483    }
1484 done:
1485    pthread_mutex_unlock(&wsi->wait_mutex);
1486 
1487    if (result != VK_SUCCESS)
1488       return result;
1489 
1490    return chain->status;
1491 }
1492 
1493 /*
1494  * Check whether there are any other connectors driven by this crtc
1495  */
1496 static bool
wsi_display_crtc_solo(struct wsi_display * wsi,drmModeResPtr mode_res,drmModeConnectorPtr connector,uint32_t crtc_id)1497 wsi_display_crtc_solo(struct wsi_display *wsi,
1498                       drmModeResPtr mode_res,
1499                       drmModeConnectorPtr connector,
1500                       uint32_t crtc_id)
1501 {
1502    /* See if any other connectors share the same encoder */
1503    for (int c = 0; c < mode_res->count_connectors; c++) {
1504       if (mode_res->connectors[c] == connector->connector_id)
1505          continue;
1506 
1507       drmModeConnectorPtr other_connector =
1508          drmModeGetConnector(wsi->fd, mode_res->connectors[c]);
1509 
1510       if (other_connector) {
1511          bool match = (other_connector->encoder_id == connector->encoder_id);
1512          drmModeFreeConnector(other_connector);
1513          if (match)
1514             return false;
1515       }
1516    }
1517 
1518    /* See if any other encoders share the same crtc */
1519    for (int e = 0; e < mode_res->count_encoders; e++) {
1520       if (mode_res->encoders[e] == connector->encoder_id)
1521          continue;
1522 
1523       drmModeEncoderPtr other_encoder =
1524          drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);
1525 
1526       if (other_encoder) {
1527          bool match = (other_encoder->crtc_id == crtc_id);
1528          drmModeFreeEncoder(other_encoder);
1529          if (match)
1530             return false;
1531       }
1532    }
1533    return true;
1534 }
1535 
1536 /*
1537  * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1538  * currently driving this connector and not any others. Settle for a CRTC
1539  * which is currently idle.
1540  */
1541 static uint32_t
wsi_display_select_crtc(const struct wsi_display_connector * connector,drmModeResPtr mode_res,drmModeConnectorPtr drm_connector)1542 wsi_display_select_crtc(const struct wsi_display_connector *connector,
1543                         drmModeResPtr mode_res,
1544                         drmModeConnectorPtr drm_connector)
1545 {
1546    struct wsi_display *wsi = connector->wsi;
1547 
1548    /* See what CRTC is currently driving this connector */
1549    if (drm_connector->encoder_id) {
1550       drmModeEncoderPtr encoder =
1551          drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);
1552 
1553       if (encoder) {
1554          uint32_t crtc_id = encoder->crtc_id;
1555          drmModeFreeEncoder(encoder);
1556          if (crtc_id) {
1557             if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))
1558                return crtc_id;
1559          }
1560       }
1561    }
1562    uint32_t crtc_id = 0;
1563    for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
1564       drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
1565       if (crtc && crtc->buffer_id == 0)
1566          crtc_id = crtc->crtc_id;
1567       drmModeFreeCrtc(crtc);
1568    }
1569    return crtc_id;
1570 }
1571 
1572 static VkResult
wsi_display_setup_connector(wsi_display_connector * connector,wsi_display_mode * display_mode)1573 wsi_display_setup_connector(wsi_display_connector *connector,
1574                             wsi_display_mode *display_mode)
1575 {
1576    struct wsi_display *wsi = connector->wsi;
1577 
1578    if (connector->current_mode == display_mode && connector->crtc_id)
1579       return VK_SUCCESS;
1580 
1581    VkResult result = VK_SUCCESS;
1582 
1583    drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
1584    if (!mode_res) {
1585       if (errno == ENOMEM)
1586          result = VK_ERROR_OUT_OF_HOST_MEMORY;
1587       else
1588          result = VK_ERROR_SURFACE_LOST_KHR;
1589       goto bail;
1590    }
1591 
1592    drmModeConnectorPtr drm_connector =
1593       drmModeGetConnectorCurrent(wsi->fd, connector->id);
1594 
1595    if (!drm_connector) {
1596       if (errno == ENOMEM)
1597          result = VK_ERROR_OUT_OF_HOST_MEMORY;
1598       else
1599          result = VK_ERROR_SURFACE_LOST_KHR;
1600       goto bail_mode_res;
1601    }
1602 
1603    /* Pick a CRTC if we don't have one */
1604    if (!connector->crtc_id) {
1605       connector->crtc_id = wsi_display_select_crtc(connector,
1606                                                    mode_res, drm_connector);
1607       if (!connector->crtc_id) {
1608          result = VK_ERROR_SURFACE_LOST_KHR;
1609          goto bail_connector;
1610       }
1611    }
1612 
1613    if (connector->current_mode != display_mode) {
1614 
1615       /* Find the drm mode corresponding to the requested VkDisplayMode */
1616       drmModeModeInfoPtr drm_mode = NULL;
1617 
1618       for (int m = 0; m < drm_connector->count_modes; m++) {
1619          drm_mode = &drm_connector->modes[m];
1620          if (wsi_display_mode_matches_drm(display_mode, drm_mode))
1621             break;
1622          drm_mode = NULL;
1623       }
1624 
1625       if (!drm_mode) {
1626          result = VK_ERROR_SURFACE_LOST_KHR;
1627          goto bail_connector;
1628       }
1629 
1630       connector->current_mode = display_mode;
1631       connector->current_drm_mode = *drm_mode;
1632    }
1633 
1634 bail_connector:
1635    drmModeFreeConnector(drm_connector);
1636 bail_mode_res:
1637    drmModeFreeResources(mode_res);
1638 bail:
1639    return result;
1640 
1641 }
1642 
1643 static VkResult
wsi_display_fence_wait(struct wsi_display_fence * fence,uint64_t timeout)1644 wsi_display_fence_wait(struct wsi_display_fence *fence, uint64_t timeout)
1645 {
1646    wsi_display_debug("%9lu wait fence %lu %ld\n",
1647                      pthread_self(), fence->sequence,
1648                      (int64_t) (timeout - os_time_get_nano()));
1649    wsi_display_debug_code(uint64_t start_ns = os_time_get_nano());
1650    pthread_mutex_lock(&fence->wsi->wait_mutex);
1651 
1652    VkResult result;
1653    int ret = 0;
1654    for (;;) {
1655       if (fence->event_received) {
1656          wsi_display_debug("%9lu fence %lu passed\n",
1657                            pthread_self(), fence->sequence);
1658          result = VK_SUCCESS;
1659          break;
1660       }
1661 
1662       if (ret == ETIMEDOUT) {
1663          wsi_display_debug("%9lu fence %lu timeout\n",
1664                            pthread_self(), fence->sequence);
1665          result = VK_TIMEOUT;
1666          break;
1667       }
1668 
1669       if (fence->device_event)
1670          ret = wsi_device_wait_for_event(fence->wsi, timeout);
1671       else
1672          ret = wsi_display_wait_for_event(fence->wsi, timeout);
1673 
1674       if (ret && ret != ETIMEDOUT) {
1675          wsi_display_debug("%9lu fence %lu error\n",
1676                            pthread_self(), fence->sequence);
1677          result = VK_ERROR_DEVICE_LOST;
1678          break;
1679       }
1680    }
1681    pthread_mutex_unlock(&fence->wsi->wait_mutex);
1682    wsi_display_debug("%9lu fence wait %f ms\n",
1683                      pthread_self(),
1684                      ((int64_t) (os_time_get_nano() - start_ns)) /
1685                      1.0e6);
1686    return result;
1687 }
1688 
1689 static void
wsi_display_fence_check_free(struct wsi_display_fence * fence)1690 wsi_display_fence_check_free(struct wsi_display_fence *fence)
1691 {
1692    if (fence->event_received && fence->destroyed)
1693       vk_free(fence->wsi->alloc, fence);
1694 }
1695 
wsi_display_fence_event_handler(struct wsi_display_fence * fence)1696 static void wsi_display_fence_event_handler(struct wsi_display_fence *fence)
1697 {
1698    if (fence->syncobj) {
1699       (void) drmSyncobjSignal(fence->wsi->syncobj_fd, &fence->syncobj, 1);
1700       (void) drmSyncobjDestroy(fence->wsi->syncobj_fd, fence->syncobj);
1701    }
1702 
1703    fence->event_received = true;
1704    wsi_display_fence_check_free(fence);
1705 }
1706 
1707 static void
wsi_display_fence_destroy(struct wsi_display_fence * fence)1708 wsi_display_fence_destroy(struct wsi_display_fence *fence)
1709 {
1710    /* Destroy hotplug fence list. */
1711    if (fence->device_event) {
1712       pthread_mutex_lock(&fence->wsi->wait_mutex);
1713       list_del(&fence->link);
1714       pthread_mutex_unlock(&fence->wsi->wait_mutex);
1715       fence->event_received = true;
1716    }
1717 
1718    assert(!fence->destroyed);
1719    fence->destroyed = true;
1720    wsi_display_fence_check_free(fence);
1721 }
1722 
1723 static struct wsi_display_fence *
wsi_display_fence_alloc(struct wsi_display * wsi,int sync_fd)1724 wsi_display_fence_alloc(struct wsi_display *wsi, int sync_fd)
1725 {
1726    struct wsi_display_fence *fence =
1727       vk_zalloc(wsi->alloc, sizeof (*fence),
1728                8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1729 
1730    if (!fence)
1731       return NULL;
1732 
1733    if (sync_fd >= 0) {
1734       int ret = drmSyncobjFDToHandle(wsi->syncobj_fd, sync_fd, &fence->syncobj);
1735 
1736       if (ret) {
1737          vk_free(wsi->alloc, fence);
1738          return NULL;
1739       }
1740    }
1741 
1742    fence->wsi = wsi;
1743    fence->event_received = false;
1744    fence->destroyed = false;
1745    fence->sequence = ++fence_sequence;
1746    return fence;
1747 }
1748 
1749 static VkResult
wsi_display_sync_init(struct vk_device * device,struct vk_sync * sync,uint64_t initial_value)1750 wsi_display_sync_init(struct vk_device *device,
1751                       struct vk_sync *sync,
1752                       uint64_t initial_value)
1753 {
1754    assert(initial_value == 0);
1755    return VK_SUCCESS;
1756 }
1757 
1758 static void
wsi_display_sync_finish(struct vk_device * device,struct vk_sync * sync)1759 wsi_display_sync_finish(struct vk_device *device,
1760                         struct vk_sync *sync)
1761 {
1762    struct wsi_display_sync *wsi_sync =
1763       container_of(sync, struct wsi_display_sync, sync);
1764    if (wsi_sync->fence)
1765       wsi_display_fence_destroy(wsi_sync->fence);
1766 }
1767 
1768 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)1769 wsi_display_sync_wait(struct vk_device *device,
1770                       struct vk_sync *sync,
1771                       uint64_t wait_value,
1772                       enum vk_sync_wait_flags wait_flags,
1773                       uint64_t abs_timeout_ns)
1774 {
1775    struct wsi_display_sync *wsi_sync =
1776       container_of(sync, struct wsi_display_sync, sync);
1777 
1778    assert(wait_value == 0);
1779    assert(wait_flags == VK_SYNC_WAIT_COMPLETE);
1780 
1781    return wsi_display_fence_wait(wsi_sync->fence, abs_timeout_ns);
1782 }
1783 
1784 static const struct vk_sync_type wsi_display_sync_type = {
1785    .size = sizeof(struct wsi_display_sync),
1786    .features = VK_SYNC_FEATURE_BINARY |
1787                VK_SYNC_FEATURE_CPU_WAIT,
1788    .init = wsi_display_sync_init,
1789    .finish = wsi_display_sync_finish,
1790    .wait = wsi_display_sync_wait,
1791 };
1792 
1793 static VkResult
wsi_display_sync_create(struct vk_device * device,struct wsi_display_fence * fence,struct vk_sync ** sync_out)1794 wsi_display_sync_create(struct vk_device *device,
1795                         struct wsi_display_fence *fence,
1796                         struct vk_sync **sync_out)
1797 {
1798    VkResult result = vk_sync_create(device, &wsi_display_sync_type,
1799                                     0 /* flags */,
1800                                     0 /* initial_value */, sync_out);
1801    if (result != VK_SUCCESS)
1802       return result;
1803 
1804    struct wsi_display_sync *sync =
1805       container_of(*sync_out, struct wsi_display_sync, sync);
1806 
1807    sync->fence = fence;
1808 
1809    return VK_SUCCESS;
1810 }
1811 
1812 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)1813 wsi_register_vblank_event(struct wsi_display_fence *fence,
1814                           const struct wsi_device *wsi_device,
1815                           VkDisplayKHR display,
1816                           uint32_t flags,
1817                           uint64_t frame_requested,
1818                           uint64_t *frame_queued)
1819 {
1820    struct wsi_display *wsi =
1821       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1822    struct wsi_display_connector *connector =
1823       wsi_display_connector_from_handle(display);
1824 
1825    if (wsi->fd < 0)
1826       return VK_ERROR_INITIALIZATION_FAILED;
1827 
1828    /* A display event may be registered before the first page flip at which
1829     * point crtc_id will be 0. If this is the case we setup the connector
1830     * here to allow drmCrtcQueueSequence to succeed.
1831     */
1832    if (!connector->crtc_id) {
1833       VkResult ret = wsi_display_setup_connector(connector,
1834                                                  connector->current_mode);
1835       if (ret != VK_SUCCESS)
1836          return VK_ERROR_INITIALIZATION_FAILED;
1837    }
1838 
1839    for (;;) {
1840       int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id,
1841                                      flags,
1842                                      frame_requested,
1843                                      frame_queued,
1844                                      (uintptr_t) fence);
1845 
1846       if (!ret)
1847          return VK_SUCCESS;
1848 
1849       if (errno != ENOMEM) {
1850 
1851          /* Something unexpected happened. Pause for a moment so the
1852           * application doesn't just spin and then return a failure indication
1853           */
1854 
1855          wsi_display_debug("queue vblank event %lu failed\n", fence->sequence);
1856          struct timespec delay = {
1857             .tv_sec = 0,
1858             .tv_nsec = 100000000ull,
1859          };
1860          nanosleep(&delay, NULL);
1861          return VK_ERROR_OUT_OF_HOST_MEMORY;
1862       }
1863 
1864       /* The kernel event queue is full. Wait for some events to be
1865        * processed and try again
1866        */
1867 
1868       pthread_mutex_lock(&wsi->wait_mutex);
1869       ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull));
1870       pthread_mutex_unlock(&wsi->wait_mutex);
1871 
1872       if (ret) {
1873          wsi_display_debug("vblank queue full, event wait failed\n");
1874          return VK_ERROR_OUT_OF_HOST_MEMORY;
1875       }
1876    }
1877 }
1878 
1879 /*
1880  * Check to see if the kernel has no flip queued and if there's an image
1881  * waiting to be displayed.
1882  */
1883 static VkResult
_wsi_display_queue_next(struct wsi_swapchain * drv_chain)1884 _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
1885 {
1886    struct wsi_display_swapchain *chain =
1887       (struct wsi_display_swapchain *) drv_chain;
1888    struct wsi_display *wsi = chain->wsi;
1889    VkIcdSurfaceDisplay *surface = chain->surface;
1890    wsi_display_mode *display_mode =
1891       wsi_display_mode_from_handle(surface->displayMode);
1892    wsi_display_connector *connector = display_mode->connector;
1893 
1894    if (wsi->fd < 0) {
1895       wsi_display_surface_error(chain, VK_ERROR_SURFACE_LOST_KHR);
1896       return VK_ERROR_SURFACE_LOST_KHR;
1897    }
1898 
1899    if (display_mode != connector->current_mode)
1900       connector->active = false;
1901 
1902    for (;;) {
1903 
1904       /* Check to see if there is an image to display, or if some image is
1905        * already queued */
1906 
1907       struct wsi_display_image *image = NULL;
1908 
1909       for (uint32_t i = 0; i < chain->base.image_count; i++) {
1910          struct wsi_display_image *tmp_image = &chain->images[i];
1911 
1912          switch (tmp_image->state) {
1913          case WSI_IMAGE_FLIPPING:
1914             /* already flipping, don't send another to the kernel yet */
1915             return VK_SUCCESS;
1916          case WSI_IMAGE_QUEUED:
1917             /* find the oldest queued */
1918             if (!image || tmp_image->flip_sequence < image->flip_sequence)
1919                image = tmp_image;
1920             break;
1921          default:
1922             break;
1923          }
1924       }
1925 
1926       if (!image)
1927          return VK_SUCCESS;
1928 
1929       int ret;
1930       if (connector->active) {
1931          ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
1932                                    DRM_MODE_PAGE_FLIP_EVENT, image);
1933          if (ret == 0) {
1934             image->state = WSI_IMAGE_FLIPPING;
1935             return VK_SUCCESS;
1936          }
1937          wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
1938       } else {
1939          ret = -EINVAL;
1940       }
1941 
1942       if (ret == -EINVAL) {
1943          VkResult result = wsi_display_setup_connector(connector, display_mode);
1944 
1945          if (result != VK_SUCCESS) {
1946             image->state = WSI_IMAGE_IDLE;
1947             return result;
1948          }
1949 
1950          /* XXX allow setting of position */
1951          ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
1952                               image->fb_id, 0, 0,
1953                               &connector->id, 1,
1954                               &connector->current_drm_mode);
1955          if (ret == 0) {
1956             /* Disable the HW cursor as the app doesn't have a mechanism
1957              * to control it.
1958              * Refer to question 12 of the VK_KHR_display spec.
1959              */
1960             ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 );
1961             if (ret != 0) {
1962                wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret));
1963             }
1964 
1965             /* Assume that the mode set is synchronous and that any
1966              * previous image is now idle.
1967              */
1968             image->state = WSI_IMAGE_DISPLAYING;
1969             wsi_display_present_complete(chain, image);
1970             wsi_display_idle_old_displaying(image);
1971             connector->active = true;
1972             return VK_SUCCESS;
1973          }
1974       }
1975 
1976       if (ret != -EACCES) {
1977          connector->active = false;
1978          image->state = WSI_IMAGE_IDLE;
1979          wsi_display_surface_error(chain, VK_ERROR_SURFACE_LOST_KHR);
1980          return VK_ERROR_SURFACE_LOST_KHR;
1981       }
1982 
1983       /* Some other VT is currently active. Sit here waiting for
1984        * our VT to become active again by polling once a second
1985        */
1986       usleep(1000 * 1000);
1987       connector->active = false;
1988    }
1989 }
1990 
1991 static VkResult
wsi_display_queue_present(struct wsi_swapchain * drv_chain,uint32_t image_index,uint64_t present_id,const VkPresentRegionKHR * damage)1992 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
1993                           uint32_t image_index,
1994                           uint64_t present_id,
1995                           const VkPresentRegionKHR *damage)
1996 {
1997    struct wsi_display_swapchain *chain =
1998       (struct wsi_display_swapchain *) drv_chain;
1999    struct wsi_display *wsi = chain->wsi;
2000    struct wsi_display_image *image = &chain->images[image_index];
2001    VkResult result;
2002 
2003    /* Bail early if the swapchain is broken */
2004    if (chain->status != VK_SUCCESS)
2005       return chain->status;
2006 
2007    image->present_id = present_id;
2008 
2009    assert(image->state == WSI_IMAGE_DRAWING);
2010    wsi_display_debug("present %d\n", image_index);
2011 
2012    pthread_mutex_lock(&wsi->wait_mutex);
2013 
2014    /* Make sure that the page flip handler is processed in finite time if using present wait. */
2015    if (present_id)
2016       wsi_display_start_wait_thread(wsi);
2017 
2018    image->flip_sequence = ++chain->flip_sequence;
2019    image->state = WSI_IMAGE_QUEUED;
2020 
2021    result = _wsi_display_queue_next(drv_chain);
2022    if (result != VK_SUCCESS)
2023       chain->status = result;
2024 
2025    pthread_mutex_unlock(&wsi->wait_mutex);
2026 
2027    if (result != VK_SUCCESS)
2028       return result;
2029 
2030    return chain->status;
2031 }
2032 
2033 static VkResult
wsi_display_wait_for_present(struct wsi_swapchain * wsi_chain,uint64_t waitValue,uint64_t timeout)2034 wsi_display_wait_for_present(struct wsi_swapchain *wsi_chain,
2035                              uint64_t waitValue,
2036                              uint64_t timeout)
2037 {
2038    struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)wsi_chain;
2039    struct timespec abs_timespec;
2040    uint64_t abs_timeout = 0;
2041 
2042    if (timeout != 0)
2043       abs_timeout = os_time_get_absolute_timeout(timeout);
2044 
2045    /* Need to observe that the swapchain semaphore has been unsignalled,
2046     * as this is guaranteed when a present is complete. */
2047    VkResult result = wsi_swapchain_wait_for_present_semaphore(
2048       &chain->base, waitValue, timeout);
2049    if (result != VK_SUCCESS)
2050       return result;
2051 
2052    timespec_from_nsec(&abs_timespec, abs_timeout);
2053 
2054    pthread_mutex_lock(&chain->present_id_mutex);
2055    while (chain->present_id < waitValue) {
2056       int ret = pthread_cond_timedwait(&chain->present_id_cond,
2057                                        &chain->present_id_mutex,
2058                                        &abs_timespec);
2059       if (ret == ETIMEDOUT) {
2060          result = VK_TIMEOUT;
2061          break;
2062       }
2063       if (ret) {
2064          result = VK_ERROR_DEVICE_LOST;
2065          break;
2066       }
2067    }
2068 
2069    if (result == VK_SUCCESS && chain->present_id_error)
2070       result = chain->present_id_error;
2071    pthread_mutex_unlock(&chain->present_id_mutex);
2072    return result;
2073 }
2074 
2075 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)2076 wsi_display_surface_create_swapchain(
2077    VkIcdSurfaceBase *icd_surface,
2078    VkDevice device,
2079    struct wsi_device *wsi_device,
2080    const VkSwapchainCreateInfoKHR *create_info,
2081    const VkAllocationCallbacks *allocator,
2082    struct wsi_swapchain **swapchain_out)
2083 {
2084    struct wsi_display *wsi =
2085       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2086 
2087    assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
2088 
2089    const unsigned num_images = create_info->minImageCount;
2090    struct wsi_display_swapchain *chain =
2091       vk_zalloc(allocator,
2092                 sizeof(*chain) + num_images * sizeof(chain->images[0]),
2093                 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2094 
2095    if (chain == NULL)
2096       return VK_ERROR_OUT_OF_HOST_MEMORY;
2097 
2098    struct wsi_drm_image_params image_params = {
2099       .base.image_type = WSI_IMAGE_TYPE_DRM,
2100       .same_gpu = true,
2101    };
2102 
2103    int ret = pthread_mutex_init(&chain->present_id_mutex, NULL);
2104    if (ret != 0) {
2105       vk_free(allocator, chain);
2106       return VK_ERROR_OUT_OF_HOST_MEMORY;
2107    }
2108 
2109    bool bret = wsi_init_pthread_cond_monotonic(&chain->present_id_cond);
2110    if (!bret) {
2111       pthread_mutex_destroy(&chain->present_id_mutex);
2112       vk_free(allocator, chain);
2113       return VK_ERROR_OUT_OF_HOST_MEMORY;
2114    }
2115 
2116    VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
2117                                         create_info, &image_params.base,
2118                                         allocator);
2119    if (result != VK_SUCCESS) {
2120       pthread_cond_destroy(&chain->present_id_cond);
2121       pthread_mutex_destroy(&chain->present_id_mutex);
2122       vk_free(allocator, chain);
2123       return result;
2124    }
2125 
2126    chain->base.destroy = wsi_display_swapchain_destroy;
2127    chain->base.get_wsi_image = wsi_display_get_wsi_image;
2128    chain->base.acquire_next_image = wsi_display_acquire_next_image;
2129    chain->base.release_images = wsi_display_release_images;
2130    chain->base.queue_present = wsi_display_queue_present;
2131    chain->base.wait_for_present = wsi_display_wait_for_present;
2132    chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
2133    chain->base.image_count = num_images;
2134 
2135    chain->wsi = wsi;
2136    chain->status = VK_SUCCESS;
2137 
2138    chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
2139 
2140    for (uint32_t image = 0; image < chain->base.image_count; image++) {
2141       result = wsi_display_image_init(&chain->base,
2142                                       create_info,
2143                                       &chain->images[image]);
2144       if (result != VK_SUCCESS) {
2145          while (image > 0) {
2146             --image;
2147             wsi_display_image_finish(&chain->base,
2148                                      &chain->images[image]);
2149          }
2150          pthread_cond_destroy(&chain->present_id_cond);
2151          pthread_mutex_destroy(&chain->present_id_mutex);
2152          wsi_swapchain_finish(&chain->base);
2153          vk_free(allocator, chain);
2154          goto fail_init_images;
2155       }
2156    }
2157 
2158    *swapchain_out = &chain->base;
2159 
2160    return VK_SUCCESS;
2161 
2162 fail_init_images:
2163    return result;
2164 }
2165 
2166 /*
2167  * Local version fo the libdrm helper. Added to avoid depending on bleeding
2168  * edge version of the library.
2169  */
2170 static int
local_drmIsMaster(int fd)2171 local_drmIsMaster(int fd)
2172 {
2173    /* Detect master by attempting something that requires master.
2174     *
2175     * Authenticating magic tokens requires master and 0 is an
2176     * internal kernel detail which we could use. Attempting this on
2177     * a master fd would fail therefore fail with EINVAL because 0
2178     * is invalid.
2179     *
2180     * A non-master fd will fail with EACCES, as the kernel checks
2181     * for master before attempting to do anything else.
2182     *
2183     * Since we don't want to leak implementation details, use
2184     * EACCES.
2185     */
2186    return drmAuthMagic(fd, 0) != -EACCES;
2187 }
2188 
2189 #ifdef HAVE_LIBUDEV
2190 static void *
udev_event_listener_thread(void * data)2191 udev_event_listener_thread(void *data)
2192 {
2193    struct wsi_device *wsi_device = data;
2194    struct wsi_display *wsi =
2195       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2196 
2197    struct udev *u = udev_new();
2198    if (!u)
2199       goto fail;
2200 
2201    struct udev_monitor *mon =
2202       udev_monitor_new_from_netlink(u, "udev");
2203    if (!mon)
2204       goto fail_udev;
2205 
2206    int ret =
2207       udev_monitor_filter_add_match_subsystem_devtype(mon, "drm", "drm_minor");
2208    if (ret < 0)
2209       goto fail_udev_monitor;
2210 
2211    ret = udev_monitor_enable_receiving(mon);
2212    if (ret < 0)
2213       goto fail_udev_monitor;
2214 
2215    int udev_fd = udev_monitor_get_fd(mon);
2216 
2217    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
2218 
2219    for (;;) {
2220       nfds_t nfds = 1;
2221       struct pollfd fds[1] =  {
2222          {
2223             .fd = udev_fd,
2224             .events = POLLIN,
2225          },
2226       };
2227 
2228       int ret = poll(fds, nfds, -1);
2229       if (ret > 0) {
2230          if (fds[0].revents & POLLIN) {
2231             struct udev_device *dev = udev_monitor_receive_device(mon);
2232 
2233             /* Ignore event if it is not a hotplug event */
2234             if (!atoi(udev_device_get_property_value(dev, "HOTPLUG")))
2235                continue;
2236 
2237             /* Note, this supports both drmSyncobjWait for fence->syncobj
2238              * and wsi_display_wait_for_event.
2239              */
2240             pthread_mutex_lock(&wsi->wait_mutex);
2241             pthread_cond_broadcast(&wsi->hotplug_cond);
2242             list_for_each_entry(struct wsi_display_fence, fence,
2243                                 &wsi_device->hotplug_fences, link) {
2244                if (fence->syncobj)
2245                   drmSyncobjSignal(wsi->syncobj_fd, &fence->syncobj, 1);
2246                fence->event_received = true;
2247             }
2248             pthread_mutex_unlock(&wsi->wait_mutex);
2249             udev_device_unref(dev);
2250          }
2251       } else if (ret < 0) {
2252          goto fail;
2253       }
2254    }
2255 
2256    udev_monitor_unref(mon);
2257    udev_unref(u);
2258 
2259    return 0;
2260 
2261 fail_udev_monitor:
2262    udev_monitor_unref(mon);
2263 fail_udev:
2264    udev_unref(u);
2265 fail:
2266    wsi_display_debug("critical hotplug thread error\n");
2267    return 0;
2268 }
2269 #endif
2270 
2271 VkResult
wsi_display_init_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc,int display_fd)2272 wsi_display_init_wsi(struct wsi_device *wsi_device,
2273                      const VkAllocationCallbacks *alloc,
2274                      int display_fd)
2275 {
2276    struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
2277                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2278    VkResult result;
2279 
2280    if (!wsi) {
2281       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2282       goto fail;
2283    }
2284 
2285    wsi->fd = display_fd;
2286    if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
2287       wsi->fd = -1;
2288 
2289    wsi->syncobj_fd = wsi->fd;
2290 
2291    wsi->alloc = alloc;
2292 
2293    list_inithead(&wsi->connectors);
2294 
2295    int ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
2296    if (ret) {
2297       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2298       goto fail_mutex;
2299    }
2300 
2301    if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) {
2302       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2303       goto fail_cond;
2304    }
2305 
2306    if (!wsi_init_pthread_cond_monotonic(&wsi->hotplug_cond)) {
2307       result = VK_ERROR_OUT_OF_HOST_MEMORY;
2308       goto fail_hotplug_cond;
2309    }
2310 
2311    wsi->base.get_support = wsi_display_surface_get_support;
2312    wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
2313    wsi->base.get_formats = wsi_display_surface_get_formats;
2314    wsi->base.get_formats2 = wsi_display_surface_get_formats2;
2315    wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
2316    wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
2317    wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
2318 
2319    wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
2320 
2321    return VK_SUCCESS;
2322 
2323 fail_hotplug_cond:
2324    pthread_cond_destroy(&wsi->wait_cond);
2325 fail_cond:
2326    pthread_mutex_destroy(&wsi->wait_mutex);
2327 fail_mutex:
2328    vk_free(alloc, wsi);
2329 fail:
2330    return result;
2331 }
2332 
2333 void
wsi_display_finish_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc)2334 wsi_display_finish_wsi(struct wsi_device *wsi_device,
2335                        const VkAllocationCallbacks *alloc)
2336 {
2337    struct wsi_display *wsi =
2338       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2339 
2340    if (wsi) {
2341       wsi_for_each_connector(connector, wsi) {
2342          wsi_for_each_display_mode(mode, connector) {
2343             vk_free(wsi->alloc, mode);
2344          }
2345          vk_free(wsi->alloc, connector);
2346       }
2347 
2348       wsi_display_stop_wait_thread(wsi);
2349 
2350       if (wsi->hotplug_thread) {
2351          pthread_cancel(wsi->hotplug_thread);
2352          pthread_join(wsi->hotplug_thread, NULL);
2353       }
2354 
2355       pthread_mutex_destroy(&wsi->wait_mutex);
2356       pthread_cond_destroy(&wsi->wait_cond);
2357       pthread_cond_destroy(&wsi->hotplug_cond);
2358 
2359       vk_free(alloc, wsi);
2360    }
2361 }
2362 
2363 /*
2364  * Implement vkReleaseDisplay
2365  */
2366 VKAPI_ATTR VkResult VKAPI_CALL
wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice,VkDisplayKHR display)2367 wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice,
2368                       VkDisplayKHR display)
2369 {
2370    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2371    struct wsi_device *wsi_device = pdevice->wsi_device;
2372    struct wsi_display *wsi =
2373       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2374 
2375    if (wsi->fd >= 0) {
2376       wsi_display_stop_wait_thread(wsi);
2377 
2378       close(wsi->fd);
2379       wsi->fd = -1;
2380    }
2381 
2382    wsi_display_connector_from_handle(display)->active = false;
2383 
2384 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2385    wsi_display_connector_from_handle(display)->output = None;
2386 #endif
2387 
2388    return VK_SUCCESS;
2389 }
2390 
2391 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
2392 
2393 static struct wsi_display_connector *
wsi_display_find_output(struct wsi_device * wsi_device,xcb_randr_output_t output)2394 wsi_display_find_output(struct wsi_device *wsi_device,
2395                         xcb_randr_output_t output)
2396 {
2397    struct wsi_display *wsi =
2398       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2399 
2400    wsi_for_each_connector(connector, wsi) {
2401       if (connector->output == output)
2402          return connector;
2403    }
2404 
2405    return NULL;
2406 }
2407 
2408 /*
2409  * Given a RandR output, find the associated kernel connector_id by
2410  * looking at the CONNECTOR_ID property provided by the X server
2411  */
2412 
2413 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)2414 wsi_display_output_to_connector_id(xcb_connection_t *connection,
2415                                    xcb_atom_t *connector_id_atom_p,
2416                                    xcb_randr_output_t output)
2417 {
2418    uint32_t connector_id = 0;
2419    xcb_atom_t connector_id_atom = *connector_id_atom_p;
2420 
2421    if (connector_id_atom == 0) {
2422    /* Go dig out the CONNECTOR_ID property */
2423       xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
2424                                                           true,
2425                                                           12,
2426                                                           "CONNECTOR_ID");
2427       xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
2428                                                                  ia_c,
2429                                                                  NULL);
2430       if (ia_r) {
2431          *connector_id_atom_p = connector_id_atom = ia_r->atom;
2432          free(ia_r);
2433       }
2434    }
2435 
2436    /* If there's an CONNECTOR_ID atom in the server, then there may be a
2437     * CONNECTOR_ID property. Otherwise, there will not be and we don't even
2438     * need to bother.
2439     */
2440    if (connector_id_atom) {
2441 
2442       xcb_randr_query_version_cookie_t qv_c =
2443          xcb_randr_query_version(connection, 1, 6);
2444       xcb_randr_get_output_property_cookie_t gop_c =
2445          xcb_randr_get_output_property(connection,
2446                                        output,
2447                                        connector_id_atom,
2448                                        0,
2449                                        0,
2450                                        0xffffffffUL,
2451                                        0,
2452                                        0);
2453       xcb_randr_query_version_reply_t *qv_r =
2454          xcb_randr_query_version_reply(connection, qv_c, NULL);
2455       free(qv_r);
2456       xcb_randr_get_output_property_reply_t *gop_r =
2457          xcb_randr_get_output_property_reply(connection, gop_c, NULL);
2458       if (gop_r) {
2459          if (gop_r->num_items == 1 && gop_r->format == 32)
2460             memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
2461          free(gop_r);
2462       }
2463    }
2464    return connector_id;
2465 }
2466 
2467 static bool
wsi_display_check_randr_version(xcb_connection_t * connection)2468 wsi_display_check_randr_version(xcb_connection_t *connection)
2469 {
2470    xcb_randr_query_version_cookie_t qv_c =
2471       xcb_randr_query_version(connection, 1, 6);
2472    xcb_randr_query_version_reply_t *qv_r =
2473       xcb_randr_query_version_reply(connection, qv_c, NULL);
2474    bool ret = false;
2475 
2476    if (!qv_r)
2477       return false;
2478 
2479    /* Check for version 1.6 or newer */
2480    ret = (qv_r->major_version > 1 ||
2481           (qv_r->major_version == 1 && qv_r->minor_version >= 6));
2482 
2483    free(qv_r);
2484    return ret;
2485 }
2486 
2487 /*
2488  * Given a kernel connector id, find the associated RandR output using the
2489  * CONNECTOR_ID property
2490  */
2491 
2492 static xcb_randr_output_t
wsi_display_connector_id_to_output(xcb_connection_t * connection,uint32_t connector_id)2493 wsi_display_connector_id_to_output(xcb_connection_t *connection,
2494                                    uint32_t connector_id)
2495 {
2496    if (!wsi_display_check_randr_version(connection))
2497       return 0;
2498 
2499    const xcb_setup_t *setup = xcb_get_setup(connection);
2500 
2501    xcb_atom_t connector_id_atom = 0;
2502    xcb_randr_output_t output = 0;
2503 
2504    /* Search all of the screens for the provided output */
2505    xcb_screen_iterator_t iter;
2506    for (iter = xcb_setup_roots_iterator(setup);
2507         output == 0 && iter.rem;
2508         xcb_screen_next(&iter))
2509    {
2510       xcb_randr_get_screen_resources_cookie_t gsr_c =
2511          xcb_randr_get_screen_resources(connection, iter.data->root);
2512       xcb_randr_get_screen_resources_reply_t *gsr_r =
2513          xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2514 
2515       if (!gsr_r)
2516          return 0;
2517 
2518       xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2519       int o;
2520 
2521       for (o = 0; o < gsr_r->num_outputs; o++) {
2522          if (wsi_display_output_to_connector_id(connection,
2523                                                 &connector_id_atom, ro[o])
2524              == connector_id)
2525          {
2526             output = ro[o];
2527             break;
2528          }
2529       }
2530       free(gsr_r);
2531    }
2532    return output;
2533 }
2534 
2535 /*
2536  * Given a RandR output, find out which screen it's associated with
2537  */
2538 static xcb_window_t
wsi_display_output_to_root(xcb_connection_t * connection,xcb_randr_output_t output)2539 wsi_display_output_to_root(xcb_connection_t *connection,
2540                            xcb_randr_output_t output)
2541 {
2542    if (!wsi_display_check_randr_version(connection))
2543       return 0;
2544 
2545    const xcb_setup_t *setup = xcb_get_setup(connection);
2546    xcb_window_t root = 0;
2547 
2548    /* Search all of the screens for the provided output */
2549    for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
2550         root == 0 && iter.rem;
2551         xcb_screen_next(&iter))
2552    {
2553       xcb_randr_get_screen_resources_cookie_t gsr_c =
2554          xcb_randr_get_screen_resources(connection, iter.data->root);
2555       xcb_randr_get_screen_resources_reply_t *gsr_r =
2556          xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2557 
2558       if (!gsr_r)
2559          return 0;
2560 
2561       xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2562 
2563       for (int o = 0; o < gsr_r->num_outputs; o++) {
2564          if (ro[o] == output) {
2565             root = iter.data->root;
2566             break;
2567          }
2568       }
2569       free(gsr_r);
2570    }
2571    return root;
2572 }
2573 
2574 static bool
wsi_display_mode_matches_x(struct wsi_display_mode * wsi,xcb_randr_mode_info_t * xcb)2575 wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
2576                            xcb_randr_mode_info_t *xcb)
2577 {
2578    return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
2579       wsi->hdisplay == xcb->width &&
2580       wsi->hsync_start == xcb->hsync_start &&
2581       wsi->hsync_end == xcb->hsync_end &&
2582       wsi->htotal == xcb->htotal &&
2583       wsi->hskew == xcb->hskew &&
2584       wsi->vdisplay == xcb->height &&
2585       wsi->vsync_start == xcb->vsync_start &&
2586       wsi->vsync_end == xcb->vsync_end &&
2587       wsi->vtotal == xcb->vtotal &&
2588       wsi->vscan <= 1 &&
2589       wsi->flags == xcb->mode_flags;
2590 }
2591 
2592 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)2593 wsi_display_find_x_mode(struct wsi_device *wsi_device,
2594                         struct wsi_display_connector *connector,
2595                         xcb_randr_mode_info_t *mode)
2596 {
2597    wsi_for_each_display_mode(display_mode, connector) {
2598       if (wsi_display_mode_matches_x(display_mode, mode))
2599          return display_mode;
2600    }
2601    return NULL;
2602 }
2603 
2604 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)2605 wsi_display_register_x_mode(struct wsi_device *wsi_device,
2606                             struct wsi_display_connector *connector,
2607                             xcb_randr_mode_info_t *x_mode,
2608                             bool preferred)
2609 {
2610    struct wsi_display *wsi =
2611       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2612    struct wsi_display_mode *display_mode =
2613       wsi_display_find_x_mode(wsi_device, connector, x_mode);
2614 
2615    if (display_mode) {
2616       display_mode->valid = true;
2617       return VK_SUCCESS;
2618    }
2619 
2620    display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
2621                             8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2622    if (!display_mode)
2623       return VK_ERROR_OUT_OF_HOST_MEMORY;
2624 
2625    display_mode->connector = connector;
2626    display_mode->valid = true;
2627    display_mode->preferred = preferred;
2628    display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
2629    display_mode->hdisplay = x_mode->width;
2630    display_mode->hsync_start = x_mode->hsync_start;
2631    display_mode->hsync_end = x_mode->hsync_end;
2632    display_mode->htotal = x_mode->htotal;
2633    display_mode->hskew = x_mode->hskew;
2634    display_mode->vdisplay = x_mode->height;
2635    display_mode->vsync_start = x_mode->vsync_start;
2636    display_mode->vsync_end = x_mode->vsync_end;
2637    display_mode->vtotal = x_mode->vtotal;
2638    display_mode->vscan = 0;
2639    display_mode->flags = x_mode->mode_flags;
2640 
2641    list_addtail(&display_mode->list, &connector->display_modes);
2642    return VK_SUCCESS;
2643 }
2644 
2645 static struct wsi_display_connector *
wsi_display_get_output(struct wsi_device * wsi_device,xcb_connection_t * connection,xcb_randr_output_t output)2646 wsi_display_get_output(struct wsi_device *wsi_device,
2647                        xcb_connection_t *connection,
2648                        xcb_randr_output_t output)
2649 {
2650    struct wsi_display *wsi =
2651       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2652    struct wsi_display_connector *connector;
2653    uint32_t connector_id;
2654 
2655    xcb_window_t root = wsi_display_output_to_root(connection, output);
2656    if (!root)
2657       return NULL;
2658 
2659    /* See if we already have a connector for this output */
2660    connector = wsi_display_find_output(wsi_device, output);
2661 
2662    if (!connector) {
2663       xcb_atom_t connector_id_atom = 0;
2664 
2665       /*
2666        * Go get the kernel connector ID for this X output
2667        */
2668       connector_id = wsi_display_output_to_connector_id(connection,
2669                                                         &connector_id_atom,
2670                                                         output);
2671 
2672       /* Any X server with lease support will have this atom */
2673       if (!connector_id) {
2674          return NULL;
2675       }
2676 
2677       /* See if we already have a connector for this id */
2678       connector = wsi_display_find_connector(wsi_device, connector_id);
2679 
2680       if (connector == NULL) {
2681          connector = wsi_display_alloc_connector(wsi, connector_id);
2682          if (!connector) {
2683             return NULL;
2684          }
2685          list_addtail(&connector->list, &wsi->connectors);
2686       }
2687       connector->output = output;
2688    }
2689 
2690    xcb_randr_get_screen_resources_cookie_t src =
2691       xcb_randr_get_screen_resources(connection, root);
2692    xcb_randr_get_output_info_cookie_t oic =
2693       xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
2694    xcb_randr_get_screen_resources_reply_t *srr =
2695       xcb_randr_get_screen_resources_reply(connection, src, NULL);
2696    xcb_randr_get_output_info_reply_t *oir =
2697       xcb_randr_get_output_info_reply(connection, oic, NULL);
2698 
2699    if (oir && srr) {
2700       /* Get X modes and add them */
2701 
2702       connector->connected =
2703          oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
2704 
2705       wsi_display_invalidate_connector_modes(connector);
2706 
2707       xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
2708       for (int m = 0; m < oir->num_modes; m++) {
2709          xcb_randr_mode_info_iterator_t i =
2710             xcb_randr_get_screen_resources_modes_iterator(srr);
2711          while (i.rem) {
2712             xcb_randr_mode_info_t *mi = i.data;
2713             if (mi->id == x_modes[m]) {
2714                VkResult result = wsi_display_register_x_mode(
2715                   wsi_device, connector, mi, m < oir->num_preferred);
2716                if (result != VK_SUCCESS) {
2717                   free(oir);
2718                   free(srr);
2719                   return NULL;
2720                }
2721                break;
2722             }
2723             xcb_randr_mode_info_next(&i);
2724          }
2725       }
2726    }
2727 
2728    free(oir);
2729    free(srr);
2730    return connector;
2731 }
2732 
2733 static xcb_randr_crtc_t
wsi_display_find_crtc_for_output(xcb_connection_t * connection,xcb_window_t root,xcb_randr_output_t output)2734 wsi_display_find_crtc_for_output(xcb_connection_t *connection,
2735                                  xcb_window_t root,
2736                                  xcb_randr_output_t output)
2737 {
2738    xcb_randr_get_screen_resources_cookie_t gsr_c =
2739       xcb_randr_get_screen_resources(connection, root);
2740    xcb_randr_get_screen_resources_reply_t *gsr_r =
2741       xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2742 
2743    if (!gsr_r)
2744       return 0;
2745 
2746    xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
2747    xcb_randr_crtc_t idle_crtc = 0;
2748    xcb_randr_crtc_t active_crtc = 0;
2749 
2750    /* Find either a crtc already connected to the desired output or idle */
2751    for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
2752       xcb_randr_get_crtc_info_cookie_t gci_c =
2753          xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
2754       xcb_randr_get_crtc_info_reply_t *gci_r =
2755          xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
2756 
2757       if (gci_r) {
2758          if (gci_r->mode) {
2759             int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
2760             xcb_randr_output_t *outputs =
2761                xcb_randr_get_crtc_info_outputs(gci_r);
2762 
2763             if (num_outputs == 1 && outputs[0] == output)
2764                active_crtc = rc[c];
2765 
2766          } else if (idle_crtc == 0) {
2767             int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
2768             xcb_randr_output_t *possible =
2769                xcb_randr_get_crtc_info_possible(gci_r);
2770 
2771             for (int p = 0; p < num_possible; p++)
2772                if (possible[p] == output) {
2773                   idle_crtc = rc[c];
2774                   break;
2775                }
2776          }
2777          free(gci_r);
2778       }
2779    }
2780    free(gsr_r);
2781 
2782    if (active_crtc)
2783       return active_crtc;
2784    return idle_crtc;
2785 }
2786 
2787 VKAPI_ATTR VkResult VKAPI_CALL
wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice,Display * dpy,VkDisplayKHR display)2788 wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice,
2789                           Display *dpy,
2790                           VkDisplayKHR display)
2791 {
2792    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2793    struct wsi_device *wsi_device = pdevice->wsi_device;
2794    struct wsi_display *wsi =
2795       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2796    xcb_connection_t *connection = XGetXCBConnection(dpy);
2797    struct wsi_display_connector *connector =
2798       wsi_display_connector_from_handle(display);
2799    xcb_window_t root;
2800 
2801    /* XXX no support for multiple leases yet */
2802    if (wsi->fd >= 0)
2803       return VK_ERROR_INITIALIZATION_FAILED;
2804 
2805    if (!connector->output) {
2806       connector->output = wsi_display_connector_id_to_output(connection,
2807                                                              connector->id);
2808 
2809       /* Check and see if we found the output */
2810       if (!connector->output)
2811          return VK_ERROR_INITIALIZATION_FAILED;
2812    }
2813 
2814    root = wsi_display_output_to_root(connection, connector->output);
2815    if (!root)
2816       return VK_ERROR_INITIALIZATION_FAILED;
2817 
2818    xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
2819                                                             root,
2820                                                             connector->output);
2821 
2822    if (!crtc)
2823       return VK_ERROR_INITIALIZATION_FAILED;
2824 
2825 #ifdef HAVE_DRI3_MODIFIERS
2826    xcb_randr_lease_t lease = xcb_generate_id(connection);
2827    xcb_randr_create_lease_cookie_t cl_c =
2828       xcb_randr_create_lease(connection, root, lease, 1, 1,
2829                              &crtc, &connector->output);
2830    xcb_randr_create_lease_reply_t *cl_r =
2831       xcb_randr_create_lease_reply(connection, cl_c, NULL);
2832    if (!cl_r)
2833       return VK_ERROR_INITIALIZATION_FAILED;
2834 
2835    int fd = -1;
2836    if (cl_r->nfd > 0) {
2837       int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
2838 
2839       fd = rcl_f[0];
2840    }
2841    free (cl_r);
2842    if (fd < 0)
2843       return VK_ERROR_INITIALIZATION_FAILED;
2844 
2845    wsi->fd = fd;
2846 #endif
2847 
2848    return VK_SUCCESS;
2849 }
2850 
2851 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice,Display * dpy,RROutput rrOutput,VkDisplayKHR * pDisplay)2852 wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice,
2853                              Display *dpy,
2854                              RROutput rrOutput,
2855                              VkDisplayKHR *pDisplay)
2856 {
2857    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
2858    struct wsi_device *wsi_device = pdevice->wsi_device;
2859    xcb_connection_t *connection = XGetXCBConnection(dpy);
2860    struct wsi_display_connector *connector =
2861       wsi_display_get_output(wsi_device, connection,
2862                              (xcb_randr_output_t) rrOutput);
2863 
2864    if (connector)
2865       *pDisplay = wsi_display_connector_to_handle(connector);
2866    else
2867       *pDisplay = VK_NULL_HANDLE;
2868    return VK_SUCCESS;
2869 }
2870 
2871 #endif
2872 
2873 /* VK_EXT_display_control */
2874 VKAPI_ATTR VkResult VKAPI_CALL
wsi_DisplayPowerControlEXT(VkDevice _device,VkDisplayKHR display,const VkDisplayPowerInfoEXT * pDisplayPowerInfo)2875 wsi_DisplayPowerControlEXT(VkDevice _device,
2876                            VkDisplayKHR display,
2877                            const VkDisplayPowerInfoEXT *pDisplayPowerInfo)
2878 {
2879    VK_FROM_HANDLE(vk_device, device, _device);
2880    struct wsi_device *wsi_device = device->physical->wsi_device;
2881    struct wsi_display *wsi =
2882       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2883    struct wsi_display_connector *connector =
2884       wsi_display_connector_from_handle(display);
2885    int mode;
2886 
2887    if (wsi->fd < 0)
2888       return VK_ERROR_INITIALIZATION_FAILED;
2889 
2890    switch (pDisplayPowerInfo->powerState) {
2891    case VK_DISPLAY_POWER_STATE_OFF_EXT:
2892       mode = DRM_MODE_DPMS_OFF;
2893       break;
2894    case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
2895       mode = DRM_MODE_DPMS_SUSPEND;
2896       break;
2897    default:
2898       mode = DRM_MODE_DPMS_ON;
2899       break;
2900    }
2901    drmModeConnectorSetProperty(wsi->fd,
2902                                connector->id,
2903                                connector->dpms_property,
2904                                mode);
2905    return VK_SUCCESS;
2906 }
2907 
2908 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)2909 wsi_register_device_event(VkDevice _device,
2910                           struct wsi_device *wsi_device,
2911                           const VkDeviceEventInfoEXT *device_event_info,
2912                           const VkAllocationCallbacks *allocator,
2913                           struct vk_sync **sync_out,
2914                           int sync_fd)
2915 {
2916    VK_FROM_HANDLE(vk_device, device, _device);
2917    struct wsi_display *wsi =
2918       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2919    VkResult ret = VK_SUCCESS;
2920 
2921 #ifdef HAVE_LIBUDEV
2922    /* Start listening for output change notifications. */
2923    pthread_mutex_lock(&wsi->wait_mutex);
2924    if (!wsi->hotplug_thread) {
2925       if (pthread_create(&wsi->hotplug_thread, NULL, udev_event_listener_thread,
2926                          wsi_device)) {
2927          pthread_mutex_unlock(&wsi->wait_mutex);
2928          return VK_ERROR_OUT_OF_HOST_MEMORY;
2929       }
2930    }
2931    pthread_mutex_unlock(&wsi->wait_mutex);
2932 #endif
2933 
2934    struct wsi_display_fence *fence;
2935    assert(device_event_info->deviceEvent ==
2936           VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT);
2937 
2938    fence = wsi_display_fence_alloc(wsi, sync_fd);
2939 
2940    if (!fence)
2941       return VK_ERROR_OUT_OF_HOST_MEMORY;
2942 
2943    fence->device_event = true;
2944 
2945    pthread_mutex_lock(&wsi->wait_mutex);
2946    list_addtail(&fence->link, &wsi_device->hotplug_fences);
2947    pthread_mutex_unlock(&wsi->wait_mutex);
2948 
2949    if (sync_out) {
2950       ret = wsi_display_sync_create(device, fence, sync_out);
2951       if (ret != VK_SUCCESS)
2952          wsi_display_fence_destroy(fence);
2953    } else {
2954       wsi_display_fence_destroy(fence);
2955    }
2956 
2957    return ret;
2958 }
2959 
2960 VKAPI_ATTR VkResult VKAPI_CALL
wsi_RegisterDeviceEventEXT(VkDevice _device,const VkDeviceEventInfoEXT * device_event_info,const VkAllocationCallbacks * allocator,VkFence * _fence)2961 wsi_RegisterDeviceEventEXT(VkDevice _device, const VkDeviceEventInfoEXT *device_event_info,
2962                             const VkAllocationCallbacks *allocator, VkFence *_fence)
2963 {
2964    VK_FROM_HANDLE(vk_device, device, _device);
2965    struct vk_fence *fence;
2966    VkResult ret;
2967 
2968    const VkFenceCreateInfo info = {
2969       .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
2970       .flags = 0,
2971    };
2972    ret = vk_fence_create(device, &info, allocator, &fence);
2973    if (ret != VK_SUCCESS)
2974       return ret;
2975 
2976    ret = wsi_register_device_event(_device,
2977                                    device->physical->wsi_device,
2978                                    device_event_info,
2979                                    allocator,
2980                                    &fence->temporary,
2981                                    -1);
2982    if (ret == VK_SUCCESS)
2983       *_fence = vk_fence_to_handle(fence);
2984    else
2985       vk_fence_destroy(device, fence, allocator);
2986    return ret;
2987 }
2988 
2989 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)2990 wsi_register_display_event(VkDevice _device,
2991                            struct wsi_device *wsi_device,
2992                            VkDisplayKHR display,
2993                            const VkDisplayEventInfoEXT *display_event_info,
2994                            const VkAllocationCallbacks *allocator,
2995                            struct vk_sync **sync_out,
2996                            int sync_fd)
2997 {
2998    VK_FROM_HANDLE(vk_device, device, _device);
2999    struct wsi_display *wsi =
3000       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3001    struct wsi_display_fence *fence;
3002    VkResult ret;
3003 
3004    switch (display_event_info->displayEvent) {
3005    case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
3006 
3007       fence = wsi_display_fence_alloc(wsi, sync_fd);
3008 
3009       if (!fence)
3010          return VK_ERROR_OUT_OF_HOST_MEMORY;
3011 
3012       ret = wsi_register_vblank_event(fence, wsi_device, display,
3013                                       DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
3014 
3015       if (ret == VK_SUCCESS) {
3016          if (sync_out) {
3017             ret = wsi_display_sync_create(device, fence, sync_out);
3018             if (ret != VK_SUCCESS)
3019                wsi_display_fence_destroy(fence);
3020          } else {
3021             wsi_display_fence_destroy(fence);
3022          }
3023       } else if (fence != NULL) {
3024          if (fence->syncobj)
3025             drmSyncobjDestroy(wsi->syncobj_fd, fence->syncobj);
3026          vk_free2(wsi->alloc, allocator, fence);
3027       }
3028 
3029       break;
3030    default:
3031       ret = VK_ERROR_FEATURE_NOT_PRESENT;
3032       break;
3033    }
3034 
3035    return ret;
3036 }
3037 
3038 VKAPI_ATTR VkResult VKAPI_CALL
wsi_RegisterDisplayEventEXT(VkDevice _device,VkDisplayKHR display,const VkDisplayEventInfoEXT * display_event_info,const VkAllocationCallbacks * allocator,VkFence * _fence)3039 wsi_RegisterDisplayEventEXT(VkDevice _device, VkDisplayKHR display,
3040                              const VkDisplayEventInfoEXT *display_event_info,
3041                              const VkAllocationCallbacks *allocator, VkFence *_fence)
3042 {
3043    VK_FROM_HANDLE(vk_device, device, _device);
3044    struct vk_fence *fence;
3045    VkResult ret;
3046 
3047    const VkFenceCreateInfo info = {
3048       .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
3049       .flags = 0,
3050    };
3051    ret = vk_fence_create(device, &info, allocator, &fence);
3052    if (ret != VK_SUCCESS)
3053       return ret;
3054 
3055    ret = wsi_register_display_event(
3056       _device, device->physical->wsi_device,
3057       display, display_event_info, allocator, &fence->temporary, -1);
3058 
3059    if (ret == VK_SUCCESS)
3060       *_fence = vk_fence_to_handle(fence);
3061    else
3062       vk_fence_destroy(device, fence, allocator);
3063    return ret;
3064 }
3065 
3066 void
wsi_display_setup_syncobj_fd(struct wsi_device * wsi_device,int fd)3067 wsi_display_setup_syncobj_fd(struct wsi_device *wsi_device,
3068                              int fd)
3069 {
3070    struct wsi_display *wsi =
3071       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3072    wsi->syncobj_fd = fd;
3073 }
3074 
3075 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetSwapchainCounterEXT(VkDevice _device,VkSwapchainKHR _swapchain,VkSurfaceCounterFlagBitsEXT counter,uint64_t * pCounterValue)3076 wsi_GetSwapchainCounterEXT(VkDevice _device,
3077                            VkSwapchainKHR _swapchain,
3078                            VkSurfaceCounterFlagBitsEXT counter,
3079                            uint64_t *pCounterValue)
3080 {
3081    VK_FROM_HANDLE(vk_device, device, _device);
3082    struct wsi_device *wsi_device = device->physical->wsi_device;
3083    struct wsi_display *wsi =
3084       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3085    struct wsi_display_swapchain *swapchain =
3086       (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
3087    struct wsi_display_connector *connector =
3088       wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
3089 
3090    if (wsi->fd < 0)
3091       return VK_ERROR_INITIALIZATION_FAILED;
3092 
3093    if (!connector->active) {
3094       *pCounterValue = 0;
3095       return VK_SUCCESS;
3096    }
3097 
3098    int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id,
3099                                 pCounterValue, NULL);
3100    if (ret)
3101       *pCounterValue = 0;
3102 
3103    return VK_SUCCESS;
3104 }
3105 
3106 VKAPI_ATTR VkResult VKAPI_CALL
wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice,int32_t drmFd,VkDisplayKHR display)3107 wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice,
3108                          int32_t drmFd,
3109                          VkDisplayKHR display)
3110 {
3111    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
3112    struct wsi_device *wsi_device = pdevice->wsi_device;
3113 
3114    if (!wsi_device_matches_drm_fd(wsi_device, drmFd))
3115       return VK_ERROR_UNKNOWN;
3116 
3117    struct wsi_display *wsi =
3118       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
3119 
3120    /* XXX no support for mulitple leases yet */
3121    if (wsi->fd >= 0 || !local_drmIsMaster(drmFd))
3122       return VK_ERROR_INITIALIZATION_FAILED;
3123 
3124    struct wsi_display_connector *connector =
3125          wsi_display_connector_from_handle(display);
3126 
3127    drmModeConnectorPtr drm_connector =
3128          drmModeGetConnectorCurrent(drmFd, connector->id);
3129 
3130    if (!drm_connector)
3131       return VK_ERROR_INITIALIZATION_FAILED;
3132 
3133    drmModeFreeConnector(drm_connector);
3134 
3135    wsi->fd = drmFd;
3136    return VK_SUCCESS;
3137 }
3138 
3139 VKAPI_ATTR VkResult VKAPI_CALL
wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice,int32_t drmFd,uint32_t connectorId,VkDisplayKHR * pDisplay)3140 wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice,
3141                      int32_t drmFd,
3142                      uint32_t connectorId,
3143                      VkDisplayKHR *pDisplay)
3144 {
3145    VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
3146    struct wsi_device *wsi_device = pdevice->wsi_device;
3147 
3148    if (!wsi_device_matches_drm_fd(wsi_device, drmFd)) {
3149       *pDisplay = VK_NULL_HANDLE;
3150       return VK_ERROR_UNKNOWN;
3151    }
3152 
3153    struct wsi_display_connector *connector =
3154       wsi_display_get_connector(wsi_device, drmFd, connectorId);
3155 
3156    if (!connector) {
3157       *pDisplay = VK_NULL_HANDLE;
3158       return VK_ERROR_UNKNOWN;
3159    }
3160 
3161    *pDisplay = wsi_display_connector_to_handle(connector);
3162    return VK_SUCCESS;
3163 }
3164