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