Commit c81c6ffe authored by Keith Packard's avatar Keith Packard

Start work on VK_MESA_present_period

This allows applications to specify the minimum time that a presented
image must be shown. Times may be specified as frames or ns.
Signed-off-by: Keith Packard's avatarKeith Packard <keithp@keithp.com>
parent 807dbe46
Pipeline #104367 failed with stages
in 43 minutes and 49 seconds
......@@ -560,6 +560,7 @@ typedef enum VkStructureType {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT = 1000276000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT = 1000281000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT = 1000281001,
VK_STRUCTURE_TYPE_PRESENT_PERIOD_MESA = 1000329000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES,
VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
......@@ -10715,6 +10716,18 @@ typedef struct VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT {
#define VK_GOOGLE_USER_TYPE_SPEC_VERSION 1
#define VK_GOOGLE_USER_TYPE_EXTENSION_NAME "VK_GOOGLE_user_type"
#define VK_MESA_present_period 1
#define VK_MESA_PRESENT_PERIOD_SPEC_VERSION 1
#define VK_MESA_PRESENT_PERIOD_EXTENSION_NAME "VK_MESA_present_period"
typedef struct VkPresentPeriodMESA {
VkStructureType sType;
const void* pNext;
uint32_t swapchainCount;
const int64_t* pPresentPeriods;
  • I like this extension in general.

    However, I think allowing the period to be specified in frames might be a mistake, because it won't work well with variable refresh rate. But it'll be tempting for application / toolkit developers not to bother with proper time calculations but to just use frames instead.

    P.S. It would be good to create a WIP merge request for this in the main Mesa project, to have a central place for gathering feedback and tracking progress.

    Edited by Michel Dänzer
  • Thanks for your kind words!

    I added the ability to specify periods in frames because I wanted to make it familiar to developers used to GL's swap interval, but I have to agree that it may discourage support for variable refresh rate.

    Hrm. Given that applications are going to need the refresh period to compute when frames will be displayed, maybe having everything done in nanoseconds wouldn't be a huge burden.

Please register or sign in to reply
} VkPresentPeriodMESA;
#ifdef __cplusplus
}
#endif
......
......@@ -167,6 +167,7 @@ EXTENSIONS = [
Extension('VK_GOOGLE_decorate_string', 1, True),
Extension('VK_GOOGLE_hlsl_functionality1', 1, True),
Extension('VK_GOOGLE_display_timing', 1, True),
Extension('VK_MESA_present_period', 1, True),
Extension('VK_NV_compute_shader_derivatives', 1, 'device->rad_info.chip_class >= GFX8'),
]
......
......@@ -174,6 +174,7 @@ EXTENSIONS = [
Extension('VK_GOOGLE_hlsl_functionality1', 1, True),
Extension('VK_INTEL_performance_query', 1, 'device->perf'),
Extension('VK_INTEL_shader_integer_functions2', 1, 'device->info.gen >= 8'),
Extension('VK_MESA_present_period', 1, True),
Extension('VK_NV_compute_shader_derivatives', 1, True),
]
......
......@@ -2546,6 +2546,12 @@ typedef void <name>CAMetalLayer</name>;
<member><type>float</type> <name>x</name></member>
<member><type>float</type> <name>y</name></member>
</type>
<type category="struct" name="VkPresentPeriodMESA" structextends="VkPresentInfoKHR">
<member values="VK_STRUCTURE_TYPE_PRESENT_PERIOD_MESA"><type>VkStructureType</type> <name>sType</name></member>
<member>const <type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>swapchainCount</name><comment>Copy of VkPresentInfoKHR::swapchainCount</comment></member>
<member len="swapchainCount" optional="true">const <type>int64_t</type>* <name>pPresentPeriods</name><comment>Present period values for each swapchain</comment></member>
</type>
<type category="struct" name="VkHdrMetadataEXT">
<comment>Display primary in chromaticity coordinates</comment>
<member values="VK_STRUCTURE_TYPE_HDR_METADATA_EXT"><type>VkStructureType</type> <name>sType</name></member>
......@@ -12453,5 +12459,13 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="2" extends="VkMemoryHeapFlagBits" name="VK_MEMORY_HEAP_RESERVED_2_BIT_KHR"/>
</require>
</extension>
<extension name="VK_MESA_present_period" number="330" type="device" requires="VK_KHR_swapchain" author="MESA" contact="Keith Packard @keithp" supported="vulkan">
<require>
<enum value="1" name="VK_MESA_PRESENT_PERIOD_SPEC_VERSION"/>
<enum value="&quot;VK_MESA_present_period&quot;" name="VK_MESA_PRESENT_PERIOD_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRESENT_PERIOD_MESA"/>
<type name="VkPresentPeriodMESA"/>
</require>
</extension>
</extensions>
</registry>
This diff is collapsed.
......@@ -54,6 +54,11 @@ struct wsi_image {
VkCommandBuffer timestamp_buffer;
struct wsi_timing *timing;
struct wsi_image *pending;
uint64_t pending_msc;
uint32_t image_index;
const VkPresentRegionKHR *region;
};
#define WSI_TIMING_HISTORY 16
......@@ -79,6 +84,8 @@ struct wsi_swapchain {
float timestamp_period;
struct wsi_image *pending;
/* Command pools, one per queue family */
VkCommandPool *cmd_pools;
......
......@@ -45,6 +45,8 @@
#include "wsi_common_x11.h"
#include "wsi_common_queue.h"
double mytime(void);
#define typed_memcpy(dest, src, count) ({ \
STATIC_ASSERT(sizeof(*src) == sizeof(*dest)); \
memcpy((dest), (src), (count) * sizeof(*(src))); \
......@@ -778,6 +780,10 @@ struct x11_swapchain {
struct wsi_queue acquire_queue;
pthread_t queue_manager;
pthread_t event_thread;
pthread_mutex_t event_mutex;
pthread_cond_t event_cond;
struct x11_image images[0];
};
WSI_DEFINE_NONDISP_HANDLE_CASTS(x11_swapchain, VkSwapchainKHR)
......@@ -940,62 +946,50 @@ static VkResult
x11_acquire_next_image_poll_x11(struct x11_swapchain *chain,
uint32_t *image_index, uint64_t timeout)
{
xcb_generic_event_t *event;
struct pollfd pfds;
uint64_t atimeout;
struct timespec abs_timeout = { 0, 0 };
while (1) {
pthread_mutex_lock(&chain->event_mutex);
for (uint32_t i = 0; i < chain->base.image_count; i++) {
if (!chain->images[i].busy) {
pthread_mutex_unlock(&chain->event_mutex);
/* We found a non-busy image */
xshmfence_await(chain->images[i].shm_fence);
*image_index = i;
chain->images[i].busy = true;
// printf("%9.4f image %d ready\n", mytime(), i);
return x11_swapchain_result(chain, VK_SUCCESS);
}
}
xcb_flush(chain->conn);
if (timeout == UINT64_MAX) {
event = xcb_wait_for_special_event(chain->conn, chain->special_event);
if (!event)
return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
} else {
event = xcb_poll_for_special_event(chain->conn, chain->special_event);
if (!event) {
int ret;
if (timeout == 0)
return x11_swapchain_result(chain, VK_NOT_READY);
if (timeout == 0) {
pthread_mutex_unlock(&chain->event_mutex);
return x11_swapchain_result(chain, VK_NOT_READY);
}
if (!abs_timeout.tv_sec) {
uint64_t atimeout;
if (timeout == UINT64_MAX)
atimeout = UINT64_MAX;
else
atimeout = wsi_get_absolute_timeout(timeout);
abs_timeout.tv_sec = atimeout / 1000000000ULL;
abs_timeout.tv_nsec = atimeout % 1000000000ULL;
}
pfds.fd = xcb_get_file_descriptor(chain->conn);
pfds.events = POLLIN;
ret = poll(&pfds, 1, timeout / 1000 / 1000);
if (ret == 0)
return x11_swapchain_result(chain, VK_TIMEOUT);
if (ret == -1)
return x11_swapchain_result(chain, VK_ERROR_OUT_OF_DATE_KHR);
int ret = pthread_cond_timedwait(&chain->event_cond, &chain->event_mutex,
&abs_timeout);
/* If a non-special event happens, the fd will still
* poll. So recalculate the timeout now just in case.
*/
uint64_t current_time = wsi_common_get_current_time();
if (atimeout > current_time)
timeout = atimeout - current_time;
else
timeout = 0;
continue;
}
}
pthread_mutex_unlock(&chain->event_mutex);
// printf("%9.4f check for image ready\n", mytime());
/* Update the swapchain status here. We may catch non-fatal errors here,
* in which case we need to update the status and continue.
*/
VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
free(event);
if (result < 0)
return x11_swapchain_result(chain, result);
if (ret) {
if (ret == ETIMEDOUT)
return x11_swapchain_result(chain, VK_NOT_READY);
return x11_swapchain_result(chain, VK_ERROR_SURFACE_LOST_KHR);
}
}
}
......@@ -1119,6 +1113,7 @@ x11_queue_present(struct wsi_swapchain *anv_chain,
chain->images[image_index].busy = true;
if (chain->has_present_queue) {
// printf("%9.4f queue push %d\n", mytime(), image_index);
wsi_queue_push(&chain->present_queue, image_index);
return chain->status;
} else {
......@@ -1162,7 +1157,9 @@ x11_manage_fifo_queues(void *state)
*/
uint32_t image_index = 0;
struct x11_image *image;
// printf("%9.4f wait for fifo queue\n", mytime());
result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
// printf("%9.4f fifo queue %d\n", mytime(), image_index);
assert(result != VK_TIMEOUT);
if (result < 0) {
goto fail;
......@@ -1193,25 +1190,26 @@ x11_manage_fifo_queues(void *state)
if (timing && timing->target_msc != 0 && timing->target_msc > target_msc)
target_msc = timing->target_msc;
printf("%9.4f present to x11 %d %ld\n", mytime(), image_index, target_msc);
result = x11_present_to_x11(chain, image_index, target_msc);
if (result < 0)
goto fail;
xcb_flush(chain->conn);
#if 1
if (chain->has_acquire_queue) {
pthread_mutex_lock(&chain->event_mutex);
while (chain->last_present_msc < target_msc) {
xcb_generic_event_t *event =
xcb_wait_for_special_event(chain->conn, chain->special_event);
if (!event) {
int ret = pthread_cond_wait(&chain->event_cond, &chain->event_mutex);
if (ret) {
pthread_mutex_unlock(&chain->event_mutex);
result = VK_ERROR_OUT_OF_DATE_KHR;
goto fail;
}
result = x11_handle_dri3_present_event(chain, (void *)event);
free(event);
if (result < 0)
goto fail;
}
pthread_mutex_unlock(&chain->event_mutex);
}
#endif
}
fail:
......@@ -1447,6 +1445,10 @@ x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
XCB_PRESENT_EVENT_MASK_NO_EVENT);
xcb_discard_reply(chain->conn, cookie.sequence);
pthread_cancel(chain->event_thread);
pthread_join(chain->event_thread, NULL);
pthread_cond_destroy(&chain->event_cond);
pthread_mutex_destroy(&chain->event_mutex);
wsi_swapchain_finish(&chain->base);
vk_free(pAllocator, chain);
......@@ -1480,6 +1482,36 @@ wsi_x11_set_adaptive_sync_property(xcb_connection_t *conn,
free(reply);
}
static void*
x11_event_thread(void *data)
{
struct x11_swapchain *chain = data;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
for (;;) {
xcb_generic_event_t *event;
xcb_flush(chain->conn);
// printf("%9.4f wait event\n", mytime());
event = xcb_wait_for_special_event(chain->conn, chain->special_event);
if (!event)
break;
// printf("%9.4f got event\n", mytime());
/* Update the swapchain status here. We may catch non-fatal errors here,
* in which case we need to update the status and continue.
*/
pthread_mutex_lock(&chain->event_mutex);
(void) x11_handle_dri3_present_event(chain, (void *)event);
pthread_mutex_unlock(&chain->event_mutex);
pthread_cond_broadcast(&chain->event_cond);
free(event);
}
return NULL;
}
static VkResult
x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
......@@ -1575,6 +1607,17 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
xcb_register_for_special_xge(chain->conn, &xcb_present_id,
chain->event_id, NULL);
if (pthread_mutex_init(&chain->event_mutex, NULL))
goto fail_mutex;
if (!wsi_init_pthread_cond_monotonic(&chain->event_cond))
goto fail_cond;
int ret = pthread_create(&chain->event_thread, NULL,
x11_event_thread, chain);
if (ret)
goto fail_thread;
chain->gc = xcb_generate_id(chain->conn);
if (!chain->gc) {
/* FINISHME: Choose a better error. */
......@@ -1671,6 +1714,11 @@ fail_init_images:
fail_register:
xcb_unregister_for_special_event(chain->conn, chain->special_event);
fail_thread:
pthread_cond_destroy(&chain->event_cond);
fail_cond:
pthread_mutex_destroy(&chain->event_mutex);
fail_mutex:
wsi_swapchain_finish(&chain->base);
fail_alloc:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment