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