2 * Copyright © 2017 Keith Packard
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.
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
23 #include "util/macros.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>
40 #include "util/hash_table.h"
41 #include "util/list.h"
44 #include "wsi_common_private.h"
45 #include "wsi_common_display.h"
46 #include "wsi_common_queue.h"
49 #define wsi_display_debug(...) fprintf(stderr, __VA_ARGS__)
50 #define wsi_display_debug_code(...) __VA_ARGS__
52 #define wsi_display_debug(...)
53 #define wsi_display_debug_code(...)
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.
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 */
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
;
71 typedef struct wsi_display_connector
{
72 struct list_head list
;
73 struct wsi_display
*wsi
;
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
;
86 } wsi_display_connector
;
89 struct wsi_interface base
;
91 const VkAllocationCallbacks
*alloc
;
95 pthread_mutex_t wait_mutex
;
96 pthread_cond_t wait_cond
;
97 pthread_t wait_thread
;
99 struct list_head connectors
; /* list of all discovered connectors */
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)
106 #define wsi_for_each_connector(_conn, _dev) \
107 list_for_each_entry_safe(struct wsi_display_connector, _conn, \
108 &(_dev)->connectors, list)
110 enum wsi_image_state
{
118 struct wsi_display_image
{
119 struct wsi_image base
;
120 struct wsi_display_swapchain
*chain
;
121 enum wsi_image_state state
;
124 uint64_t flip_sequence
;
127 struct wsi_display_swapchain
{
128 struct wsi_swapchain base
;
129 struct wsi_display
*wsi
;
130 VkIcdSurfaceDisplay
*surface
;
131 uint64_t flip_sequence
;
133 struct wsi_display_image images
[0];
136 struct wsi_display_fence
{
137 struct wsi_fence base
;
143 static uint64_t fence_sequence
;
145 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode
, VkDisplayModeKHR
)
146 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector
, VkDisplayKHR
)
149 wsi_display_mode_matches_drm(wsi_display_mode
*wsi
,
150 drmModeModeInfoPtr drm
)
152 return wsi
->clock
== drm
->clock
&&
153 wsi
->hdisplay
== drm
->hdisplay
&&
154 wsi
->hsync_start
== drm
->hsync_start
&&
155 wsi
->hsync_end
== drm
->hsync_end
&&
156 wsi
->htotal
== drm
->htotal
&&
157 wsi
->hskew
== drm
->hskew
&&
158 wsi
->vdisplay
== drm
->vdisplay
&&
159 wsi
->vsync_start
== drm
->vsync_start
&&
160 wsi
->vsync_end
== drm
->vsync_end
&&
161 wsi
->vtotal
== drm
->vtotal
&&
162 MAX2(wsi
->vscan
, 1) == MAX2(drm
->vscan
, 1) &&
163 wsi
->flags
== drm
->flags
;
167 wsi_display_mode_refresh(struct wsi_display_mode
*wsi
)
169 return (double) wsi
->clock
* 1000.0 / ((double) wsi
->htotal
*
170 (double) wsi
->vtotal
*
171 (double) MAX2(wsi
->vscan
, 1));
174 static uint64_t wsi_rel_to_abs_time(uint64_t rel_time
)
176 uint64_t current_time
= wsi_common_get_current_time();
178 /* check for overflow */
179 if (rel_time
> UINT64_MAX
- current_time
)
182 return current_time
+ rel_time
;
185 static struct wsi_display_mode
*
186 wsi_display_find_drm_mode(struct wsi_device
*wsi_device
,
187 struct wsi_display_connector
*connector
,
188 drmModeModeInfoPtr mode
)
190 wsi_for_each_display_mode(display_mode
, connector
) {
191 if (wsi_display_mode_matches_drm(display_mode
, mode
))
198 wsi_display_invalidate_connector_modes(struct wsi_device
*wsi_device
,
199 struct wsi_display_connector
*connector
)
201 wsi_for_each_display_mode(display_mode
, connector
) {
202 display_mode
->valid
= false;
207 wsi_display_register_drm_mode(struct wsi_device
*wsi_device
,
208 struct wsi_display_connector
*connector
,
209 drmModeModeInfoPtr drm_mode
)
211 struct wsi_display
*wsi
=
212 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
213 struct wsi_display_mode
*display_mode
=
214 wsi_display_find_drm_mode(wsi_device
, connector
, drm_mode
);
217 display_mode
->valid
= true;
221 display_mode
= vk_zalloc(wsi
->alloc
, sizeof (struct wsi_display_mode
),
222 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
224 return VK_ERROR_OUT_OF_HOST_MEMORY
;
226 display_mode
->connector
= connector
;
227 display_mode
->valid
= true;
228 display_mode
->preferred
= (drm_mode
->type
& DRM_MODE_TYPE_PREFERRED
) != 0;
229 display_mode
->clock
= drm_mode
->clock
; /* kHz */
230 display_mode
->hdisplay
= drm_mode
->hdisplay
;
231 display_mode
->hsync_start
= drm_mode
->hsync_start
;
232 display_mode
->hsync_end
= drm_mode
->hsync_end
;
233 display_mode
->htotal
= drm_mode
->htotal
;
234 display_mode
->hskew
= drm_mode
->hskew
;
235 display_mode
->vdisplay
= drm_mode
->vdisplay
;
236 display_mode
->vsync_start
= drm_mode
->vsync_start
;
237 display_mode
->vsync_end
= drm_mode
->vsync_end
;
238 display_mode
->vtotal
= drm_mode
->vtotal
;
239 display_mode
->vscan
= drm_mode
->vscan
;
240 display_mode
->flags
= drm_mode
->flags
;
242 list_addtail(&display_mode
->list
, &connector
->display_modes
);
247 * Update our information about a specific connector
250 static struct wsi_display_connector
*
251 wsi_display_find_connector(struct wsi_device
*wsi_device
,
252 uint32_t connector_id
)
254 struct wsi_display
*wsi
=
255 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
257 wsi_for_each_connector(connector
, wsi
) {
258 if (connector
->id
== connector_id
)
265 static struct wsi_display_connector
*
266 wsi_display_alloc_connector(struct wsi_display
*wsi
,
267 uint32_t connector_id
)
269 struct wsi_display_connector
*connector
=
270 vk_zalloc(wsi
->alloc
, sizeof (struct wsi_display_connector
),
271 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
273 connector
->id
= connector_id
;
274 connector
->wsi
= wsi
;
275 connector
->active
= false;
276 /* XXX use EDID name */
277 connector
->name
= "monitor";
278 list_inithead(&connector
->display_modes
);
282 static struct wsi_display_connector
*
283 wsi_display_get_connector(struct wsi_device
*wsi_device
,
284 uint32_t connector_id
)
286 struct wsi_display
*wsi
=
287 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
292 drmModeConnectorPtr drm_connector
=
293 drmModeGetConnector(wsi
->fd
, connector_id
);
298 struct wsi_display_connector
*connector
=
299 wsi_display_find_connector(wsi_device
, connector_id
);
302 connector
= wsi_display_alloc_connector(wsi
, connector_id
);
304 drmModeFreeConnector(drm_connector
);
307 list_addtail(&connector
->list
, &wsi
->connectors
);
310 connector
->connected
= drm_connector
->connection
!= DRM_MODE_DISCONNECTED
;
312 /* Look for a DPMS property if we haven't already found one */
313 for (int p
= 0; connector
->dpms_property
== 0 &&
314 p
< drm_connector
->count_props
; p
++)
316 drmModePropertyPtr prop
= drmModeGetProperty(wsi
->fd
,
317 drm_connector
->props
[p
]);
320 if (prop
->flags
& DRM_MODE_PROP_ENUM
) {
321 if (!strcmp(prop
->name
, "DPMS"))
322 connector
->dpms_property
= drm_connector
->props
[p
];
324 drmModeFreeProperty(prop
);
327 /* Mark all connector modes as invalid */
328 wsi_display_invalidate_connector_modes(wsi_device
, connector
);
331 * List current modes, adding new ones and marking existing ones as
334 for (int m
= 0; m
< drm_connector
->count_modes
; m
++) {
335 VkResult result
= wsi_display_register_drm_mode(wsi_device
,
337 &drm_connector
->modes
[m
]);
338 if (result
!= VK_SUCCESS
) {
339 drmModeFreeConnector(drm_connector
);
344 drmModeFreeConnector(drm_connector
);
349 #define MM_PER_PIXEL (1.0/96.0 * 25.4)
352 mode_size(struct wsi_display_mode
*mode
)
354 /* fortunately, these are both uint16_t, so this is easy */
355 return (uint32_t) mode
->hdisplay
* (uint32_t) mode
->vdisplay
;
359 wsi_display_fill_in_display_properties(struct wsi_device
*wsi_device
,
360 struct wsi_display_connector
*connector
,
361 VkDisplayProperties2KHR
*properties2
)
363 assert(properties2
->sType
== VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR
);
364 VkDisplayPropertiesKHR
*properties
= &properties2
->displayProperties
;
366 properties
->display
= wsi_display_connector_to_handle(connector
);
367 properties
->displayName
= connector
->name
;
369 /* Find the first preferred mode and assume that's the physical
370 * resolution. If there isn't a preferred mode, find the largest mode and
374 struct wsi_display_mode
*preferred_mode
= NULL
, *largest_mode
= NULL
;
375 wsi_for_each_display_mode(display_mode
, connector
) {
376 if (!display_mode
->valid
)
378 if (display_mode
->preferred
) {
379 preferred_mode
= display_mode
;
382 if (largest_mode
== NULL
||
383 mode_size(display_mode
) > mode_size(largest_mode
))
385 largest_mode
= display_mode
;
389 if (preferred_mode
) {
390 properties
->physicalResolution
.width
= preferred_mode
->hdisplay
;
391 properties
->physicalResolution
.height
= preferred_mode
->vdisplay
;
392 } else if (largest_mode
) {
393 properties
->physicalResolution
.width
= largest_mode
->hdisplay
;
394 properties
->physicalResolution
.height
= largest_mode
->vdisplay
;
396 properties
->physicalResolution
.width
= 1024;
397 properties
->physicalResolution
.height
= 768;
400 /* Make up physical size based on 96dpi */
401 properties
->physicalDimensions
.width
=
402 floor(properties
->physicalResolution
.width
* MM_PER_PIXEL
+ 0.5);
403 properties
->physicalDimensions
.height
=
404 floor(properties
->physicalResolution
.height
* MM_PER_PIXEL
+ 0.5);
406 properties
->supportedTransforms
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
407 properties
->planeReorderPossible
= VK_FALSE
;
408 properties
->persistentContent
= VK_FALSE
;
412 * Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display)
415 wsi_display_get_physical_device_display_properties(
416 VkPhysicalDevice physical_device
,
417 struct wsi_device
*wsi_device
,
418 uint32_t *property_count
,
419 VkDisplayPropertiesKHR
*properties
)
421 struct wsi_display
*wsi
=
422 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
424 if (properties
== NULL
) {
425 return wsi_display_get_physical_device_display_properties2(
426 physical_device
, wsi_device
, property_count
, NULL
);
428 /* If we're actually returning properties, allocate a temporary array of
429 * VkDisplayProperties2KHR structs, call properties2 to fill them out,
430 * and then copy them to the client. This seems a bit expensive but
431 * wsi_display_get_physical_device_display_properties2() calls
432 * drmModeGetResources() which does an ioctl and then a bunch of
433 * allocations so this should get lost in the noise.
435 VkDisplayProperties2KHR
*props2
=
436 vk_zalloc(wsi
->alloc
, sizeof(*props2
) * *property_count
, 8,
437 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
439 return VK_ERROR_OUT_OF_HOST_MEMORY
;
441 for (uint32_t i
= 0; i
< *property_count
; i
++)
442 props2
[i
].sType
= VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR
;
444 VkResult result
= wsi_display_get_physical_device_display_properties2(
445 physical_device
, wsi_device
, property_count
, props2
);
447 if (result
== VK_SUCCESS
|| result
== VK_INCOMPLETE
) {
448 for (uint32_t i
= 0; i
< *property_count
; i
++)
449 properties
[i
] = props2
[i
].displayProperties
;
452 vk_free(wsi
->alloc
, props2
);
459 wsi_display_get_physical_device_display_properties2(
460 VkPhysicalDevice physical_device
,
461 struct wsi_device
*wsi_device
,
462 uint32_t *property_count
,
463 VkDisplayProperties2KHR
*properties
)
465 struct wsi_display
*wsi
=
466 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
471 drmModeResPtr mode_res
= drmModeGetResources(wsi
->fd
);
476 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
478 /* Get current information */
480 for (int c
= 0; c
< mode_res
->count_connectors
; c
++) {
481 struct wsi_display_connector
*connector
=
482 wsi_display_get_connector(wsi_device
, mode_res
->connectors
[c
]);
485 drmModeFreeResources(mode_res
);
486 return VK_ERROR_OUT_OF_HOST_MEMORY
;
489 if (connector
->connected
) {
490 vk_outarray_append(&conn
, prop
) {
491 wsi_display_fill_in_display_properties(wsi_device
,
498 drmModeFreeResources(mode_res
);
500 return vk_outarray_status(&conn
);
508 * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
511 wsi_display_fill_in_display_plane_properties(
512 struct wsi_device
*wsi_device
,
513 struct wsi_display_connector
*connector
,
514 VkDisplayPlaneProperties2KHR
*properties
)
516 assert(properties
->sType
== VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR
);
517 VkDisplayPlanePropertiesKHR
*prop
= &properties
->displayPlaneProperties
;
519 if (connector
&& connector
->active
) {
520 prop
->currentDisplay
= wsi_display_connector_to_handle(connector
);
521 prop
->currentStackIndex
= 0;
523 prop
->currentDisplay
= VK_NULL_HANDLE
;
524 prop
->currentStackIndex
= 0;
529 wsi_display_get_physical_device_display_plane_properties(
530 VkPhysicalDevice physical_device
,
531 struct wsi_device
*wsi_device
,
532 uint32_t *property_count
,
533 VkDisplayPlanePropertiesKHR
*properties
)
535 struct wsi_display
*wsi
=
536 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
538 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
540 wsi_for_each_connector(connector
, wsi
) {
541 vk_outarray_append(&conn
, prop
) {
542 VkDisplayPlaneProperties2KHR prop2
= {
543 .sType
= VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR
,
545 wsi_display_fill_in_display_plane_properties(wsi_device
, connector
,
547 *prop
= prop2
.displayPlaneProperties
;
550 return vk_outarray_status(&conn
);
554 wsi_display_get_physical_device_display_plane_properties2(
555 VkPhysicalDevice physical_device
,
556 struct wsi_device
*wsi_device
,
557 uint32_t *property_count
,
558 VkDisplayPlaneProperties2KHR
*properties
)
560 struct wsi_display
*wsi
=
561 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
563 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
565 wsi_for_each_connector(connector
, wsi
) {
566 vk_outarray_append(&conn
, prop
) {
567 wsi_display_fill_in_display_plane_properties(wsi_device
, connector
,
571 return vk_outarray_status(&conn
);
575 * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display)
579 wsi_display_get_display_plane_supported_displays(
580 VkPhysicalDevice physical_device
,
581 struct wsi_device
*wsi_device
,
582 uint32_t plane_index
,
583 uint32_t *display_count
,
584 VkDisplayKHR
*displays
)
586 struct wsi_display
*wsi
=
587 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
589 VK_OUTARRAY_MAKE(conn
, displays
, display_count
);
593 wsi_for_each_connector(connector
, wsi
) {
594 if (c
== plane_index
&& connector
->connected
) {
595 vk_outarray_append(&conn
, display
) {
596 *display
= wsi_display_connector_to_handle(connector
);
601 return vk_outarray_status(&conn
);
605 * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
609 wsi_display_fill_in_display_mode_properties(
610 struct wsi_device
*wsi_device
,
611 struct wsi_display_mode
*display_mode
,
612 VkDisplayModeProperties2KHR
*properties
)
614 assert(properties
->sType
== VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR
);
615 VkDisplayModePropertiesKHR
*prop
= &properties
->displayModeProperties
;
617 prop
->displayMode
= wsi_display_mode_to_handle(display_mode
);
618 prop
->parameters
.visibleRegion
.width
= display_mode
->hdisplay
;
619 prop
->parameters
.visibleRegion
.height
= display_mode
->vdisplay
;
620 prop
->parameters
.refreshRate
=
621 (uint32_t) (wsi_display_mode_refresh(display_mode
) * 1000 + 0.5);
625 wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device
,
626 struct wsi_device
*wsi_device
,
627 VkDisplayKHR display
,
628 uint32_t *property_count
,
629 VkDisplayModePropertiesKHR
*properties
)
631 struct wsi_display_connector
*connector
=
632 wsi_display_connector_from_handle(display
);
634 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
636 wsi_for_each_display_mode(display_mode
, connector
) {
637 if (!display_mode
->valid
)
640 vk_outarray_append(&conn
, prop
) {
641 VkDisplayModeProperties2KHR prop2
= {
642 .sType
= VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR
,
644 wsi_display_fill_in_display_mode_properties(wsi_device
,
645 display_mode
, &prop2
);
646 *prop
= prop2
.displayModeProperties
;
649 return vk_outarray_status(&conn
);
653 wsi_display_get_display_mode_properties2(VkPhysicalDevice physical_device
,
654 struct wsi_device
*wsi_device
,
655 VkDisplayKHR display
,
656 uint32_t *property_count
,
657 VkDisplayModeProperties2KHR
*properties
)
659 struct wsi_display_connector
*connector
=
660 wsi_display_connector_from_handle(display
);
662 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
664 wsi_for_each_display_mode(display_mode
, connector
) {
665 if (!display_mode
->valid
)
668 vk_outarray_append(&conn
, prop
) {
669 wsi_display_fill_in_display_mode_properties(wsi_device
,
673 return vk_outarray_status(&conn
);
677 wsi_display_mode_matches_vk(wsi_display_mode
*wsi
,
678 const VkDisplayModeParametersKHR
*vk
)
680 return (vk
->visibleRegion
.width
== wsi
->hdisplay
&&
681 vk
->visibleRegion
.height
== wsi
->vdisplay
&&
682 fabs(wsi_display_mode_refresh(wsi
) * 1000.0 - vk
->refreshRate
) < 10);
686 * Implement vkCreateDisplayModeKHR (VK_KHR_display)
689 wsi_display_create_display_mode(VkPhysicalDevice physical_device
,
690 struct wsi_device
*wsi_device
,
691 VkDisplayKHR display
,
692 const VkDisplayModeCreateInfoKHR
*create_info
,
693 const VkAllocationCallbacks
*allocator
,
694 VkDisplayModeKHR
*mode
)
696 struct wsi_display_connector
*connector
=
697 wsi_display_connector_from_handle(display
);
699 if (create_info
->flags
!= 0)
700 return VK_ERROR_INITIALIZATION_FAILED
;
702 /* Check and see if the requested mode happens to match an existing one and
703 * return that. This makes the conformance suite happy. Doing more than
704 * this would involve embedding the CVT function into the driver, which seems
707 wsi_for_each_display_mode(display_mode
, connector
) {
708 if (display_mode
->valid
) {
709 if (wsi_display_mode_matches_vk(display_mode
, &create_info
->parameters
)) {
710 *mode
= wsi_display_mode_to_handle(display_mode
);
715 return VK_ERROR_INITIALIZATION_FAILED
;
719 * Implement vkGetDisplayPlaneCapabilities
722 wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device
,
723 struct wsi_device
*wsi_device
,
724 VkDisplayModeKHR mode_khr
,
725 uint32_t plane_index
,
726 VkDisplayPlaneCapabilitiesKHR
*capabilities
)
728 struct wsi_display_mode
*mode
= wsi_display_mode_from_handle(mode_khr
);
730 /* XXX use actual values */
731 capabilities
->supportedAlpha
= VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR
;
732 capabilities
->minSrcPosition
.x
= 0;
733 capabilities
->minSrcPosition
.y
= 0;
734 capabilities
->maxSrcPosition
.x
= 0;
735 capabilities
->maxSrcPosition
.y
= 0;
736 capabilities
->minSrcExtent
.width
= mode
->hdisplay
;
737 capabilities
->minSrcExtent
.height
= mode
->vdisplay
;
738 capabilities
->maxSrcExtent
.width
= mode
->hdisplay
;
739 capabilities
->maxSrcExtent
.height
= mode
->vdisplay
;
740 capabilities
->minDstPosition
.x
= 0;
741 capabilities
->minDstPosition
.y
= 0;
742 capabilities
->maxDstPosition
.x
= 0;
743 capabilities
->maxDstPosition
.y
= 0;
744 capabilities
->minDstExtent
.width
= mode
->hdisplay
;
745 capabilities
->minDstExtent
.height
= mode
->vdisplay
;
746 capabilities
->maxDstExtent
.width
= mode
->hdisplay
;
747 capabilities
->maxDstExtent
.height
= mode
->vdisplay
;
752 wsi_get_display_plane_capabilities2(
753 VkPhysicalDevice physical_device
,
754 struct wsi_device
*wsi_device
,
755 const VkDisplayPlaneInfo2KHR
*pDisplayPlaneInfo
,
756 VkDisplayPlaneCapabilities2KHR
*capabilities
)
758 assert(capabilities
->sType
==
759 VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR
);
762 wsi_get_display_plane_capabilities(physical_device
, wsi_device
,
763 pDisplayPlaneInfo
->mode
,
764 pDisplayPlaneInfo
->planeIndex
,
765 &capabilities
->capabilities
);
767 vk_foreach_struct(ext
, capabilities
->pNext
) {
768 switch (ext
->sType
) {
769 case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR
: {
770 VkSurfaceProtectedCapabilitiesKHR
*protected = (void *)ext
;
771 protected->supportsProtected
= VK_FALSE
;
785 wsi_create_display_surface(VkInstance instance
,
786 const VkAllocationCallbacks
*allocator
,
787 const VkDisplaySurfaceCreateInfoKHR
*create_info
,
788 VkSurfaceKHR
*surface_khr
)
790 VkIcdSurfaceDisplay
*surface
= vk_zalloc(allocator
, sizeof *surface
, 8,
791 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
794 return VK_ERROR_OUT_OF_HOST_MEMORY
;
796 surface
->base
.platform
= VK_ICD_WSI_PLATFORM_DISPLAY
;
798 surface
->displayMode
= create_info
->displayMode
;
799 surface
->planeIndex
= create_info
->planeIndex
;
800 surface
->planeStackIndex
= create_info
->planeStackIndex
;
801 surface
->transform
= create_info
->transform
;
802 surface
->globalAlpha
= create_info
->globalAlpha
;
803 surface
->alphaMode
= create_info
->alphaMode
;
804 surface
->imageExtent
= create_info
->imageExtent
;
806 *surface_khr
= VkIcdSurfaceBase_to_handle(&surface
->base
);
812 wsi_display_surface_get_support(VkIcdSurfaceBase
*surface
,
813 struct wsi_device
*wsi_device
,
814 uint32_t queueFamilyIndex
,
815 VkBool32
* pSupported
)
817 *pSupported
= VK_TRUE
;
822 wsi_display_surface_get_capabilities(VkIcdSurfaceBase
*surface_base
,
823 struct wsi_device
*wsi_device
,
824 VkSurfaceCapabilitiesKHR
* caps
)
826 VkIcdSurfaceDisplay
*surface
= (VkIcdSurfaceDisplay
*) surface_base
;
827 wsi_display_mode
*mode
= wsi_display_mode_from_handle(surface
->displayMode
);
829 caps
->currentExtent
.width
= mode
->hdisplay
;
830 caps
->currentExtent
.height
= mode
->vdisplay
;
832 caps
->minImageExtent
= (VkExtent2D
) { 1, 1 };
833 caps
->maxImageExtent
= (VkExtent2D
) {
834 wsi_device
->maxImageDimension2D
,
835 wsi_device
->maxImageDimension2D
,
838 caps
->supportedCompositeAlpha
= VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
;
840 caps
->minImageCount
= 2;
841 caps
->maxImageCount
= 0;
843 caps
->supportedTransforms
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
844 caps
->currentTransform
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
845 caps
->maxImageArrayLayers
= 1;
846 caps
->supportedUsageFlags
=
847 VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
848 VK_IMAGE_USAGE_SAMPLED_BIT
|
849 VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
850 VK_IMAGE_USAGE_STORAGE_BIT
|
851 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
;
857 wsi_display_surface_get_surface_counters(
858 VkIcdSurfaceBase
*surface_base
,
859 VkSurfaceCounterFlagsEXT
*counters
)
861 *counters
= VK_SURFACE_COUNTER_VBLANK_EXT
;
866 wsi_display_surface_get_capabilities2(VkIcdSurfaceBase
*icd_surface
,
867 struct wsi_device
*wsi_device
,
868 const void *info_next
,
869 VkSurfaceCapabilities2KHR
*caps
)
871 assert(caps
->sType
== VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR
);
874 result
= wsi_display_surface_get_capabilities(icd_surface
, wsi_device
,
875 &caps
->surfaceCapabilities
);
876 if (result
!= VK_SUCCESS
)
879 struct wsi_surface_supported_counters
*counters
=
880 vk_find_struct( caps
->pNext
, WSI_SURFACE_SUPPORTED_COUNTERS_MESA
);
883 result
= wsi_display_surface_get_surface_counters(
885 &counters
->supported_surface_counters
);
891 static const struct {
894 } available_surface_formats
[] = {
895 { .format
= VK_FORMAT_B8G8R8A8_SRGB
, .drm_format
= DRM_FORMAT_XRGB8888
},
896 { .format
= VK_FORMAT_B8G8R8A8_UNORM
, .drm_format
= DRM_FORMAT_XRGB8888
},
900 get_sorted_vk_formats(struct wsi_device
*wsi_device
, VkFormat
*sorted_formats
)
902 for (unsigned i
= 0; i
< ARRAY_SIZE(available_surface_formats
); i
++)
903 sorted_formats
[i
] = available_surface_formats
[i
].format
;
905 if (wsi_device
->force_bgra8_unorm_first
) {
906 for (unsigned i
= 0; i
< ARRAY_SIZE(available_surface_formats
); i
++) {
907 if (sorted_formats
[i
] == VK_FORMAT_B8G8R8A8_UNORM
) {
908 sorted_formats
[i
] = sorted_formats
[0];
909 sorted_formats
[0] = VK_FORMAT_B8G8R8A8_UNORM
;
917 wsi_display_surface_get_formats(VkIcdSurfaceBase
*icd_surface
,
918 struct wsi_device
*wsi_device
,
919 uint32_t *surface_format_count
,
920 VkSurfaceFormatKHR
*surface_formats
)
922 VK_OUTARRAY_MAKE(out
, surface_formats
, surface_format_count
);
924 VkFormat sorted_formats
[ARRAY_SIZE(available_surface_formats
)];
925 get_sorted_vk_formats(wsi_device
, sorted_formats
);
927 for (unsigned i
= 0; i
< ARRAY_SIZE(sorted_formats
); i
++) {
928 vk_outarray_append(&out
, f
) {
929 f
->format
= sorted_formats
[i
];
930 f
->colorSpace
= VK_COLORSPACE_SRGB_NONLINEAR_KHR
;
934 return vk_outarray_status(&out
);
938 wsi_display_surface_get_formats2(VkIcdSurfaceBase
*surface
,
939 struct wsi_device
*wsi_device
,
940 const void *info_next
,
941 uint32_t *surface_format_count
,
942 VkSurfaceFormat2KHR
*surface_formats
)
944 VK_OUTARRAY_MAKE(out
, surface_formats
, surface_format_count
);
946 VkFormat sorted_formats
[ARRAY_SIZE(available_surface_formats
)];
947 get_sorted_vk_formats(wsi_device
, sorted_formats
);
949 for (unsigned i
= 0; i
< ARRAY_SIZE(sorted_formats
); i
++) {
950 vk_outarray_append(&out
, f
) {
951 assert(f
->sType
== VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR
);
952 f
->surfaceFormat
.format
= sorted_formats
[i
];
953 f
->surfaceFormat
.colorSpace
= VK_COLORSPACE_SRGB_NONLINEAR_KHR
;
957 return vk_outarray_status(&out
);
961 wsi_display_surface_get_present_modes(VkIcdSurfaceBase
*surface
,
962 uint32_t *present_mode_count
,
963 VkPresentModeKHR
*present_modes
)
965 VK_OUTARRAY_MAKE(conn
, present_modes
, present_mode_count
);
967 vk_outarray_append(&conn
, present
) {
968 *present
= VK_PRESENT_MODE_FIFO_KHR
;
971 return vk_outarray_status(&conn
);
975 wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase
*surface_base
,
976 struct wsi_device
*wsi_device
,
977 uint32_t* pRectCount
,
980 VkIcdSurfaceDisplay
*surface
= (VkIcdSurfaceDisplay
*) surface_base
;
981 wsi_display_mode
*mode
= wsi_display_mode_from_handle(surface
->displayMode
);
982 VK_OUTARRAY_MAKE(out
, pRects
, pRectCount
);
984 if (wsi_device_matches_drm_fd(wsi_device
, mode
->connector
->wsi
->fd
)) {
985 vk_outarray_append(&out
, rect
) {
988 .extent
= { mode
->hdisplay
, mode
->vdisplay
},
993 return vk_outarray_status(&out
);
997 wsi_display_destroy_buffer(struct wsi_display
*wsi
,
1000 (void) drmIoctl(wsi
->fd
, DRM_IOCTL_GEM_CLOSE
,
1001 &((struct drm_gem_close
) { .handle
= buffer
}));
1005 wsi_display_image_init(VkDevice device_h
,
1006 struct wsi_swapchain
*drv_chain
,
1007 const VkSwapchainCreateInfoKHR
*create_info
,
1008 const VkAllocationCallbacks
*allocator
,
1009 struct wsi_display_image
*image
)
1011 struct wsi_display_swapchain
*chain
=
1012 (struct wsi_display_swapchain
*) drv_chain
;
1013 struct wsi_display
*wsi
= chain
->wsi
;
1014 uint32_t drm_format
= 0;
1016 for (unsigned i
= 0; i
< ARRAY_SIZE(available_surface_formats
); i
++) {
1017 if (create_info
->imageFormat
== available_surface_formats
[i
].format
) {
1018 drm_format
= available_surface_formats
[i
].drm_format
;
1023 /* the application provided an invalid format, bail */
1024 if (drm_format
== 0)
1025 return VK_ERROR_DEVICE_LOST
;
1027 VkResult result
= wsi_create_native_image(&chain
->base
, create_info
,
1030 if (result
!= VK_SUCCESS
)
1033 memset(image
->buffer
, 0, sizeof (image
->buffer
));
1035 for (unsigned int i
= 0; i
< image
->base
.num_planes
; i
++) {
1036 int ret
= drmPrimeFDToHandle(wsi
->fd
, image
->base
.fds
[i
],
1039 close(image
->base
.fds
[i
]);
1040 image
->base
.fds
[i
] = -1;
1045 image
->chain
= chain
;
1046 image
->state
= WSI_IMAGE_IDLE
;
1049 int ret
= drmModeAddFB2(wsi
->fd
,
1050 create_info
->imageExtent
.width
,
1051 create_info
->imageExtent
.height
,
1054 image
->base
.row_pitches
,
1055 image
->base
.offsets
,
1065 for (unsigned int i
= 0; i
< image
->base
.num_planes
; i
++) {
1066 if (image
->buffer
[i
])
1067 wsi_display_destroy_buffer(wsi
, image
->buffer
[i
]);
1068 if (image
->base
.fds
[i
] != -1) {
1069 close(image
->base
.fds
[i
]);
1070 image
->base
.fds
[i
] = -1;
1074 wsi_destroy_image(&chain
->base
, &image
->base
);
1076 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1080 wsi_display_image_finish(struct wsi_swapchain
*drv_chain
,
1081 const VkAllocationCallbacks
*allocator
,
1082 struct wsi_display_image
*image
)
1084 struct wsi_display_swapchain
*chain
=
1085 (struct wsi_display_swapchain
*) drv_chain
;
1086 struct wsi_display
*wsi
= chain
->wsi
;
1088 drmModeRmFB(wsi
->fd
, image
->fb_id
);
1089 for (unsigned int i
= 0; i
< image
->base
.num_planes
; i
++)
1090 wsi_display_destroy_buffer(wsi
, image
->buffer
[i
]);
1091 wsi_destroy_image(&chain
->base
, &image
->base
);
1095 wsi_display_swapchain_destroy(struct wsi_swapchain
*drv_chain
,
1096 const VkAllocationCallbacks
*allocator
)
1098 struct wsi_display_swapchain
*chain
=
1099 (struct wsi_display_swapchain
*) drv_chain
;
1101 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++)
1102 wsi_display_image_finish(drv_chain
, allocator
, &chain
->images
[i
]);
1104 wsi_swapchain_finish(&chain
->base
);
1105 vk_free(allocator
, chain
);
1109 static struct wsi_image
*
1110 wsi_display_get_wsi_image(struct wsi_swapchain
*drv_chain
,
1111 uint32_t image_index
)
1113 struct wsi_display_swapchain
*chain
=
1114 (struct wsi_display_swapchain
*) drv_chain
;
1116 return &chain
->images
[image_index
].base
;
1120 wsi_display_idle_old_displaying(struct wsi_display_image
*active_image
)
1122 struct wsi_display_swapchain
*chain
= active_image
->chain
;
1124 wsi_display_debug("idle everyone but %ld\n",
1125 active_image
- &(chain
->images
[0]));
1126 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++)
1127 if (chain
->images
[i
].state
== WSI_IMAGE_DISPLAYING
&&
1128 &chain
->images
[i
] != active_image
)
1130 wsi_display_debug("idle %d\n", i
);
1131 chain
->images
[i
].state
= WSI_IMAGE_IDLE
;
1136 _wsi_display_queue_next(struct wsi_swapchain
*drv_chain
);
1139 wsi_display_page_flip_handler2(int fd
,
1146 struct wsi_display_image
*image
= data
;
1147 struct wsi_display_swapchain
*chain
= image
->chain
;
1149 wsi_display_debug("image %ld displayed at %d\n",
1150 image
- &(image
->chain
->images
[0]), frame
);
1151 image
->state
= WSI_IMAGE_DISPLAYING
;
1152 wsi_display_idle_old_displaying(image
);
1153 VkResult result
= _wsi_display_queue_next(&(chain
->base
));
1154 if (result
!= VK_SUCCESS
)
1155 chain
->status
= result
;
1158 static void wsi_display_fence_event_handler(struct wsi_display_fence
*fence
);
1160 static void wsi_display_page_flip_handler(int fd
,
1166 wsi_display_page_flip_handler2(fd
, frame
, sec
, usec
, 0, data
);
1169 static void wsi_display_vblank_handler(int fd
, unsigned int frame
,
1170 unsigned int sec
, unsigned int usec
,
1173 struct wsi_display_fence
*fence
= data
;
1175 wsi_display_fence_event_handler(fence
);
1178 static void wsi_display_sequence_handler(int fd
, uint64_t frame
,
1179 uint64_t nsec
, uint64_t user_data
)
1181 struct wsi_display_fence
*fence
=
1182 (struct wsi_display_fence
*) (uintptr_t) user_data
;
1184 wsi_display_fence_event_handler(fence
);
1187 static drmEventContext event_context
= {
1188 .version
= DRM_EVENT_CONTEXT_VERSION
,
1189 .page_flip_handler
= wsi_display_page_flip_handler
,
1190 #if DRM_EVENT_CONTEXT_VERSION >= 3
1191 .page_flip_handler2
= wsi_display_page_flip_handler2
,
1193 .vblank_handler
= wsi_display_vblank_handler
,
1194 .sequence_handler
= wsi_display_sequence_handler
,
1198 wsi_display_wait_thread(void *data
)
1200 struct wsi_display
*wsi
= data
;
1201 struct pollfd pollfd
= {
1206 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
1208 int ret
= poll(&pollfd
, 1, -1);
1210 pthread_mutex_lock(&wsi
->wait_mutex
);
1211 (void) drmHandleEvent(wsi
->fd
, &event_context
);
1212 pthread_mutex_unlock(&wsi
->wait_mutex
);
1213 pthread_cond_broadcast(&wsi
->wait_cond
);
1220 wsi_display_start_wait_thread(struct wsi_display
*wsi
)
1222 if (!wsi
->wait_thread
) {
1223 int ret
= pthread_create(&wsi
->wait_thread
, NULL
,
1224 wsi_display_wait_thread
, wsi
);
1232 * Wait for at least one event from the kernel to be processed.
1233 * Call with wait_mutex held
1236 wsi_display_wait_for_event(struct wsi_display
*wsi
,
1237 uint64_t timeout_ns
)
1241 ret
= wsi_display_start_wait_thread(wsi
);
1246 struct timespec abs_timeout
= {
1247 .tv_sec
= timeout_ns
/ 1000000000ULL,
1248 .tv_nsec
= timeout_ns
% 1000000000ULL,
1251 ret
= pthread_cond_timedwait(&wsi
->wait_cond
, &wsi
->wait_mutex
,
1254 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret
);
1259 wsi_display_acquire_next_image(struct wsi_swapchain
*drv_chain
,
1260 const VkAcquireNextImageInfoKHR
*info
,
1261 uint32_t *image_index
)
1263 struct wsi_display_swapchain
*chain
=
1264 (struct wsi_display_swapchain
*)drv_chain
;
1265 struct wsi_display
*wsi
= chain
->wsi
;
1267 VkResult result
= VK_SUCCESS
;
1269 /* Bail early if the swapchain is broken */
1270 if (chain
->status
!= VK_SUCCESS
)
1271 return chain
->status
;
1273 uint64_t timeout
= info
->timeout
;
1274 if (timeout
!= 0 && timeout
!= UINT64_MAX
)
1275 timeout
= wsi_rel_to_abs_time(timeout
);
1277 pthread_mutex_lock(&wsi
->wait_mutex
);
1279 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++) {
1280 if (chain
->images
[i
].state
== WSI_IMAGE_IDLE
) {
1282 wsi_display_debug("image %d available\n", i
);
1283 chain
->images
[i
].state
= WSI_IMAGE_DRAWING
;
1284 result
= VK_SUCCESS
;
1287 wsi_display_debug("image %d state %d\n", i
, chain
->images
[i
].state
);
1290 if (ret
== ETIMEDOUT
) {
1291 result
= VK_TIMEOUT
;
1295 ret
= wsi_display_wait_for_event(wsi
, timeout
);
1297 if (ret
&& ret
!= ETIMEDOUT
) {
1298 result
= VK_ERROR_SURFACE_LOST_KHR
;
1303 pthread_mutex_unlock(&wsi
->wait_mutex
);
1305 if (result
!= VK_SUCCESS
)
1308 return chain
->status
;
1312 * Check whether there are any other connectors driven by this crtc
1315 wsi_display_crtc_solo(struct wsi_display
*wsi
,
1316 drmModeResPtr mode_res
,
1317 drmModeConnectorPtr connector
,
1320 /* See if any other connectors share the same encoder */
1321 for (int c
= 0; c
< mode_res
->count_connectors
; c
++) {
1322 if (mode_res
->connectors
[c
] == connector
->connector_id
)
1325 drmModeConnectorPtr other_connector
=
1326 drmModeGetConnector(wsi
->fd
, mode_res
->connectors
[c
]);
1328 if (other_connector
) {
1329 bool match
= (other_connector
->encoder_id
== connector
->encoder_id
);
1330 drmModeFreeConnector(other_connector
);
1336 /* See if any other encoders share the same crtc */
1337 for (int e
= 0; e
< mode_res
->count_encoders
; e
++) {
1338 if (mode_res
->encoders
[e
] == connector
->encoder_id
)
1341 drmModeEncoderPtr other_encoder
=
1342 drmModeGetEncoder(wsi
->fd
, mode_res
->encoders
[e
]);
1344 if (other_encoder
) {
1345 bool match
= (other_encoder
->crtc_id
== crtc_id
);
1346 drmModeFreeEncoder(other_encoder
);
1355 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1356 * currently driving this connector and not any others. Settle for a CRTC
1357 * which is currently idle.
1360 wsi_display_select_crtc(const struct wsi_display_connector
*connector
,
1361 drmModeResPtr mode_res
,
1362 drmModeConnectorPtr drm_connector
)
1364 struct wsi_display
*wsi
= connector
->wsi
;
1366 /* See what CRTC is currently driving this connector */
1367 if (drm_connector
->encoder_id
) {
1368 drmModeEncoderPtr encoder
=
1369 drmModeGetEncoder(wsi
->fd
, drm_connector
->encoder_id
);
1372 uint32_t crtc_id
= encoder
->crtc_id
;
1373 drmModeFreeEncoder(encoder
);
1375 if (wsi_display_crtc_solo(wsi
, mode_res
, drm_connector
, crtc_id
))
1380 uint32_t crtc_id
= 0;
1381 for (int c
= 0; crtc_id
== 0 && c
< mode_res
->count_crtcs
; c
++) {
1382 drmModeCrtcPtr crtc
= drmModeGetCrtc(wsi
->fd
, mode_res
->crtcs
[c
]);
1383 if (crtc
&& crtc
->buffer_id
== 0)
1384 crtc_id
= crtc
->crtc_id
;
1385 drmModeFreeCrtc(crtc
);
1391 wsi_display_setup_connector(wsi_display_connector
*connector
,
1392 wsi_display_mode
*display_mode
)
1394 struct wsi_display
*wsi
= connector
->wsi
;
1396 if (connector
->current_mode
== display_mode
&& connector
->crtc_id
)
1399 VkResult result
= VK_SUCCESS
;
1401 drmModeResPtr mode_res
= drmModeGetResources(wsi
->fd
);
1403 if (errno
== ENOMEM
)
1404 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1406 result
= VK_ERROR_SURFACE_LOST_KHR
;
1410 drmModeConnectorPtr drm_connector
=
1411 drmModeGetConnectorCurrent(wsi
->fd
, connector
->id
);
1413 if (!drm_connector
) {
1414 if (errno
== ENOMEM
)
1415 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1417 result
= VK_ERROR_SURFACE_LOST_KHR
;
1421 /* Pick a CRTC if we don't have one */
1422 if (!connector
->crtc_id
) {
1423 connector
->crtc_id
= wsi_display_select_crtc(connector
,
1424 mode_res
, drm_connector
);
1425 if (!connector
->crtc_id
) {
1426 result
= VK_ERROR_SURFACE_LOST_KHR
;
1427 goto bail_connector
;
1431 if (connector
->current_mode
!= display_mode
) {
1433 /* Find the drm mode corresponding to the requested VkDisplayMode */
1434 drmModeModeInfoPtr drm_mode
= NULL
;
1436 for (int m
= 0; m
< drm_connector
->count_modes
; m
++) {
1437 drm_mode
= &drm_connector
->modes
[m
];
1438 if (wsi_display_mode_matches_drm(display_mode
, drm_mode
))
1444 result
= VK_ERROR_SURFACE_LOST_KHR
;
1445 goto bail_connector
;
1448 connector
->current_mode
= display_mode
;
1449 connector
->current_drm_mode
= *drm_mode
;
1453 drmModeFreeConnector(drm_connector
);
1455 drmModeFreeResources(mode_res
);
1462 wsi_display_fence_wait(struct wsi_fence
*fence_wsi
, uint64_t timeout
)
1464 const struct wsi_device
*wsi_device
= fence_wsi
->wsi_device
;
1465 struct wsi_display
*wsi
=
1466 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1467 struct wsi_display_fence
*fence
= (struct wsi_display_fence
*) fence_wsi
;
1469 wsi_display_debug("%9lu wait fence %lu %ld\n",
1470 pthread_self(), fence
->sequence
,
1471 (int64_t) (timeout
- wsi_common_get_current_time()));
1472 wsi_display_debug_code(uint64_t start_ns
= wsi_common_get_current_time());
1473 pthread_mutex_lock(&wsi
->wait_mutex
);
1478 if (fence
->event_received
) {
1479 wsi_display_debug("%9lu fence %lu passed\n",
1480 pthread_self(), fence
->sequence
);
1481 result
= VK_SUCCESS
;
1485 if (ret
== ETIMEDOUT
) {
1486 wsi_display_debug("%9lu fence %lu timeout\n",
1487 pthread_self(), fence
->sequence
);
1488 result
= VK_TIMEOUT
;
1492 ret
= wsi_display_wait_for_event(wsi
, timeout
);
1494 if (ret
&& ret
!= ETIMEDOUT
) {
1495 wsi_display_debug("%9lu fence %lu error\n",
1496 pthread_self(), fence
->sequence
);
1497 result
= VK_ERROR_DEVICE_LOST
;
1501 pthread_mutex_unlock(&wsi
->wait_mutex
);
1502 wsi_display_debug("%9lu fence wait %f ms\n",
1504 ((int64_t) (wsi_common_get_current_time() - start_ns
)) /
1510 wsi_display_fence_check_free(struct wsi_display_fence
*fence
)
1512 if (fence
->event_received
&& fence
->destroyed
)
1513 vk_free(fence
->base
.alloc
, fence
);
1516 static void wsi_display_fence_event_handler(struct wsi_display_fence
*fence
)
1518 fence
->event_received
= true;
1519 wsi_display_fence_check_free(fence
);
1523 wsi_display_fence_destroy(struct wsi_fence
*fence_wsi
)
1525 struct wsi_display_fence
*fence
= (struct wsi_display_fence
*) fence_wsi
;
1527 assert(!fence
->destroyed
);
1528 fence
->destroyed
= true;
1529 wsi_display_fence_check_free(fence
);
1532 static struct wsi_display_fence
*
1533 wsi_display_fence_alloc(VkDevice device
,
1534 const struct wsi_device
*wsi_device
,
1535 VkDisplayKHR display
,
1536 const VkAllocationCallbacks
*allocator
)
1538 struct wsi_display
*wsi
=
1539 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1540 struct wsi_display_fence
*fence
=
1541 vk_zalloc2(wsi
->alloc
, allocator
, sizeof (*fence
),
1542 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
1547 fence
->base
.device
= device
;
1548 fence
->base
.display
= display
;
1549 fence
->base
.wsi_device
= wsi_device
;
1550 fence
->base
.alloc
= allocator
? allocator
: wsi
->alloc
;
1551 fence
->base
.wait
= wsi_display_fence_wait
;
1552 fence
->base
.destroy
= wsi_display_fence_destroy
;
1553 fence
->event_received
= false;
1554 fence
->destroyed
= false;
1555 fence
->sequence
= ++fence_sequence
;
1560 wsi_register_vblank_event(struct wsi_display_fence
*fence
,
1561 const struct wsi_device
*wsi_device
,
1562 VkDisplayKHR display
,
1564 uint64_t frame_requested
,
1565 uint64_t *frame_queued
)
1567 struct wsi_display
*wsi
=
1568 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1569 struct wsi_display_connector
*connector
=
1570 wsi_display_connector_from_handle(display
);
1573 return VK_ERROR_INITIALIZATION_FAILED
;
1576 int ret
= drmCrtcQueueSequence(wsi
->fd
, connector
->crtc_id
,
1585 if (errno
!= ENOMEM
) {
1587 /* Something unexpected happened. Pause for a moment so the
1588 * application doesn't just spin and then return a failure indication
1591 wsi_display_debug("queue vblank event %lu failed\n", fence
->sequence
);
1592 struct timespec delay
= {
1594 .tv_nsec
= 100000000ull,
1596 nanosleep(&delay
, NULL
);
1597 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1600 /* The kernel event queue is full. Wait for some events to be
1601 * processed and try again
1604 pthread_mutex_lock(&wsi
->wait_mutex
);
1605 ret
= wsi_display_wait_for_event(wsi
, wsi_rel_to_abs_time(100000000ull));
1606 pthread_mutex_unlock(&wsi
->wait_mutex
);
1609 wsi_display_debug("vblank queue full, event wait failed\n");
1610 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1616 * Check to see if the kernel has no flip queued and if there's an image
1617 * waiting to be displayed.
1620 _wsi_display_queue_next(struct wsi_swapchain
*drv_chain
)
1622 struct wsi_display_swapchain
*chain
=
1623 (struct wsi_display_swapchain
*) drv_chain
;
1624 struct wsi_display
*wsi
= chain
->wsi
;
1625 VkIcdSurfaceDisplay
*surface
= chain
->surface
;
1626 wsi_display_mode
*display_mode
=
1627 wsi_display_mode_from_handle(surface
->displayMode
);
1628 wsi_display_connector
*connector
= display_mode
->connector
;
1631 return VK_ERROR_SURFACE_LOST_KHR
;
1633 if (display_mode
!= connector
->current_mode
)
1634 connector
->active
= false;
1638 /* Check to see if there is an image to display, or if some image is
1641 struct wsi_display_image
*image
= NULL
;
1643 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++) {
1644 struct wsi_display_image
*tmp_image
= &chain
->images
[i
];
1646 switch (tmp_image
->state
) {
1647 case WSI_IMAGE_FLIPPING
:
1648 /* already flipping, don't send another to the kernel yet */
1650 case WSI_IMAGE_QUEUED
:
1651 /* find the oldest queued */
1652 if (!image
|| tmp_image
->flip_sequence
< image
->flip_sequence
)
1664 if (connector
->active
) {
1665 ret
= drmModePageFlip(wsi
->fd
, connector
->crtc_id
, image
->fb_id
,
1666 DRM_MODE_PAGE_FLIP_EVENT
, image
);
1668 image
->state
= WSI_IMAGE_FLIPPING
;
1671 wsi_display_debug("page flip err %d %s\n", ret
, strerror(-ret
));
1676 if (ret
== -EINVAL
) {
1677 VkResult result
= wsi_display_setup_connector(connector
, display_mode
);
1679 if (result
!= VK_SUCCESS
) {
1680 image
->state
= WSI_IMAGE_IDLE
;
1684 /* XXX allow setting of position */
1685 ret
= drmModeSetCrtc(wsi
->fd
, connector
->crtc_id
,
1688 &connector
->current_drm_mode
);
1690 /* Disable the HW cursor as the app doesn't have a mechanism
1692 * Refer to question 12 of the VK_KHR_display spec.
1694 ret
= drmModeSetCursor(wsi
->fd
, connector
->crtc_id
, 0, 0, 0 );
1696 wsi_display_debug("failed to hide cursor err %d %s\n", ret
, strerror(-ret
));
1699 /* Assume that the mode set is synchronous and that any
1700 * previous image is now idle.
1702 image
->state
= WSI_IMAGE_DISPLAYING
;
1703 wsi_display_idle_old_displaying(image
);
1704 connector
->active
= true;
1709 if (ret
!= -EACCES
) {
1710 connector
->active
= false;
1711 image
->state
= WSI_IMAGE_IDLE
;
1712 return VK_ERROR_SURFACE_LOST_KHR
;
1715 /* Some other VT is currently active. Sit here waiting for
1716 * our VT to become active again by polling once a second
1718 usleep(1000 * 1000);
1719 connector
->active
= false;
1724 wsi_display_queue_present(struct wsi_swapchain
*drv_chain
,
1725 uint32_t image_index
,
1726 const VkPresentRegionKHR
*damage
)
1728 struct wsi_display_swapchain
*chain
=
1729 (struct wsi_display_swapchain
*) drv_chain
;
1730 struct wsi_display
*wsi
= chain
->wsi
;
1731 struct wsi_display_image
*image
= &chain
->images
[image_index
];
1734 /* Bail early if the swapchain is broken */
1735 if (chain
->status
!= VK_SUCCESS
)
1736 return chain
->status
;
1738 assert(image
->state
== WSI_IMAGE_DRAWING
);
1739 wsi_display_debug("present %d\n", image_index
);
1741 pthread_mutex_lock(&wsi
->wait_mutex
);
1743 image
->flip_sequence
= ++chain
->flip_sequence
;
1744 image
->state
= WSI_IMAGE_QUEUED
;
1746 result
= _wsi_display_queue_next(drv_chain
);
1747 if (result
!= VK_SUCCESS
)
1748 chain
->status
= result
;
1750 pthread_mutex_unlock(&wsi
->wait_mutex
);
1752 if (result
!= VK_SUCCESS
)
1755 return chain
->status
;
1759 wsi_display_surface_create_swapchain(
1760 VkIcdSurfaceBase
*icd_surface
,
1762 struct wsi_device
*wsi_device
,
1763 const VkSwapchainCreateInfoKHR
*create_info
,
1764 const VkAllocationCallbacks
*allocator
,
1765 struct wsi_swapchain
**swapchain_out
)
1767 struct wsi_display
*wsi
=
1768 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1770 assert(create_info
->sType
== VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
);
1772 const unsigned num_images
= create_info
->minImageCount
;
1773 struct wsi_display_swapchain
*chain
=
1774 vk_zalloc(allocator
,
1775 sizeof(*chain
) + num_images
* sizeof(chain
->images
[0]),
1776 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
1779 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1781 VkResult result
= wsi_swapchain_init(wsi_device
, &chain
->base
, device
,
1782 create_info
, allocator
);
1783 if (result
!= VK_SUCCESS
) {
1784 vk_free(allocator
, chain
);
1788 chain
->base
.destroy
= wsi_display_swapchain_destroy
;
1789 chain
->base
.get_wsi_image
= wsi_display_get_wsi_image
;
1790 chain
->base
.acquire_next_image
= wsi_display_acquire_next_image
;
1791 chain
->base
.queue_present
= wsi_display_queue_present
;
1792 chain
->base
.present_mode
= wsi_swapchain_get_present_mode(wsi_device
, create_info
);
1793 chain
->base
.image_count
= num_images
;
1796 chain
->status
= VK_SUCCESS
;
1798 chain
->surface
= (VkIcdSurfaceDisplay
*) icd_surface
;
1800 for (uint32_t image
= 0; image
< chain
->base
.image_count
; image
++) {
1801 result
= wsi_display_image_init(device
, &chain
->base
,
1802 create_info
, allocator
,
1803 &chain
->images
[image
]);
1804 if (result
!= VK_SUCCESS
) {
1807 wsi_display_image_finish(&chain
->base
, allocator
,
1808 &chain
->images
[image
]);
1810 vk_free(allocator
, chain
);
1811 goto fail_init_images
;
1815 *swapchain_out
= &chain
->base
;
1824 wsi_init_pthread_cond_monotonic(pthread_cond_t
*cond
)
1826 pthread_condattr_t condattr
;
1829 if (pthread_condattr_init(&condattr
) != 0)
1830 goto fail_attr_init
;
1832 if (pthread_condattr_setclock(&condattr
, CLOCK_MONOTONIC
) != 0)
1835 if (pthread_cond_init(cond
, &condattr
) != 0)
1836 goto fail_cond_init
;
1842 pthread_condattr_destroy(&condattr
);
1849 * Local version fo the libdrm helper. Added to avoid depending on bleeding
1850 * edge version of the library.
1853 local_drmIsMaster(int fd
)
1855 /* Detect master by attempting something that requires master.
1857 * Authenticating magic tokens requires master and 0 is an
1858 * internal kernel detail which we could use. Attempting this on
1859 * a master fd would fail therefore fail with EINVAL because 0
1862 * A non-master fd will fail with EACCES, as the kernel checks
1863 * for master before attempting to do anything else.
1865 * Since we don't want to leak implementation details, use
1868 return drmAuthMagic(fd
, 0) != -EACCES
;
1872 wsi_display_init_wsi(struct wsi_device
*wsi_device
,
1873 const VkAllocationCallbacks
*alloc
,
1876 struct wsi_display
*wsi
= vk_zalloc(alloc
, sizeof(*wsi
), 8,
1877 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
1881 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1885 wsi
->fd
= display_fd
;
1886 if (wsi
->fd
!= -1 && !local_drmIsMaster(wsi
->fd
))
1891 list_inithead(&wsi
->connectors
);
1893 int ret
= pthread_mutex_init(&wsi
->wait_mutex
, NULL
);
1895 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1899 if (!wsi_init_pthread_cond_monotonic(&wsi
->wait_cond
)) {
1900 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1904 wsi
->base
.get_support
= wsi_display_surface_get_support
;
1905 wsi
->base
.get_capabilities2
= wsi_display_surface_get_capabilities2
;
1906 wsi
->base
.get_formats
= wsi_display_surface_get_formats
;
1907 wsi
->base
.get_formats2
= wsi_display_surface_get_formats2
;
1908 wsi
->base
.get_present_modes
= wsi_display_surface_get_present_modes
;
1909 wsi
->base
.get_present_rectangles
= wsi_display_surface_get_present_rectangles
;
1910 wsi
->base
.create_swapchain
= wsi_display_surface_create_swapchain
;
1912 wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
] = &wsi
->base
;
1917 pthread_mutex_destroy(&wsi
->wait_mutex
);
1919 vk_free(alloc
, wsi
);
1925 wsi_display_finish_wsi(struct wsi_device
*wsi_device
,
1926 const VkAllocationCallbacks
*alloc
)
1928 struct wsi_display
*wsi
=
1929 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1932 wsi_for_each_connector(connector
, wsi
) {
1933 wsi_for_each_display_mode(mode
, connector
) {
1934 vk_free(wsi
->alloc
, mode
);
1936 vk_free(wsi
->alloc
, connector
);
1939 pthread_mutex_lock(&wsi
->wait_mutex
);
1940 if (wsi
->wait_thread
) {
1941 pthread_cancel(wsi
->wait_thread
);
1942 pthread_join(wsi
->wait_thread
, NULL
);
1944 pthread_mutex_unlock(&wsi
->wait_mutex
);
1945 pthread_mutex_destroy(&wsi
->wait_mutex
);
1946 pthread_cond_destroy(&wsi
->wait_cond
);
1948 vk_free(alloc
, wsi
);
1953 * Implement vkReleaseDisplay
1956 wsi_release_display(VkPhysicalDevice physical_device
,
1957 struct wsi_device
*wsi_device
,
1958 VkDisplayKHR display
)
1960 struct wsi_display
*wsi
=
1961 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1967 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1968 wsi_display_connector_from_handle(display
)->output
= None
;
1974 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1976 static struct wsi_display_connector
*
1977 wsi_display_find_output(struct wsi_device
*wsi_device
,
1978 xcb_randr_output_t output
)
1980 struct wsi_display
*wsi
=
1981 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1983 wsi_for_each_connector(connector
, wsi
) {
1984 if (connector
->output
== output
)
1992 * Given a RandR output, find the associated kernel connector_id by
1993 * looking at the CONNECTOR_ID property provided by the X server
1997 wsi_display_output_to_connector_id(xcb_connection_t
*connection
,
1998 xcb_atom_t
*connector_id_atom_p
,
1999 xcb_randr_output_t output
)
2001 uint32_t connector_id
= 0;
2002 xcb_atom_t connector_id_atom
= *connector_id_atom_p
;
2004 if (connector_id_atom
== 0) {
2005 /* Go dig out the CONNECTOR_ID property */
2006 xcb_intern_atom_cookie_t ia_c
= xcb_intern_atom(connection
,
2010 xcb_intern_atom_reply_t
*ia_r
= xcb_intern_atom_reply(connection
,
2014 *connector_id_atom_p
= connector_id_atom
= ia_r
->atom
;
2019 /* If there's an CONNECTOR_ID atom in the server, then there may be a
2020 * CONNECTOR_ID property. Otherwise, there will not be and we don't even
2023 if (connector_id_atom
) {
2025 xcb_randr_query_version_cookie_t qv_c
=
2026 xcb_randr_query_version(connection
, 1, 6);
2027 xcb_randr_get_output_property_cookie_t gop_c
=
2028 xcb_randr_get_output_property(connection
,
2036 xcb_randr_query_version_reply_t
*qv_r
=
2037 xcb_randr_query_version_reply(connection
, qv_c
, NULL
);
2039 xcb_randr_get_output_property_reply_t
*gop_r
=
2040 xcb_randr_get_output_property_reply(connection
, gop_c
, NULL
);
2042 if (gop_r
->num_items
== 1 && gop_r
->format
== 32)
2043 memcpy(&connector_id
, xcb_randr_get_output_property_data(gop_r
), 4);
2047 return connector_id
;
2051 wsi_display_check_randr_version(xcb_connection_t
*connection
)
2053 xcb_randr_query_version_cookie_t qv_c
=
2054 xcb_randr_query_version(connection
, 1, 6);
2055 xcb_randr_query_version_reply_t
*qv_r
=
2056 xcb_randr_query_version_reply(connection
, qv_c
, NULL
);
2062 /* Check for version 1.6 or newer */
2063 ret
= (qv_r
->major_version
> 1 ||
2064 (qv_r
->major_version
== 1 && qv_r
->minor_version
>= 6));
2071 * Given a kernel connector id, find the associated RandR output using the
2072 * CONNECTOR_ID property
2075 static xcb_randr_output_t
2076 wsi_display_connector_id_to_output(xcb_connection_t
*connection
,
2077 uint32_t connector_id
)
2079 if (!wsi_display_check_randr_version(connection
))
2082 const xcb_setup_t
*setup
= xcb_get_setup(connection
);
2084 xcb_atom_t connector_id_atom
= 0;
2085 xcb_randr_output_t output
= 0;
2087 /* Search all of the screens for the provided output */
2088 xcb_screen_iterator_t iter
;
2089 for (iter
= xcb_setup_roots_iterator(setup
);
2090 output
== 0 && iter
.rem
;
2091 xcb_screen_next(&iter
))
2093 xcb_randr_get_screen_resources_cookie_t gsr_c
=
2094 xcb_randr_get_screen_resources(connection
, iter
.data
->root
);
2095 xcb_randr_get_screen_resources_reply_t
*gsr_r
=
2096 xcb_randr_get_screen_resources_reply(connection
, gsr_c
, NULL
);
2101 xcb_randr_output_t
*ro
= xcb_randr_get_screen_resources_outputs(gsr_r
);
2104 for (o
= 0; o
< gsr_r
->num_outputs
; o
++) {
2105 if (wsi_display_output_to_connector_id(connection
,
2106 &connector_id_atom
, ro
[o
])
2119 * Given a RandR output, find out which screen it's associated with
2122 wsi_display_output_to_root(xcb_connection_t
*connection
,
2123 xcb_randr_output_t output
)
2125 if (!wsi_display_check_randr_version(connection
))
2128 const xcb_setup_t
*setup
= xcb_get_setup(connection
);
2129 xcb_window_t root
= 0;
2131 /* Search all of the screens for the provided output */
2132 for (xcb_screen_iterator_t iter
= xcb_setup_roots_iterator(setup
);
2133 root
== 0 && iter
.rem
;
2134 xcb_screen_next(&iter
))
2136 xcb_randr_get_screen_resources_cookie_t gsr_c
=
2137 xcb_randr_get_screen_resources(connection
, iter
.data
->root
);
2138 xcb_randr_get_screen_resources_reply_t
*gsr_r
=
2139 xcb_randr_get_screen_resources_reply(connection
, gsr_c
, NULL
);
2144 xcb_randr_output_t
*ro
= xcb_randr_get_screen_resources_outputs(gsr_r
);
2146 for (int o
= 0; o
< gsr_r
->num_outputs
; o
++) {
2147 if (ro
[o
] == output
) {
2148 root
= iter
.data
->root
;
2158 wsi_display_mode_matches_x(struct wsi_display_mode
*wsi
,
2159 xcb_randr_mode_info_t
*xcb
)
2161 return wsi
->clock
== (xcb
->dot_clock
+ 500) / 1000 &&
2162 wsi
->hdisplay
== xcb
->width
&&
2163 wsi
->hsync_start
== xcb
->hsync_start
&&
2164 wsi
->hsync_end
== xcb
->hsync_end
&&
2165 wsi
->htotal
== xcb
->htotal
&&
2166 wsi
->hskew
== xcb
->hskew
&&
2167 wsi
->vdisplay
== xcb
->height
&&
2168 wsi
->vsync_start
== xcb
->vsync_start
&&
2169 wsi
->vsync_end
== xcb
->vsync_end
&&
2170 wsi
->vtotal
== xcb
->vtotal
&&
2172 wsi
->flags
== xcb
->mode_flags
;
2175 static struct wsi_display_mode
*
2176 wsi_display_find_x_mode(struct wsi_device
*wsi_device
,
2177 struct wsi_display_connector
*connector
,
2178 xcb_randr_mode_info_t
*mode
)
2180 wsi_for_each_display_mode(display_mode
, connector
) {
2181 if (wsi_display_mode_matches_x(display_mode
, mode
))
2182 return display_mode
;
2188 wsi_display_register_x_mode(struct wsi_device
*wsi_device
,
2189 struct wsi_display_connector
*connector
,
2190 xcb_randr_mode_info_t
*x_mode
,
2193 struct wsi_display
*wsi
=
2194 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
2195 struct wsi_display_mode
*display_mode
=
2196 wsi_display_find_x_mode(wsi_device
, connector
, x_mode
);
2199 display_mode
->valid
= true;
2203 display_mode
= vk_zalloc(wsi
->alloc
, sizeof (struct wsi_display_mode
),
2204 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
2206 return VK_ERROR_OUT_OF_HOST_MEMORY
;
2208 display_mode
->connector
= connector
;
2209 display_mode
->valid
= true;
2210 display_mode
->preferred
= preferred
;
2211 display_mode
->clock
= (x_mode
->dot_clock
+ 500) / 1000; /* kHz */
2212 display_mode
->hdisplay
= x_mode
->width
;
2213 display_mode
->hsync_start
= x_mode
->hsync_start
;
2214 display_mode
->hsync_end
= x_mode
->hsync_end
;
2215 display_mode
->htotal
= x_mode
->htotal
;
2216 display_mode
->hskew
= x_mode
->hskew
;
2217 display_mode
->vdisplay
= x_mode
->height
;
2218 display_mode
->vsync_start
= x_mode
->vsync_start
;
2219 display_mode
->vsync_end
= x_mode
->vsync_end
;
2220 display_mode
->vtotal
= x_mode
->vtotal
;
2221 display_mode
->vscan
= 0;
2222 display_mode
->flags
= x_mode
->mode_flags
;
2224 list_addtail(&display_mode
->list
, &connector
->display_modes
);
2228 static struct wsi_display_connector
*
2229 wsi_display_get_output(struct wsi_device
*wsi_device
,
2230 xcb_connection_t
*connection
,
2231 xcb_randr_output_t output
)
2233 struct wsi_display
*wsi
=
2234 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
2235 struct wsi_display_connector
*connector
;
2236 uint32_t connector_id
;
2238 xcb_window_t root
= wsi_display_output_to_root(connection
, output
);
2242 /* See if we already have a connector for this output */
2243 connector
= wsi_display_find_output(wsi_device
, output
);
2246 xcb_atom_t connector_id_atom
= 0;
2249 * Go get the kernel connector ID for this X output
2251 connector_id
= wsi_display_output_to_connector_id(connection
,
2255 /* Any X server with lease support will have this atom */
2256 if (!connector_id
) {
2260 /* See if we already have a connector for this id */
2261 connector
= wsi_display_find_connector(wsi_device
, connector_id
);
2263 if (connector
== NULL
) {
2264 connector
= wsi_display_alloc_connector(wsi
, connector_id
);
2268 list_addtail(&connector
->list
, &wsi
->connectors
);
2270 connector
->output
= output
;
2273 xcb_randr_get_screen_resources_cookie_t src
=
2274 xcb_randr_get_screen_resources(connection
, root
);
2275 xcb_randr_get_output_info_cookie_t oic
=
2276 xcb_randr_get_output_info(connection
, output
, XCB_CURRENT_TIME
);
2277 xcb_randr_get_screen_resources_reply_t
*srr
=
2278 xcb_randr_get_screen_resources_reply(connection
, src
, NULL
);
2279 xcb_randr_get_output_info_reply_t
*oir
=
2280 xcb_randr_get_output_info_reply(connection
, oic
, NULL
);
2283 /* Get X modes and add them */
2285 connector
->connected
=
2286 oir
->connection
!= XCB_RANDR_CONNECTION_DISCONNECTED
;
2288 wsi_display_invalidate_connector_modes(wsi_device
, connector
);
2290 xcb_randr_mode_t
*x_modes
= xcb_randr_get_output_info_modes(oir
);
2291 for (int m
= 0; m
< oir
->num_modes
; m
++) {
2292 xcb_randr_mode_info_iterator_t i
=
2293 xcb_randr_get_screen_resources_modes_iterator(srr
);
2295 xcb_randr_mode_info_t
*mi
= i
.data
;
2296 if (mi
->id
== x_modes
[m
]) {
2297 VkResult result
= wsi_display_register_x_mode(
2298 wsi_device
, connector
, mi
, m
< oir
->num_preferred
);
2299 if (result
!= VK_SUCCESS
) {
2306 xcb_randr_mode_info_next(&i
);
2316 static xcb_randr_crtc_t
2317 wsi_display_find_crtc_for_output(xcb_connection_t
*connection
,
2319 xcb_randr_output_t output
)
2321 xcb_randr_get_screen_resources_cookie_t gsr_c
=
2322 xcb_randr_get_screen_resources(connection
, root
);
2323 xcb_randr_get_screen_resources_reply_t
*gsr_r
=
2324 xcb_randr_get_screen_resources_reply(connection
, gsr_c
, NULL
);
2329 xcb_randr_crtc_t
*rc
= xcb_randr_get_screen_resources_crtcs(gsr_r
);
2330 xcb_randr_crtc_t idle_crtc
= 0;
2331 xcb_randr_crtc_t active_crtc
= 0;
2333 /* Find either a crtc already connected to the desired output or idle */
2334 for (int c
= 0; active_crtc
== 0 && c
< gsr_r
->num_crtcs
; c
++) {
2335 xcb_randr_get_crtc_info_cookie_t gci_c
=
2336 xcb_randr_get_crtc_info(connection
, rc
[c
], gsr_r
->config_timestamp
);
2337 xcb_randr_get_crtc_info_reply_t
*gci_r
=
2338 xcb_randr_get_crtc_info_reply(connection
, gci_c
, NULL
);
2342 int num_outputs
= xcb_randr_get_crtc_info_outputs_length(gci_r
);
2343 xcb_randr_output_t
*outputs
=
2344 xcb_randr_get_crtc_info_outputs(gci_r
);
2346 if (num_outputs
== 1 && outputs
[0] == output
)
2347 active_crtc
= rc
[c
];
2349 } else if (idle_crtc
== 0) {
2350 int num_possible
= xcb_randr_get_crtc_info_possible_length(gci_r
);
2351 xcb_randr_output_t
*possible
=
2352 xcb_randr_get_crtc_info_possible(gci_r
);
2354 for (int p
= 0; p
< num_possible
; p
++)
2355 if (possible
[p
] == output
) {
2371 wsi_acquire_xlib_display(VkPhysicalDevice physical_device
,
2372 struct wsi_device
*wsi_device
,
2374 VkDisplayKHR display
)
2376 struct wsi_display
*wsi
=
2377 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
2378 xcb_connection_t
*connection
= XGetXCBConnection(dpy
);
2379 struct wsi_display_connector
*connector
=
2380 wsi_display_connector_from_handle(display
);
2383 /* XXX no support for multiple leases yet */
2385 return VK_ERROR_INITIALIZATION_FAILED
;
2387 if (!connector
->output
) {
2388 connector
->output
= wsi_display_connector_id_to_output(connection
,
2391 /* Check and see if we found the output */
2392 if (!connector
->output
)
2393 return VK_ERROR_INITIALIZATION_FAILED
;
2396 root
= wsi_display_output_to_root(connection
, connector
->output
);
2398 return VK_ERROR_INITIALIZATION_FAILED
;
2400 xcb_randr_crtc_t crtc
= wsi_display_find_crtc_for_output(connection
,
2405 return VK_ERROR_INITIALIZATION_FAILED
;
2407 #ifdef HAVE_DRI3_MODIFIERS
2408 xcb_randr_lease_t lease
= xcb_generate_id(connection
);
2409 xcb_randr_create_lease_cookie_t cl_c
=
2410 xcb_randr_create_lease(connection
, root
, lease
, 1, 1,
2411 &crtc
, &connector
->output
);
2412 xcb_randr_create_lease_reply_t
*cl_r
=
2413 xcb_randr_create_lease_reply(connection
, cl_c
, NULL
);
2415 return VK_ERROR_INITIALIZATION_FAILED
;
2418 if (cl_r
->nfd
> 0) {
2419 int *rcl_f
= xcb_randr_create_lease_reply_fds(connection
, cl_r
);
2425 return VK_ERROR_INITIALIZATION_FAILED
;
2434 wsi_get_randr_output_display(VkPhysicalDevice physical_device
,
2435 struct wsi_device
*wsi_device
,
2438 VkDisplayKHR
*display
)
2440 xcb_connection_t
*connection
= XGetXCBConnection(dpy
);
2441 struct wsi_display_connector
*connector
=
2442 wsi_display_get_output(wsi_device
, connection
, (xcb_randr_output_t
) output
);
2445 *display
= wsi_display_connector_to_handle(connector
);
2447 *display
= VK_NULL_HANDLE
;
2453 /* VK_EXT_display_control */
2455 wsi_display_power_control(VkDevice device
,
2456 struct wsi_device
*wsi_device
,
2457 VkDisplayKHR display
,
2458 const VkDisplayPowerInfoEXT
*display_power_info
)
2460 struct wsi_display
*wsi
=
2461 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
2462 struct wsi_display_connector
*connector
=
2463 wsi_display_connector_from_handle(display
);
2467 return VK_ERROR_INITIALIZATION_FAILED
;
2469 switch (display_power_info
->powerState
) {
2470 case VK_DISPLAY_POWER_STATE_OFF_EXT
:
2471 mode
= DRM_MODE_DPMS_OFF
;
2473 case VK_DISPLAY_POWER_STATE_SUSPEND_EXT
:
2474 mode
= DRM_MODE_DPMS_SUSPEND
;
2477 mode
= DRM_MODE_DPMS_ON
;
2480 drmModeConnectorSetProperty(wsi
->fd
,
2482 connector
->dpms_property
,
2488 wsi_register_device_event(VkDevice device
,
2489 struct wsi_device
*wsi_device
,
2490 const VkDeviceEventInfoEXT
*device_event_info
,
2491 const VkAllocationCallbacks
*allocator
,
2492 struct wsi_fence
**fence_p
)
2494 return VK_ERROR_FEATURE_NOT_PRESENT
;
2498 wsi_register_display_event(VkDevice device
,
2499 struct wsi_device
*wsi_device
,
2500 VkDisplayKHR display
,
2501 const VkDisplayEventInfoEXT
*display_event_info
,
2502 const VkAllocationCallbacks
*allocator
,
2503 struct wsi_fence
**fence_p
)
2505 struct wsi_display
*wsi
=
2506 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
2507 struct wsi_display_fence
*fence
;
2510 switch (display_event_info
->displayEvent
) {
2511 case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT
:
2513 fence
= wsi_display_fence_alloc(device
, wsi_device
, display
, allocator
);
2516 return VK_ERROR_OUT_OF_HOST_MEMORY
;
2518 ret
= wsi_register_vblank_event(fence
, wsi_device
, display
,
2519 DRM_CRTC_SEQUENCE_RELATIVE
, 1, NULL
);
2521 if (ret
== VK_SUCCESS
)
2522 *fence_p
= &fence
->base
;
2523 else if (fence
!= NULL
)
2524 vk_free2(wsi
->alloc
, allocator
, fence
);
2528 ret
= VK_ERROR_FEATURE_NOT_PRESENT
;
2537 wsi_get_swapchain_counter(VkDevice device
,
2538 struct wsi_device
*wsi_device
,
2539 VkSwapchainKHR _swapchain
,
2540 VkSurfaceCounterFlagBitsEXT flag_bits
,
2543 struct wsi_display
*wsi
=
2544 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
2545 struct wsi_display_swapchain
*swapchain
=
2546 (struct wsi_display_swapchain
*) wsi_swapchain_from_handle(_swapchain
);
2547 struct wsi_display_connector
*connector
=
2548 wsi_display_mode_from_handle(swapchain
->surface
->displayMode
)->connector
;
2551 return VK_ERROR_INITIALIZATION_FAILED
;
2553 if (!connector
->active
) {
2558 int ret
= drmCrtcGetSequence(wsi
->fd
, connector
->crtc_id
, value
, NULL
);