diff --git a/include/vulkan/vulkan_core.h b/include/vulkan/vulkan_core.h index 6b3ab8476a2d823875d43b536f52dc0d5b09d198..666c9b83c0e3c1c6f8570300ef29643e613b6097 100644 --- a/include/vulkan/vulkan_core.h +++ b/include/vulkan/vulkan_core.h @@ -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; +} VkPresentPeriodMESA; + + #ifdef __cplusplus } #endif diff --git a/src/amd/vulkan/radv_extensions.py b/src/amd/vulkan/radv_extensions.py index c255b49437a62c5ac047fd816a5001b09e17e19a..3048560dceac1990a802f41292b93df2f7c59bbe 100644 --- a/src/amd/vulkan/radv_extensions.py +++ b/src/amd/vulkan/radv_extensions.py @@ -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'), ] diff --git a/src/intel/vulkan/anv_extensions.py b/src/intel/vulkan/anv_extensions.py index 256814a8584aa03cf360a21e77932b5d57caa038..7e744d67e6f2f56c40d768b6ee1aed1cc684b05c 100644 --- a/src/intel/vulkan/anv_extensions.py +++ b/src/intel/vulkan/anv_extensions.py @@ -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), ] diff --git a/src/vulkan/registry/vk.xml b/src/vulkan/registry/vk.xml index 88d421aca0feb256799827ad230202992ac19f7d..4d482786fc41b63fa8bdf57fd9db037df31849b9 100644 --- a/src/vulkan/registry/vk.xml +++ b/src/vulkan/registry/vk.xml @@ -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=""VK_MESA_present_period"" 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> diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index 7f5199878b6c9de33362735de81cc0f2c4531014..deff16d75c83e96f0df7614b68a94777b45f2e9a 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -1244,6 +1244,20 @@ wsi_next_timing(struct wsi_swapchain *chain, int image_index) return timing; } +double +mytime(void); + +double +mytime(void) +{ + static uint64_t first; + + uint64_t now = wsi_common_get_current_time(); + if (first == 0) + first = now; + return (double)(now - first) / 1.0e9; +} + void wsi_present_complete(struct wsi_swapchain *swapchain, struct wsi_image *image, @@ -1251,91 +1265,111 @@ wsi_present_complete(struct wsi_swapchain *swapchain, uint64_t msc) { const struct wsi_device *wsi = swapchain->wsi; - struct wsi_timing *timing = image->timing; - if (!timing) - return; +// printf("%9.4f present complete %d %ld\n", mytime(), image->image_index, msc); - uint64_t render_timestamp; + if (image == swapchain->pending) { + struct wsi_image *pending = image->pending; + uint64_t target_msc = image->pending_msc + msc; - VkResult result = wsi->GetQueryPoolResults( - swapchain->device, image->query_pool, - 0, 1, sizeof(render_timestamp), &render_timestamp, - sizeof (uint64_t), - VK_QUERY_RESULT_64_BIT|VK_QUERY_RESULT_WAIT_BIT); - if (result != VK_SUCCESS) - return; + while ((swapchain->pending = pending) != NULL) { - static const VkCalibratedTimestampInfoEXT timestampInfo[2] = { - { - .sType = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, - .pNext = NULL, - .timeDomain = VK_TIME_DOMAIN_DEVICE_EXT, - }, - { - .sType = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, - .pNext = NULL, - .timeDomain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT, - }, - }; + if (target_msc > pending->timing->target_msc) + pending->timing->target_msc = target_msc; +// printf("delayed queuing index %d for %ld\n", pending->image_index, pending->timing->target_msc); + (void) swapchain->queue_present(swapchain, pending->image_index, image->region); + if (pending->pending_msc != 0) + break; + pending = pending->pending; + } + } - uint64_t timestamps[2]; - uint64_t maxDeviation; + struct wsi_timing *timing = image->timing; - result = wsi->GetCalibratedTimestampsEXT(swapchain->device, - 2, - timestampInfo, - timestamps, - &maxDeviation); - if (result != VK_SUCCESS) - return; + if (timing != NULL && timing->timing.presentID) { - uint64_t current_gpu_timestamp = timestamps[0]; - uint64_t current_time = timestamps[1]; + uint64_t render_timestamp; - VkRefreshCycleDurationGOOGLE display_timings; - swapchain->get_refresh_cycle_duration(swapchain, &display_timings); + VkResult result = wsi->GetQueryPoolResults( + swapchain->device, image->query_pool, + 0, 1, sizeof(render_timestamp), &render_timestamp, + sizeof (uint64_t), + VK_QUERY_RESULT_64_BIT|VK_QUERY_RESULT_WAIT_BIT); + if (result != VK_SUCCESS) + return; + + static const VkCalibratedTimestampInfoEXT timestampInfo[2] = { + { + .sType = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, + .pNext = NULL, + .timeDomain = VK_TIME_DOMAIN_DEVICE_EXT, + }, + { + .sType = VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT, + .pNext = NULL, + .timeDomain = VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT, + }, + }; - uint64_t refresh_duration = display_timings.refreshDuration; + uint64_t timestamps[2]; + uint64_t maxDeviation; - /* When did drawing complete (in nsec) */ + result = wsi->GetCalibratedTimestampsEXT(swapchain->device, + 2, + timestampInfo, + timestamps, + &maxDeviation); + if (result != VK_SUCCESS) + return; - int64_t since_render = (int64_t) floor ((double) (current_gpu_timestamp - render_timestamp) * - (double) wsi->timestamp_period + 0.5); - uint64_t render_time = current_time - since_render; + uint64_t current_gpu_timestamp = timestamps[0]; + uint64_t current_time = timestamps[1]; - if (render_time > ust) - render_time = ust; + VkRefreshCycleDurationGOOGLE display_timings; + swapchain->get_refresh_cycle_duration(swapchain, &display_timings); - uint64_t render_frames = (ust - render_time) / refresh_duration; + uint64_t refresh_duration = display_timings.refreshDuration; - uint64_t earliest_time = ust - render_frames * refresh_duration; + /* When did drawing complete (in nsec) */ - /* Use the presentation mode to figure out when the image could have been - * displayed. It couldn't have been displayed before the previous image, so - * use that as a lower bound. If we're in FIFO mode, then it couldn't have - * been displayed before one frame *after* the previous image - */ - uint64_t possible_frame = swapchain->frame_ust; + int64_t since_render = (int64_t) floor ((double) (current_gpu_timestamp - render_timestamp) * + (double) wsi->timestamp_period + 0.5); + uint64_t render_time = current_time - since_render; - switch (swapchain->present_mode) { - case VK_PRESENT_MODE_FIFO_KHR: - case VK_PRESENT_MODE_FIFO_RELAXED_KHR: - possible_frame += refresh_duration; - break; - default: - break; - } - if (earliest_time < possible_frame) - earliest_time = possible_frame; + if (render_time > ust) + render_time = ust; - if (earliest_time > ust) - earliest_time = ust; + uint64_t render_frames = (ust - render_time) / refresh_duration; - timing->timing.actualPresentTime = ust; - timing->timing.earliestPresentTime = earliest_time; - timing->timing.presentMargin = earliest_time - render_time; - timing->complete = true; + uint64_t earliest_time = ust - render_frames * refresh_duration; + + /* Use the presentation mode to figure out when the image could have been + * displayed. It couldn't have been displayed before the previous image, so + * use that as a lower bound. If we're in FIFO mode, then it couldn't have + * been displayed before one frame *after* the previous image + */ + uint64_t possible_frame = swapchain->frame_ust; + + switch (swapchain->present_mode) { + case VK_PRESENT_MODE_FIFO_KHR: + case VK_PRESENT_MODE_FIFO_RELAXED_KHR: + possible_frame += refresh_duration; + break; + default: + break; + } + if (earliest_time < possible_frame) + earliest_time = possible_frame; + + if (earliest_time > ust) + earliest_time = ust; + + timing->timing.actualPresentTime = ust; + timing->timing.earliestPresentTime = earliest_time; + timing->timing.presentMargin = earliest_time - render_time; + } + if (timing) + timing->complete = true; swapchain->frame_msc = msc; swapchain->frame_ust = ust; @@ -1354,6 +1388,8 @@ wsi_common_queue_present(const struct wsi_device *wsi, vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR); const VkPresentTimesInfoGOOGLE *present_times_info = vk_find_struct_const(pPresentInfo->pNext, PRESENT_TIMES_INFO_GOOGLE); + const VkPresentPeriodMESA *present_periods = + vk_find_struct_const(pPresentInfo->pNext, PRESENT_PERIOD_MESA); for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); @@ -1387,6 +1423,7 @@ wsi_common_queue_present(const struct wsi_device *wsi, struct wsi_image *image = swapchain->get_wsi_image(swapchain, image_index); + image->image_index = image_index; struct wsi_memory_signal_submit_info mem_signal = { .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA, @@ -1435,6 +1472,51 @@ wsi_common_queue_present(const struct wsi_device *wsi, image->prime.blit_cmd_buffers[queue_family_index]; } + image->pending_msc = 0; + image->pending = NULL; + + int64_t present_period = 0; + if (present_periods && present_periods->pPresentPeriods) { + present_period = present_periods->pPresentPeriods[i]; + if (present_period) { + if (present_period < 0) + present_period = -present_period; + else { + VkRefreshCycleDurationGOOGLE refresh_timing; + + swapchain->get_refresh_cycle_duration(swapchain, + &refresh_timing); + + /* Round to nearest MSC */ + present_period = (present_period + refresh_timing.refreshDuration/2) / refresh_timing.refreshDuration; + } + image->pending_msc = present_period; +// printf("%9.4f index %d pending_msc %ld\n", mytime(), image_index, present_period); + } + } + + const VkPresentRegionKHR *region = NULL; + image->region = NULL; + if (regions && regions->pRegions) { + region = ®ions->pRegions[i]; + image->region = region; + } + + if (swapchain->pending) { + if (timing == NULL) { + timing = wsi_next_timing(swapchain, pPresentInfo->pImageIndices[i]); + timing->timing.presentID = 0; + image->timing = timing; + } + } + + if (swapchain->pending || image->pending_msc) { + struct wsi_image **prev = &swapchain->pending; + while (*prev) + prev = &(*prev)->pending; + *prev = image; + } + /* Set up GOOGLE_display_timing bits */ if (present_times_info && present_times_info->pTimes != NULL && @@ -1443,11 +1525,13 @@ wsi_common_queue_present(const struct wsi_device *wsi, const VkPresentTimeGOOGLE *present_time = &present_times_info->pTimes[i]; - timing = wsi_next_timing(swapchain, pPresentInfo->pImageIndices[i]); + if (timing == NULL) { + timing = wsi_next_timing(swapchain, pPresentInfo->pImageIndices[i]); + image->timing = timing; + } timing->timing.presentID = present_time->presentID; timing->timing.desiredPresentTime = present_time->desiredPresentTime; timing->target_msc = 0; - image->timing = timing; if (present_time->desiredPresentTime != 0) { @@ -1469,8 +1553,10 @@ wsi_common_queue_present(const struct wsi_device *wsi, } } - submit_buffers[submit_info.commandBufferCount++] = - image->timestamp_buffer; + if (present_time->presentID) { + submit_buffers[submit_info.commandBufferCount++] = + image->timestamp_buffer; + } } result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[image_index]); @@ -1478,13 +1564,11 @@ wsi_common_queue_present(const struct wsi_device *wsi, if (result != VK_SUCCESS) goto fail_present; - const VkPresentRegionKHR *region = NULL; - if (regions && regions->pRegions) - region = ®ions->pRegions[i]; - - result = swapchain->queue_present(swapchain, image_index, region); - if (result != VK_SUCCESS) - goto fail_present; + if (!swapchain->pending || swapchain->pending == image) { + result = swapchain->queue_present(swapchain, image_index, region); + if (result != VK_SUCCESS) + goto fail_present; + } fail_present: if (pPresentInfo->pResults != NULL) diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h index 0fbda6f7d36ed9cfbd2f0b471112064c811176cc..d244f567c5d79909f031e13481ecde5e029c91bc 100644 --- a/src/vulkan/wsi/wsi_common_private.h +++ b/src/vulkan/wsi/wsi_common_private.h @@ -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; diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index 2f283f530506b4228f2ce6879d5c8847133a36a7..c4030d5393438045f4f3fe9f979f7985262a2272 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -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: