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