This extension provides fences and frame count information to direct display contexts. It uses new kernel ioctls to provide 64-bits of vblank sequence and nanosecond resolution. v2: Remove DRM_CRTC_SEQUENCE_FIRST_PIXEL_OUT flag. This has been removed from the proposed kernel API. Add NULL parameter to drmCrtcQueueSequence ioctl as we don't care what sequence the event was actually queued to. v3: Adapt to pthread clock switch to MONOTONIC v4: Add support for anv Signed-off-by: Keith Packard <keithp@xxxxxxxxxx> --- src/amd/vulkan/radv_extensions.py | 1 + src/amd/vulkan/radv_private.h | 11 +- src/amd/vulkan/radv_wsi_display.c | 109 ++++++++++++++ src/intel/vulkan/anv_extensions.py | 1 + src/intel/vulkan/anv_private.h | 4 + src/intel/vulkan/anv_queue.c | 59 +++++++- src/intel/vulkan/anv_wsi_display.c | 103 +++++++++++++ src/vulkan/wsi/wsi_common.h | 9 ++ src/vulkan/wsi/wsi_common_display.c | 286 +++++++++++++++++++++++++++++++++++- src/vulkan/wsi/wsi_common_display.h | 29 ++++ 10 files changed, 603 insertions(+), 9 deletions(-) diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py index 3f315e074b5..775d1ed4be6 100644 --- a/src/amd/vulkan/radv_extensions.py +++ b/src/amd/vulkan/radv_extensions.py @@ -85,6 +85,7 @@ EXTENSIONS = [ Extension('VK_EXT_direct_mode_display', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), Extension('VK_EXT_acquire_xlib_display', 1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'), Extension('VK_EXT_display_surface_counter', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), + Extension('VK_EXT_display_control', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), Extension('VK_KHX_multiview', 1, '!ANDROID'), Extension('VK_EXT_debug_report', 9, True), Extension('VK_EXT_discard_rectangles', 1, True), diff --git a/src/amd/vulkan/radv_private.h b/src/amd/vulkan/radv_private.h index 1e3719bcc4f..2aee38f0159 100644 --- a/src/amd/vulkan/radv_private.h +++ b/src/amd/vulkan/radv_private.h @@ -1647,8 +1647,17 @@ void radv_initialise_cmask(struct radv_cmd_buffer *cmd_buffer, void radv_initialize_dcc(struct radv_cmd_buffer *cmd_buffer, struct radv_image *image, uint32_t value); +enum radv_fence_type { + RADV_FENCE_TYPE_WINSYS = 0, + RADV_FENCE_TYPE_WSI = 1 +}; + struct radv_fence { - struct radeon_winsys_fence *fence; + enum radv_fence_type type; + union { + struct radeon_winsys_fence *fence; + struct wsi_fence *fence_wsi; + }; bool submitted; bool signalled; diff --git a/src/amd/vulkan/radv_wsi_display.c b/src/amd/vulkan/radv_wsi_display.c index 9b76ce623b0..5dd66b34a1a 100644 --- a/src/amd/vulkan/radv_wsi_display.c +++ b/src/amd/vulkan/radv_wsi_display.c @@ -182,3 +182,112 @@ radv_GetRandROutputDisplayEXT(VkPhysicalDevice physical_device, display); } #endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ + +/* VK_EXT_display_control */ + +VkResult +radv_DisplayPowerControlEXT(VkDevice _device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *display_power_info) +{ + RADV_FROM_HANDLE(radv_device, device, _device); + + return wsi_display_power_control(_device, + &device->physical_device->wsi_device, + display, + display_power_info); +} + +VkResult +radv_RegisterDeviceEventEXT(VkDevice _device, + const VkDeviceEventInfoEXT *device_event_info, + const VkAllocationCallbacks *allocator, + VkFence *_fence) +{ + RADV_FROM_HANDLE(radv_device, device, _device); + const VkAllocationCallbacks *alloc; + struct radv_fence *fence; + VkResult ret; + + if (allocator) + alloc = allocator; + else + alloc = &device->instance->alloc; + + fence = vk_alloc(alloc, sizeof (*fence), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!fence) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + fence->type = RADV_FENCE_TYPE_WSI; + fence->submitted = true; + fence->signalled = false; + + ret = wsi_register_device_event(_device, + &device->physical_device->wsi_device, + device_event_info, + alloc, + &fence->fence_wsi); + if (ret == VK_SUCCESS) + *_fence = radv_fence_to_handle(fence); + else + vk_free(alloc, fence); + return ret; +} + +VkResult +radv_RegisterDisplayEventEXT(VkDevice _device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT *display_event_info, + const VkAllocationCallbacks *allocator, + VkFence *_fence) +{ + RADV_FROM_HANDLE(radv_device, device, _device); + + const VkAllocationCallbacks *alloc; + struct radv_fence *fence; + VkResult ret; + + if (allocator) + alloc = allocator; + else + alloc = &device->instance->alloc; + + fence = vk_alloc(alloc, sizeof (*fence), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!fence) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + fence->type = RADV_FENCE_TYPE_WSI; + fence->submitted = true; + fence->signalled = false; + + ret = wsi_register_display_event(_device, + &device->physical_device->wsi_device, + display, + display_event_info, + alloc, + &(fence->fence_wsi)); + + if (ret == VK_SUCCESS) + *_fence = radv_fence_to_handle(fence); + else + vk_free(alloc, fence); + return ret; +} + +VkResult +radv_GetSwapchainCounterEXT(VkDevice _device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT flag_bits, + uint64_t *value) +{ + RADV_FROM_HANDLE(radv_device, device, _device); + + return wsi_get_swapchain_counter(_device, + &device->physical_device->wsi_device, + swapchain, + flag_bits, + value); +} + diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py index 8265077d894..f44598b305a 100644 --- a/src/intel/vulkan/anv_extensions.py +++ b/src/intel/vulkan/anv_extensions.py @@ -90,6 +90,7 @@ EXTENSIONS = [ Extension('VK_EXT_debug_report', 8, True), Extension('VK_EXT_external_memory_dma_buf', 1, True), Extension('VK_EXT_display_surface_counter', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), + Extension('VK_EXT_display_control', 1, 'VK_USE_PLATFORM_DISPLAY_KHR'), ] class VkVersion: diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index d38dd9e4220..1d3e5fcd921 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -1941,6 +1941,7 @@ enum anv_fence_type { ANV_FENCE_TYPE_NONE = 0, ANV_FENCE_TYPE_BO, ANV_FENCE_TYPE_SYNCOBJ, + ANV_FENCE_TYPE_WSI, }; enum anv_bo_fence_state { @@ -1975,6 +1976,9 @@ struct anv_fence_impl { /** DRM syncobj handle for syncobj-based fences */ uint32_t syncobj; + + /** WSI fence */ + struct wsi_fence *fence_wsi; }; }; diff --git a/src/intel/vulkan/anv_queue.c b/src/intel/vulkan/anv_queue.c index c6b2e01c628..d0bfad742d7 100644 --- a/src/intel/vulkan/anv_queue.c +++ b/src/intel/vulkan/anv_queue.c @@ -320,6 +320,10 @@ anv_fence_impl_cleanup(struct anv_device *device, case ANV_FENCE_TYPE_SYNCOBJ: anv_gem_syncobj_destroy(device, impl->syncobj); return; + + case ANV_FENCE_TYPE_WSI: + impl->fence_wsi->destroy(impl->fence_wsi); + return; } unreachable("Invalid fence type"); @@ -465,11 +469,32 @@ anv_wait_for_syncobj_fences(struct anv_device *device, uint32_t *syncobjs = vk_zalloc(&device->alloc, sizeof(*syncobjs) * fenceCount, 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + uint32_t syncobjCount = 0; if (!syncobjs) return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); for (uint32_t i = 0; i < fenceCount; i++) { ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); + + if (fence->permanent.type == ANV_FENCE_TYPE_WSI) { + struct anv_fence_impl *impl = &fence->permanent; + bool expired = impl->fence_wsi->wait(impl->fence_wsi, true, _timeout); + + VkResult result; + + if (!expired) { + result = VK_TIMEOUT; + goto done; + } + if (!waitAll) { + result = VK_SUCCESS; + goto done; + } + continue; + done: + vk_free(&device->alloc, syncobjs); + return result; + } assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ); struct anv_fence_impl *impl = @@ -477,7 +502,7 @@ anv_wait_for_syncobj_fences(struct anv_device *device, &fence->temporary : &fence->permanent; assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ); - syncobjs[i] = impl->syncobj; + syncobjs[syncobjCount++] = impl->syncobj; } int64_t abs_timeout_ns = 0; @@ -499,7 +524,7 @@ anv_wait_for_syncobj_fences(struct anv_device *device, */ int ret; do { - ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount, + ret = anv_gem_syncobj_wait(device, syncobjs, syncobjCount, abs_timeout_ns, waitAll); } while (ret == -1 && errno == ETIME && gettime_ns() < abs_timeout_ns); @@ -545,14 +570,33 @@ anv_wait_for_bo_fences(struct anv_device *device, for (uint32_t i = 0; i < fenceCount; i++) { ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); - /* This function assumes that all fences are BO fences and that they - * have no temporary state. Since BO fences will never be exported, - * this should be a safe assumption. + /* This function assumes that all fences have no temporary + * state.Since BO fences will never be exported, this should be a + * safe assumption. */ - assert(fence->permanent.type == ANV_FENCE_TYPE_BO); assert(fence->temporary.type == ANV_FENCE_TYPE_NONE); struct anv_fence_impl *impl = &fence->permanent; + /* This function assumes that all fences are either BO fences or WSI + * fences + */ + + if (impl->type == ANV_FENCE_TYPE_WSI) { + bool expired = impl->fence_wsi->wait(impl->fence_wsi, true, timeout); + + if (!expired) { + result = VK_TIMEOUT; + goto done; + } + if (!waitAll) { + result = VK_SUCCESS; + goto done; + } + continue; + } + + assert(impl->type == ANV_FENCE_TYPE_BO); + switch (impl->bo.state) { case ANV_BO_FENCE_STATE_RESET: /* This fence hasn't been submitted yet, we'll catch it the next @@ -610,7 +654,8 @@ anv_wait_for_bo_fences(struct anv_device *device, uint32_t now_pending_fences = 0; for (uint32_t i = 0; i < fenceCount; i++) { ANV_FROM_HANDLE(anv_fence, fence, pFences[i]); - if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET) + if (fence->permanent.type == ANV_FENCE_TYPE_BO && + fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET) now_pending_fences++; } assert(now_pending_fences <= pending_fences); diff --git a/src/intel/vulkan/anv_wsi_display.c b/src/intel/vulkan/anv_wsi_display.c index e87aed49f7d..32a948d76ca 100644 --- a/src/intel/vulkan/anv_wsi_display.c +++ b/src/intel/vulkan/anv_wsi_display.c @@ -168,3 +168,106 @@ anv_GetRandROutputDisplayEXT(VkPhysicalDevice physical_device, display); } #endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ + +/* VK_EXT_display_control */ + +VkResult +anv_DisplayPowerControlEXT(VkDevice _device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *display_power_info) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + return wsi_display_power_control(_device, + &device->instance->physicalDevice.wsi_device, + display, + display_power_info); +} + +VkResult +anv_RegisterDeviceEventEXT(VkDevice _device, + const VkDeviceEventInfoEXT *device_event_info, + const VkAllocationCallbacks *allocator, + VkFence *_fence) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + const VkAllocationCallbacks *alloc; + struct anv_fence *fence; + VkResult ret; + + if (allocator) + alloc = allocator; + else + alloc = &device->instance->alloc; + + fence = vk_alloc(alloc, sizeof (*fence), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!fence) + return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY); + + fence->permanent.type = ANV_FENCE_TYPE_WSI; + + ret = wsi_register_device_event(_device, + &device->instance->physicalDevice.wsi_device, + device_event_info, + alloc, + &fence->permanent.fence_wsi); + if (ret == VK_SUCCESS) + *_fence = anv_fence_to_handle(fence); + else + vk_free(alloc, fence); + return ret; +} + +VkResult +anv_RegisterDisplayEventEXT(VkDevice _device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT *display_event_info, + const VkAllocationCallbacks *allocator, + VkFence *_fence) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + const VkAllocationCallbacks *alloc; + struct anv_fence *fence; + VkResult ret; + + if (allocator) + alloc = allocator; + else + alloc = &device->instance->alloc; + + fence = vk_zalloc2(&device->alloc, allocator, sizeof (*fence), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!fence) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + fence->permanent.type = ANV_FENCE_TYPE_WSI; + + ret = wsi_register_display_event(_device, + &device->instance->physicalDevice.wsi_device, + display, + display_event_info, + alloc, + &(fence->permanent.fence_wsi)); + + if (ret == VK_SUCCESS) + *_fence = anv_fence_to_handle(fence); + else + vk_free(alloc, fence); + return ret; +} + +VkResult +anv_GetSwapchainCounterEXT(VkDevice _device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT flag_bits, + uint64_t *value) +{ + ANV_FROM_HANDLE(anv_device, device, _device); + + return wsi_get_swapchain_counter(_device, + &device->instance->physicalDevice.wsi_device, + swapchain, + flag_bits, + value); +} diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index 124d096170a..e504f4120ad 100644 --- a/src/vulkan/wsi/wsi_common.h +++ b/src/vulkan/wsi/wsi_common.h @@ -48,6 +48,15 @@ struct wsi_memory_allocate_info { bool implicit_sync; }; +struct wsi_fence { + VkDevice device; + const struct wsi_device *wsi_device; + VkDisplayKHR display; + const VkAllocationCallbacks *alloc; + bool (*wait)(struct wsi_fence *fence, bool absolute, uint64_t timeout); + void (*destroy)(struct wsi_fence *fence); +}; + struct wsi_interface; #define VK_ICD_WSI_PLATFORM_MAX 6 diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c index e63700e2e65..c3608f13e54 100644 --- a/src/vulkan/wsi/wsi_common_display.c +++ b/src/vulkan/wsi/wsi_common_display.c @@ -77,6 +77,7 @@ typedef struct wsi_display_connector { bool active; 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 @@ -124,6 +125,15 @@ struct wsi_display_swapchain { 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) @@ -271,6 +281,7 @@ wsi_display_get_connector(struct wsi_device *wsi_device, drmModeConnectorPtr drm_connector; VkResult result; int m; + int p; if (wsi->master_fd < 0) return NULL; @@ -292,6 +303,18 @@ wsi_display_get_connector(struct wsi_device *wsi_device, connector->connected = drm_connector->connection != DRM_MODE_DISCONNECTED; + /* Look for a DPMS property */ + for (p = 0; p < drm_connector->count_props; p++) { + drmModePropertyPtr prop = drmModeGetProperty(wsi->master_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); @@ -677,7 +700,7 @@ wsi_display_surface_get_capabilities2ext(VkIcdSurfaceBase *icd_surface, caps->currentTransform = khr_caps.currentTransform; caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha; caps->supportedUsageFlags = khr_caps.supportedUsageFlags; - caps->supportedSurfaceCounters = 0; + caps->supportedSurfaceCounters = VK_SURFACE_COUNTER_VBLANK_EXT; return ret; } @@ -865,12 +888,20 @@ static void wsi_display_page_flip_handler(int fd, unsigned int frame, 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); + +static void wsi_display_sequence_handler(int fd, uint64_t frame, + uint64_t ns, uint64_t user_data); + 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 * @@ -1117,6 +1148,135 @@ bail: } +static bool +wsi_display_fence_wait(struct wsi_fence *fence_wsi, + bool absolute, + 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; + int ret = 0; + bool value; + + if (!absolute) + timeout += wsi_get_current_monotonic(); + + wsi_display_debug("%9lu wait fence %lu %ld\n", pthread_self(), fence->sequence, (int64_t) (timeout - wsi_get_current_monotonic())); + wsi_display_debug_code(uint64_t start_ns = wsi_get_current_monotonic()); + pthread_mutex_lock(&wsi->wait_mutex); + for (;;) { + if (fence->event_received) { + wsi_display_debug("%9lu fence %lu passed\n", pthread_self(), fence->sequence); + value = true; + break; + } + + if (ret == ETIMEDOUT) { + wsi_display_debug("%9lu fence %lu timeout\n", pthread_self(), fence->sequence); + value = false; + 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); + value = false; + break; + } + } + pthread_mutex_unlock(&wsi->wait_mutex); + wsi_display_debug("%9lu fence wait %f ms\n", pthread_self(), ((int64_t) (wsi_get_current_monotonic() - start_ns)) / 1.0e6); + return value; +} + +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_destroy(struct wsi_fence *fence_wsi) +{ + struct wsi_display_fence *fence = (struct wsi_display_fence *) fence_wsi; + + 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_fence *fence = vk_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; + 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); + int ret; + + if (wsi->master_fd < 0) + return VK_ERROR_INITIALIZATION_FAILED; + + for (;;) { + ret = drmCrtcQueueSequence(wsi->master_fd, connector->crtc_id, + flags, + frame_requested, + frame_queued, + (uint64_t) fence); + + if (!ret) + return VK_SUCCESS; + + if (errno != ENOMEM) { + 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; + } + + pthread_mutex_lock(&wsi->wait_mutex); + ret = wsi_display_wait_for_event(wsi, wsi_get_current_monotonic() + 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. @@ -1882,3 +2042,127 @@ wsi_get_randr_output_display(VkPhysicalDevice physical_device, } #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->master_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->master_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_fence *fence = NULL; + VkResult ret = VK_ERROR_FEATURE_NOT_PRESENT; + + 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); + + break; + default: + ret = VK_ERROR_FEATURE_NOT_PRESENT; + } + + if (ret == VK_SUCCESS) + *fence_p = &fence->base; + else if (fence != NULL) + vk_free(allocator, fence); + 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; + int ret; + + if (wsi->master_fd < 0) + return VK_ERROR_INITIALIZATION_FAILED; + + if (!connector->active) { + *value = 0; + return VK_SUCCESS; + } + + ret = drmCrtcGetSequence(wsi->master_fd, connector->crtc_id, value, NULL); + if (ret) + *value = 0; + + return VK_SUCCESS; +} + +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_debug("%9lu fence %lu received %d\n", pthread_self(), fence->sequence, frame); + fence->event_received = true; + wsi_display_fence_check_free(fence); +} + +static void wsi_display_sequence_handler(int fd, uint64_t frame, + uint64_t ns, uint64_t user_data) +{ + struct wsi_display_fence *fence = (struct wsi_display_fence *) (uintptr_t) user_data; + + wsi_display_debug("%9lu fence %lu received %lu\n", pthread_self(), fence->sequence, frame); + fence->event_received = true; + wsi_display_fence_check_free(fence); +} + diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h index 1997c2a3c40..ec91ba471ae 100644 --- a/src/vulkan/wsi/wsi_common_display.h +++ b/src/vulkan/wsi/wsi_common_display.h @@ -91,4 +91,33 @@ wsi_get_randr_output_display(VkPhysicalDevice physical_device, #endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ +/* VK_EXT_display_control */ +VkResult +wsi_display_power_control(VkDevice device, + struct wsi_device *wsi_device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *display_power_info); + +VkResult +wsi_register_device_event(VkDevice device, + struct wsi_device *wsi_device, + const VkDeviceEventInfoEXT *device_event_info, + const VkAllocationCallbacks *allocator, + struct wsi_fence **fence); + +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); + +VkResult +wsi_get_swapchain_counter(VkDevice device, + struct wsi_device *wsi_device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT flag_bits, + uint64_t *value); + #endif -- 2.15.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel