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