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  */
60 typedef 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 
71 typedef 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 
88 struct 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 
110 enum 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 
118 struct 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 
127 struct 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 
136 struct wsi_display_fence {
137    struct wsi_fence             base;
138    bool                         event_received;
139    bool                         destroyed;
140    uint64_t                     sequence;
141 };
142 
143 static uint64_t fence_sequence;
144 
ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode,VkDisplayModeKHR)145 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
146 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
147 
148 static bool
149 wsi_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 
166 static double
wsi_display_mode_refresh(struct wsi_display_mode * wsi)167 wsi_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 
wsi_rel_to_abs_time(uint64_t rel_time)174 static 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 
185 static struct wsi_display_mode *
wsi_display_find_drm_mode(struct wsi_device * wsi_device,struct wsi_display_connector * connector,drmModeModeInfoPtr mode)186 wsi_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 
197 static void
wsi_display_invalidate_connector_modes(struct wsi_device * wsi_device,struct wsi_display_connector * connector)198 wsi_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 
206 static VkResult
wsi_display_register_drm_mode(struct wsi_device * wsi_device,struct wsi_display_connector * connector,drmModeModeInfoPtr drm_mode)207 wsi_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 
250 static struct wsi_display_connector *
wsi_display_find_connector(struct wsi_device * wsi_device,uint32_t connector_id)251 wsi_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 
265 static struct wsi_display_connector *
wsi_display_alloc_connector(struct wsi_display * wsi,uint32_t connector_id)266 wsi_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 
282 static struct wsi_display_connector *
wsi_display_get_connector(struct wsi_device * wsi_device,uint32_t connector_id)283 wsi_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 
351 static uint32_t
mode_size(struct wsi_display_mode * mode)352 mode_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 
358 static void
wsi_display_fill_in_display_properties(struct wsi_device * wsi_device,struct wsi_display_connector * connector,VkDisplayProperties2KHR * properties2)359 wsi_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  */
414 VkResult
wsi_display_get_physical_device_display_properties(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,uint32_t * property_count,VkDisplayPropertiesKHR * properties)415 wsi_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 
458 VkResult
wsi_display_get_physical_device_display_properties2(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,uint32_t * property_count,VkDisplayProperties2KHR * properties)459 wsi_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 
502 bail:
503    *property_count = 0;
504    return VK_SUCCESS;
505 }
506 
507 /*
508  * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
509  */
510 static void
wsi_display_fill_in_display_plane_properties(struct wsi_device * wsi_device,struct wsi_display_connector * connector,VkDisplayPlaneProperties2KHR * properties)511 wsi_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 
528 VkResult
wsi_display_get_physical_device_display_plane_properties(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,uint32_t * property_count,VkDisplayPlanePropertiesKHR * properties)529 wsi_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 
553 VkResult
wsi_display_get_physical_device_display_plane_properties2(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,uint32_t * property_count,VkDisplayPlaneProperties2KHR * properties)554 wsi_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 
578 VkResult
wsi_display_get_display_plane_supported_displays(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,uint32_t plane_index,uint32_t * display_count,VkDisplayKHR * displays)579 wsi_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 
608 static void
wsi_display_fill_in_display_mode_properties(struct wsi_device * wsi_device,struct wsi_display_mode * display_mode,VkDisplayModeProperties2KHR * properties)609 wsi_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 
624 VkResult
wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,VkDisplayKHR display,uint32_t * property_count,VkDisplayModePropertiesKHR * properties)625 wsi_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 
652 VkResult
wsi_display_get_display_mode_properties2(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,VkDisplayKHR display,uint32_t * property_count,VkDisplayModeProperties2KHR * properties)653 wsi_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 
676 static bool
wsi_display_mode_matches_vk(wsi_display_mode * wsi,const VkDisplayModeParametersKHR * vk)677 wsi_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  */
688 VkResult
wsi_display_create_display_mode(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,VkDisplayKHR display,const VkDisplayModeCreateInfoKHR * create_info,const VkAllocationCallbacks * allocator,VkDisplayModeKHR * mode)689 wsi_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  */
721 VkResult
wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,VkDisplayModeKHR mode_khr,uint32_t plane_index,VkDisplayPlaneCapabilitiesKHR * capabilities)722 wsi_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 
751 VkResult
wsi_get_display_plane_capabilities2(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,const VkDisplayPlaneInfo2KHR * pDisplayPlaneInfo,VkDisplayPlaneCapabilities2KHR * capabilities)752 wsi_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 
784 VkResult
wsi_create_display_surface(VkInstance instance,const VkAllocationCallbacks * allocator,const VkDisplaySurfaceCreateInfoKHR * create_info,VkSurfaceKHR * surface_khr)785 wsi_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 
811 static VkResult
wsi_display_surface_get_support(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t queueFamilyIndex,VkBool32 * pSupported)812 wsi_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 
821 static VkResult
wsi_display_surface_get_capabilities(VkIcdSurfaceBase * surface_base,struct wsi_device * wsi_device,VkSurfaceCapabilitiesKHR * caps)822 wsi_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 
856 static VkResult
wsi_display_surface_get_surface_counters(VkIcdSurfaceBase * surface_base,VkSurfaceCounterFlagsEXT * counters)857 wsi_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 
865 static VkResult
wsi_display_surface_get_capabilities2(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,const void * info_next,VkSurfaceCapabilities2KHR * caps)866 wsi_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 
891 static 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 
899 static void
get_sorted_vk_formats(struct wsi_device * wsi_device,VkFormat * sorted_formats)900 get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)
901 {
902    for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)
903       sorted_formats[i] = available_surface_formats[i].format;
904 
905    if (wsi_device->force_bgra8_unorm_first) {
906       for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
907          if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {
908             sorted_formats[i] = sorted_formats[0];
909             sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
910             break;
911          }
912       }
913    }
914 }
915 
916 static VkResult
wsi_display_surface_get_formats(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,uint32_t * surface_format_count,VkSurfaceFormatKHR * surface_formats)917 wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
918                                 struct wsi_device *wsi_device,
919                                 uint32_t *surface_format_count,
920                                 VkSurfaceFormatKHR *surface_formats)
921 {
922    VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
923 
924    VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
925    get_sorted_vk_formats(wsi_device, sorted_formats);
926 
927    for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
928       vk_outarray_append(&out, f) {
929          f->format = sorted_formats[i];
930          f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
931       }
932    }
933 
934    return vk_outarray_status(&out);
935 }
936 
937 static VkResult
wsi_display_surface_get_formats2(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,const void * info_next,uint32_t * surface_format_count,VkSurfaceFormat2KHR * surface_formats)938 wsi_display_surface_get_formats2(VkIcdSurfaceBase *surface,
939                                  struct wsi_device *wsi_device,
940                                  const void *info_next,
941                                  uint32_t *surface_format_count,
942                                  VkSurfaceFormat2KHR *surface_formats)
943 {
944    VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
945 
946    VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
947    get_sorted_vk_formats(wsi_device, sorted_formats);
948 
949    for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
950       vk_outarray_append(&out, f) {
951          assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
952          f->surfaceFormat.format = sorted_formats[i];
953          f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
954       }
955    }
956 
957    return vk_outarray_status(&out);
958 }
959 
960 static VkResult
wsi_display_surface_get_present_modes(VkIcdSurfaceBase * surface,uint32_t * present_mode_count,VkPresentModeKHR * present_modes)961 wsi_display_surface_get_present_modes(VkIcdSurfaceBase *surface,
962                                       uint32_t *present_mode_count,
963                                       VkPresentModeKHR *present_modes)
964 {
965    VK_OUTARRAY_MAKE(conn, present_modes, present_mode_count);
966 
967    vk_outarray_append(&conn, present) {
968       *present = VK_PRESENT_MODE_FIFO_KHR;
969    }
970 
971    return vk_outarray_status(&conn);
972 }
973 
974 static VkResult
wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase * surface_base,struct wsi_device * wsi_device,uint32_t * pRectCount,VkRect2D * pRects)975 wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base,
976                                            struct wsi_device *wsi_device,
977                                            uint32_t* pRectCount,
978                                            VkRect2D* pRects)
979 {
980    VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
981    wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
982    VK_OUTARRAY_MAKE(out, pRects, pRectCount);
983 
984    if (wsi_device_matches_drm_fd(wsi_device, mode->connector->wsi->fd)) {
985       vk_outarray_append(&out, rect) {
986          *rect = (VkRect2D) {
987             .offset = { 0, 0 },
988             .extent = { mode->hdisplay, mode->vdisplay },
989          };
990       }
991    }
992 
993    return vk_outarray_status(&out);
994 }
995 
996 static void
wsi_display_destroy_buffer(struct wsi_display * wsi,uint32_t buffer)997 wsi_display_destroy_buffer(struct wsi_display *wsi,
998                            uint32_t buffer)
999 {
1000    (void) drmIoctl(wsi->fd, DRM_IOCTL_GEM_CLOSE,
1001                    &((struct drm_gem_close) { .handle = buffer }));
1002 }
1003 
1004 static VkResult
wsi_display_image_init(VkDevice device_h,struct wsi_swapchain * drv_chain,const VkSwapchainCreateInfoKHR * create_info,const VkAllocationCallbacks * allocator,struct wsi_display_image * image)1005 wsi_display_image_init(VkDevice device_h,
1006                        struct wsi_swapchain *drv_chain,
1007                        const VkSwapchainCreateInfoKHR *create_info,
1008                        const VkAllocationCallbacks *allocator,
1009                        struct wsi_display_image *image)
1010 {
1011    struct wsi_display_swapchain *chain =
1012       (struct wsi_display_swapchain *) drv_chain;
1013    struct wsi_display *wsi = chain->wsi;
1014    uint32_t drm_format = 0;
1015 
1016    for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
1017       if (create_info->imageFormat == available_surface_formats[i].format) {
1018          drm_format = available_surface_formats[i].drm_format;
1019          break;
1020       }
1021    }
1022 
1023    /* the application provided an invalid format, bail */
1024    if (drm_format == 0)
1025       return VK_ERROR_DEVICE_LOST;
1026 
1027    VkResult result = wsi_create_native_image(&chain->base, create_info,
1028                                              0, NULL, NULL,
1029                                              &image->base);
1030    if (result != VK_SUCCESS)
1031       return result;
1032 
1033    memset(image->buffer, 0, sizeof (image->buffer));
1034 
1035    for (unsigned int i = 0; i < image->base.num_planes; i++) {
1036       int ret = drmPrimeFDToHandle(wsi->fd, image->base.fds[i],
1037                                    &image->buffer[i]);
1038 
1039       close(image->base.fds[i]);
1040       image->base.fds[i] = -1;
1041       if (ret < 0)
1042          goto fail_handle;
1043    }
1044 
1045    image->chain = chain;
1046    image->state = WSI_IMAGE_IDLE;
1047    image->fb_id = 0;
1048 
1049    int ret = drmModeAddFB2(wsi->fd,
1050                            create_info->imageExtent.width,
1051                            create_info->imageExtent.height,
1052                            drm_format,
1053                            image->buffer,
1054                            image->base.row_pitches,
1055                            image->base.offsets,
1056                            &image->fb_id, 0);
1057 
1058    if (ret)
1059       goto fail_fb;
1060 
1061    return VK_SUCCESS;
1062 
1063 fail_fb:
1064 fail_handle:
1065    for (unsigned int i = 0; i < image->base.num_planes; i++) {
1066       if (image->buffer[i])
1067          wsi_display_destroy_buffer(wsi, image->buffer[i]);
1068       if (image->base.fds[i] != -1) {
1069          close(image->base.fds[i]);
1070          image->base.fds[i] = -1;
1071       }
1072    }
1073 
1074    wsi_destroy_image(&chain->base, &image->base);
1075 
1076    return VK_ERROR_OUT_OF_HOST_MEMORY;
1077 }
1078 
1079 static void
wsi_display_image_finish(struct wsi_swapchain * drv_chain,const VkAllocationCallbacks * allocator,struct wsi_display_image * image)1080 wsi_display_image_finish(struct wsi_swapchain *drv_chain,
1081                          const VkAllocationCallbacks *allocator,
1082                          struct wsi_display_image *image)
1083 {
1084    struct wsi_display_swapchain *chain =
1085       (struct wsi_display_swapchain *) drv_chain;
1086    struct wsi_display *wsi = chain->wsi;
1087 
1088    drmModeRmFB(wsi->fd, image->fb_id);
1089    for (unsigned int i = 0; i < image->base.num_planes; i++)
1090       wsi_display_destroy_buffer(wsi, image->buffer[i]);
1091    wsi_destroy_image(&chain->base, &image->base);
1092 }
1093 
1094 static VkResult
wsi_display_swapchain_destroy(struct wsi_swapchain * drv_chain,const VkAllocationCallbacks * allocator)1095 wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain,
1096                               const VkAllocationCallbacks *allocator)
1097 {
1098    struct wsi_display_swapchain *chain =
1099       (struct wsi_display_swapchain *) drv_chain;
1100 
1101    for (uint32_t i = 0; i < chain->base.image_count; i++)
1102       wsi_display_image_finish(drv_chain, allocator, &chain->images[i]);
1103 
1104    wsi_swapchain_finish(&chain->base);
1105    vk_free(allocator, chain);
1106    return VK_SUCCESS;
1107 }
1108 
1109 static struct wsi_image *
wsi_display_get_wsi_image(struct wsi_swapchain * drv_chain,uint32_t image_index)1110 wsi_display_get_wsi_image(struct wsi_swapchain *drv_chain,
1111                           uint32_t image_index)
1112 {
1113    struct wsi_display_swapchain *chain =
1114       (struct wsi_display_swapchain *) drv_chain;
1115 
1116    return &chain->images[image_index].base;
1117 }
1118 
1119 static void
wsi_display_idle_old_displaying(struct wsi_display_image * active_image)1120 wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
1121 {
1122    struct wsi_display_swapchain *chain = active_image->chain;
1123 
1124    wsi_display_debug("idle everyone but %ld\n",
1125                      active_image - &(chain->images[0]));
1126    for (uint32_t i = 0; i < chain->base.image_count; i++)
1127       if (chain->images[i].state == WSI_IMAGE_DISPLAYING &&
1128           &chain->images[i] != active_image)
1129       {
1130          wsi_display_debug("idle %d\n", i);
1131          chain->images[i].state = WSI_IMAGE_IDLE;
1132       }
1133 }
1134 
1135 static VkResult
1136 _wsi_display_queue_next(struct wsi_swapchain *drv_chain);
1137 
1138 static void
wsi_display_page_flip_handler2(int fd,unsigned int frame,unsigned int sec,unsigned int usec,uint32_t crtc_id,void * data)1139 wsi_display_page_flip_handler2(int fd,
1140                                unsigned int frame,
1141                                unsigned int sec,
1142                                unsigned int usec,
1143                                uint32_t crtc_id,
1144                                void *data)
1145 {
1146    struct wsi_display_image *image = data;
1147    struct wsi_display_swapchain *chain = image->chain;
1148 
1149    wsi_display_debug("image %ld displayed at %d\n",
1150                      image - &(image->chain->images[0]), frame);
1151    image->state = WSI_IMAGE_DISPLAYING;
1152    wsi_display_idle_old_displaying(image);
1153    VkResult result = _wsi_display_queue_next(&(chain->base));
1154    if (result != VK_SUCCESS)
1155       chain->status = result;
1156 }
1157 
1158 static void wsi_display_fence_event_handler(struct wsi_display_fence *fence);
1159 
wsi_display_page_flip_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)1160 static void wsi_display_page_flip_handler(int fd,
1161                                           unsigned int frame,
1162                                           unsigned int sec,
1163                                           unsigned int usec,
1164                                           void *data)
1165 {
1166    wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
1167 }
1168 
wsi_display_vblank_handler(int fd,unsigned int frame,unsigned int sec,unsigned int usec,void * data)1169 static void wsi_display_vblank_handler(int fd, unsigned int frame,
1170                                        unsigned int sec, unsigned int usec,
1171                                        void *data)
1172 {
1173    struct wsi_display_fence *fence = data;
1174 
1175    wsi_display_fence_event_handler(fence);
1176 }
1177 
wsi_display_sequence_handler(int fd,uint64_t frame,uint64_t nsec,uint64_t user_data)1178 static void wsi_display_sequence_handler(int fd, uint64_t frame,
1179                                          uint64_t nsec, uint64_t user_data)
1180 {
1181    struct wsi_display_fence *fence =
1182       (struct wsi_display_fence *) (uintptr_t) user_data;
1183 
1184    wsi_display_fence_event_handler(fence);
1185 }
1186 
1187 static drmEventContext event_context = {
1188    .version = DRM_EVENT_CONTEXT_VERSION,
1189    .page_flip_handler = wsi_display_page_flip_handler,
1190 #if DRM_EVENT_CONTEXT_VERSION >= 3
1191    .page_flip_handler2 = wsi_display_page_flip_handler2,
1192 #endif
1193    .vblank_handler = wsi_display_vblank_handler,
1194    .sequence_handler = wsi_display_sequence_handler,
1195 };
1196 
1197 static void *
wsi_display_wait_thread(void * data)1198 wsi_display_wait_thread(void *data)
1199 {
1200    struct wsi_display *wsi = data;
1201    struct pollfd pollfd = {
1202       .fd = wsi->fd,
1203       .events = POLLIN
1204    };
1205 
1206    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
1207    for (;;) {
1208       int ret = poll(&pollfd, 1, -1);
1209       if (ret > 0) {
1210          pthread_mutex_lock(&wsi->wait_mutex);
1211          (void) drmHandleEvent(wsi->fd, &event_context);
1212          pthread_cond_broadcast(&wsi->wait_cond);
1213          pthread_mutex_unlock(&wsi->wait_mutex);
1214       }
1215    }
1216    return NULL;
1217 }
1218 
1219 static int
wsi_display_start_wait_thread(struct wsi_display * wsi)1220 wsi_display_start_wait_thread(struct wsi_display *wsi)
1221 {
1222    if (!wsi->wait_thread) {
1223       int ret = pthread_create(&wsi->wait_thread, NULL,
1224                                wsi_display_wait_thread, wsi);
1225       if (ret)
1226          return ret;
1227    }
1228    return 0;
1229 }
1230 
1231 static void
wsi_display_stop_wait_thread(struct wsi_display * wsi)1232 wsi_display_stop_wait_thread(struct wsi_display *wsi)
1233 {
1234    pthread_mutex_lock(&wsi->wait_mutex);
1235    if (wsi->wait_thread) {
1236       pthread_cancel(wsi->wait_thread);
1237       pthread_join(wsi->wait_thread, NULL);
1238       wsi->wait_thread = 0;
1239    }
1240    pthread_mutex_unlock(&wsi->wait_mutex);
1241 }
1242 
1243 /*
1244  * Wait for at least one event from the kernel to be processed.
1245  * Call with wait_mutex held
1246  */
1247 static int
wsi_display_wait_for_event(struct wsi_display * wsi,uint64_t timeout_ns)1248 wsi_display_wait_for_event(struct wsi_display *wsi,
1249                            uint64_t timeout_ns)
1250 {
1251    int ret;
1252 
1253    ret = wsi_display_start_wait_thread(wsi);
1254 
1255    if (ret)
1256       return ret;
1257 
1258    struct timespec abs_timeout = {
1259       .tv_sec = timeout_ns / 1000000000ULL,
1260       .tv_nsec = timeout_ns % 1000000000ULL,
1261    };
1262 
1263    ret = pthread_cond_timedwait(&wsi->wait_cond, &wsi->wait_mutex,
1264                                 &abs_timeout);
1265 
1266    wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret);
1267    return ret;
1268 }
1269 
1270 static VkResult
wsi_display_acquire_next_image(struct wsi_swapchain * drv_chain,const VkAcquireNextImageInfoKHR * info,uint32_t * image_index)1271 wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
1272                                const VkAcquireNextImageInfoKHR *info,
1273                                uint32_t *image_index)
1274 {
1275    struct wsi_display_swapchain *chain =
1276       (struct wsi_display_swapchain *)drv_chain;
1277    struct wsi_display *wsi = chain->wsi;
1278    int ret = 0;
1279    VkResult result = VK_SUCCESS;
1280 
1281    /* Bail early if the swapchain is broken */
1282    if (chain->status != VK_SUCCESS)
1283       return chain->status;
1284 
1285    uint64_t timeout = info->timeout;
1286    if (timeout != 0 && timeout != UINT64_MAX)
1287       timeout = wsi_rel_to_abs_time(timeout);
1288 
1289    pthread_mutex_lock(&wsi->wait_mutex);
1290    for (;;) {
1291       for (uint32_t i = 0; i < chain->base.image_count; i++) {
1292          if (chain->images[i].state == WSI_IMAGE_IDLE) {
1293             *image_index = i;
1294             wsi_display_debug("image %d available\n", i);
1295             chain->images[i].state = WSI_IMAGE_DRAWING;
1296             result = VK_SUCCESS;
1297             goto done;
1298          }
1299          wsi_display_debug("image %d state %d\n", i, chain->images[i].state);
1300       }
1301 
1302       if (ret == ETIMEDOUT) {
1303          result = VK_TIMEOUT;
1304          goto done;
1305       }
1306 
1307       ret = wsi_display_wait_for_event(wsi, timeout);
1308 
1309       if (ret && ret != ETIMEDOUT) {
1310          result = VK_ERROR_SURFACE_LOST_KHR;
1311          goto done;
1312       }
1313    }
1314 done:
1315    pthread_mutex_unlock(&wsi->wait_mutex);
1316 
1317    if (result != VK_SUCCESS)
1318       return result;
1319 
1320    return chain->status;
1321 }
1322 
1323 /*
1324  * Check whether there are any other connectors driven by this crtc
1325  */
1326 static bool
wsi_display_crtc_solo(struct wsi_display * wsi,drmModeResPtr mode_res,drmModeConnectorPtr connector,uint32_t crtc_id)1327 wsi_display_crtc_solo(struct wsi_display *wsi,
1328                       drmModeResPtr mode_res,
1329                       drmModeConnectorPtr connector,
1330                       uint32_t crtc_id)
1331 {
1332    /* See if any other connectors share the same encoder */
1333    for (int c = 0; c < mode_res->count_connectors; c++) {
1334       if (mode_res->connectors[c] == connector->connector_id)
1335          continue;
1336 
1337       drmModeConnectorPtr other_connector =
1338          drmModeGetConnector(wsi->fd, mode_res->connectors[c]);
1339 
1340       if (other_connector) {
1341          bool match = (other_connector->encoder_id == connector->encoder_id);
1342          drmModeFreeConnector(other_connector);
1343          if (match)
1344             return false;
1345       }
1346    }
1347 
1348    /* See if any other encoders share the same crtc */
1349    for (int e = 0; e < mode_res->count_encoders; e++) {
1350       if (mode_res->encoders[e] == connector->encoder_id)
1351          continue;
1352 
1353       drmModeEncoderPtr other_encoder =
1354          drmModeGetEncoder(wsi->fd, mode_res->encoders[e]);
1355 
1356       if (other_encoder) {
1357          bool match = (other_encoder->crtc_id == crtc_id);
1358          drmModeFreeEncoder(other_encoder);
1359          if (match)
1360             return false;
1361       }
1362    }
1363    return true;
1364 }
1365 
1366 /*
1367  * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1368  * currently driving this connector and not any others. Settle for a CRTC
1369  * which is currently idle.
1370  */
1371 static uint32_t
wsi_display_select_crtc(const struct wsi_display_connector * connector,drmModeResPtr mode_res,drmModeConnectorPtr drm_connector)1372 wsi_display_select_crtc(const struct wsi_display_connector *connector,
1373                         drmModeResPtr mode_res,
1374                         drmModeConnectorPtr drm_connector)
1375 {
1376    struct wsi_display *wsi = connector->wsi;
1377 
1378    /* See what CRTC is currently driving this connector */
1379    if (drm_connector->encoder_id) {
1380       drmModeEncoderPtr encoder =
1381          drmModeGetEncoder(wsi->fd, drm_connector->encoder_id);
1382 
1383       if (encoder) {
1384          uint32_t crtc_id = encoder->crtc_id;
1385          drmModeFreeEncoder(encoder);
1386          if (crtc_id) {
1387             if (wsi_display_crtc_solo(wsi, mode_res, drm_connector, crtc_id))
1388                return crtc_id;
1389          }
1390       }
1391    }
1392    uint32_t crtc_id = 0;
1393    for (int c = 0; crtc_id == 0 && c < mode_res->count_crtcs; c++) {
1394       drmModeCrtcPtr crtc = drmModeGetCrtc(wsi->fd, mode_res->crtcs[c]);
1395       if (crtc && crtc->buffer_id == 0)
1396          crtc_id = crtc->crtc_id;
1397       drmModeFreeCrtc(crtc);
1398    }
1399    return crtc_id;
1400 }
1401 
1402 static VkResult
wsi_display_setup_connector(wsi_display_connector * connector,wsi_display_mode * display_mode)1403 wsi_display_setup_connector(wsi_display_connector *connector,
1404                             wsi_display_mode *display_mode)
1405 {
1406    struct wsi_display *wsi = connector->wsi;
1407 
1408    if (connector->current_mode == display_mode && connector->crtc_id)
1409       return VK_SUCCESS;
1410 
1411    VkResult result = VK_SUCCESS;
1412 
1413    drmModeResPtr mode_res = drmModeGetResources(wsi->fd);
1414    if (!mode_res) {
1415       if (errno == ENOMEM)
1416          result = VK_ERROR_OUT_OF_HOST_MEMORY;
1417       else
1418          result = VK_ERROR_SURFACE_LOST_KHR;
1419       goto bail;
1420    }
1421 
1422    drmModeConnectorPtr drm_connector =
1423       drmModeGetConnectorCurrent(wsi->fd, connector->id);
1424 
1425    if (!drm_connector) {
1426       if (errno == ENOMEM)
1427          result = VK_ERROR_OUT_OF_HOST_MEMORY;
1428       else
1429          result = VK_ERROR_SURFACE_LOST_KHR;
1430       goto bail_mode_res;
1431    }
1432 
1433    /* Pick a CRTC if we don't have one */
1434    if (!connector->crtc_id) {
1435       connector->crtc_id = wsi_display_select_crtc(connector,
1436                                                    mode_res, drm_connector);
1437       if (!connector->crtc_id) {
1438          result = VK_ERROR_SURFACE_LOST_KHR;
1439          goto bail_connector;
1440       }
1441    }
1442 
1443    if (connector->current_mode != display_mode) {
1444 
1445       /* Find the drm mode corresponding to the requested VkDisplayMode */
1446       drmModeModeInfoPtr drm_mode = NULL;
1447 
1448       for (int m = 0; m < drm_connector->count_modes; m++) {
1449          drm_mode = &drm_connector->modes[m];
1450          if (wsi_display_mode_matches_drm(display_mode, drm_mode))
1451             break;
1452          drm_mode = NULL;
1453       }
1454 
1455       if (!drm_mode) {
1456          result = VK_ERROR_SURFACE_LOST_KHR;
1457          goto bail_connector;
1458       }
1459 
1460       connector->current_mode = display_mode;
1461       connector->current_drm_mode = *drm_mode;
1462    }
1463 
1464 bail_connector:
1465    drmModeFreeConnector(drm_connector);
1466 bail_mode_res:
1467    drmModeFreeResources(mode_res);
1468 bail:
1469    return result;
1470 
1471 }
1472 
1473 static VkResult
wsi_display_fence_wait(struct wsi_fence * fence_wsi,uint64_t timeout)1474 wsi_display_fence_wait(struct wsi_fence *fence_wsi, uint64_t timeout)
1475 {
1476    const struct wsi_device *wsi_device = fence_wsi->wsi_device;
1477    struct wsi_display *wsi =
1478       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1479    struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
1480 
1481    wsi_display_debug("%9lu wait fence %lu %ld\n",
1482                      pthread_self(), fence->sequence,
1483                      (int64_t) (timeout - wsi_common_get_current_time()));
1484    wsi_display_debug_code(uint64_t start_ns = wsi_common_get_current_time());
1485    pthread_mutex_lock(&wsi->wait_mutex);
1486 
1487    VkResult result;
1488    int ret = 0;
1489    for (;;) {
1490       if (fence->event_received) {
1491          wsi_display_debug("%9lu fence %lu passed\n",
1492                            pthread_self(), fence->sequence);
1493          result = VK_SUCCESS;
1494          break;
1495       }
1496 
1497       if (ret == ETIMEDOUT) {
1498          wsi_display_debug("%9lu fence %lu timeout\n",
1499                            pthread_self(), fence->sequence);
1500          result = VK_TIMEOUT;
1501          break;
1502       }
1503 
1504       ret = wsi_display_wait_for_event(wsi, timeout);
1505 
1506       if (ret && ret != ETIMEDOUT) {
1507          wsi_display_debug("%9lu fence %lu error\n",
1508                            pthread_self(), fence->sequence);
1509          result = VK_ERROR_DEVICE_LOST;
1510          break;
1511       }
1512    }
1513    pthread_mutex_unlock(&wsi->wait_mutex);
1514    wsi_display_debug("%9lu fence wait %f ms\n",
1515                      pthread_self(),
1516                      ((int64_t) (wsi_common_get_current_time() - start_ns)) /
1517                      1.0e6);
1518    return result;
1519 }
1520 
1521 static void
wsi_display_fence_check_free(struct wsi_display_fence * fence)1522 wsi_display_fence_check_free(struct wsi_display_fence *fence)
1523 {
1524    if (fence->event_received && fence->destroyed)
1525       vk_free(fence->base.alloc, fence);
1526 }
1527 
wsi_display_fence_event_handler(struct wsi_display_fence * fence)1528 static void wsi_display_fence_event_handler(struct wsi_display_fence *fence)
1529 {
1530    fence->event_received = true;
1531    wsi_display_fence_check_free(fence);
1532 }
1533 
1534 static void
wsi_display_fence_destroy(struct wsi_fence * fence_wsi)1535 wsi_display_fence_destroy(struct wsi_fence *fence_wsi)
1536 {
1537    struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
1538 
1539    assert(!fence->destroyed);
1540    fence->destroyed = true;
1541    wsi_display_fence_check_free(fence);
1542 }
1543 
1544 static struct wsi_display_fence *
wsi_display_fence_alloc(VkDevice device,const struct wsi_device * wsi_device,VkDisplayKHR display,const VkAllocationCallbacks * allocator)1545 wsi_display_fence_alloc(VkDevice device,
1546                         const struct wsi_device *wsi_device,
1547                         VkDisplayKHR display,
1548                         const VkAllocationCallbacks *allocator)
1549 {
1550    struct wsi_display *wsi =
1551       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1552    struct wsi_display_fence *fence =
1553       vk_zalloc2(wsi->alloc, allocator, sizeof (*fence),
1554                 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1555 
1556    if (!fence)
1557       return NULL;
1558 
1559    fence->base.device = device;
1560    fence->base.display = display;
1561    fence->base.wsi_device = wsi_device;
1562    fence->base.alloc = allocator ? allocator : wsi->alloc;
1563    fence->base.wait = wsi_display_fence_wait;
1564    fence->base.destroy = wsi_display_fence_destroy;
1565    fence->event_received = false;
1566    fence->destroyed = false;
1567    fence->sequence = ++fence_sequence;
1568    return fence;
1569 }
1570 
1571 static VkResult
wsi_register_vblank_event(struct wsi_display_fence * fence,const struct wsi_device * wsi_device,VkDisplayKHR display,uint32_t flags,uint64_t frame_requested,uint64_t * frame_queued)1572 wsi_register_vblank_event(struct wsi_display_fence *fence,
1573                           const struct wsi_device *wsi_device,
1574                           VkDisplayKHR display,
1575                           uint32_t flags,
1576                           uint64_t frame_requested,
1577                           uint64_t *frame_queued)
1578 {
1579    struct wsi_display *wsi =
1580       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1581    struct wsi_display_connector *connector =
1582       wsi_display_connector_from_handle(display);
1583 
1584    if (wsi->fd < 0)
1585       return VK_ERROR_INITIALIZATION_FAILED;
1586 
1587    for (;;) {
1588       int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id,
1589                                      flags,
1590                                      frame_requested,
1591                                      frame_queued,
1592                                      (uintptr_t) fence);
1593 
1594       if (!ret)
1595          return VK_SUCCESS;
1596 
1597       if (errno != ENOMEM) {
1598 
1599          /* Something unexpected happened. Pause for a moment so the
1600           * application doesn't just spin and then return a failure indication
1601           */
1602 
1603          wsi_display_debug("queue vblank event %lu failed\n", fence->sequence);
1604          struct timespec delay = {
1605             .tv_sec = 0,
1606             .tv_nsec = 100000000ull,
1607          };
1608          nanosleep(&delay, NULL);
1609          return VK_ERROR_OUT_OF_HOST_MEMORY;
1610       }
1611 
1612       /* The kernel event queue is full. Wait for some events to be
1613        * processed and try again
1614        */
1615 
1616       pthread_mutex_lock(&wsi->wait_mutex);
1617       ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull));
1618       pthread_mutex_unlock(&wsi->wait_mutex);
1619 
1620       if (ret) {
1621          wsi_display_debug("vblank queue full, event wait failed\n");
1622          return VK_ERROR_OUT_OF_HOST_MEMORY;
1623       }
1624    }
1625 }
1626 
1627 /*
1628  * Check to see if the kernel has no flip queued and if there's an image
1629  * waiting to be displayed.
1630  */
1631 static VkResult
_wsi_display_queue_next(struct wsi_swapchain * drv_chain)1632 _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
1633 {
1634    struct wsi_display_swapchain *chain =
1635       (struct wsi_display_swapchain *) drv_chain;
1636    struct wsi_display *wsi = chain->wsi;
1637    VkIcdSurfaceDisplay *surface = chain->surface;
1638    wsi_display_mode *display_mode =
1639       wsi_display_mode_from_handle(surface->displayMode);
1640    wsi_display_connector *connector = display_mode->connector;
1641 
1642    if (wsi->fd < 0)
1643       return VK_ERROR_SURFACE_LOST_KHR;
1644 
1645    if (display_mode != connector->current_mode)
1646       connector->active = false;
1647 
1648    for (;;) {
1649 
1650       /* Check to see if there is an image to display, or if some image is
1651        * already queued */
1652 
1653       struct wsi_display_image *image = NULL;
1654 
1655       for (uint32_t i = 0; i < chain->base.image_count; i++) {
1656          struct wsi_display_image *tmp_image = &chain->images[i];
1657 
1658          switch (tmp_image->state) {
1659          case WSI_IMAGE_FLIPPING:
1660             /* already flipping, don't send another to the kernel yet */
1661             return VK_SUCCESS;
1662          case WSI_IMAGE_QUEUED:
1663             /* find the oldest queued */
1664             if (!image || tmp_image->flip_sequence < image->flip_sequence)
1665                image = tmp_image;
1666             break;
1667          default:
1668             break;
1669          }
1670       }
1671 
1672       if (!image)
1673          return VK_SUCCESS;
1674 
1675       int ret;
1676       if (connector->active) {
1677          ret = drmModePageFlip(wsi->fd, connector->crtc_id, image->fb_id,
1678                                    DRM_MODE_PAGE_FLIP_EVENT, image);
1679          if (ret == 0) {
1680             image->state = WSI_IMAGE_FLIPPING;
1681             return VK_SUCCESS;
1682          }
1683          wsi_display_debug("page flip err %d %s\n", ret, strerror(-ret));
1684       } else {
1685          ret = -EINVAL;
1686       }
1687 
1688       if (ret == -EINVAL) {
1689          VkResult result = wsi_display_setup_connector(connector, display_mode);
1690 
1691          if (result != VK_SUCCESS) {
1692             image->state = WSI_IMAGE_IDLE;
1693             return result;
1694          }
1695 
1696          /* XXX allow setting of position */
1697          ret = drmModeSetCrtc(wsi->fd, connector->crtc_id,
1698                               image->fb_id, 0, 0,
1699                               &connector->id, 1,
1700                               &connector->current_drm_mode);
1701          if (ret == 0) {
1702             /* Disable the HW cursor as the app doesn't have a mechanism
1703              * to control it.
1704              * Refer to question 12 of the VK_KHR_display spec.
1705              */
1706             ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 );
1707             if (ret != 0) {
1708                wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret));
1709             }
1710 
1711             /* Assume that the mode set is synchronous and that any
1712              * previous image is now idle.
1713              */
1714             image->state = WSI_IMAGE_DISPLAYING;
1715             wsi_display_idle_old_displaying(image);
1716             connector->active = true;
1717             return VK_SUCCESS;
1718          }
1719       }
1720 
1721       if (ret != -EACCES) {
1722          connector->active = false;
1723          image->state = WSI_IMAGE_IDLE;
1724          return VK_ERROR_SURFACE_LOST_KHR;
1725       }
1726 
1727       /* Some other VT is currently active. Sit here waiting for
1728        * our VT to become active again by polling once a second
1729        */
1730       usleep(1000 * 1000);
1731       connector->active = false;
1732    }
1733 }
1734 
1735 static VkResult
wsi_display_queue_present(struct wsi_swapchain * drv_chain,uint32_t image_index,const VkPresentRegionKHR * damage)1736 wsi_display_queue_present(struct wsi_swapchain *drv_chain,
1737                           uint32_t image_index,
1738                           const VkPresentRegionKHR *damage)
1739 {
1740    struct wsi_display_swapchain *chain =
1741       (struct wsi_display_swapchain *) drv_chain;
1742    struct wsi_display *wsi = chain->wsi;
1743    struct wsi_display_image *image = &chain->images[image_index];
1744    VkResult result;
1745 
1746    /* Bail early if the swapchain is broken */
1747    if (chain->status != VK_SUCCESS)
1748       return chain->status;
1749 
1750    assert(image->state == WSI_IMAGE_DRAWING);
1751    wsi_display_debug("present %d\n", image_index);
1752 
1753    pthread_mutex_lock(&wsi->wait_mutex);
1754 
1755    image->flip_sequence = ++chain->flip_sequence;
1756    image->state = WSI_IMAGE_QUEUED;
1757 
1758    result = _wsi_display_queue_next(drv_chain);
1759    if (result != VK_SUCCESS)
1760       chain->status = result;
1761 
1762    pthread_mutex_unlock(&wsi->wait_mutex);
1763 
1764    if (result != VK_SUCCESS)
1765       return result;
1766 
1767    return chain->status;
1768 }
1769 
1770 static VkResult
wsi_display_surface_create_swapchain(VkIcdSurfaceBase * icd_surface,VkDevice device,struct wsi_device * wsi_device,const VkSwapchainCreateInfoKHR * create_info,const VkAllocationCallbacks * allocator,struct wsi_swapchain ** swapchain_out)1771 wsi_display_surface_create_swapchain(
1772    VkIcdSurfaceBase *icd_surface,
1773    VkDevice device,
1774    struct wsi_device *wsi_device,
1775    const VkSwapchainCreateInfoKHR *create_info,
1776    const VkAllocationCallbacks *allocator,
1777    struct wsi_swapchain **swapchain_out)
1778 {
1779    struct wsi_display *wsi =
1780       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1781 
1782    assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
1783 
1784    const unsigned num_images = create_info->minImageCount;
1785    struct wsi_display_swapchain *chain =
1786       vk_zalloc(allocator,
1787                 sizeof(*chain) + num_images * sizeof(chain->images[0]),
1788                 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1789 
1790    if (chain == NULL)
1791       return VK_ERROR_OUT_OF_HOST_MEMORY;
1792 
1793    VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
1794                                         create_info, allocator);
1795    if (result != VK_SUCCESS) {
1796       vk_free(allocator, chain);
1797       return result;
1798    }
1799 
1800    chain->base.destroy = wsi_display_swapchain_destroy;
1801    chain->base.get_wsi_image = wsi_display_get_wsi_image;
1802    chain->base.acquire_next_image = wsi_display_acquire_next_image;
1803    chain->base.queue_present = wsi_display_queue_present;
1804    chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
1805    chain->base.image_count = num_images;
1806 
1807    chain->wsi = wsi;
1808    chain->status = VK_SUCCESS;
1809 
1810    chain->surface = (VkIcdSurfaceDisplay *) icd_surface;
1811 
1812    for (uint32_t image = 0; image < chain->base.image_count; image++) {
1813       result = wsi_display_image_init(device, &chain->base,
1814                                       create_info, allocator,
1815                                       &chain->images[image]);
1816       if (result != VK_SUCCESS) {
1817          while (image > 0) {
1818             --image;
1819             wsi_display_image_finish(&chain->base, allocator,
1820                                      &chain->images[image]);
1821          }
1822          vk_free(allocator, chain);
1823          goto fail_init_images;
1824       }
1825    }
1826 
1827    *swapchain_out = &chain->base;
1828 
1829    return VK_SUCCESS;
1830 
1831 fail_init_images:
1832    return result;
1833 }
1834 
1835 static bool
wsi_init_pthread_cond_monotonic(pthread_cond_t * cond)1836 wsi_init_pthread_cond_monotonic(pthread_cond_t *cond)
1837 {
1838    pthread_condattr_t condattr;
1839    bool ret = false;
1840 
1841    if (pthread_condattr_init(&condattr) != 0)
1842       goto fail_attr_init;
1843 
1844    if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) != 0)
1845       goto fail_attr_set;
1846 
1847    if (pthread_cond_init(cond, &condattr) != 0)
1848       goto fail_cond_init;
1849 
1850    ret = true;
1851 
1852 fail_cond_init:
1853 fail_attr_set:
1854    pthread_condattr_destroy(&condattr);
1855 fail_attr_init:
1856    return ret;
1857 }
1858 
1859 
1860 /*
1861  * Local version fo the libdrm helper. Added to avoid depending on bleeding
1862  * edge version of the library.
1863  */
1864 static int
local_drmIsMaster(int fd)1865 local_drmIsMaster(int fd)
1866 {
1867    /* Detect master by attempting something that requires master.
1868     *
1869     * Authenticating magic tokens requires master and 0 is an
1870     * internal kernel detail which we could use. Attempting this on
1871     * a master fd would fail therefore fail with EINVAL because 0
1872     * is invalid.
1873     *
1874     * A non-master fd will fail with EACCES, as the kernel checks
1875     * for master before attempting to do anything else.
1876     *
1877     * Since we don't want to leak implementation details, use
1878     * EACCES.
1879     */
1880    return drmAuthMagic(fd, 0) != -EACCES;
1881 }
1882 
1883 VkResult
wsi_display_init_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc,int display_fd)1884 wsi_display_init_wsi(struct wsi_device *wsi_device,
1885                      const VkAllocationCallbacks *alloc,
1886                      int display_fd)
1887 {
1888    struct wsi_display *wsi = vk_zalloc(alloc, sizeof(*wsi), 8,
1889                                        VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1890    VkResult result;
1891 
1892    if (!wsi) {
1893       result = VK_ERROR_OUT_OF_HOST_MEMORY;
1894       goto fail;
1895    }
1896 
1897    wsi->fd = display_fd;
1898    if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
1899       wsi->fd = -1;
1900 
1901    wsi->alloc = alloc;
1902 
1903    list_inithead(&wsi->connectors);
1904 
1905    int ret = pthread_mutex_init(&wsi->wait_mutex, NULL);
1906    if (ret) {
1907       result = VK_ERROR_OUT_OF_HOST_MEMORY;
1908       goto fail_mutex;
1909    }
1910 
1911    if (!wsi_init_pthread_cond_monotonic(&wsi->wait_cond)) {
1912       result = VK_ERROR_OUT_OF_HOST_MEMORY;
1913       goto fail_cond;
1914    }
1915 
1916    wsi->base.get_support = wsi_display_surface_get_support;
1917    wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
1918    wsi->base.get_formats = wsi_display_surface_get_formats;
1919    wsi->base.get_formats2 = wsi_display_surface_get_formats2;
1920    wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
1921    wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
1922    wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
1923 
1924    wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
1925 
1926    return VK_SUCCESS;
1927 
1928 fail_cond:
1929    pthread_mutex_destroy(&wsi->wait_mutex);
1930 fail_mutex:
1931    vk_free(alloc, wsi);
1932 fail:
1933    return result;
1934 }
1935 
1936 void
wsi_display_finish_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc)1937 wsi_display_finish_wsi(struct wsi_device *wsi_device,
1938                        const VkAllocationCallbacks *alloc)
1939 {
1940    struct wsi_display *wsi =
1941       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1942 
1943    if (wsi) {
1944       wsi_for_each_connector(connector, wsi) {
1945          wsi_for_each_display_mode(mode, connector) {
1946             vk_free(wsi->alloc, mode);
1947          }
1948          vk_free(wsi->alloc, connector);
1949       }
1950 
1951       wsi_display_stop_wait_thread(wsi);
1952       pthread_mutex_destroy(&wsi->wait_mutex);
1953       pthread_cond_destroy(&wsi->wait_cond);
1954 
1955       vk_free(alloc, wsi);
1956    }
1957 }
1958 
1959 /*
1960  * Implement vkReleaseDisplay
1961  */
1962 VkResult
wsi_release_display(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,VkDisplayKHR display)1963 wsi_release_display(VkPhysicalDevice            physical_device,
1964                     struct wsi_device           *wsi_device,
1965                     VkDisplayKHR                display)
1966 {
1967    struct wsi_display *wsi =
1968       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1969 
1970    if (wsi->fd >= 0) {
1971       wsi_display_stop_wait_thread(wsi);
1972 
1973       close(wsi->fd);
1974       wsi->fd = -1;
1975    }
1976 
1977 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1978    wsi_display_connector_from_handle(display)->output = None;
1979 #endif
1980 
1981    return VK_SUCCESS;
1982 }
1983 
1984 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1985 
1986 static struct wsi_display_connector *
wsi_display_find_output(struct wsi_device * wsi_device,xcb_randr_output_t output)1987 wsi_display_find_output(struct wsi_device *wsi_device,
1988                         xcb_randr_output_t output)
1989 {
1990    struct wsi_display *wsi =
1991       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
1992 
1993    wsi_for_each_connector(connector, wsi) {
1994       if (connector->output == output)
1995          return connector;
1996    }
1997 
1998    return NULL;
1999 }
2000 
2001 /*
2002  * Given a RandR output, find the associated kernel connector_id by
2003  * looking at the CONNECTOR_ID property provided by the X server
2004  */
2005 
2006 static uint32_t
wsi_display_output_to_connector_id(xcb_connection_t * connection,xcb_atom_t * connector_id_atom_p,xcb_randr_output_t output)2007 wsi_display_output_to_connector_id(xcb_connection_t *connection,
2008                                    xcb_atom_t *connector_id_atom_p,
2009                                    xcb_randr_output_t output)
2010 {
2011    uint32_t connector_id = 0;
2012    xcb_atom_t connector_id_atom = *connector_id_atom_p;
2013 
2014    if (connector_id_atom == 0) {
2015    /* Go dig out the CONNECTOR_ID property */
2016       xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
2017                                                           true,
2018                                                           12,
2019                                                           "CONNECTOR_ID");
2020       xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
2021                                                                  ia_c,
2022                                                                  NULL);
2023       if (ia_r) {
2024          *connector_id_atom_p = connector_id_atom = ia_r->atom;
2025          free(ia_r);
2026       }
2027    }
2028 
2029    /* If there's an CONNECTOR_ID atom in the server, then there may be a
2030     * CONNECTOR_ID property. Otherwise, there will not be and we don't even
2031     * need to bother.
2032     */
2033    if (connector_id_atom) {
2034 
2035       xcb_randr_query_version_cookie_t qv_c =
2036          xcb_randr_query_version(connection, 1, 6);
2037       xcb_randr_get_output_property_cookie_t gop_c =
2038          xcb_randr_get_output_property(connection,
2039                                        output,
2040                                        connector_id_atom,
2041                                        0,
2042                                        0,
2043                                        0xffffffffUL,
2044                                        0,
2045                                        0);
2046       xcb_randr_query_version_reply_t *qv_r =
2047          xcb_randr_query_version_reply(connection, qv_c, NULL);
2048       free(qv_r);
2049       xcb_randr_get_output_property_reply_t *gop_r =
2050          xcb_randr_get_output_property_reply(connection, gop_c, NULL);
2051       if (gop_r) {
2052          if (gop_r->num_items == 1 && gop_r->format == 32)
2053             memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
2054          free(gop_r);
2055       }
2056    }
2057    return connector_id;
2058 }
2059 
2060 static bool
wsi_display_check_randr_version(xcb_connection_t * connection)2061 wsi_display_check_randr_version(xcb_connection_t *connection)
2062 {
2063    xcb_randr_query_version_cookie_t qv_c =
2064       xcb_randr_query_version(connection, 1, 6);
2065    xcb_randr_query_version_reply_t *qv_r =
2066       xcb_randr_query_version_reply(connection, qv_c, NULL);
2067    bool ret = false;
2068 
2069    if (!qv_r)
2070       return false;
2071 
2072    /* Check for version 1.6 or newer */
2073    ret = (qv_r->major_version > 1 ||
2074           (qv_r->major_version == 1 && qv_r->minor_version >= 6));
2075 
2076    free(qv_r);
2077    return ret;
2078 }
2079 
2080 /*
2081  * Given a kernel connector id, find the associated RandR output using the
2082  * CONNECTOR_ID property
2083  */
2084 
2085 static xcb_randr_output_t
wsi_display_connector_id_to_output(xcb_connection_t * connection,uint32_t connector_id)2086 wsi_display_connector_id_to_output(xcb_connection_t *connection,
2087                                    uint32_t connector_id)
2088 {
2089    if (!wsi_display_check_randr_version(connection))
2090       return 0;
2091 
2092    const xcb_setup_t *setup = xcb_get_setup(connection);
2093 
2094    xcb_atom_t connector_id_atom = 0;
2095    xcb_randr_output_t output = 0;
2096 
2097    /* Search all of the screens for the provided output */
2098    xcb_screen_iterator_t iter;
2099    for (iter = xcb_setup_roots_iterator(setup);
2100         output == 0 && iter.rem;
2101         xcb_screen_next(&iter))
2102    {
2103       xcb_randr_get_screen_resources_cookie_t gsr_c =
2104          xcb_randr_get_screen_resources(connection, iter.data->root);
2105       xcb_randr_get_screen_resources_reply_t *gsr_r =
2106          xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2107 
2108       if (!gsr_r)
2109          return 0;
2110 
2111       xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2112       int o;
2113 
2114       for (o = 0; o < gsr_r->num_outputs; o++) {
2115          if (wsi_display_output_to_connector_id(connection,
2116                                                 &connector_id_atom, ro[o])
2117              == connector_id)
2118          {
2119             output = ro[o];
2120             break;
2121          }
2122       }
2123       free(gsr_r);
2124    }
2125    return output;
2126 }
2127 
2128 /*
2129  * Given a RandR output, find out which screen it's associated with
2130  */
2131 static xcb_window_t
wsi_display_output_to_root(xcb_connection_t * connection,xcb_randr_output_t output)2132 wsi_display_output_to_root(xcb_connection_t *connection,
2133                            xcb_randr_output_t output)
2134 {
2135    if (!wsi_display_check_randr_version(connection))
2136       return 0;
2137 
2138    const xcb_setup_t *setup = xcb_get_setup(connection);
2139    xcb_window_t root = 0;
2140 
2141    /* Search all of the screens for the provided output */
2142    for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
2143         root == 0 && iter.rem;
2144         xcb_screen_next(&iter))
2145    {
2146       xcb_randr_get_screen_resources_cookie_t gsr_c =
2147          xcb_randr_get_screen_resources(connection, iter.data->root);
2148       xcb_randr_get_screen_resources_reply_t *gsr_r =
2149          xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2150 
2151       if (!gsr_r)
2152          return 0;
2153 
2154       xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
2155 
2156       for (int o = 0; o < gsr_r->num_outputs; o++) {
2157          if (ro[o] == output) {
2158             root = iter.data->root;
2159             break;
2160          }
2161       }
2162       free(gsr_r);
2163    }
2164    return root;
2165 }
2166 
2167 static bool
wsi_display_mode_matches_x(struct wsi_display_mode * wsi,xcb_randr_mode_info_t * xcb)2168 wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
2169                            xcb_randr_mode_info_t *xcb)
2170 {
2171    return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
2172       wsi->hdisplay == xcb->width &&
2173       wsi->hsync_start == xcb->hsync_start &&
2174       wsi->hsync_end == xcb->hsync_end &&
2175       wsi->htotal == xcb->htotal &&
2176       wsi->hskew == xcb->hskew &&
2177       wsi->vdisplay == xcb->height &&
2178       wsi->vsync_start == xcb->vsync_start &&
2179       wsi->vsync_end == xcb->vsync_end &&
2180       wsi->vtotal == xcb->vtotal &&
2181       wsi->vscan <= 1 &&
2182       wsi->flags == xcb->mode_flags;
2183 }
2184 
2185 static struct wsi_display_mode *
wsi_display_find_x_mode(struct wsi_device * wsi_device,struct wsi_display_connector * connector,xcb_randr_mode_info_t * mode)2186 wsi_display_find_x_mode(struct wsi_device *wsi_device,
2187                         struct wsi_display_connector *connector,
2188                         xcb_randr_mode_info_t *mode)
2189 {
2190    wsi_for_each_display_mode(display_mode, connector) {
2191       if (wsi_display_mode_matches_x(display_mode, mode))
2192          return display_mode;
2193    }
2194    return NULL;
2195 }
2196 
2197 static VkResult
wsi_display_register_x_mode(struct wsi_device * wsi_device,struct wsi_display_connector * connector,xcb_randr_mode_info_t * x_mode,bool preferred)2198 wsi_display_register_x_mode(struct wsi_device *wsi_device,
2199                             struct wsi_display_connector *connector,
2200                             xcb_randr_mode_info_t *x_mode,
2201                             bool preferred)
2202 {
2203    struct wsi_display *wsi =
2204       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2205    struct wsi_display_mode *display_mode =
2206       wsi_display_find_x_mode(wsi_device, connector, x_mode);
2207 
2208    if (display_mode) {
2209       display_mode->valid = true;
2210       return VK_SUCCESS;
2211    }
2212 
2213    display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
2214                             8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
2215    if (!display_mode)
2216       return VK_ERROR_OUT_OF_HOST_MEMORY;
2217 
2218    display_mode->connector = connector;
2219    display_mode->valid = true;
2220    display_mode->preferred = preferred;
2221    display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
2222    display_mode->hdisplay = x_mode->width;
2223    display_mode->hsync_start = x_mode->hsync_start;
2224    display_mode->hsync_end = x_mode->hsync_end;
2225    display_mode->htotal = x_mode->htotal;
2226    display_mode->hskew = x_mode->hskew;
2227    display_mode->vdisplay = x_mode->height;
2228    display_mode->vsync_start = x_mode->vsync_start;
2229    display_mode->vsync_end = x_mode->vsync_end;
2230    display_mode->vtotal = x_mode->vtotal;
2231    display_mode->vscan = 0;
2232    display_mode->flags = x_mode->mode_flags;
2233 
2234    list_addtail(&display_mode->list, &connector->display_modes);
2235    return VK_SUCCESS;
2236 }
2237 
2238 static struct wsi_display_connector *
wsi_display_get_output(struct wsi_device * wsi_device,xcb_connection_t * connection,xcb_randr_output_t output)2239 wsi_display_get_output(struct wsi_device *wsi_device,
2240                        xcb_connection_t *connection,
2241                        xcb_randr_output_t output)
2242 {
2243    struct wsi_display *wsi =
2244       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2245    struct wsi_display_connector *connector;
2246    uint32_t connector_id;
2247 
2248    xcb_window_t root = wsi_display_output_to_root(connection, output);
2249    if (!root)
2250       return NULL;
2251 
2252    /* See if we already have a connector for this output */
2253    connector = wsi_display_find_output(wsi_device, output);
2254 
2255    if (!connector) {
2256       xcb_atom_t connector_id_atom = 0;
2257 
2258       /*
2259        * Go get the kernel connector ID for this X output
2260        */
2261       connector_id = wsi_display_output_to_connector_id(connection,
2262                                                         &connector_id_atom,
2263                                                         output);
2264 
2265       /* Any X server with lease support will have this atom */
2266       if (!connector_id) {
2267          return NULL;
2268       }
2269 
2270       /* See if we already have a connector for this id */
2271       connector = wsi_display_find_connector(wsi_device, connector_id);
2272 
2273       if (connector == NULL) {
2274          connector = wsi_display_alloc_connector(wsi, connector_id);
2275          if (!connector) {
2276             return NULL;
2277          }
2278          list_addtail(&connector->list, &wsi->connectors);
2279       }
2280       connector->output = output;
2281    }
2282 
2283    xcb_randr_get_screen_resources_cookie_t src =
2284       xcb_randr_get_screen_resources(connection, root);
2285    xcb_randr_get_output_info_cookie_t oic =
2286       xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
2287    xcb_randr_get_screen_resources_reply_t *srr =
2288       xcb_randr_get_screen_resources_reply(connection, src, NULL);
2289    xcb_randr_get_output_info_reply_t *oir =
2290       xcb_randr_get_output_info_reply(connection, oic, NULL);
2291 
2292    if (oir && srr) {
2293       /* Get X modes and add them */
2294 
2295       connector->connected =
2296          oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
2297 
2298       wsi_display_invalidate_connector_modes(wsi_device, connector);
2299 
2300       xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
2301       for (int m = 0; m < oir->num_modes; m++) {
2302          xcb_randr_mode_info_iterator_t i =
2303             xcb_randr_get_screen_resources_modes_iterator(srr);
2304          while (i.rem) {
2305             xcb_randr_mode_info_t *mi = i.data;
2306             if (mi->id == x_modes[m]) {
2307                VkResult result = wsi_display_register_x_mode(
2308                   wsi_device, connector, mi, m < oir->num_preferred);
2309                if (result != VK_SUCCESS) {
2310                   free(oir);
2311                   free(srr);
2312                   return NULL;
2313                }
2314                break;
2315             }
2316             xcb_randr_mode_info_next(&i);
2317          }
2318       }
2319    }
2320 
2321    free(oir);
2322    free(srr);
2323    return connector;
2324 }
2325 
2326 static xcb_randr_crtc_t
wsi_display_find_crtc_for_output(xcb_connection_t * connection,xcb_window_t root,xcb_randr_output_t output)2327 wsi_display_find_crtc_for_output(xcb_connection_t *connection,
2328                                  xcb_window_t root,
2329                                  xcb_randr_output_t output)
2330 {
2331    xcb_randr_get_screen_resources_cookie_t gsr_c =
2332       xcb_randr_get_screen_resources(connection, root);
2333    xcb_randr_get_screen_resources_reply_t *gsr_r =
2334       xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
2335 
2336    if (!gsr_r)
2337       return 0;
2338 
2339    xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
2340    xcb_randr_crtc_t idle_crtc = 0;
2341    xcb_randr_crtc_t active_crtc = 0;
2342 
2343    /* Find either a crtc already connected to the desired output or idle */
2344    for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
2345       xcb_randr_get_crtc_info_cookie_t gci_c =
2346          xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
2347       xcb_randr_get_crtc_info_reply_t *gci_r =
2348          xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
2349 
2350       if (gci_r) {
2351          if (gci_r->mode) {
2352             int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
2353             xcb_randr_output_t *outputs =
2354                xcb_randr_get_crtc_info_outputs(gci_r);
2355 
2356             if (num_outputs == 1 && outputs[0] == output)
2357                active_crtc = rc[c];
2358 
2359          } else if (idle_crtc == 0) {
2360             int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
2361             xcb_randr_output_t *possible =
2362                xcb_randr_get_crtc_info_possible(gci_r);
2363 
2364             for (int p = 0; p < num_possible; p++)
2365                if (possible[p] == output) {
2366                   idle_crtc = rc[c];
2367                   break;
2368                }
2369          }
2370          free(gci_r);
2371       }
2372    }
2373    free(gsr_r);
2374 
2375    if (active_crtc)
2376       return active_crtc;
2377    return idle_crtc;
2378 }
2379 
2380 VkResult
wsi_acquire_xlib_display(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,Display * dpy,VkDisplayKHR display)2381 wsi_acquire_xlib_display(VkPhysicalDevice physical_device,
2382                          struct wsi_device *wsi_device,
2383                          Display *dpy,
2384                          VkDisplayKHR display)
2385 {
2386    struct wsi_display *wsi =
2387       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2388    xcb_connection_t *connection = XGetXCBConnection(dpy);
2389    struct wsi_display_connector *connector =
2390       wsi_display_connector_from_handle(display);
2391    xcb_window_t root;
2392 
2393    /* XXX no support for multiple leases yet */
2394    if (wsi->fd >= 0)
2395       return VK_ERROR_INITIALIZATION_FAILED;
2396 
2397    if (!connector->output) {
2398       connector->output = wsi_display_connector_id_to_output(connection,
2399                                                              connector->id);
2400 
2401       /* Check and see if we found the output */
2402       if (!connector->output)
2403          return VK_ERROR_INITIALIZATION_FAILED;
2404    }
2405 
2406    root = wsi_display_output_to_root(connection, connector->output);
2407    if (!root)
2408       return VK_ERROR_INITIALIZATION_FAILED;
2409 
2410    xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
2411                                                             root,
2412                                                             connector->output);
2413 
2414    if (!crtc)
2415       return VK_ERROR_INITIALIZATION_FAILED;
2416 
2417 #ifdef HAVE_DRI3_MODIFIERS
2418    xcb_randr_lease_t lease = xcb_generate_id(connection);
2419    xcb_randr_create_lease_cookie_t cl_c =
2420       xcb_randr_create_lease(connection, root, lease, 1, 1,
2421                              &crtc, &connector->output);
2422    xcb_randr_create_lease_reply_t *cl_r =
2423       xcb_randr_create_lease_reply(connection, cl_c, NULL);
2424    if (!cl_r)
2425       return VK_ERROR_INITIALIZATION_FAILED;
2426 
2427    int fd = -1;
2428    if (cl_r->nfd > 0) {
2429       int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
2430 
2431       fd = rcl_f[0];
2432    }
2433    free (cl_r);
2434    if (fd < 0)
2435       return VK_ERROR_INITIALIZATION_FAILED;
2436 
2437    wsi->fd = fd;
2438 #endif
2439 
2440    return VK_SUCCESS;
2441 }
2442 
2443 VkResult
wsi_get_randr_output_display(VkPhysicalDevice physical_device,struct wsi_device * wsi_device,Display * dpy,RROutput output,VkDisplayKHR * display)2444 wsi_get_randr_output_display(VkPhysicalDevice physical_device,
2445                              struct wsi_device *wsi_device,
2446                              Display *dpy,
2447                              RROutput output,
2448                              VkDisplayKHR *display)
2449 {
2450    xcb_connection_t *connection = XGetXCBConnection(dpy);
2451    struct wsi_display_connector *connector =
2452       wsi_display_get_output(wsi_device, connection, (xcb_randr_output_t) output);
2453 
2454    if (connector)
2455       *display = wsi_display_connector_to_handle(connector);
2456    else
2457       *display = VK_NULL_HANDLE;
2458    return VK_SUCCESS;
2459 }
2460 
2461 #endif
2462 
2463 /* VK_EXT_display_control */
2464 VkResult
wsi_display_power_control(VkDevice device,struct wsi_device * wsi_device,VkDisplayKHR display,const VkDisplayPowerInfoEXT * display_power_info)2465 wsi_display_power_control(VkDevice device,
2466                           struct wsi_device *wsi_device,
2467                           VkDisplayKHR display,
2468                           const VkDisplayPowerInfoEXT *display_power_info)
2469 {
2470    struct wsi_display *wsi =
2471       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2472    struct wsi_display_connector *connector =
2473       wsi_display_connector_from_handle(display);
2474    int mode;
2475 
2476    if (wsi->fd < 0)
2477       return VK_ERROR_INITIALIZATION_FAILED;
2478 
2479    switch (display_power_info->powerState) {
2480    case VK_DISPLAY_POWER_STATE_OFF_EXT:
2481       mode = DRM_MODE_DPMS_OFF;
2482       break;
2483    case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
2484       mode = DRM_MODE_DPMS_SUSPEND;
2485       break;
2486    default:
2487       mode = DRM_MODE_DPMS_ON;
2488       break;
2489    }
2490    drmModeConnectorSetProperty(wsi->fd,
2491                                connector->id,
2492                                connector->dpms_property,
2493                                mode);
2494    return VK_SUCCESS;
2495 }
2496 
2497 VkResult
wsi_register_device_event(VkDevice device,struct wsi_device * wsi_device,const VkDeviceEventInfoEXT * device_event_info,const VkAllocationCallbacks * allocator,struct wsi_fence ** fence_p)2498 wsi_register_device_event(VkDevice device,
2499                           struct wsi_device *wsi_device,
2500                           const VkDeviceEventInfoEXT *device_event_info,
2501                           const VkAllocationCallbacks *allocator,
2502                           struct wsi_fence **fence_p)
2503 {
2504    return VK_ERROR_FEATURE_NOT_PRESENT;
2505 }
2506 
2507 VkResult
wsi_register_display_event(VkDevice device,struct wsi_device * wsi_device,VkDisplayKHR display,const VkDisplayEventInfoEXT * display_event_info,const VkAllocationCallbacks * allocator,struct wsi_fence ** fence_p)2508 wsi_register_display_event(VkDevice device,
2509                            struct wsi_device *wsi_device,
2510                            VkDisplayKHR display,
2511                            const VkDisplayEventInfoEXT *display_event_info,
2512                            const VkAllocationCallbacks *allocator,
2513                            struct wsi_fence **fence_p)
2514 {
2515    struct wsi_display *wsi =
2516       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2517    struct wsi_display_fence *fence;
2518    VkResult ret;
2519 
2520    switch (display_event_info->displayEvent) {
2521    case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
2522 
2523       fence = wsi_display_fence_alloc(device, wsi_device, display, allocator);
2524 
2525       if (!fence)
2526          return VK_ERROR_OUT_OF_HOST_MEMORY;
2527 
2528       ret = wsi_register_vblank_event(fence, wsi_device, display,
2529                                       DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
2530 
2531       if (ret == VK_SUCCESS)
2532          *fence_p = &fence->base;
2533       else if (fence != NULL)
2534          vk_free2(wsi->alloc, allocator, fence);
2535 
2536       break;
2537    default:
2538       ret = VK_ERROR_FEATURE_NOT_PRESENT;
2539       break;
2540    }
2541 
2542    return ret;
2543 }
2544 
2545 
2546 VkResult
wsi_get_swapchain_counter(VkDevice device,struct wsi_device * wsi_device,VkSwapchainKHR _swapchain,VkSurfaceCounterFlagBitsEXT flag_bits,uint64_t * value)2547 wsi_get_swapchain_counter(VkDevice device,
2548                           struct wsi_device *wsi_device,
2549                           VkSwapchainKHR _swapchain,
2550                           VkSurfaceCounterFlagBitsEXT flag_bits,
2551                           uint64_t *value)
2552 {
2553    struct wsi_display *wsi =
2554       (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
2555    struct wsi_display_swapchain *swapchain =
2556       (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
2557    struct wsi_display_connector *connector =
2558       wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
2559 
2560    if (wsi->fd < 0)
2561       return VK_ERROR_INITIALIZATION_FAILED;
2562 
2563    if (!connector->active) {
2564       *value = 0;
2565       return VK_SUCCESS;
2566    }
2567 
2568    int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, value, NULL);
2569    if (ret)
2570       *value = 0;
2571 
2572    return VK_SUCCESS;
2573 }
2574 
2575