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_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 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
83 xcb_randr_output_t output
;
85 } wsi_display_connector
;
88 struct wsi_interface base
;
90 const VkAllocationCallbacks
*alloc
;
94 pthread_mutex_t wait_mutex
;
95 pthread_cond_t wait_cond
;
96 pthread_t wait_thread
;
98 struct list_head connectors
;
101 #define wsi_for_each_display_mode(_mode, _conn) \
102 list_for_each_entry_safe(struct wsi_display_mode, _mode, \
103 &(_conn)->display_modes, list)
105 #define wsi_for_each_connector(_conn, _dev) \
106 list_for_each_entry_safe(struct wsi_display_connector, _conn, \
107 &(_dev)->connectors, list)
109 enum wsi_image_state
{
117 struct wsi_display_image
{
118 struct wsi_image base
;
119 struct wsi_display_swapchain
*chain
;
120 enum wsi_image_state state
;
123 uint64_t flip_sequence
;
126 struct wsi_display_swapchain
{
127 struct wsi_swapchain base
;
128 struct wsi_display
*wsi
;
129 VkIcdSurfaceDisplay
*surface
;
130 uint64_t flip_sequence
;
132 struct wsi_display_image images
[0];
135 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode
, VkDisplayModeKHR
)
136 ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector
, VkDisplayKHR
)
139 wsi_display_mode_matches_drm(wsi_display_mode
*wsi
,
140 drmModeModeInfoPtr drm
)
142 return wsi
->clock
== drm
->clock
&&
143 wsi
->hdisplay
== drm
->hdisplay
&&
144 wsi
->hsync_start
== drm
->hsync_start
&&
145 wsi
->hsync_end
== drm
->hsync_end
&&
146 wsi
->htotal
== drm
->htotal
&&
147 wsi
->hskew
== drm
->hskew
&&
148 wsi
->vdisplay
== drm
->vdisplay
&&
149 wsi
->vsync_start
== drm
->vsync_start
&&
150 wsi
->vsync_end
== drm
->vsync_end
&&
151 wsi
->vtotal
== drm
->vtotal
&&
152 MAX2(wsi
->vscan
, 1) == MAX2(drm
->vscan
, 1) &&
153 wsi
->flags
== drm
->flags
;
157 wsi_display_mode_refresh(struct wsi_display_mode
*wsi
)
159 return (double) wsi
->clock
* 1000.0 / ((double) wsi
->htotal
*
160 (double) wsi
->vtotal
*
161 (double) MAX2(wsi
->vscan
, 1));
164 static uint64_t wsi_get_current_monotonic(void)
168 clock_gettime(CLOCK_MONOTONIC
, &tv
);
169 return tv
.tv_nsec
+ tv
.tv_sec
*1000000000ull;
172 static uint64_t wsi_rel_to_abs_time(uint64_t rel_time
)
174 uint64_t current_time
= wsi_get_current_monotonic();
176 /* check for overflow */
177 if (rel_time
> UINT64_MAX
- current_time
)
180 return current_time
+ rel_time
;
183 static struct wsi_display_mode
*
184 wsi_display_find_drm_mode(struct wsi_device
*wsi_device
,
185 struct wsi_display_connector
*connector
,
186 drmModeModeInfoPtr mode
)
188 wsi_for_each_display_mode(display_mode
, connector
) {
189 if (wsi_display_mode_matches_drm(display_mode
, mode
))
196 wsi_display_invalidate_connector_modes(struct wsi_device
*wsi_device
,
197 struct wsi_display_connector
*connector
)
199 wsi_for_each_display_mode(display_mode
, connector
) {
200 display_mode
->valid
= false;
205 wsi_display_register_drm_mode(struct wsi_device
*wsi_device
,
206 struct wsi_display_connector
*connector
,
207 drmModeModeInfoPtr drm_mode
)
209 struct wsi_display
*wsi
=
210 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
211 struct wsi_display_mode
*display_mode
=
212 wsi_display_find_drm_mode(wsi_device
, connector
, drm_mode
);
215 display_mode
->valid
= true;
219 display_mode
= vk_zalloc(wsi
->alloc
, sizeof (struct wsi_display_mode
),
220 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
222 return VK_ERROR_OUT_OF_HOST_MEMORY
;
224 display_mode
->connector
= connector
;
225 display_mode
->valid
= true;
226 display_mode
->preferred
= (drm_mode
->type
& DRM_MODE_TYPE_PREFERRED
) != 0;
227 display_mode
->clock
= drm_mode
->clock
; /* kHz */
228 display_mode
->hdisplay
= drm_mode
->hdisplay
;
229 display_mode
->hsync_start
= drm_mode
->hsync_start
;
230 display_mode
->hsync_end
= drm_mode
->hsync_end
;
231 display_mode
->htotal
= drm_mode
->htotal
;
232 display_mode
->hskew
= drm_mode
->hskew
;
233 display_mode
->vdisplay
= drm_mode
->vdisplay
;
234 display_mode
->vsync_start
= drm_mode
->vsync_start
;
235 display_mode
->vsync_end
= drm_mode
->vsync_end
;
236 display_mode
->vtotal
= drm_mode
->vtotal
;
237 display_mode
->vscan
= drm_mode
->vscan
;
238 display_mode
->flags
= drm_mode
->flags
;
240 list_addtail(&display_mode
->list
, &connector
->display_modes
);
245 * Update our information about a specific connector
248 static struct wsi_display_connector
*
249 wsi_display_find_connector(struct wsi_device
*wsi_device
,
250 uint32_t connector_id
)
252 struct wsi_display
*wsi
=
253 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
255 wsi_for_each_connector(connector
, wsi
) {
256 if (connector
->id
== connector_id
)
263 static struct wsi_display_connector
*
264 wsi_display_alloc_connector(struct wsi_display
*wsi
,
265 uint32_t connector_id
)
267 struct wsi_display_connector
*connector
=
268 vk_zalloc(wsi
->alloc
, sizeof (struct wsi_display_connector
),
269 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
271 connector
->id
= connector_id
;
272 connector
->wsi
= wsi
;
273 connector
->active
= false;
274 /* XXX use EDID name */
275 connector
->name
= "monitor";
276 list_inithead(&connector
->display_modes
);
280 static struct wsi_display_connector
*
281 wsi_display_get_connector(struct wsi_device
*wsi_device
,
282 uint32_t connector_id
)
284 struct wsi_display
*wsi
=
285 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
290 drmModeConnectorPtr drm_connector
=
291 drmModeGetConnector(wsi
->fd
, connector_id
);
296 struct wsi_display_connector
*connector
=
297 wsi_display_find_connector(wsi_device
, connector_id
);
300 connector
= wsi_display_alloc_connector(wsi
, connector_id
);
302 drmModeFreeConnector(drm_connector
);
305 list_addtail(&connector
->list
, &wsi
->connectors
);
308 connector
->connected
= drm_connector
->connection
!= DRM_MODE_DISCONNECTED
;
310 /* Mark all connector modes as invalid */
311 wsi_display_invalidate_connector_modes(wsi_device
, connector
);
314 * List current modes, adding new ones and marking existing ones as
317 for (int m
= 0; m
< drm_connector
->count_modes
; m
++) {
318 VkResult result
= wsi_display_register_drm_mode(wsi_device
,
320 &drm_connector
->modes
[m
]);
321 if (result
!= VK_SUCCESS
) {
322 drmModeFreeConnector(drm_connector
);
327 drmModeFreeConnector(drm_connector
);
332 #define MM_PER_PIXEL (1.0/96.0 * 25.4)
335 mode_size(struct wsi_display_mode
*mode
)
337 /* fortunately, these are both uint16_t, so this is easy */
338 return (uint32_t) mode
->hdisplay
* (uint32_t) mode
->vdisplay
;
342 wsi_display_fill_in_display_properties(struct wsi_device
*wsi_device
,
343 struct wsi_display_connector
*connector
,
344 VkDisplayPropertiesKHR
*properties
)
346 properties
->display
= wsi_display_connector_to_handle(connector
);
347 properties
->displayName
= connector
->name
;
349 /* Find the first preferred mode and assume that's the physical
350 * resolution. If there isn't a preferred mode, find the largest mode and
354 struct wsi_display_mode
*preferred_mode
= NULL
, *largest_mode
= NULL
;
355 wsi_for_each_display_mode(display_mode
, connector
) {
356 if (!display_mode
->valid
)
358 if (display_mode
->preferred
) {
359 preferred_mode
= display_mode
;
362 if (largest_mode
== NULL
||
363 mode_size(display_mode
) > mode_size(largest_mode
))
365 largest_mode
= display_mode
;
369 if (preferred_mode
) {
370 properties
->physicalResolution
.width
= preferred_mode
->hdisplay
;
371 properties
->physicalResolution
.height
= preferred_mode
->vdisplay
;
372 } else if (largest_mode
) {
373 properties
->physicalResolution
.width
= largest_mode
->hdisplay
;
374 properties
->physicalResolution
.height
= largest_mode
->vdisplay
;
376 properties
->physicalResolution
.width
= 1024;
377 properties
->physicalResolution
.height
= 768;
380 /* Make up physical size based on 96dpi */
381 properties
->physicalDimensions
.width
=
382 floor(properties
->physicalResolution
.width
* MM_PER_PIXEL
+ 0.5);
383 properties
->physicalDimensions
.height
=
384 floor(properties
->physicalResolution
.height
* MM_PER_PIXEL
+ 0.5);
386 properties
->supportedTransforms
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
387 properties
->planeReorderPossible
= VK_FALSE
;
388 properties
->persistentContent
= VK_FALSE
;
392 * Implement vkGetPhysicalDeviceDisplayPropertiesKHR (VK_KHR_display)
395 wsi_display_get_physical_device_display_properties(
396 VkPhysicalDevice physical_device
,
397 struct wsi_device
*wsi_device
,
398 uint32_t *property_count
,
399 VkDisplayPropertiesKHR
*properties
)
401 struct wsi_display
*wsi
=
402 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
407 drmModeResPtr mode_res
= drmModeGetResources(wsi
->fd
);
412 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
414 /* Get current information */
416 for (int c
= 0; c
< mode_res
->count_connectors
; c
++) {
417 struct wsi_display_connector
*connector
=
418 wsi_display_get_connector(wsi_device
, mode_res
->connectors
[c
]);
421 drmModeFreeResources(mode_res
);
422 return VK_ERROR_OUT_OF_HOST_MEMORY
;
425 if (connector
->connected
) {
426 vk_outarray_append(&conn
, prop
) {
427 wsi_display_fill_in_display_properties(wsi_device
,
434 drmModeFreeResources(mode_res
);
436 return vk_outarray_status(&conn
);
444 * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
447 wsi_display_get_physical_device_display_plane_properties(
448 VkPhysicalDevice physical_device
,
449 struct wsi_device
*wsi_device
,
450 uint32_t *property_count
,
451 VkDisplayPlanePropertiesKHR
*properties
)
453 struct wsi_display
*wsi
=
454 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
456 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
458 wsi_for_each_connector(connector
, wsi
) {
459 vk_outarray_append(&conn
, prop
) {
460 if (connector
&& connector
->active
) {
461 prop
->currentDisplay
= wsi_display_connector_to_handle(connector
);
462 prop
->currentStackIndex
= 0;
464 prop
->currentDisplay
= VK_NULL_HANDLE
;
465 prop
->currentStackIndex
= 0;
469 return vk_outarray_status(&conn
);
473 * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display)
477 wsi_display_get_display_plane_supported_displays(
478 VkPhysicalDevice physical_device
,
479 struct wsi_device
*wsi_device
,
480 uint32_t plane_index
,
481 uint32_t *display_count
,
482 VkDisplayKHR
*displays
)
484 struct wsi_display
*wsi
=
485 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
487 VK_OUTARRAY_MAKE(conn
, displays
, display_count
);
491 wsi_for_each_connector(connector
, wsi
) {
492 if (c
== plane_index
&& connector
->connected
) {
493 vk_outarray_append(&conn
, display
) {
494 *display
= wsi_display_connector_to_handle(connector
);
499 return vk_outarray_status(&conn
);
503 * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
507 wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device
,
508 struct wsi_device
*wsi_device
,
509 VkDisplayKHR display
,
510 uint32_t *property_count
,
511 VkDisplayModePropertiesKHR
*properties
)
513 struct wsi_display_connector
*connector
=
514 wsi_display_connector_from_handle(display
);
516 VK_OUTARRAY_MAKE(conn
, properties
, property_count
);
518 wsi_for_each_display_mode(display_mode
, connector
) {
519 if (display_mode
->valid
) {
520 vk_outarray_append(&conn
, prop
) {
521 prop
->displayMode
= wsi_display_mode_to_handle(display_mode
);
522 prop
->parameters
.visibleRegion
.width
= display_mode
->hdisplay
;
523 prop
->parameters
.visibleRegion
.height
= display_mode
->vdisplay
;
524 prop
->parameters
.refreshRate
=
525 (uint32_t) (wsi_display_mode_refresh(display_mode
) * 1000 + 0.5);
529 return vk_outarray_status(&conn
);
533 wsi_display_mode_matches_vk(wsi_display_mode
*wsi
,
534 const VkDisplayModeParametersKHR
*vk
)
536 return (vk
->visibleRegion
.width
== wsi
->hdisplay
&&
537 vk
->visibleRegion
.height
== wsi
->vdisplay
&&
538 fabs(wsi_display_mode_refresh(wsi
) * 1000.0 - vk
->refreshRate
) < 10);
542 * Implement vkCreateDisplayModeKHR (VK_KHR_display)
545 wsi_display_create_display_mode(VkPhysicalDevice physical_device
,
546 struct wsi_device
*wsi_device
,
547 VkDisplayKHR display
,
548 const VkDisplayModeCreateInfoKHR
*create_info
,
549 const VkAllocationCallbacks
*allocator
,
550 VkDisplayModeKHR
*mode
)
552 struct wsi_display_connector
*connector
=
553 wsi_display_connector_from_handle(display
);
555 if (create_info
->flags
!= 0)
556 return VK_ERROR_INITIALIZATION_FAILED
;
558 /* Check and see if the requested mode happens to match an existing one and
559 * return that. This makes the conformance suite happy. Doing more than
560 * this would involve embedding the CVT function into the driver, which seems
563 wsi_for_each_display_mode(display_mode
, connector
) {
564 if (display_mode
->valid
) {
565 if (wsi_display_mode_matches_vk(display_mode
, &create_info
->parameters
)) {
566 *mode
= wsi_display_mode_to_handle(display_mode
);
571 return VK_ERROR_INITIALIZATION_FAILED
;
575 * Implement vkGetDisplayPlaneCapabilities
578 wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device
,
579 struct wsi_device
*wsi_device
,
580 VkDisplayModeKHR mode_khr
,
581 uint32_t plane_index
,
582 VkDisplayPlaneCapabilitiesKHR
*capabilities
)
584 struct wsi_display_mode
*mode
= wsi_display_mode_from_handle(mode_khr
);
586 /* XXX use actual values */
587 capabilities
->supportedAlpha
= VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR
;
588 capabilities
->minSrcPosition
.x
= 0;
589 capabilities
->minSrcPosition
.y
= 0;
590 capabilities
->maxSrcPosition
.x
= 0;
591 capabilities
->maxSrcPosition
.y
= 0;
592 capabilities
->minSrcExtent
.width
= mode
->hdisplay
;
593 capabilities
->minSrcExtent
.height
= mode
->vdisplay
;
594 capabilities
->maxSrcExtent
.width
= mode
->hdisplay
;
595 capabilities
->maxSrcExtent
.height
= mode
->vdisplay
;
596 capabilities
->minDstPosition
.x
= 0;
597 capabilities
->minDstPosition
.y
= 0;
598 capabilities
->maxDstPosition
.x
= 0;
599 capabilities
->maxDstPosition
.y
= 0;
600 capabilities
->minDstExtent
.width
= mode
->hdisplay
;
601 capabilities
->minDstExtent
.height
= mode
->vdisplay
;
602 capabilities
->maxDstExtent
.width
= mode
->hdisplay
;
603 capabilities
->maxDstExtent
.height
= mode
->vdisplay
;
608 wsi_create_display_surface(VkInstance instance
,
609 const VkAllocationCallbacks
*allocator
,
610 const VkDisplaySurfaceCreateInfoKHR
*create_info
,
611 VkSurfaceKHR
*surface_khr
)
613 VkIcdSurfaceDisplay
*surface
= vk_zalloc(allocator
, sizeof *surface
, 8,
614 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
617 return VK_ERROR_OUT_OF_HOST_MEMORY
;
619 surface
->base
.platform
= VK_ICD_WSI_PLATFORM_DISPLAY
;
621 surface
->displayMode
= create_info
->displayMode
;
622 surface
->planeIndex
= create_info
->planeIndex
;
623 surface
->planeStackIndex
= create_info
->planeStackIndex
;
624 surface
->transform
= create_info
->transform
;
625 surface
->globalAlpha
= create_info
->globalAlpha
;
626 surface
->alphaMode
= create_info
->alphaMode
;
627 surface
->imageExtent
= create_info
->imageExtent
;
629 *surface_khr
= VkIcdSurfaceBase_to_handle(&surface
->base
);
635 wsi_display_surface_get_support(VkIcdSurfaceBase
*surface
,
636 struct wsi_device
*wsi_device
,
637 const VkAllocationCallbacks
*allocator
,
638 uint32_t queueFamilyIndex
,
640 VkBool32
* pSupported
)
642 *pSupported
= VK_TRUE
;
647 wsi_display_surface_get_capabilities(VkIcdSurfaceBase
*surface_base
,
648 VkSurfaceCapabilitiesKHR
* caps
)
650 VkIcdSurfaceDisplay
*surface
= (VkIcdSurfaceDisplay
*) surface_base
;
651 wsi_display_mode
*mode
= wsi_display_mode_from_handle(surface
->displayMode
);
653 caps
->currentExtent
.width
= mode
->hdisplay
;
654 caps
->currentExtent
.height
= mode
->vdisplay
;
656 /* XXX Figure out extents based on driver capabilities */
657 caps
->maxImageExtent
= caps
->minImageExtent
= caps
->currentExtent
;
659 caps
->supportedCompositeAlpha
= VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR
;
661 caps
->minImageCount
= 2;
662 caps
->maxImageCount
= 0;
664 caps
->supportedTransforms
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
665 caps
->currentTransform
= VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
;
666 caps
->maxImageArrayLayers
= 1;
667 caps
->supportedUsageFlags
=
668 VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
669 VK_IMAGE_USAGE_SAMPLED_BIT
|
670 VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
671 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
;
677 wsi_display_surface_get_capabilities2(VkIcdSurfaceBase
*icd_surface
,
678 const void *info_next
,
679 VkSurfaceCapabilities2KHR
*caps
)
681 assert(caps
->sType
== VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR
);
683 return wsi_display_surface_get_capabilities(icd_surface
,
684 &caps
->surfaceCapabilities
);
687 static const struct {
690 } available_surface_formats
[] = {
691 { .format
= VK_FORMAT_B8G8R8A8_SRGB
, .drm_format
= DRM_FORMAT_XRGB8888
},
692 { .format
= VK_FORMAT_B8G8R8A8_UNORM
, .drm_format
= DRM_FORMAT_XRGB8888
},
696 wsi_display_surface_get_formats(VkIcdSurfaceBase
*icd_surface
,
697 struct wsi_device
*wsi_device
,
698 uint32_t *surface_format_count
,
699 VkSurfaceFormatKHR
*surface_formats
)
701 VK_OUTARRAY_MAKE(out
, surface_formats
, surface_format_count
);
703 for (unsigned i
= 0; i
< ARRAY_SIZE(available_surface_formats
); i
++) {
704 vk_outarray_append(&out
, f
) {
705 f
->format
= available_surface_formats
[i
].format
;
706 f
->colorSpace
= VK_COLORSPACE_SRGB_NONLINEAR_KHR
;
710 return vk_outarray_status(&out
);
714 wsi_display_surface_get_formats2(VkIcdSurfaceBase
*surface
,
715 struct wsi_device
*wsi_device
,
716 const void *info_next
,
717 uint32_t *surface_format_count
,
718 VkSurfaceFormat2KHR
*surface_formats
)
720 VK_OUTARRAY_MAKE(out
, surface_formats
, surface_format_count
);
722 for (unsigned i
= 0; i
< ARRAY_SIZE(available_surface_formats
); i
++) {
723 vk_outarray_append(&out
, f
) {
724 assert(f
->sType
== VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR
);
725 f
->surfaceFormat
.format
= available_surface_formats
[i
].format
;
726 f
->surfaceFormat
.colorSpace
= VK_COLORSPACE_SRGB_NONLINEAR_KHR
;
730 return vk_outarray_status(&out
);
734 wsi_display_surface_get_present_modes(VkIcdSurfaceBase
*surface
,
735 uint32_t *present_mode_count
,
736 VkPresentModeKHR
*present_modes
)
738 VK_OUTARRAY_MAKE(conn
, present_modes
, present_mode_count
);
740 vk_outarray_append(&conn
, present
) {
741 *present
= VK_PRESENT_MODE_FIFO_KHR
;
744 return vk_outarray_status(&conn
);
748 wsi_display_destroy_buffer(struct wsi_display
*wsi
,
751 (void) drmIoctl(wsi
->fd
, DRM_IOCTL_MODE_DESTROY_DUMB
,
752 &((struct drm_mode_destroy_dumb
) { .handle
= buffer
}));
756 wsi_display_image_init(VkDevice device_h
,
757 struct wsi_swapchain
*drv_chain
,
758 const VkSwapchainCreateInfoKHR
*create_info
,
759 const VkAllocationCallbacks
*allocator
,
760 struct wsi_display_image
*image
)
762 struct wsi_display_swapchain
*chain
=
763 (struct wsi_display_swapchain
*) drv_chain
;
764 struct wsi_display
*wsi
= chain
->wsi
;
765 uint32_t drm_format
= 0;
767 for (unsigned i
= 0; i
< ARRAY_SIZE(available_surface_formats
); i
++) {
768 if (create_info
->imageFormat
== available_surface_formats
[i
].format
) {
769 drm_format
= available_surface_formats
[i
].drm_format
;
774 /* the application provided an invalid format, bail */
776 return VK_ERROR_DEVICE_LOST
;
778 VkResult result
= wsi_create_native_image(&chain
->base
, create_info
,
781 if (result
!= VK_SUCCESS
)
784 memset(image
->buffer
, 0, sizeof (image
->buffer
));
786 for (unsigned int i
= 0; i
< image
->base
.num_planes
; i
++) {
787 int ret
= drmPrimeFDToHandle(wsi
->fd
, image
->base
.fds
[i
],
790 close(image
->base
.fds
[i
]);
791 image
->base
.fds
[i
] = -1;
796 image
->chain
= chain
;
797 image
->state
= WSI_IMAGE_IDLE
;
800 int ret
= drmModeAddFB2(wsi
->fd
,
801 create_info
->imageExtent
.width
,
802 create_info
->imageExtent
.height
,
805 image
->base
.row_pitches
,
816 for (unsigned int i
= 0; i
< image
->base
.num_planes
; i
++) {
817 if (image
->buffer
[i
])
818 wsi_display_destroy_buffer(wsi
, image
->buffer
[i
]);
819 if (image
->base
.fds
[i
] != -1) {
820 close(image
->base
.fds
[i
]);
821 image
->base
.fds
[i
] = -1;
825 wsi_destroy_image(&chain
->base
, &image
->base
);
827 return VK_ERROR_OUT_OF_HOST_MEMORY
;
831 wsi_display_image_finish(struct wsi_swapchain
*drv_chain
,
832 const VkAllocationCallbacks
*allocator
,
833 struct wsi_display_image
*image
)
835 struct wsi_display_swapchain
*chain
=
836 (struct wsi_display_swapchain
*) drv_chain
;
837 struct wsi_display
*wsi
= chain
->wsi
;
839 drmModeRmFB(wsi
->fd
, image
->fb_id
);
840 for (unsigned int i
= 0; i
< image
->base
.num_planes
; i
++)
841 wsi_display_destroy_buffer(wsi
, image
->buffer
[i
]);
842 wsi_destroy_image(&chain
->base
, &image
->base
);
846 wsi_display_swapchain_destroy(struct wsi_swapchain
*drv_chain
,
847 const VkAllocationCallbacks
*allocator
)
849 struct wsi_display_swapchain
*chain
=
850 (struct wsi_display_swapchain
*) drv_chain
;
852 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++)
853 wsi_display_image_finish(drv_chain
, allocator
, &chain
->images
[i
]);
854 vk_free(allocator
, chain
);
858 static struct wsi_image
*
859 wsi_display_get_wsi_image(struct wsi_swapchain
*drv_chain
,
860 uint32_t image_index
)
862 struct wsi_display_swapchain
*chain
=
863 (struct wsi_display_swapchain
*) drv_chain
;
865 return &chain
->images
[image_index
].base
;
869 wsi_display_idle_old_displaying(struct wsi_display_image
*active_image
)
871 struct wsi_display_swapchain
*chain
= active_image
->chain
;
873 wsi_display_debug("idle everyone but %ld\n",
874 active_image
- &(chain
->images
[0]));
875 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++)
876 if (chain
->images
[i
].state
== WSI_IMAGE_DISPLAYING
&&
877 &chain
->images
[i
] != active_image
)
879 wsi_display_debug("idle %d\n", i
);
880 chain
->images
[i
].state
= WSI_IMAGE_IDLE
;
885 _wsi_display_queue_next(struct wsi_swapchain
*drv_chain
);
888 wsi_display_page_flip_handler2(int fd
,
895 struct wsi_display_image
*image
= data
;
896 struct wsi_display_swapchain
*chain
= image
->chain
;
898 wsi_display_debug("image %ld displayed at %d\n",
899 image
- &(image
->chain
->images
[0]), frame
);
900 image
->state
= WSI_IMAGE_DISPLAYING
;
901 wsi_display_idle_old_displaying(image
);
902 VkResult result
= _wsi_display_queue_next(&(chain
->base
));
903 if (result
!= VK_SUCCESS
)
904 chain
->status
= result
;
907 static void wsi_display_page_flip_handler(int fd
,
913 wsi_display_page_flip_handler2(fd
, frame
, sec
, usec
, 0, data
);
916 static drmEventContext event_context
= {
917 .version
= DRM_EVENT_CONTEXT_VERSION
,
918 .page_flip_handler
= wsi_display_page_flip_handler
,
919 #if DRM_EVENT_CONTEXT_VERSION >= 3
920 .page_flip_handler2
= wsi_display_page_flip_handler2
,
925 wsi_display_wait_thread(void *data
)
927 struct wsi_display
*wsi
= data
;
928 struct pollfd pollfd
= {
933 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
935 int ret
= poll(&pollfd
, 1, -1);
937 pthread_mutex_lock(&wsi
->wait_mutex
);
938 (void) drmHandleEvent(wsi
->fd
, &event_context
);
939 pthread_mutex_unlock(&wsi
->wait_mutex
);
940 pthread_cond_broadcast(&wsi
->wait_cond
);
947 wsi_display_start_wait_thread(struct wsi_display
*wsi
)
949 if (!wsi
->wait_thread
) {
950 int ret
= pthread_create(&wsi
->wait_thread
, NULL
,
951 wsi_display_wait_thread
, wsi
);
959 * Wait for at least one event from the kernel to be processed.
960 * Call with wait_mutex held
963 wsi_display_wait_for_event(struct wsi_display
*wsi
,
968 ret
= wsi_display_start_wait_thread(wsi
);
973 struct timespec abs_timeout
= {
974 .tv_sec
= timeout_ns
/ 1000000000ULL,
975 .tv_nsec
= timeout_ns
% 1000000000ULL,
978 ret
= pthread_cond_timedwait(&wsi
->wait_cond
, &wsi
->wait_mutex
,
981 wsi_display_debug("%9ld done waiting for event %d\n", pthread_self(), ret
);
986 wsi_display_acquire_next_image(struct wsi_swapchain
*drv_chain
,
988 VkSemaphore semaphore
,
989 uint32_t *image_index
)
991 struct wsi_display_swapchain
*chain
=
992 (struct wsi_display_swapchain
*)drv_chain
;
993 struct wsi_display
*wsi
= chain
->wsi
;
995 VkResult result
= VK_SUCCESS
;
997 /* Bail early if the swapchain is broken */
998 if (chain
->status
!= VK_SUCCESS
)
999 return chain
->status
;
1001 if (timeout
!= 0 && timeout
!= UINT64_MAX
)
1002 timeout
= wsi_rel_to_abs_time(timeout
);
1004 pthread_mutex_lock(&wsi
->wait_mutex
);
1006 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++) {
1007 if (chain
->images
[i
].state
== WSI_IMAGE_IDLE
) {
1009 wsi_display_debug("image %d available\n", i
);
1010 chain
->images
[i
].state
= WSI_IMAGE_DRAWING
;
1011 result
= VK_SUCCESS
;
1014 wsi_display_debug("image %d state %d\n", i
, chain
->images
[i
].state
);
1017 if (ret
== ETIMEDOUT
) {
1018 result
= VK_TIMEOUT
;
1022 ret
= wsi_display_wait_for_event(wsi
, timeout
);
1024 if (ret
&& ret
!= ETIMEDOUT
) {
1025 result
= VK_ERROR_OUT_OF_DATE_KHR
;
1030 pthread_mutex_unlock(&wsi
->wait_mutex
);
1032 if (result
!= VK_SUCCESS
)
1035 return chain
->status
;
1039 * Check whether there are any other connectors driven by this crtc
1042 wsi_display_crtc_solo(struct wsi_display
*wsi
,
1043 drmModeResPtr mode_res
,
1044 drmModeConnectorPtr connector
,
1047 /* See if any other connectors share the same encoder */
1048 for (int c
= 0; c
< mode_res
->count_connectors
; c
++) {
1049 if (mode_res
->connectors
[c
] == connector
->connector_id
)
1052 drmModeConnectorPtr other_connector
=
1053 drmModeGetConnector(wsi
->fd
, mode_res
->connectors
[c
]);
1055 if (other_connector
) {
1056 bool match
= (other_connector
->encoder_id
== connector
->encoder_id
);
1057 drmModeFreeConnector(other_connector
);
1063 /* See if any other encoders share the same crtc */
1064 for (int e
= 0; e
< mode_res
->count_encoders
; e
++) {
1065 if (mode_res
->encoders
[e
] == connector
->encoder_id
)
1068 drmModeEncoderPtr other_encoder
=
1069 drmModeGetEncoder(wsi
->fd
, mode_res
->encoders
[e
]);
1071 if (other_encoder
) {
1072 bool match
= (other_encoder
->crtc_id
== crtc_id
);
1073 drmModeFreeEncoder(other_encoder
);
1082 * Pick a suitable CRTC to drive this connector. Prefer a CRTC which is
1083 * currently driving this connector and not any others. Settle for a CRTC
1084 * which is currently idle.
1087 wsi_display_select_crtc(struct wsi_display_connector
*connector
,
1088 drmModeResPtr mode_res
,
1089 drmModeConnectorPtr drm_connector
)
1091 struct wsi_display
*wsi
= connector
->wsi
;
1093 /* See what CRTC is currently driving this connector */
1094 if (drm_connector
->encoder_id
) {
1095 drmModeEncoderPtr encoder
=
1096 drmModeGetEncoder(wsi
->fd
, drm_connector
->encoder_id
);
1099 uint32_t crtc_id
= encoder
->crtc_id
;
1100 drmModeFreeEncoder(encoder
);
1102 if (wsi_display_crtc_solo(wsi
, mode_res
, drm_connector
, crtc_id
))
1107 uint32_t crtc_id
= 0;
1108 for (int c
= 0; crtc_id
== 0 && c
< mode_res
->count_crtcs
; c
++) {
1109 drmModeCrtcPtr crtc
= drmModeGetCrtc(wsi
->fd
, mode_res
->crtcs
[c
]);
1110 if (crtc
&& crtc
->buffer_id
== 0)
1111 crtc_id
= crtc
->crtc_id
;
1112 drmModeFreeCrtc(crtc
);
1118 wsi_display_setup_connector(wsi_display_connector
*connector
,
1119 wsi_display_mode
*display_mode
)
1121 struct wsi_display
*wsi
= connector
->wsi
;
1123 if (connector
->current_mode
== display_mode
&& connector
->crtc_id
)
1126 VkResult result
= VK_SUCCESS
;
1128 drmModeResPtr mode_res
= drmModeGetResources(wsi
->fd
);
1130 if (errno
== ENOMEM
)
1131 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1133 result
= VK_ERROR_OUT_OF_DATE_KHR
;
1137 drmModeConnectorPtr drm_connector
=
1138 drmModeGetConnectorCurrent(wsi
->fd
, connector
->id
);
1140 if (!drm_connector
) {
1141 if (errno
== ENOMEM
)
1142 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1144 result
= VK_ERROR_OUT_OF_DATE_KHR
;
1148 /* Pick a CRTC if we don't have one */
1149 if (!connector
->crtc_id
) {
1150 connector
->crtc_id
= wsi_display_select_crtc(connector
,
1151 mode_res
, drm_connector
);
1152 if (!connector
->crtc_id
) {
1153 result
= VK_ERROR_OUT_OF_DATE_KHR
;
1154 goto bail_connector
;
1158 if (connector
->current_mode
!= display_mode
) {
1160 /* Find the drm mode corresponding to the requested VkDisplayMode */
1161 drmModeModeInfoPtr drm_mode
= NULL
;
1163 for (int m
= 0; m
< drm_connector
->count_modes
; m
++) {
1164 drm_mode
= &drm_connector
->modes
[m
];
1165 if (wsi_display_mode_matches_drm(display_mode
, drm_mode
))
1171 result
= VK_ERROR_OUT_OF_DATE_KHR
;
1172 goto bail_connector
;
1175 connector
->current_mode
= display_mode
;
1176 connector
->current_drm_mode
= *drm_mode
;
1180 drmModeFreeConnector(drm_connector
);
1182 drmModeFreeResources(mode_res
);
1189 * Check to see if the kernel has no flip queued and if there's an image
1190 * waiting to be displayed.
1193 _wsi_display_queue_next(struct wsi_swapchain
*drv_chain
)
1195 struct wsi_display_swapchain
*chain
=
1196 (struct wsi_display_swapchain
*) drv_chain
;
1197 struct wsi_display
*wsi
= chain
->wsi
;
1198 VkIcdSurfaceDisplay
*surface
= chain
->surface
;
1199 wsi_display_mode
*display_mode
=
1200 wsi_display_mode_from_handle(surface
->displayMode
);
1201 wsi_display_connector
*connector
= display_mode
->connector
;
1204 return VK_ERROR_OUT_OF_DATE_KHR
;
1206 if (display_mode
!= connector
->current_mode
)
1207 connector
->active
= false;
1211 /* Check to see if there is an image to display, or if some image is
1214 struct wsi_display_image
*image
= NULL
;
1216 for (uint32_t i
= 0; i
< chain
->base
.image_count
; i
++) {
1217 struct wsi_display_image
*tmp_image
= &chain
->images
[i
];
1219 switch (tmp_image
->state
) {
1220 case WSI_IMAGE_FLIPPING
:
1221 /* already flipping, don't send another to the kernel yet */
1223 case WSI_IMAGE_QUEUED
:
1224 /* find the oldest queued */
1225 if (!image
|| tmp_image
->flip_sequence
< image
->flip_sequence
)
1237 if (connector
->active
) {
1238 ret
= drmModePageFlip(wsi
->fd
, connector
->crtc_id
, image
->fb_id
,
1239 DRM_MODE_PAGE_FLIP_EVENT
, image
);
1241 image
->state
= WSI_IMAGE_FLIPPING
;
1244 wsi_display_debug("page flip err %d %s\n", ret
, strerror(-ret
));
1249 if (ret
== -EINVAL
) {
1250 VkResult result
= wsi_display_setup_connector(connector
, display_mode
);
1252 if (result
!= VK_SUCCESS
) {
1253 image
->state
= WSI_IMAGE_IDLE
;
1257 /* XXX allow setting of position */
1258 ret
= drmModeSetCrtc(wsi
->fd
, connector
->crtc_id
,
1261 &connector
->current_drm_mode
);
1263 /* Assume that the mode set is synchronous and that any
1264 * previous image is now idle.
1266 image
->state
= WSI_IMAGE_DISPLAYING
;
1267 wsi_display_idle_old_displaying(image
);
1268 connector
->active
= true;
1273 if (ret
!= -EACCES
) {
1274 connector
->active
= false;
1275 image
->state
= WSI_IMAGE_IDLE
;
1276 return VK_ERROR_OUT_OF_DATE_KHR
;
1279 /* Some other VT is currently active. Sit here waiting for
1280 * our VT to become active again by polling once a second
1282 usleep(1000 * 1000);
1283 connector
->active
= false;
1288 wsi_display_queue_present(struct wsi_swapchain
*drv_chain
,
1289 uint32_t image_index
,
1290 const VkPresentRegionKHR
*damage
)
1292 struct wsi_display_swapchain
*chain
=
1293 (struct wsi_display_swapchain
*) drv_chain
;
1294 struct wsi_display
*wsi
= chain
->wsi
;
1295 struct wsi_display_image
*image
= &chain
->images
[image_index
];
1298 /* Bail early if the swapchain is broken */
1299 if (chain
->status
!= VK_SUCCESS
)
1300 return chain
->status
;
1302 assert(image
->state
== WSI_IMAGE_DRAWING
);
1303 wsi_display_debug("present %d\n", image_index
);
1305 pthread_mutex_lock(&wsi
->wait_mutex
);
1307 image
->flip_sequence
= ++chain
->flip_sequence
;
1308 image
->state
= WSI_IMAGE_QUEUED
;
1310 result
= _wsi_display_queue_next(drv_chain
);
1311 if (result
!= VK_SUCCESS
)
1312 chain
->status
= result
;
1314 pthread_mutex_unlock(&wsi
->wait_mutex
);
1316 if (result
!= VK_SUCCESS
)
1319 return chain
->status
;
1323 wsi_display_surface_create_swapchain(
1324 VkIcdSurfaceBase
*icd_surface
,
1326 struct wsi_device
*wsi_device
,
1328 const VkSwapchainCreateInfoKHR
*create_info
,
1329 const VkAllocationCallbacks
*allocator
,
1330 struct wsi_swapchain
**swapchain_out
)
1332 struct wsi_display
*wsi
=
1333 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1335 assert(create_info
->sType
== VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR
);
1337 const unsigned num_images
= create_info
->minImageCount
;
1338 struct wsi_display_swapchain
*chain
=
1339 vk_zalloc(allocator
,
1340 sizeof(*chain
) + num_images
* sizeof(chain
->images
[0]),
1341 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
1344 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1346 VkResult result
= wsi_swapchain_init(wsi_device
, &chain
->base
, device
,
1347 create_info
, allocator
);
1349 chain
->base
.destroy
= wsi_display_swapchain_destroy
;
1350 chain
->base
.get_wsi_image
= wsi_display_get_wsi_image
;
1351 chain
->base
.acquire_next_image
= wsi_display_acquire_next_image
;
1352 chain
->base
.queue_present
= wsi_display_queue_present
;
1353 chain
->base
.present_mode
= create_info
->presentMode
;
1354 chain
->base
.image_count
= num_images
;
1357 chain
->status
= VK_SUCCESS
;
1359 chain
->surface
= (VkIcdSurfaceDisplay
*) icd_surface
;
1361 for (uint32_t image
= 0; image
< chain
->base
.image_count
; image
++) {
1362 result
= wsi_display_image_init(device
, &chain
->base
,
1363 create_info
, allocator
,
1364 &chain
->images
[image
]);
1365 if (result
!= VK_SUCCESS
) {
1368 wsi_display_image_finish(&chain
->base
, allocator
,
1369 &chain
->images
[image
]);
1371 vk_free(allocator
, chain
);
1372 goto fail_init_images
;
1376 *swapchain_out
= &chain
->base
;
1385 wsi_init_pthread_cond_monotonic(pthread_cond_t
*cond
)
1387 pthread_condattr_t condattr
;
1390 if (pthread_condattr_init(&condattr
) != 0)
1391 goto fail_attr_init
;
1393 if (pthread_condattr_setclock(&condattr
, CLOCK_MONOTONIC
) != 0)
1396 if (pthread_cond_init(cond
, &condattr
) != 0)
1397 goto fail_cond_init
;
1403 pthread_condattr_destroy(&condattr
);
1409 wsi_display_init_wsi(struct wsi_device
*wsi_device
,
1410 const VkAllocationCallbacks
*alloc
,
1413 struct wsi_display
*wsi
= vk_zalloc(alloc
, sizeof(*wsi
), 8,
1414 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
1418 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1422 wsi
->fd
= display_fd
;
1425 list_inithead(&wsi
->connectors
);
1427 int ret
= pthread_mutex_init(&wsi
->wait_mutex
, NULL
);
1429 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1433 if (!wsi_init_pthread_cond_monotonic(&wsi
->wait_cond
)) {
1434 result
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1438 wsi
->base
.get_support
= wsi_display_surface_get_support
;
1439 wsi
->base
.get_capabilities
= wsi_display_surface_get_capabilities
;
1440 wsi
->base
.get_capabilities2
= wsi_display_surface_get_capabilities2
;
1441 wsi
->base
.get_formats
= wsi_display_surface_get_formats
;
1442 wsi
->base
.get_formats2
= wsi_display_surface_get_formats2
;
1443 wsi
->base
.get_present_modes
= wsi_display_surface_get_present_modes
;
1444 wsi
->base
.create_swapchain
= wsi_display_surface_create_swapchain
;
1446 wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
] = &wsi
->base
;
1451 pthread_mutex_destroy(&wsi
->wait_mutex
);
1453 vk_free(alloc
, wsi
);
1459 wsi_display_finish_wsi(struct wsi_device
*wsi_device
,
1460 const VkAllocationCallbacks
*alloc
)
1462 struct wsi_display
*wsi
=
1463 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1466 wsi_for_each_connector(connector
, wsi
) {
1467 wsi_for_each_display_mode(mode
, connector
) {
1468 vk_free(wsi
->alloc
, mode
);
1470 vk_free(wsi
->alloc
, connector
);
1473 pthread_mutex_lock(&wsi
->wait_mutex
);
1474 if (wsi
->wait_thread
) {
1475 pthread_cancel(wsi
->wait_thread
);
1476 pthread_join(wsi
->wait_thread
, NULL
);
1478 pthread_mutex_unlock(&wsi
->wait_mutex
);
1479 pthread_mutex_destroy(&wsi
->wait_mutex
);
1480 pthread_cond_destroy(&wsi
->wait_cond
);
1482 vk_free(alloc
, wsi
);
1487 * Implement vkReleaseDisplay
1490 wsi_release_display(VkPhysicalDevice physical_device
,
1491 struct wsi_device
*wsi_device
,
1492 VkDisplayKHR display
)
1494 struct wsi_display
*wsi
=
1495 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1501 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1502 wsi_display_connector_from_handle(display
)->output
= None
;
1508 #ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
1510 static struct wsi_display_connector
*
1511 wsi_display_find_output(struct wsi_device
*wsi_device
,
1512 xcb_randr_output_t output
)
1514 struct wsi_display
*wsi
=
1515 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1517 wsi_for_each_connector(connector
, wsi
) {
1518 if (connector
->output
== output
)
1526 * Given a RandR output, find the associated kernel connector_id by
1527 * looking at the CONNECTOR_ID property provided by the X server
1531 wsi_display_output_to_connector_id(xcb_connection_t
*connection
,
1532 xcb_atom_t
*connector_id_atom_p
,
1533 xcb_randr_output_t output
)
1535 uint32_t connector_id
= 0;
1536 xcb_atom_t connector_id_atom
= *connector_id_atom_p
;
1538 if (connector_id_atom
== 0) {
1539 /* Go dig out the CONNECTOR_ID property */
1540 xcb_intern_atom_cookie_t ia_c
= xcb_intern_atom(connection
,
1544 xcb_intern_atom_reply_t
*ia_r
= xcb_intern_atom_reply(connection
,
1548 *connector_id_atom_p
= connector_id_atom
= ia_r
->atom
;
1553 /* If there's an CONNECTOR_ID atom in the server, then there may be a
1554 * CONNECTOR_ID property. Otherwise, there will not be and we don't even
1557 if (connector_id_atom
) {
1559 xcb_randr_query_version_cookie_t qv_c
=
1560 xcb_randr_query_version(connection
, 1, 6);
1561 xcb_randr_get_output_property_cookie_t gop_c
=
1562 xcb_randr_get_output_property(connection
,
1570 xcb_randr_query_version_reply_t
*qv_r
=
1571 xcb_randr_query_version_reply(connection
, qv_c
, NULL
);
1573 xcb_randr_get_output_property_reply_t
*gop_r
=
1574 xcb_randr_get_output_property_reply(connection
, gop_c
, NULL
);
1576 if (gop_r
->num_items
== 1 && gop_r
->format
== 32)
1577 memcpy(&connector_id
, xcb_randr_get_output_property_data(gop_r
), 4);
1581 return connector_id
;
1585 wsi_display_check_randr_version(xcb_connection_t
*connection
)
1587 xcb_randr_query_version_cookie_t qv_c
=
1588 xcb_randr_query_version(connection
, 1, 6);
1589 xcb_randr_query_version_reply_t
*qv_r
=
1590 xcb_randr_query_version_reply(connection
, qv_c
, NULL
);
1596 /* Check for version 1.6 or newer */
1597 ret
= (qv_r
->major_version
> 1 ||
1598 (qv_r
->major_version
== 1 && qv_r
->minor_version
>= 6));
1605 * Given a kernel connector id, find the associated RandR output using the
1606 * CONNECTOR_ID property
1609 static xcb_randr_output_t
1610 wsi_display_connector_id_to_output(xcb_connection_t
*connection
,
1611 uint32_t connector_id
)
1613 if (!wsi_display_check_randr_version(connection
))
1616 const xcb_setup_t
*setup
= xcb_get_setup(connection
);
1618 xcb_atom_t connector_id_atom
= 0;
1619 xcb_randr_output_t output
= 0;
1621 /* Search all of the screens for the provided output */
1622 xcb_screen_iterator_t iter
;
1623 for (iter
= xcb_setup_roots_iterator(setup
);
1624 output
== 0 && iter
.rem
;
1625 xcb_screen_next(&iter
))
1627 xcb_randr_get_screen_resources_cookie_t gsr_c
=
1628 xcb_randr_get_screen_resources(connection
, iter
.data
->root
);
1629 xcb_randr_get_screen_resources_reply_t
*gsr_r
=
1630 xcb_randr_get_screen_resources_reply(connection
, gsr_c
, NULL
);
1635 xcb_randr_output_t
*ro
= xcb_randr_get_screen_resources_outputs(gsr_r
);
1638 for (o
= 0; o
< gsr_r
->num_outputs
; o
++) {
1639 if (wsi_display_output_to_connector_id(connection
,
1640 &connector_id_atom
, ro
[o
])
1653 * Given a RandR output, find out which screen it's associated with
1656 wsi_display_output_to_root(xcb_connection_t
*connection
,
1657 xcb_randr_output_t output
)
1659 if (!wsi_display_check_randr_version(connection
))
1662 const xcb_setup_t
*setup
= xcb_get_setup(connection
);
1663 xcb_window_t root
= 0;
1665 /* Search all of the screens for the provided output */
1666 for (xcb_screen_iterator_t iter
= xcb_setup_roots_iterator(setup
);
1667 root
== 0 && iter
.rem
;
1668 xcb_screen_next(&iter
))
1670 xcb_randr_get_screen_resources_cookie_t gsr_c
=
1671 xcb_randr_get_screen_resources(connection
, iter
.data
->root
);
1672 xcb_randr_get_screen_resources_reply_t
*gsr_r
=
1673 xcb_randr_get_screen_resources_reply(connection
, gsr_c
, NULL
);
1678 xcb_randr_output_t
*ro
= xcb_randr_get_screen_resources_outputs(gsr_r
);
1680 for (int o
= 0; o
< gsr_r
->num_outputs
; o
++) {
1681 if (ro
[o
] == output
) {
1682 root
= iter
.data
->root
;
1692 wsi_display_mode_matches_x(struct wsi_display_mode
*wsi
,
1693 xcb_randr_mode_info_t
*xcb
)
1695 return wsi
->clock
== (xcb
->dot_clock
+ 500) / 1000 &&
1696 wsi
->hdisplay
== xcb
->width
&&
1697 wsi
->hsync_start
== xcb
->hsync_start
&&
1698 wsi
->hsync_end
== xcb
->hsync_end
&&
1699 wsi
->htotal
== xcb
->htotal
&&
1700 wsi
->hskew
== xcb
->hskew
&&
1701 wsi
->vdisplay
== xcb
->height
&&
1702 wsi
->vsync_start
== xcb
->vsync_start
&&
1703 wsi
->vsync_end
== xcb
->vsync_end
&&
1704 wsi
->vtotal
== xcb
->vtotal
&&
1706 wsi
->flags
== xcb
->mode_flags
;
1709 static struct wsi_display_mode
*
1710 wsi_display_find_x_mode(struct wsi_device
*wsi_device
,
1711 struct wsi_display_connector
*connector
,
1712 xcb_randr_mode_info_t
*mode
)
1714 wsi_for_each_display_mode(display_mode
, connector
) {
1715 if (wsi_display_mode_matches_x(display_mode
, mode
))
1716 return display_mode
;
1722 wsi_display_register_x_mode(struct wsi_device
*wsi_device
,
1723 struct wsi_display_connector
*connector
,
1724 xcb_randr_mode_info_t
*x_mode
,
1727 struct wsi_display
*wsi
=
1728 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1729 struct wsi_display_mode
*display_mode
=
1730 wsi_display_find_x_mode(wsi_device
, connector
, x_mode
);
1733 display_mode
->valid
= true;
1737 display_mode
= vk_zalloc(wsi
->alloc
, sizeof (struct wsi_display_mode
),
1738 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE
);
1740 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1742 display_mode
->connector
= connector
;
1743 display_mode
->valid
= true;
1744 display_mode
->preferred
= preferred
;
1745 display_mode
->clock
= (x_mode
->dot_clock
+ 500) / 1000; /* kHz */
1746 display_mode
->hdisplay
= x_mode
->width
;
1747 display_mode
->hsync_start
= x_mode
->hsync_start
;
1748 display_mode
->hsync_end
= x_mode
->hsync_end
;
1749 display_mode
->htotal
= x_mode
->htotal
;
1750 display_mode
->hskew
= x_mode
->hskew
;
1751 display_mode
->vdisplay
= x_mode
->height
;
1752 display_mode
->vsync_start
= x_mode
->vsync_start
;
1753 display_mode
->vsync_end
= x_mode
->vsync_end
;
1754 display_mode
->vtotal
= x_mode
->vtotal
;
1755 display_mode
->vscan
= 0;
1756 display_mode
->flags
= x_mode
->mode_flags
;
1758 list_addtail(&display_mode
->list
, &connector
->display_modes
);
1762 static struct wsi_display_connector
*
1763 wsi_display_get_output(struct wsi_device
*wsi_device
,
1764 xcb_connection_t
*connection
,
1765 xcb_randr_output_t output
)
1767 struct wsi_display
*wsi
=
1768 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1769 struct wsi_display_connector
*connector
;
1770 uint32_t connector_id
;
1772 xcb_window_t root
= wsi_display_output_to_root(connection
, output
);
1776 /* See if we already have a connector for this output */
1777 connector
= wsi_display_find_output(wsi_device
, output
);
1780 xcb_atom_t connector_id_atom
= 0;
1783 * Go get the kernel connector ID for this X output
1785 connector_id
= wsi_display_output_to_connector_id(connection
,
1789 /* Any X server with lease support will have this atom */
1790 if (!connector_id
) {
1794 /* See if we already have a connector for this id */
1795 connector
= wsi_display_find_connector(wsi_device
, connector_id
);
1797 if (connector
== NULL
) {
1798 connector
= wsi_display_alloc_connector(wsi
, connector_id
);
1802 list_addtail(&connector
->list
, &wsi
->connectors
);
1804 connector
->output
= output
;
1807 xcb_randr_get_screen_resources_cookie_t src
=
1808 xcb_randr_get_screen_resources(connection
, root
);
1809 xcb_randr_get_output_info_cookie_t oic
=
1810 xcb_randr_get_output_info(connection
, output
, XCB_CURRENT_TIME
);
1811 xcb_randr_get_screen_resources_reply_t
*srr
=
1812 xcb_randr_get_screen_resources_reply(connection
, src
, NULL
);
1813 xcb_randr_get_output_info_reply_t
*oir
=
1814 xcb_randr_get_output_info_reply(connection
, oic
, NULL
);
1817 /* Get X modes and add them */
1819 connector
->connected
=
1820 oir
->connection
!= XCB_RANDR_CONNECTION_DISCONNECTED
;
1822 wsi_display_invalidate_connector_modes(wsi_device
, connector
);
1824 xcb_randr_mode_t
*x_modes
= xcb_randr_get_output_info_modes(oir
);
1825 for (int m
= 0; m
< oir
->num_modes
; m
++) {
1826 xcb_randr_mode_info_iterator_t i
=
1827 xcb_randr_get_screen_resources_modes_iterator(srr
);
1829 xcb_randr_mode_info_t
*mi
= i
.data
;
1830 if (mi
->id
== x_modes
[m
]) {
1831 VkResult result
= wsi_display_register_x_mode(
1832 wsi_device
, connector
, mi
, m
< oir
->num_preferred
);
1833 if (result
!= VK_SUCCESS
) {
1840 xcb_randr_mode_info_next(&i
);
1850 static xcb_randr_crtc_t
1851 wsi_display_find_crtc_for_output(xcb_connection_t
*connection
,
1853 xcb_randr_output_t output
)
1855 xcb_randr_get_screen_resources_cookie_t gsr_c
=
1856 xcb_randr_get_screen_resources(connection
, root
);
1857 xcb_randr_get_screen_resources_reply_t
*gsr_r
=
1858 xcb_randr_get_screen_resources_reply(connection
, gsr_c
, NULL
);
1863 xcb_randr_crtc_t
*rc
= xcb_randr_get_screen_resources_crtcs(gsr_r
);
1864 xcb_randr_crtc_t idle_crtc
= 0;
1865 xcb_randr_crtc_t active_crtc
= 0;
1867 /* Find either a crtc already connected to the desired output or idle */
1868 for (int c
= 0; active_crtc
== 0 && c
< gsr_r
->num_crtcs
; c
++) {
1869 xcb_randr_get_crtc_info_cookie_t gci_c
=
1870 xcb_randr_get_crtc_info(connection
, rc
[c
], gsr_r
->config_timestamp
);
1871 xcb_randr_get_crtc_info_reply_t
*gci_r
=
1872 xcb_randr_get_crtc_info_reply(connection
, gci_c
, NULL
);
1876 int num_outputs
= xcb_randr_get_crtc_info_outputs_length(gci_r
);
1877 xcb_randr_output_t
*outputs
=
1878 xcb_randr_get_crtc_info_outputs(gci_r
);
1880 if (num_outputs
== 1 && outputs
[0] == output
)
1881 active_crtc
= rc
[c
];
1883 } else if (idle_crtc
== 0) {
1884 int num_possible
= xcb_randr_get_crtc_info_possible_length(gci_r
);
1885 xcb_randr_output_t
*possible
=
1886 xcb_randr_get_crtc_info_possible(gci_r
);
1888 for (int p
= 0; p
< num_possible
; p
++)
1889 if (possible
[p
] == output
) {
1905 wsi_acquire_xlib_display(VkPhysicalDevice physical_device
,
1906 struct wsi_device
*wsi_device
,
1908 VkDisplayKHR display
)
1910 struct wsi_display
*wsi
=
1911 (struct wsi_display
*) wsi_device
->wsi
[VK_ICD_WSI_PLATFORM_DISPLAY
];
1912 xcb_connection_t
*connection
= XGetXCBConnection(dpy
);
1913 struct wsi_display_connector
*connector
=
1914 wsi_display_connector_from_handle(display
);
1917 /* XXX no support for multiple leases yet */
1919 return VK_ERROR_INITIALIZATION_FAILED
;
1921 if (!connector
->output
) {
1922 connector
->output
= wsi_display_connector_id_to_output(connection
,
1925 /* Check and see if we found the output */
1926 if (!connector
->output
)
1927 return VK_ERROR_INITIALIZATION_FAILED
;
1930 root
= wsi_display_output_to_root(connection
, connector
->output
);
1932 return VK_ERROR_INITIALIZATION_FAILED
;
1934 xcb_randr_crtc_t crtc
= wsi_display_find_crtc_for_output(connection
,
1939 return VK_ERROR_INITIALIZATION_FAILED
;
1941 xcb_randr_lease_t lease
= xcb_generate_id(connection
);
1942 xcb_randr_create_lease_cookie_t cl_c
=
1943 xcb_randr_create_lease(connection
, root
, lease
, 1, 1,
1944 &crtc
, &connector
->output
);
1945 xcb_randr_create_lease_reply_t
*cl_r
=
1946 xcb_randr_create_lease_reply(connection
, cl_c
, NULL
);
1948 return VK_ERROR_INITIALIZATION_FAILED
;
1951 if (cl_r
->nfd
> 0) {
1952 int *rcl_f
= xcb_randr_create_lease_reply_fds(connection
, cl_r
);
1958 return VK_ERROR_INITIALIZATION_FAILED
;
1966 wsi_get_randr_output_display(VkPhysicalDevice physical_device
,
1967 struct wsi_device
*wsi_device
,
1970 VkDisplayKHR
*display
)
1972 xcb_connection_t
*connection
= XGetXCBConnection(dpy
);
1973 struct wsi_display_connector
*connector
=
1974 wsi_display_get_output(wsi_device
, connection
, (xcb_randr_output_t
) output
);
1977 *display
= wsi_display_connector_to_handle(connector
);