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