All of lore.kernel.org
 help / color / mirror / Atom feed
From: Keith Packard <keithp@keithp.com>
To: mesa-dev@lists.freedesktop.org
Cc: Keith Packard <keithp@keithp.com>, dri-devel@lists.freedesktop.org
Subject: [PATCH 5/7] vulkan: add VK_EXT_display_control [v4]
Date: Fri,  9 Feb 2018 20:45:14 -0800	[thread overview]
Message-ID: <20180210044516.16944-6-keithp@keithp.com> (raw)
In-Reply-To: <20180210044516.16944-1-keithp@keithp.com>

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@keithp.com>
---
 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@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2018-02-10  4:45 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-10  4:45 [PATCH 0/7] vulkan: Add direct display extensions Keith Packard
2018-02-10  4:45 ` [PATCH 1/7] vulkan: Add KHR_display extension to anv and radv using DRM Keith Packard
2018-02-12 15:27   ` Eric Engestrom
2018-02-12 22:16     ` Keith Packard
2018-02-12 16:18   ` [Mesa-dev] " Emil Velikov
2018-02-12 23:12     ` Keith Packard
2018-02-14  1:10   ` Jason Ekstrand
2018-02-15 17:46     ` Keith Packard
2018-02-23 23:00       ` Jason Ekstrand
2018-02-23 23:43         ` Keith Packard
2018-02-24  0:51           ` Jason Ekstrand
2018-03-12 23:02             ` Keith Packard
2018-03-29  6:59   ` Mao, David
2018-03-29 15:05     ` Keith Packard
2018-02-10  4:45 ` [PATCH 2/7] vulkan: Add EXT_direct_mode_display Keith Packard
2018-02-10  4:45 ` [PATCH 3/7] vulkan: Add EXT_acquire_xlib_display Keith Packard
2018-02-13  0:16   ` Dylan Baker
2018-02-10  4:45 ` [PATCH 4/7] vulkan: Add VK_EXT_display_surface_counter [v4] Keith Packard
2018-02-10  4:45 ` Keith Packard [this message]
2018-02-10  4:45 ` [PATCH 6/7] vulkan: Add new VK_MESA_query_timestamp extension Keith Packard
2018-02-13  0:20   ` Dylan Baker
2018-02-13 10:49     ` [Mesa-dev] " Lionel Landwerlin
2018-02-13 21:11       ` Keith Packard
2018-02-10  4:45 ` [PATCH 7/7] vulkan: Add VK_GOOGLE_display_timing extension (x11 and display backends) Keith Packard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180210044516.16944-6-keithp@keithp.com \
    --to=keithp@keithp.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=mesa-dev@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.