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