#include <math.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <drm_fourcc.h>
+#include "drm-uapi/drm_fourcc.h"
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+#include <xcb/randr.h>
+#include <X11/Xlib-xcb.h>
+#endif
#include "util/hash_table.h"
#include "util/list.h"
struct list_head display_modes;
wsi_display_mode *current_mode;
drmModeModeInfo current_drm_mode;
+ uint32_t dpms_property;
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+ xcb_randr_output_t output;
+#endif
} wsi_display_connector;
struct wsi_display {
pthread_cond_t wait_cond;
pthread_t wait_thread;
- struct list_head connectors;
+ struct list_head connectors; /* list of all discovered connectors */
};
#define wsi_for_each_display_mode(_mode, _conn) \
struct wsi_display_image images[0];
};
+struct wsi_display_fence {
+ struct wsi_fence base;
+ bool event_received;
+ bool destroyed;
+ uint64_t sequence;
+};
+
+static uint64_t fence_sequence;
+
ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_mode, VkDisplayModeKHR)
ICD_DEFINE_NONDISP_HANDLE_CASTS(wsi_display_connector, VkDisplayKHR)
(double) MAX2(wsi->vscan, 1));
}
-static uint64_t wsi_get_current_monotonic(void)
-{
- struct timespec tv;
-
- clock_gettime(CLOCK_MONOTONIC, &tv);
- return tv.tv_nsec + tv.tv_sec*1000000000ull;
-}
-
static uint64_t wsi_rel_to_abs_time(uint64_t rel_time)
{
- uint64_t current_time = wsi_get_current_monotonic();
+ uint64_t current_time = wsi_common_get_current_time();
/* check for overflow */
if (rel_time > UINT64_MAX - current_time)
connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED;
+ /* Look for a DPMS property if we haven't already found one */
+ for (int p = 0; connector->dpms_property == 0 &&
+ p < drm_connector->count_props; p++)
+ {
+ drmModePropertyPtr prop = drmModeGetProperty(wsi->fd,
+ drm_connector->props[p]);
+ if (!prop)
+ continue;
+ if (prop->flags & DRM_MODE_PROP_ENUM) {
+ if (!strcmp(prop->name, "DPMS"))
+ connector->dpms_property = drm_connector->props[p];
+ }
+ drmModeFreeProperty(prop);
+ }
+
/* Mark all connector modes as invalid */
wsi_display_invalidate_connector_modes(wsi_device, connector);
static void
wsi_display_fill_in_display_properties(struct wsi_device *wsi_device,
struct wsi_display_connector *connector,
- VkDisplayPropertiesKHR *properties)
+ VkDisplayProperties2KHR *properties2)
{
+ assert(properties2->sType == VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR);
+ VkDisplayPropertiesKHR *properties = &properties2->displayProperties;
+
properties->display = wsi_display_connector_to_handle(connector);
properties->displayName = connector->name;
struct wsi_display *wsi =
(struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ if (properties == NULL) {
+ return wsi_display_get_physical_device_display_properties2(
+ physical_device, wsi_device, property_count, NULL);
+ } else {
+ /* If we're actually returning properties, allocate a temporary array of
+ * VkDisplayProperties2KHR structs, call properties2 to fill them out,
+ * and then copy them to the client. This seems a bit expensive but
+ * wsi_display_get_physical_device_display_properties2() calls
+ * drmModeGetResources() which does an ioctl and then a bunch of
+ * allocations so this should get lost in the noise.
+ */
+ VkDisplayProperties2KHR *props2 =
+ vk_zalloc(wsi->alloc, sizeof(*props2) * *property_count, 8,
+ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+ if (props2 == NULL)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+ for (uint32_t i = 0; i < *property_count; i++)
+ props2[i].sType = VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR;
+
+ VkResult result = wsi_display_get_physical_device_display_properties2(
+ physical_device, wsi_device, property_count, props2);
+
+ if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
+ for (uint32_t i = 0; i < *property_count; i++)
+ properties[i] = props2[i].displayProperties;
+ }
+
+ vk_free(wsi->alloc, props2);
+
+ return result;
+ }
+}
+
+VkResult
+wsi_display_get_physical_device_display_properties2(
+ VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ uint32_t *property_count,
+ VkDisplayProperties2KHR *properties)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+
if (wsi->fd < 0)
goto bail;
/*
* Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display
*/
+static void
+wsi_display_fill_in_display_plane_properties(
+ struct wsi_device *wsi_device,
+ struct wsi_display_connector *connector,
+ VkDisplayPlaneProperties2KHR *properties)
+{
+ assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR);
+ VkDisplayPlanePropertiesKHR *prop = &properties->displayPlaneProperties;
+
+ if (connector && connector->active) {
+ prop->currentDisplay = wsi_display_connector_to_handle(connector);
+ prop->currentStackIndex = 0;
+ } else {
+ prop->currentDisplay = VK_NULL_HANDLE;
+ prop->currentStackIndex = 0;
+ }
+}
+
VkResult
wsi_display_get_physical_device_display_plane_properties(
VkPhysicalDevice physical_device,
wsi_for_each_connector(connector, wsi) {
vk_outarray_append(&conn, prop) {
- if (connector && connector->active) {
- prop->currentDisplay = wsi_display_connector_to_handle(connector);
- prop->currentStackIndex = 0;
- } else {
- prop->currentDisplay = VK_NULL_HANDLE;
- prop->currentStackIndex = 0;
- }
+ VkDisplayPlaneProperties2KHR prop2 = {
+ .sType = VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR,
+ };
+ wsi_display_fill_in_display_plane_properties(wsi_device, connector,
+ &prop2);
+ *prop = prop2.displayPlaneProperties;
+ }
+ }
+ return vk_outarray_status(&conn);
+}
+
+VkResult
+wsi_display_get_physical_device_display_plane_properties2(
+ VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ uint32_t *property_count,
+ VkDisplayPlaneProperties2KHR *properties)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+
+ VK_OUTARRAY_MAKE(conn, properties, property_count);
+
+ wsi_for_each_connector(connector, wsi) {
+ vk_outarray_append(&conn, prop) {
+ wsi_display_fill_in_display_plane_properties(wsi_device, connector,
+ prop);
}
}
return vk_outarray_status(&conn);
* Implement vkGetDisplayModePropertiesKHR (VK_KHR_display)
*/
+static void
+wsi_display_fill_in_display_mode_properties(
+ struct wsi_device *wsi_device,
+ struct wsi_display_mode *display_mode,
+ VkDisplayModeProperties2KHR *properties)
+{
+ assert(properties->sType == VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR);
+ VkDisplayModePropertiesKHR *prop = &properties->displayModeProperties;
+
+ prop->displayMode = wsi_display_mode_to_handle(display_mode);
+ prop->parameters.visibleRegion.width = display_mode->hdisplay;
+ prop->parameters.visibleRegion.height = display_mode->vdisplay;
+ prop->parameters.refreshRate =
+ (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
+}
+
VkResult
wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device,
struct wsi_device *wsi_device,
VK_OUTARRAY_MAKE(conn, properties, property_count);
wsi_for_each_display_mode(display_mode, connector) {
- if (display_mode->valid) {
- vk_outarray_append(&conn, prop) {
- prop->displayMode = wsi_display_mode_to_handle(display_mode);
- prop->parameters.visibleRegion.width = display_mode->hdisplay;
- prop->parameters.visibleRegion.height = display_mode->vdisplay;
- prop->parameters.refreshRate =
- (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5);
- }
+ if (!display_mode->valid)
+ continue;
+
+ vk_outarray_append(&conn, prop) {
+ VkDisplayModeProperties2KHR prop2 = {
+ .sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR,
+ };
+ wsi_display_fill_in_display_mode_properties(wsi_device,
+ display_mode, &prop2);
+ *prop = prop2.displayModeProperties;
+ }
+ }
+ return vk_outarray_status(&conn);
+}
+
+VkResult
+wsi_display_get_display_mode_properties2(VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ VkDisplayKHR display,
+ uint32_t *property_count,
+ VkDisplayModeProperties2KHR *properties)
+{
+ struct wsi_display_connector *connector =
+ wsi_display_connector_from_handle(display);
+
+ VK_OUTARRAY_MAKE(conn, properties, property_count);
+
+ wsi_for_each_display_mode(display_mode, connector) {
+ if (!display_mode->valid)
+ continue;
+
+ vk_outarray_append(&conn, prop) {
+ wsi_display_fill_in_display_mode_properties(wsi_device,
+ display_mode, prop);
}
}
return vk_outarray_status(&conn);
return VK_SUCCESS;
}
+VkResult
+wsi_get_display_plane_capabilities2(
+ VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo,
+ VkDisplayPlaneCapabilities2KHR *capabilities)
+{
+ assert(capabilities->sType ==
+ VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR);
+
+ VkResult result =
+ wsi_get_display_plane_capabilities(physical_device, wsi_device,
+ pDisplayPlaneInfo->mode,
+ pDisplayPlaneInfo->planeIndex,
+ &capabilities->capabilities);
+
+ vk_foreach_struct(ext, capabilities->pNext) {
+ switch (ext->sType) {
+ case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
+ VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
+ protected->supportsProtected = VK_FALSE;
+ break;
+ }
+
+ default:
+ /* Ignored */
+ break;
+ }
+ }
+
+ return result;
+}
+
VkResult
wsi_create_display_surface(VkInstance instance,
const VkAllocationCallbacks *allocator,
static VkResult
wsi_display_surface_get_support(VkIcdSurfaceBase *surface,
struct wsi_device *wsi_device,
- const VkAllocationCallbacks *allocator,
uint32_t queueFamilyIndex,
- int local_fd,
VkBool32* pSupported)
{
*pSupported = VK_TRUE;
static VkResult
wsi_display_surface_get_capabilities(VkIcdSurfaceBase *surface_base,
+ struct wsi_device *wsi_device,
VkSurfaceCapabilitiesKHR* caps)
{
VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
caps->currentExtent.width = mode->hdisplay;
caps->currentExtent.height = mode->vdisplay;
- /* XXX Figure out extents based on driver capabilities */
- caps->maxImageExtent = caps->minImageExtent = caps->currentExtent;
+ caps->minImageExtent = (VkExtent2D) { 1, 1 };
+ caps->maxImageExtent = (VkExtent2D) {
+ wsi_device->maxImageDimension2D,
+ wsi_device->maxImageDimension2D,
+ };
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
+ VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
return VK_SUCCESS;
}
+static VkResult
+wsi_display_surface_get_surface_counters(
+ VkIcdSurfaceBase *surface_base,
+ VkSurfaceCounterFlagsEXT *counters)
+{
+ *counters = VK_SURFACE_COUNTER_VBLANK_EXT;
+ return VK_SUCCESS;
+}
+
static VkResult
wsi_display_surface_get_capabilities2(VkIcdSurfaceBase *icd_surface,
+ struct wsi_device *wsi_device,
const void *info_next,
VkSurfaceCapabilities2KHR *caps)
{
assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
+ VkResult result;
+
+ result = wsi_display_surface_get_capabilities(icd_surface, wsi_device,
+ &caps->surfaceCapabilities);
+ if (result != VK_SUCCESS)
+ return result;
+
+ struct wsi_surface_supported_counters *counters =
+ vk_find_struct( caps->pNext, WSI_SURFACE_SUPPORTED_COUNTERS_MESA);
+
+ if (counters) {
+ result = wsi_display_surface_get_surface_counters(
+ icd_surface,
+ &counters->supported_surface_counters);
+ }
- return wsi_display_surface_get_capabilities(icd_surface,
- &caps->surfaceCapabilities);
+ return result;
}
static const struct {
{ .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 },
};
+static void
+get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)
+{
+ for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)
+ sorted_formats[i] = available_surface_formats[i].format;
+
+ if (wsi_device->force_bgra8_unorm_first) {
+ for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
+ if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {
+ sorted_formats[i] = sorted_formats[0];
+ sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
+ break;
+ }
+ }
+ }
+}
+
static VkResult
wsi_display_surface_get_formats(VkIcdSurfaceBase *icd_surface,
struct wsi_device *wsi_device,
{
VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
- for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
+ VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
+ get_sorted_vk_formats(wsi_device, sorted_formats);
+
+ for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
vk_outarray_append(&out, f) {
- f->format = available_surface_formats[i].format;
+ f->format = sorted_formats[i];
f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
}
}
{
VK_OUTARRAY_MAKE(out, surface_formats, surface_format_count);
- for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
+ VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
+ get_sorted_vk_formats(wsi_device, sorted_formats);
+
+ for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
vk_outarray_append(&out, f) {
assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
- f->surfaceFormat.format = available_surface_formats[i].format;
+ f->surfaceFormat.format = sorted_formats[i];
f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
}
}
return vk_outarray_status(&conn);
}
+static VkResult
+wsi_display_surface_get_present_rectangles(VkIcdSurfaceBase *surface_base,
+ struct wsi_device *wsi_device,
+ uint32_t* pRectCount,
+ VkRect2D* pRects)
+{
+ VkIcdSurfaceDisplay *surface = (VkIcdSurfaceDisplay *) surface_base;
+ wsi_display_mode *mode = wsi_display_mode_from_handle(surface->displayMode);
+ VK_OUTARRAY_MAKE(out, pRects, pRectCount);
+
+ if (wsi_device_matches_drm_fd(wsi_device, mode->connector->wsi->fd)) {
+ vk_outarray_append(&out, rect) {
+ *rect = (VkRect2D) {
+ .offset = { 0, 0 },
+ .extent = { mode->hdisplay, mode->vdisplay },
+ };
+ }
+ }
+
+ return vk_outarray_status(&out);
+}
+
static void
wsi_display_destroy_buffer(struct wsi_display *wsi,
uint32_t buffer)
{
- (void) drmIoctl(wsi->fd, DRM_IOCTL_MODE_DESTROY_DUMB,
- &((struct drm_mode_destroy_dumb) { .handle = buffer }));
+ (void) drmIoctl(wsi->fd, DRM_IOCTL_GEM_CLOSE,
+ &((struct drm_gem_close) { .handle = buffer }));
}
static VkResult
for (uint32_t i = 0; i < chain->base.image_count; i++)
wsi_display_image_finish(drv_chain, allocator, &chain->images[i]);
+
+ wsi_swapchain_finish(&chain->base);
vk_free(allocator, chain);
return VK_SUCCESS;
}
chain->status = result;
}
+static void wsi_display_fence_event_handler(struct wsi_display_fence *fence);
+
static void wsi_display_page_flip_handler(int fd,
unsigned int frame,
unsigned int sec,
wsi_display_page_flip_handler2(fd, frame, sec, usec, 0, data);
}
+static void wsi_display_vblank_handler(int fd, unsigned int frame,
+ unsigned int sec, unsigned int usec,
+ void *data)
+{
+ struct wsi_display_fence *fence = data;
+
+ wsi_display_fence_event_handler(fence);
+}
+
+static void wsi_display_sequence_handler(int fd, uint64_t frame,
+ uint64_t nsec, uint64_t user_data)
+{
+ struct wsi_display_fence *fence =
+ (struct wsi_display_fence *) (uintptr_t) user_data;
+
+ wsi_display_fence_event_handler(fence);
+}
+
static drmEventContext event_context = {
.version = DRM_EVENT_CONTEXT_VERSION,
.page_flip_handler = wsi_display_page_flip_handler,
#if DRM_EVENT_CONTEXT_VERSION >= 3
.page_flip_handler2 = wsi_display_page_flip_handler2,
#endif
+ .vblank_handler = wsi_display_vblank_handler,
+ .sequence_handler = wsi_display_sequence_handler,
};
static void *
static VkResult
wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
- uint64_t timeout,
- VkSemaphore semaphore,
+ const VkAcquireNextImageInfoKHR *info,
uint32_t *image_index)
{
struct wsi_display_swapchain *chain =
if (chain->status != VK_SUCCESS)
return chain->status;
+ uint64_t timeout = info->timeout;
if (timeout != 0 && timeout != UINT64_MAX)
timeout = wsi_rel_to_abs_time(timeout);
ret = wsi_display_wait_for_event(wsi, timeout);
if (ret && ret != ETIMEDOUT) {
- result = VK_ERROR_OUT_OF_DATE_KHR;
+ result = VK_ERROR_SURFACE_LOST_KHR;
goto done;
}
}
* which is currently idle.
*/
static uint32_t
-wsi_display_select_crtc(struct wsi_display_connector *connector,
+wsi_display_select_crtc(const struct wsi_display_connector *connector,
drmModeResPtr mode_res,
drmModeConnectorPtr drm_connector)
{
if (errno == ENOMEM)
result = VK_ERROR_OUT_OF_HOST_MEMORY;
else
- result = VK_ERROR_OUT_OF_DATE_KHR;
+ result = VK_ERROR_SURFACE_LOST_KHR;
goto bail;
}
if (errno == ENOMEM)
result = VK_ERROR_OUT_OF_HOST_MEMORY;
else
- result = VK_ERROR_OUT_OF_DATE_KHR;
+ result = VK_ERROR_SURFACE_LOST_KHR;
goto bail_mode_res;
}
connector->crtc_id = wsi_display_select_crtc(connector,
mode_res, drm_connector);
if (!connector->crtc_id) {
- result = VK_ERROR_OUT_OF_DATE_KHR;
+ result = VK_ERROR_SURFACE_LOST_KHR;
goto bail_connector;
}
}
}
if (!drm_mode) {
- result = VK_ERROR_OUT_OF_DATE_KHR;
+ result = VK_ERROR_SURFACE_LOST_KHR;
goto bail_connector;
}
}
+static VkResult
+wsi_display_fence_wait(struct wsi_fence *fence_wsi, uint64_t timeout)
+{
+ const struct wsi_device *wsi_device = fence_wsi->wsi_device;
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
+
+ wsi_display_debug("%9lu wait fence %lu %ld\n",
+ pthread_self(), fence->sequence,
+ (int64_t) (timeout - wsi_common_get_current_time()));
+ wsi_display_debug_code(uint64_t start_ns = wsi_common_get_current_time());
+ pthread_mutex_lock(&wsi->wait_mutex);
+
+ VkResult result;
+ int ret = 0;
+ for (;;) {
+ if (fence->event_received) {
+ wsi_display_debug("%9lu fence %lu passed\n",
+ pthread_self(), fence->sequence);
+ result = VK_SUCCESS;
+ break;
+ }
+
+ if (ret == ETIMEDOUT) {
+ wsi_display_debug("%9lu fence %lu timeout\n",
+ pthread_self(), fence->sequence);
+ result = VK_TIMEOUT;
+ break;
+ }
+
+ ret = wsi_display_wait_for_event(wsi, timeout);
+
+ if (ret && ret != ETIMEDOUT) {
+ wsi_display_debug("%9lu fence %lu error\n",
+ pthread_self(), fence->sequence);
+ result = VK_ERROR_DEVICE_LOST;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&wsi->wait_mutex);
+ wsi_display_debug("%9lu fence wait %f ms\n",
+ pthread_self(),
+ ((int64_t) (wsi_common_get_current_time() - start_ns)) /
+ 1.0e6);
+ return result;
+}
+
+static void
+wsi_display_fence_check_free(struct wsi_display_fence *fence)
+{
+ if (fence->event_received && fence->destroyed)
+ vk_free(fence->base.alloc, fence);
+}
+
+static void wsi_display_fence_event_handler(struct wsi_display_fence *fence)
+{
+ fence->event_received = true;
+ wsi_display_fence_check_free(fence);
+}
+
+static void
+wsi_display_fence_destroy(struct wsi_fence *fence_wsi)
+{
+ struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi;
+
+ assert(!fence->destroyed);
+ fence->destroyed = true;
+ wsi_display_fence_check_free(fence);
+}
+
+static struct wsi_display_fence *
+wsi_display_fence_alloc(VkDevice device,
+ const struct wsi_device *wsi_device,
+ VkDisplayKHR display,
+ const VkAllocationCallbacks *allocator)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_fence *fence =
+ vk_zalloc2(wsi->alloc, allocator, sizeof (*fence),
+ 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
+
+ if (!fence)
+ return NULL;
+
+ fence->base.device = device;
+ fence->base.display = display;
+ fence->base.wsi_device = wsi_device;
+ fence->base.alloc = allocator ? allocator : wsi->alloc;
+ fence->base.wait = wsi_display_fence_wait;
+ fence->base.destroy = wsi_display_fence_destroy;
+ fence->event_received = false;
+ fence->destroyed = false;
+ fence->sequence = ++fence_sequence;
+ return fence;
+}
+
+static VkResult
+wsi_register_vblank_event(struct wsi_display_fence *fence,
+ const struct wsi_device *wsi_device,
+ VkDisplayKHR display,
+ uint32_t flags,
+ uint64_t frame_requested,
+ uint64_t *frame_queued)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_connector *connector =
+ wsi_display_connector_from_handle(display);
+
+ if (wsi->fd < 0)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ for (;;) {
+ int ret = drmCrtcQueueSequence(wsi->fd, connector->crtc_id,
+ flags,
+ frame_requested,
+ frame_queued,
+ (uintptr_t) fence);
+
+ if (!ret)
+ return VK_SUCCESS;
+
+ if (errno != ENOMEM) {
+
+ /* Something unexpected happened. Pause for a moment so the
+ * application doesn't just spin and then return a failure indication
+ */
+
+ wsi_display_debug("queue vblank event %lu failed\n", fence->sequence);
+ struct timespec delay = {
+ .tv_sec = 0,
+ .tv_nsec = 100000000ull,
+ };
+ nanosleep(&delay, NULL);
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+
+ /* The kernel event queue is full. Wait for some events to be
+ * processed and try again
+ */
+
+ pthread_mutex_lock(&wsi->wait_mutex);
+ ret = wsi_display_wait_for_event(wsi, wsi_rel_to_abs_time(100000000ull));
+ pthread_mutex_unlock(&wsi->wait_mutex);
+
+ if (ret) {
+ wsi_display_debug("vblank queue full, event wait failed\n");
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ }
+}
+
/*
* Check to see if the kernel has no flip queued and if there's an image
* waiting to be displayed.
wsi_display_connector *connector = display_mode->connector;
if (wsi->fd < 0)
- return VK_ERROR_OUT_OF_DATE_KHR;
+ return VK_ERROR_SURFACE_LOST_KHR;
if (display_mode != connector->current_mode)
connector->active = false;
&connector->id, 1,
&connector->current_drm_mode);
if (ret == 0) {
+ /* Disable the HW cursor as the app doesn't have a mechanism
+ * to control it.
+ * Refer to question 12 of the VK_KHR_display spec.
+ */
+ ret = drmModeSetCursor(wsi->fd, connector->crtc_id, 0, 0, 0 );
+ if (ret != 0) {
+ wsi_display_debug("failed to hide cursor err %d %s\n", ret, strerror(-ret));
+ }
+
/* Assume that the mode set is synchronous and that any
* previous image is now idle.
*/
if (ret != -EACCES) {
connector->active = false;
image->state = WSI_IMAGE_IDLE;
- return VK_ERROR_OUT_OF_DATE_KHR;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
/* Some other VT is currently active. Sit here waiting for
VkIcdSurfaceBase *icd_surface,
VkDevice device,
struct wsi_device *wsi_device,
- int local_fd,
const VkSwapchainCreateInfoKHR *create_info,
const VkAllocationCallbacks *allocator,
struct wsi_swapchain **swapchain_out)
VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
create_info, allocator);
+ if (result != VK_SUCCESS) {
+ vk_free(allocator, chain);
+ return result;
+ }
chain->base.destroy = wsi_display_swapchain_destroy;
chain->base.get_wsi_image = wsi_display_get_wsi_image;
chain->base.acquire_next_image = wsi_display_acquire_next_image;
chain->base.queue_present = wsi_display_queue_present;
- chain->base.present_mode = create_info->presentMode;
+ chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
chain->base.image_count = num_images;
chain->wsi = wsi;
return ret;
}
+
+/*
+ * Local version fo the libdrm helper. Added to avoid depending on bleeding
+ * edge version of the library.
+ */
+static int
+local_drmIsMaster(int fd)
+{
+ /* Detect master by attempting something that requires master.
+ *
+ * Authenticating magic tokens requires master and 0 is an
+ * internal kernel detail which we could use. Attempting this on
+ * a master fd would fail therefore fail with EINVAL because 0
+ * is invalid.
+ *
+ * A non-master fd will fail with EACCES, as the kernel checks
+ * for master before attempting to do anything else.
+ *
+ * Since we don't want to leak implementation details, use
+ * EACCES.
+ */
+ return drmAuthMagic(fd, 0) != -EACCES;
+}
+
VkResult
wsi_display_init_wsi(struct wsi_device *wsi_device,
const VkAllocationCallbacks *alloc,
}
wsi->fd = display_fd;
+ if (wsi->fd != -1 && !local_drmIsMaster(wsi->fd))
+ wsi->fd = -1;
+
wsi->alloc = alloc;
list_inithead(&wsi->connectors);
}
wsi->base.get_support = wsi_display_surface_get_support;
- wsi->base.get_capabilities = wsi_display_surface_get_capabilities;
wsi->base.get_capabilities2 = wsi_display_surface_get_capabilities2;
wsi->base.get_formats = wsi_display_surface_get_formats;
wsi->base.get_formats2 = wsi_display_surface_get_formats2;
wsi->base.get_present_modes = wsi_display_surface_get_present_modes;
+ wsi->base.get_present_rectangles = wsi_display_surface_get_present_rectangles;
wsi->base.create_swapchain = wsi_display_surface_create_swapchain;
wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY] = &wsi->base;
vk_free(alloc, wsi);
}
}
+
+/*
+ * Implement vkReleaseDisplay
+ */
+VkResult
+wsi_release_display(VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ VkDisplayKHR display)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+
+ if (wsi->fd >= 0) {
+ close(wsi->fd);
+ wsi->fd = -1;
+ }
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+ wsi_display_connector_from_handle(display)->output = None;
+#endif
+
+ return VK_SUCCESS;
+}
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+
+static struct wsi_display_connector *
+wsi_display_find_output(struct wsi_device *wsi_device,
+ xcb_randr_output_t output)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+
+ wsi_for_each_connector(connector, wsi) {
+ if (connector->output == output)
+ return connector;
+ }
+
+ return NULL;
+}
+
+/*
+ * Given a RandR output, find the associated kernel connector_id by
+ * looking at the CONNECTOR_ID property provided by the X server
+ */
+
+static uint32_t
+wsi_display_output_to_connector_id(xcb_connection_t *connection,
+ xcb_atom_t *connector_id_atom_p,
+ xcb_randr_output_t output)
+{
+ uint32_t connector_id = 0;
+ xcb_atom_t connector_id_atom = *connector_id_atom_p;
+
+ if (connector_id_atom == 0) {
+ /* Go dig out the CONNECTOR_ID property */
+ xcb_intern_atom_cookie_t ia_c = xcb_intern_atom(connection,
+ true,
+ 12,
+ "CONNECTOR_ID");
+ xcb_intern_atom_reply_t *ia_r = xcb_intern_atom_reply(connection,
+ ia_c,
+ NULL);
+ if (ia_r) {
+ *connector_id_atom_p = connector_id_atom = ia_r->atom;
+ free(ia_r);
+ }
+ }
+
+ /* If there's an CONNECTOR_ID atom in the server, then there may be a
+ * CONNECTOR_ID property. Otherwise, there will not be and we don't even
+ * need to bother.
+ */
+ if (connector_id_atom) {
+
+ xcb_randr_query_version_cookie_t qv_c =
+ xcb_randr_query_version(connection, 1, 6);
+ xcb_randr_get_output_property_cookie_t gop_c =
+ xcb_randr_get_output_property(connection,
+ output,
+ connector_id_atom,
+ 0,
+ 0,
+ 0xffffffffUL,
+ 0,
+ 0);
+ xcb_randr_query_version_reply_t *qv_r =
+ xcb_randr_query_version_reply(connection, qv_c, NULL);
+ free(qv_r);
+ xcb_randr_get_output_property_reply_t *gop_r =
+ xcb_randr_get_output_property_reply(connection, gop_c, NULL);
+ if (gop_r) {
+ if (gop_r->num_items == 1 && gop_r->format == 32)
+ memcpy(&connector_id, xcb_randr_get_output_property_data(gop_r), 4);
+ free(gop_r);
+ }
+ }
+ return connector_id;
+}
+
+static bool
+wsi_display_check_randr_version(xcb_connection_t *connection)
+{
+ xcb_randr_query_version_cookie_t qv_c =
+ xcb_randr_query_version(connection, 1, 6);
+ xcb_randr_query_version_reply_t *qv_r =
+ xcb_randr_query_version_reply(connection, qv_c, NULL);
+ bool ret = false;
+
+ if (!qv_r)
+ return false;
+
+ /* Check for version 1.6 or newer */
+ ret = (qv_r->major_version > 1 ||
+ (qv_r->major_version == 1 && qv_r->minor_version >= 6));
+
+ free(qv_r);
+ return ret;
+}
+
+/*
+ * Given a kernel connector id, find the associated RandR output using the
+ * CONNECTOR_ID property
+ */
+
+static xcb_randr_output_t
+wsi_display_connector_id_to_output(xcb_connection_t *connection,
+ uint32_t connector_id)
+{
+ if (!wsi_display_check_randr_version(connection))
+ return 0;
+
+ const xcb_setup_t *setup = xcb_get_setup(connection);
+
+ xcb_atom_t connector_id_atom = 0;
+ xcb_randr_output_t output = 0;
+
+ /* Search all of the screens for the provided output */
+ xcb_screen_iterator_t iter;
+ for (iter = xcb_setup_roots_iterator(setup);
+ output == 0 && iter.rem;
+ xcb_screen_next(&iter))
+ {
+ xcb_randr_get_screen_resources_cookie_t gsr_c =
+ xcb_randr_get_screen_resources(connection, iter.data->root);
+ xcb_randr_get_screen_resources_reply_t *gsr_r =
+ xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+ if (!gsr_r)
+ return 0;
+
+ xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
+ int o;
+
+ for (o = 0; o < gsr_r->num_outputs; o++) {
+ if (wsi_display_output_to_connector_id(connection,
+ &connector_id_atom, ro[o])
+ == connector_id)
+ {
+ output = ro[o];
+ break;
+ }
+ }
+ free(gsr_r);
+ }
+ return output;
+}
+
+/*
+ * Given a RandR output, find out which screen it's associated with
+ */
+static xcb_window_t
+wsi_display_output_to_root(xcb_connection_t *connection,
+ xcb_randr_output_t output)
+{
+ if (!wsi_display_check_randr_version(connection))
+ return 0;
+
+ const xcb_setup_t *setup = xcb_get_setup(connection);
+ xcb_window_t root = 0;
+
+ /* Search all of the screens for the provided output */
+ for (xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
+ root == 0 && iter.rem;
+ xcb_screen_next(&iter))
+ {
+ xcb_randr_get_screen_resources_cookie_t gsr_c =
+ xcb_randr_get_screen_resources(connection, iter.data->root);
+ xcb_randr_get_screen_resources_reply_t *gsr_r =
+ xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+ if (!gsr_r)
+ return 0;
+
+ xcb_randr_output_t *ro = xcb_randr_get_screen_resources_outputs(gsr_r);
+
+ for (int o = 0; o < gsr_r->num_outputs; o++) {
+ if (ro[o] == output) {
+ root = iter.data->root;
+ break;
+ }
+ }
+ free(gsr_r);
+ }
+ return root;
+}
+
+static bool
+wsi_display_mode_matches_x(struct wsi_display_mode *wsi,
+ xcb_randr_mode_info_t *xcb)
+{
+ return wsi->clock == (xcb->dot_clock + 500) / 1000 &&
+ wsi->hdisplay == xcb->width &&
+ wsi->hsync_start == xcb->hsync_start &&
+ wsi->hsync_end == xcb->hsync_end &&
+ wsi->htotal == xcb->htotal &&
+ wsi->hskew == xcb->hskew &&
+ wsi->vdisplay == xcb->height &&
+ wsi->vsync_start == xcb->vsync_start &&
+ wsi->vsync_end == xcb->vsync_end &&
+ wsi->vtotal == xcb->vtotal &&
+ wsi->vscan <= 1 &&
+ wsi->flags == xcb->mode_flags;
+}
+
+static struct wsi_display_mode *
+wsi_display_find_x_mode(struct wsi_device *wsi_device,
+ struct wsi_display_connector *connector,
+ xcb_randr_mode_info_t *mode)
+{
+ wsi_for_each_display_mode(display_mode, connector) {
+ if (wsi_display_mode_matches_x(display_mode, mode))
+ return display_mode;
+ }
+ return NULL;
+}
+
+static VkResult
+wsi_display_register_x_mode(struct wsi_device *wsi_device,
+ struct wsi_display_connector *connector,
+ xcb_randr_mode_info_t *x_mode,
+ bool preferred)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_mode *display_mode =
+ wsi_display_find_x_mode(wsi_device, connector, x_mode);
+
+ if (display_mode) {
+ display_mode->valid = true;
+ return VK_SUCCESS;
+ }
+
+ display_mode = vk_zalloc(wsi->alloc, sizeof (struct wsi_display_mode),
+ 8, VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
+ if (!display_mode)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+ display_mode->connector = connector;
+ display_mode->valid = true;
+ display_mode->preferred = preferred;
+ display_mode->clock = (x_mode->dot_clock + 500) / 1000; /* kHz */
+ display_mode->hdisplay = x_mode->width;
+ display_mode->hsync_start = x_mode->hsync_start;
+ display_mode->hsync_end = x_mode->hsync_end;
+ display_mode->htotal = x_mode->htotal;
+ display_mode->hskew = x_mode->hskew;
+ display_mode->vdisplay = x_mode->height;
+ display_mode->vsync_start = x_mode->vsync_start;
+ display_mode->vsync_end = x_mode->vsync_end;
+ display_mode->vtotal = x_mode->vtotal;
+ display_mode->vscan = 0;
+ display_mode->flags = x_mode->mode_flags;
+
+ list_addtail(&display_mode->list, &connector->display_modes);
+ return VK_SUCCESS;
+}
+
+static struct wsi_display_connector *
+wsi_display_get_output(struct wsi_device *wsi_device,
+ xcb_connection_t *connection,
+ xcb_randr_output_t output)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_connector *connector;
+ uint32_t connector_id;
+
+ xcb_window_t root = wsi_display_output_to_root(connection, output);
+ if (!root)
+ return NULL;
+
+ /* See if we already have a connector for this output */
+ connector = wsi_display_find_output(wsi_device, output);
+
+ if (!connector) {
+ xcb_atom_t connector_id_atom = 0;
+
+ /*
+ * Go get the kernel connector ID for this X output
+ */
+ connector_id = wsi_display_output_to_connector_id(connection,
+ &connector_id_atom,
+ output);
+
+ /* Any X server with lease support will have this atom */
+ if (!connector_id) {
+ return NULL;
+ }
+
+ /* See if we already have a connector for this id */
+ connector = wsi_display_find_connector(wsi_device, connector_id);
+
+ if (connector == NULL) {
+ connector = wsi_display_alloc_connector(wsi, connector_id);
+ if (!connector) {
+ return NULL;
+ }
+ list_addtail(&connector->list, &wsi->connectors);
+ }
+ connector->output = output;
+ }
+
+ xcb_randr_get_screen_resources_cookie_t src =
+ xcb_randr_get_screen_resources(connection, root);
+ xcb_randr_get_output_info_cookie_t oic =
+ xcb_randr_get_output_info(connection, output, XCB_CURRENT_TIME);
+ xcb_randr_get_screen_resources_reply_t *srr =
+ xcb_randr_get_screen_resources_reply(connection, src, NULL);
+ xcb_randr_get_output_info_reply_t *oir =
+ xcb_randr_get_output_info_reply(connection, oic, NULL);
+
+ if (oir && srr) {
+ /* Get X modes and add them */
+
+ connector->connected =
+ oir->connection != XCB_RANDR_CONNECTION_DISCONNECTED;
+
+ wsi_display_invalidate_connector_modes(wsi_device, connector);
+
+ xcb_randr_mode_t *x_modes = xcb_randr_get_output_info_modes(oir);
+ for (int m = 0; m < oir->num_modes; m++) {
+ xcb_randr_mode_info_iterator_t i =
+ xcb_randr_get_screen_resources_modes_iterator(srr);
+ while (i.rem) {
+ xcb_randr_mode_info_t *mi = i.data;
+ if (mi->id == x_modes[m]) {
+ VkResult result = wsi_display_register_x_mode(
+ wsi_device, connector, mi, m < oir->num_preferred);
+ if (result != VK_SUCCESS) {
+ free(oir);
+ free(srr);
+ return NULL;
+ }
+ break;
+ }
+ xcb_randr_mode_info_next(&i);
+ }
+ }
+ }
+
+ free(oir);
+ free(srr);
+ return connector;
+}
+
+static xcb_randr_crtc_t
+wsi_display_find_crtc_for_output(xcb_connection_t *connection,
+ xcb_window_t root,
+ xcb_randr_output_t output)
+{
+ xcb_randr_get_screen_resources_cookie_t gsr_c =
+ xcb_randr_get_screen_resources(connection, root);
+ xcb_randr_get_screen_resources_reply_t *gsr_r =
+ xcb_randr_get_screen_resources_reply(connection, gsr_c, NULL);
+
+ if (!gsr_r)
+ return 0;
+
+ xcb_randr_crtc_t *rc = xcb_randr_get_screen_resources_crtcs(gsr_r);
+ xcb_randr_crtc_t idle_crtc = 0;
+ xcb_randr_crtc_t active_crtc = 0;
+
+ /* Find either a crtc already connected to the desired output or idle */
+ for (int c = 0; active_crtc == 0 && c < gsr_r->num_crtcs; c++) {
+ xcb_randr_get_crtc_info_cookie_t gci_c =
+ xcb_randr_get_crtc_info(connection, rc[c], gsr_r->config_timestamp);
+ xcb_randr_get_crtc_info_reply_t *gci_r =
+ xcb_randr_get_crtc_info_reply(connection, gci_c, NULL);
+
+ if (gci_r) {
+ if (gci_r->mode) {
+ int num_outputs = xcb_randr_get_crtc_info_outputs_length(gci_r);
+ xcb_randr_output_t *outputs =
+ xcb_randr_get_crtc_info_outputs(gci_r);
+
+ if (num_outputs == 1 && outputs[0] == output)
+ active_crtc = rc[c];
+
+ } else if (idle_crtc == 0) {
+ int num_possible = xcb_randr_get_crtc_info_possible_length(gci_r);
+ xcb_randr_output_t *possible =
+ xcb_randr_get_crtc_info_possible(gci_r);
+
+ for (int p = 0; p < num_possible; p++)
+ if (possible[p] == output) {
+ idle_crtc = rc[c];
+ break;
+ }
+ }
+ free(gci_r);
+ }
+ }
+ free(gsr_r);
+
+ if (active_crtc)
+ return active_crtc;
+ return idle_crtc;
+}
+
+VkResult
+wsi_acquire_xlib_display(VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ Display *dpy,
+ VkDisplayKHR display)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ xcb_connection_t *connection = XGetXCBConnection(dpy);
+ struct wsi_display_connector *connector =
+ wsi_display_connector_from_handle(display);
+ xcb_window_t root;
+
+ /* XXX no support for multiple leases yet */
+ if (wsi->fd >= 0)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ if (!connector->output) {
+ connector->output = wsi_display_connector_id_to_output(connection,
+ connector->id);
+
+ /* Check and see if we found the output */
+ if (!connector->output)
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
+ root = wsi_display_output_to_root(connection, connector->output);
+ if (!root)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ xcb_randr_crtc_t crtc = wsi_display_find_crtc_for_output(connection,
+ root,
+ connector->output);
+
+ if (!crtc)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+#ifdef HAVE_DRI3_MODIFIERS
+ xcb_randr_lease_t lease = xcb_generate_id(connection);
+ xcb_randr_create_lease_cookie_t cl_c =
+ xcb_randr_create_lease(connection, root, lease, 1, 1,
+ &crtc, &connector->output);
+ xcb_randr_create_lease_reply_t *cl_r =
+ xcb_randr_create_lease_reply(connection, cl_c, NULL);
+ if (!cl_r)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ int fd = -1;
+ if (cl_r->nfd > 0) {
+ int *rcl_f = xcb_randr_create_lease_reply_fds(connection, cl_r);
+
+ fd = rcl_f[0];
+ }
+ free (cl_r);
+ if (fd < 0)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ wsi->fd = fd;
+#endif
+
+ return VK_SUCCESS;
+}
+
+VkResult
+wsi_get_randr_output_display(VkPhysicalDevice physical_device,
+ struct wsi_device *wsi_device,
+ Display *dpy,
+ RROutput output,
+ VkDisplayKHR *display)
+{
+ xcb_connection_t *connection = XGetXCBConnection(dpy);
+ struct wsi_display_connector *connector =
+ wsi_display_get_output(wsi_device, connection, (xcb_randr_output_t) output);
+
+ if (connector)
+ *display = wsi_display_connector_to_handle(connector);
+ else
+ *display = VK_NULL_HANDLE;
+ return VK_SUCCESS;
+}
+
+#endif
+
+/* VK_EXT_display_control */
+VkResult
+wsi_display_power_control(VkDevice device,
+ struct wsi_device *wsi_device,
+ VkDisplayKHR display,
+ const VkDisplayPowerInfoEXT *display_power_info)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_connector *connector =
+ wsi_display_connector_from_handle(display);
+ int mode;
+
+ if (wsi->fd < 0)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ switch (display_power_info->powerState) {
+ case VK_DISPLAY_POWER_STATE_OFF_EXT:
+ mode = DRM_MODE_DPMS_OFF;
+ break;
+ case VK_DISPLAY_POWER_STATE_SUSPEND_EXT:
+ mode = DRM_MODE_DPMS_SUSPEND;
+ break;
+ default:
+ mode = DRM_MODE_DPMS_ON;
+ break;
+ }
+ drmModeConnectorSetProperty(wsi->fd,
+ connector->id,
+ connector->dpms_property,
+ mode);
+ return VK_SUCCESS;
+}
+
+VkResult
+wsi_register_device_event(VkDevice device,
+ struct wsi_device *wsi_device,
+ const VkDeviceEventInfoEXT *device_event_info,
+ const VkAllocationCallbacks *allocator,
+ struct wsi_fence **fence_p)
+{
+ return VK_ERROR_FEATURE_NOT_PRESENT;
+}
+
+VkResult
+wsi_register_display_event(VkDevice device,
+ struct wsi_device *wsi_device,
+ VkDisplayKHR display,
+ const VkDisplayEventInfoEXT *display_event_info,
+ const VkAllocationCallbacks *allocator,
+ struct wsi_fence **fence_p)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_fence *fence;
+ VkResult ret;
+
+ switch (display_event_info->displayEvent) {
+ case VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT:
+
+ fence = wsi_display_fence_alloc(device, wsi_device, display, allocator);
+
+ if (!fence)
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+ ret = wsi_register_vblank_event(fence, wsi_device, display,
+ DRM_CRTC_SEQUENCE_RELATIVE, 1, NULL);
+
+ if (ret == VK_SUCCESS)
+ *fence_p = &fence->base;
+ else if (fence != NULL)
+ vk_free2(wsi->alloc, allocator, fence);
+
+ break;
+ default:
+ ret = VK_ERROR_FEATURE_NOT_PRESENT;
+ break;
+ }
+
+ return ret;
+}
+
+
+VkResult
+wsi_get_swapchain_counter(VkDevice device,
+ struct wsi_device *wsi_device,
+ VkSwapchainKHR _swapchain,
+ VkSurfaceCounterFlagBitsEXT flag_bits,
+ uint64_t *value)
+{
+ struct wsi_display *wsi =
+ (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY];
+ struct wsi_display_swapchain *swapchain =
+ (struct wsi_display_swapchain *) wsi_swapchain_from_handle(_swapchain);
+ struct wsi_display_connector *connector =
+ wsi_display_mode_from_handle(swapchain->surface->displayMode)->connector;
+
+ if (wsi->fd < 0)
+ return VK_ERROR_INITIALIZATION_FAILED;
+
+ if (!connector->active) {
+ *value = 0;
+ return VK_SUCCESS;
+ }
+
+ int ret = drmCrtcGetSequence(wsi->fd, connector->crtc_id, value, NULL);
+ if (ret)
+ *value = 0;
+
+ return VK_SUCCESS;
+}
+