wsi/display: Implement VK_KHR_present_wait on KHR_display swapchain.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
Reviewed-by: Joshua Ashton <joshua@froggi.es>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19279>
This commit is contained in:
Hans-Kristian Arntzen
2022-10-24 16:10:01 +02:00
committed by Marge Bot
parent 8fc7927787
commit 367fa98570
+109 -1
View File
@@ -44,6 +44,7 @@
#include "util/hash_table.h"
#include "util/list.h"
#include "util/os_time.h"
#include "util/timespec.h"
#include "vk_device.h"
#include "vk_fence.h"
@@ -139,6 +140,7 @@ struct wsi_display_image {
uint32_t fb_id;
uint32_t buffer[4];
uint64_t flip_sequence;
uint64_t present_id;
};
struct wsi_display_swapchain {
@@ -147,6 +149,12 @@ struct wsi_display_swapchain {
VkIcdSurfaceDisplay *surface;
uint64_t flip_sequence;
VkResult status;
pthread_mutex_t present_id_mutex;
pthread_cond_t present_id_cond;
uint64_t present_id;
VkResult present_id_error;
struct wsi_display_image images[0];
};
@@ -1180,6 +1188,9 @@ wsi_display_swapchain_destroy(struct wsi_swapchain *drv_chain,
for (uint32_t i = 0; i < chain->base.image_count; i++)
wsi_display_image_finish(drv_chain, allocator, &chain->images[i]);
pthread_mutex_destroy(&chain->present_id_mutex);
pthread_cond_destroy(&chain->present_id_cond);
wsi_swapchain_finish(&chain->base);
vk_free(allocator, chain);
return VK_SUCCESS;
@@ -1214,6 +1225,30 @@ wsi_display_idle_old_displaying(struct wsi_display_image *active_image)
static VkResult
_wsi_display_queue_next(struct wsi_swapchain *drv_chain);
static void
wsi_display_present_complete(struct wsi_display_swapchain *swapchain,
struct wsi_display_image *image)
{
if (image->present_id) {
pthread_mutex_lock(&swapchain->present_id_mutex);
if (image->present_id > swapchain->present_id) {
swapchain->present_id = image->present_id;
pthread_cond_broadcast(&swapchain->present_id_cond);
}
pthread_mutex_unlock(&swapchain->present_id_mutex);
}
}
static void
wsi_display_surface_error(struct wsi_display_swapchain *swapchain, VkResult result)
{
pthread_mutex_lock(&swapchain->present_id_mutex);
swapchain->present_id = UINT64_MAX;
swapchain->present_id_error = result;
pthread_cond_broadcast(&swapchain->present_id_cond);
pthread_mutex_unlock(&swapchain->present_id_mutex);
}
static void
wsi_display_page_flip_handler2(int fd,
unsigned int frame,
@@ -1228,6 +1263,8 @@ wsi_display_page_flip_handler2(int fd,
wsi_display_debug("image %ld displayed at %d\n",
image - &(image->chain->images[0]), frame);
image->state = WSI_IMAGE_DISPLAYING;
wsi_display_present_complete(chain, image);
wsi_display_idle_old_displaying(image);
VkResult result = _wsi_display_queue_next(&(chain->base));
if (result != VK_SUCCESS)
@@ -1401,6 +1438,7 @@ wsi_display_acquire_next_image(struct wsi_swapchain *drv_chain,
if (ret && ret != ETIMEDOUT) {
result = VK_ERROR_SURFACE_LOST_KHR;
wsi_display_surface_error(chain, result);
goto done;
}
}
@@ -1814,8 +1852,10 @@ _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
wsi_display_mode_from_handle(surface->displayMode);
wsi_display_connector *connector = display_mode->connector;
if (wsi->fd < 0)
if (wsi->fd < 0) {
wsi_display_surface_error(chain, VK_ERROR_SURFACE_LOST_KHR);
return VK_ERROR_SURFACE_LOST_KHR;
}
if (display_mode != connector->current_mode)
connector->active = false;
@@ -1887,6 +1927,7 @@ _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
* previous image is now idle.
*/
image->state = WSI_IMAGE_DISPLAYING;
wsi_display_present_complete(chain, image);
wsi_display_idle_old_displaying(image);
connector->active = true;
return VK_SUCCESS;
@@ -1896,6 +1937,7 @@ _wsi_display_queue_next(struct wsi_swapchain *drv_chain)
if (ret != -EACCES) {
connector->active = false;
image->state = WSI_IMAGE_IDLE;
wsi_display_surface_error(chain, VK_ERROR_SURFACE_LOST_KHR);
return VK_ERROR_SURFACE_LOST_KHR;
}
@@ -1923,11 +1965,17 @@ wsi_display_queue_present(struct wsi_swapchain *drv_chain,
if (chain->status != VK_SUCCESS)
return chain->status;
image->present_id = present_id;
assert(image->state == WSI_IMAGE_DRAWING);
wsi_display_debug("present %d\n", image_index);
pthread_mutex_lock(&wsi->wait_mutex);
/* Make sure that the page flip handler is processed in finite time if using present wait. */
if (present_id)
wsi_display_start_wait_thread(wsi);
image->flip_sequence = ++chain->flip_sequence;
image->state = WSI_IMAGE_QUEUED;
@@ -1943,6 +1991,48 @@ wsi_display_queue_present(struct wsi_swapchain *drv_chain,
return chain->status;
}
static VkResult
wsi_display_wait_for_present(struct wsi_swapchain *wsi_chain,
uint64_t waitValue,
uint64_t timeout)
{
struct wsi_display_swapchain *chain = (struct wsi_display_swapchain *)wsi_chain;
struct timespec abs_timespec;
uint64_t abs_timeout = 0;
if (timeout != 0)
abs_timeout = os_time_get_absolute_timeout(timeout);
/* Need to observe that the swapchain semaphore has been unsignalled,
* as this is guaranteed when a present is complete. */
VkResult result = wsi_swapchain_wait_for_present_semaphore(
&chain->base, waitValue, timeout);
if (result != VK_SUCCESS)
return result;
timespec_from_nsec(&abs_timespec, abs_timeout);
pthread_mutex_lock(&chain->present_id_mutex);
while (chain->present_id < waitValue) {
int ret = pthread_cond_timedwait(&chain->present_id_cond,
&chain->present_id_mutex,
&abs_timespec);
if (ret == ETIMEDOUT) {
result = VK_TIMEOUT;
break;
}
if (ret) {
result = VK_ERROR_DEVICE_LOST;
break;
}
}
if (result == VK_SUCCESS && chain->present_id_error)
result = chain->present_id_error;
pthread_mutex_unlock(&chain->present_id_mutex);
return result;
}
static VkResult
wsi_display_surface_create_swapchain(
VkIcdSurfaceBase *icd_surface,
@@ -1971,10 +2061,25 @@ wsi_display_surface_create_swapchain(
.same_gpu = true,
};
int ret = pthread_mutex_init(&chain->present_id_mutex, NULL);
if (ret != 0) {
vk_free(allocator, chain);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
bool bret = wsi_init_pthread_cond_monotonic(&chain->present_id_cond);
if (!bret) {
pthread_mutex_destroy(&chain->present_id_mutex);
vk_free(allocator, chain);
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
create_info, &image_params.base,
allocator);
if (result != VK_SUCCESS) {
pthread_cond_destroy(&chain->present_id_cond);
pthread_mutex_destroy(&chain->present_id_mutex);
vk_free(allocator, chain);
return result;
}
@@ -1983,6 +2088,7 @@ wsi_display_surface_create_swapchain(
chain->base.get_wsi_image = wsi_display_get_wsi_image;
chain->base.acquire_next_image = wsi_display_acquire_next_image;
chain->base.queue_present = wsi_display_queue_present;
chain->base.wait_for_present = wsi_display_wait_for_present;
chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
chain->base.image_count = num_images;
@@ -2001,6 +2107,8 @@ wsi_display_surface_create_swapchain(
wsi_display_image_finish(&chain->base, allocator,
&chain->images[image]);
}
pthread_cond_destroy(&chain->present_id_cond);
pthread_mutex_destroy(&chain->present_id_mutex);
wsi_swapchain_finish(&chain->base);
vk_free(allocator, chain);
goto fail_init_images;