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