summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/amd/common/ac_nir_to_llvm.c9
-rw-r--r--src/amd/vulkan/radv_device.c18
-rw-r--r--src/amd/vulkan/radv_image.c14
-rw-r--r--src/amd/vulkan/radv_meta_clear.c2
-rw-r--r--src/vulkan/wsi/Makefile.sources3
-rw-r--r--src/vulkan/wsi/wsi_common.h1
-rw-r--r--src/vulkan/wsi/wsi_common_queue.h154
-rw-r--r--src/vulkan/wsi/wsi_common_wayland.c6
-rw-r--r--src/vulkan/wsi/wsi_common_x11.c241
9 files changed, 406 insertions, 42 deletions
diff --git a/src/amd/common/ac_nir_to_llvm.c b/src/amd/common/ac_nir_to_llvm.c
index 31d7b6e..0daef08 100644
--- a/src/amd/common/ac_nir_to_llvm.c
+++ b/src/amd/common/ac_nir_to_llvm.c
@@ -3517,12 +3517,13 @@ static void visit_tex(struct nir_to_llvm_context *ctx, nir_tex_instr *instr)
if (offsets && instr->op == nir_texop_txf) {
nir_const_value *const_offset =
nir_src_as_const_value(instr->src[const_src].src);
-
+ int num_offsets = instr->src[const_src].src.ssa->num_components;
assert(const_offset);
- if (instr->coord_components > 2)
+ num_offsets = MIN2(num_offsets, instr->coord_components);
+ if (num_offsets > 2)
address[2] = LLVMBuildAdd(ctx->builder,
address[2], LLVMConstInt(ctx->i32, const_offset->i32[2], false), "");
- if (instr->coord_components > 1)
+ if (num_offsets > 1)
address[1] = LLVMBuildAdd(ctx->builder,
address[1], LLVMConstInt(ctx->i32, const_offset->i32[1], false), "");
address[0] = LLVMBuildAdd(ctx->builder,
@@ -3544,6 +3545,8 @@ static void visit_tex(struct nir_to_llvm_context *ctx, nir_tex_instr *instr)
if (instr->op == nir_texop_query_levels)
result = LLVMBuildExtractElement(ctx->builder, result, LLVMConstInt(ctx->i32, 3, false), "");
+ else if (instr->is_shadow && instr->op != nir_texop_txs && instr->op != nir_texop_lod)
+ result = LLVMBuildExtractElement(ctx->builder, result, ctx->i32zero, "");
else if (instr->op == nir_texop_txs &&
instr->sampler_dim == GLSL_SAMPLER_DIM_CUBE &&
instr->is_array) {
diff --git a/src/amd/vulkan/radv_device.c b/src/amd/vulkan/radv_device.c
index 4a924ea..94a2ef0 100644
--- a/src/amd/vulkan/radv_device.c
+++ b/src/amd/vulkan/radv_device.c
@@ -659,17 +659,15 @@ VkResult radv_EnumerateInstanceExtensionProperties(
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties)
{
- unsigned i;
if (pProperties == NULL) {
*pPropertyCount = ARRAY_SIZE(global_extensions);
return VK_SUCCESS;
}
- for (i = 0; i < *pPropertyCount; i++)
- memcpy(&pProperties[i], &global_extensions[i], sizeof(VkExtensionProperties));
+ *pPropertyCount = MIN2(*pPropertyCount, ARRAY_SIZE(global_extensions));
+ typed_memcpy(pProperties, global_extensions, *pPropertyCount);
- *pPropertyCount = i;
- if (i < ARRAY_SIZE(global_extensions))
+ if (*pPropertyCount < ARRAY_SIZE(global_extensions))
return VK_INCOMPLETE;
return VK_SUCCESS;
@@ -681,19 +679,17 @@ VkResult radv_EnumerateDeviceExtensionProperties(
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties)
{
- unsigned i;
-
if (pProperties == NULL) {
*pPropertyCount = ARRAY_SIZE(device_extensions);
return VK_SUCCESS;
}
- for (i = 0; i < *pPropertyCount; i++)
- memcpy(&pProperties[i], &device_extensions[i], sizeof(VkExtensionProperties));
+ *pPropertyCount = MIN2(*pPropertyCount, ARRAY_SIZE(device_extensions));
+ typed_memcpy(pProperties, device_extensions, *pPropertyCount);
- *pPropertyCount = i;
- if (i < ARRAY_SIZE(device_extensions))
+ if (*pPropertyCount < ARRAY_SIZE(device_extensions))
return VK_INCOMPLETE;
+
return VK_SUCCESS;
}
diff --git a/src/amd/vulkan/radv_image.c b/src/amd/vulkan/radv_image.c
index 3099d83..9649158 100644
--- a/src/amd/vulkan/radv_image.c
+++ b/src/amd/vulkan/radv_image.c
@@ -831,29 +831,29 @@ void radv_image_set_optimal_micro_tile_mode(struct radv_device *device,
switch (micro_tile_mode) {
case 0: /* displayable */
switch (image->surface.bpe) {
- case 8:
+ case 1:
image->surface.tiling_index[0] = 10;
break;
- case 16:
+ case 2:
image->surface.tiling_index[0] = 11;
break;
- default: /* 32, 64 */
+ default: /* 4, 8 */
image->surface.tiling_index[0] = 12;
break;
}
break;
case 1: /* thin */
switch (image->surface.bpe) {
- case 8:
+ case 1:
image->surface.tiling_index[0] = 14;
break;
- case 16:
+ case 2:
image->surface.tiling_index[0] = 15;
break;
- case 32:
+ case 4:
image->surface.tiling_index[0] = 16;
break;
- default: /* 64, 128 */
+ default: /* 8, 16 */
image->surface.tiling_index[0] = 17;
break;
}
diff --git a/src/amd/vulkan/radv_meta_clear.c b/src/amd/vulkan/radv_meta_clear.c
index 7e3e5f4..a347703 100644
--- a/src/amd/vulkan/radv_meta_clear.c
+++ b/src/amd/vulkan/radv_meta_clear.c
@@ -998,7 +998,7 @@ radv_cmd_clear_image(struct radv_cmd_buffer *cmd_buffer,
const VkImageSubresourceRange *range = &ranges[r];
for (uint32_t l = 0; l < radv_get_levelCount(image, range); ++l) {
const uint32_t layer_count = image->type == VK_IMAGE_TYPE_3D ?
- radv_minify(image->extent.depth, l) :
+ radv_minify(image->extent.depth, range->baseMipLevel + l) :
radv_get_layerCount(image, range);
for (uint32_t s = 0; s < layer_count; ++s) {
struct radv_image_view iview;
diff --git a/src/vulkan/wsi/Makefile.sources b/src/vulkan/wsi/Makefile.sources
index 3139e6d..50660f9 100644
--- a/src/vulkan/wsi/Makefile.sources
+++ b/src/vulkan/wsi/Makefile.sources
@@ -1,6 +1,7 @@
VULKAN_WSI_FILES := \
- wsi_common.h
+ wsi_common.h \
+ wsi_common_queue.h
VULKAN_WSI_WAYLAND_FILES := \
wsi_common_wayland.c \
diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h
index ee67511..a1f5a40 100644
--- a/src/vulkan/wsi/wsi_common.h
+++ b/src/vulkan/wsi/wsi_common.h
@@ -53,6 +53,7 @@ struct wsi_swapchain {
VkAllocationCallbacks alloc;
const struct wsi_image_fns *image_fns;
VkFence fences[3];
+ VkPresentModeKHR present_mode;
VkResult (*destroy)(struct wsi_swapchain *swapchain,
const VkAllocationCallbacks *pAllocator);
diff --git a/src/vulkan/wsi/wsi_common_queue.h b/src/vulkan/wsi/wsi_common_queue.h
new file mode 100644
index 0000000..0e72c8d
--- /dev/null
+++ b/src/vulkan/wsi/wsi_common_queue.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef VULKAN_WSI_COMMON_QUEUE_H
+#define VULKAN_WSI_COMMON_QUEUE_H
+
+#include <time.h>
+#include <pthread.h>
+#include "util/u_vector.h"
+
+struct wsi_queue {
+ struct u_vector vector;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+};
+
+static inline int
+wsi_queue_init(struct wsi_queue *queue, int length)
+{
+ int ret;
+
+ uint32_t length_pow2 = 4;
+ while (length_pow2 < length)
+ length_pow2 *= 2;
+
+ ret = u_vector_init(&queue->vector, sizeof(uint32_t),
+ sizeof(uint32_t) * length_pow2);
+ if (!ret)
+ return ENOMEM;
+
+ pthread_condattr_t condattr;
+ ret = pthread_condattr_init(&condattr);
+ if (ret)
+ goto fail_vector;
+
+ ret = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
+ if (ret)
+ goto fail_condattr;
+
+ ret = pthread_cond_init(&queue->cond, &condattr);
+ if (ret)
+ goto fail_condattr;
+
+ ret = pthread_mutex_init(&queue->mutex, NULL);
+ if (ret)
+ goto fail_cond;
+
+ return 0;
+
+fail_cond:
+ pthread_cond_destroy(&queue->cond);
+fail_condattr:
+ pthread_condattr_destroy(&condattr);
+fail_vector:
+ u_vector_finish(&queue->vector);
+
+ return ret;
+}
+
+static inline void
+wsi_queue_destroy(struct wsi_queue *queue)
+{
+ u_vector_finish(&queue->vector);
+ pthread_mutex_destroy(&queue->mutex);
+ pthread_cond_destroy(&queue->cond);
+}
+
+static inline void
+wsi_queue_push(struct wsi_queue *queue, uint32_t index)
+{
+ uint32_t *elem;
+
+ pthread_mutex_lock(&queue->mutex);
+
+ if (u_vector_length(&queue->vector) == 0)
+ pthread_cond_signal(&queue->cond);
+
+ elem = u_vector_add(&queue->vector);
+ *elem = index;
+
+ pthread_mutex_unlock(&queue->mutex);
+}
+
+#define NSEC_PER_SEC 1000000000
+#define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)
+
+static inline VkResult
+wsi_queue_pull(struct wsi_queue *queue, uint32_t *index, uint64_t timeout)
+{
+ VkResult result;
+ int32_t ret;
+
+ pthread_mutex_lock(&queue->mutex);
+
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ uint32_t abs_nsec = now.tv_nsec + timeout % NSEC_PER_SEC;
+ uint64_t abs_sec = now.tv_sec + (abs_nsec / NSEC_PER_SEC) +
+ (timeout / NSEC_PER_SEC);
+ abs_nsec %= NSEC_PER_SEC;
+
+ /* Avoid roll-over in tv_sec on 32-bit systems if the user provided timeout
+ * is UINT64_MAX
+ */
+ struct timespec abstime;
+ abstime.tv_nsec = abs_nsec;
+ abstime.tv_sec = MIN2(abs_sec, INT_TYPE_MAX(abstime.tv_sec));
+
+ while (u_vector_length(&queue->vector) == 0) {
+ ret = pthread_cond_timedwait(&queue->cond, &queue->mutex, &abstime);
+ if (ret == 0) {
+ continue;
+ } else if (ret == ETIMEDOUT) {
+ result = VK_TIMEOUT;
+ goto end;
+ } else {
+ /* Something went badly wrong */
+ result = VK_ERROR_OUT_OF_DATE_KHR;
+ goto end;
+ }
+ }
+
+ uint32_t *elem = u_vector_remove(&queue->vector);
+ *index = *elem;
+ result = VK_SUCCESS;
+
+end:
+ pthread_mutex_unlock(&queue->mutex);
+
+ return result;
+}
+
+#endif /* VULKAN_WSI_COMMON_QUEUE_H */
diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c
index a8130ce..f6c218b 100644
--- a/src/vulkan/wsi/wsi_common_wayland.c
+++ b/src/vulkan/wsi/wsi_common_wayland.c
@@ -576,7 +576,7 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain,
{
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)wsi_chain;
- if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
+ if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
while (!chain->fifo_ready) {
int ret = wl_display_dispatch_queue(chain->display->display,
chain->queue);
@@ -589,7 +589,7 @@ wsi_wl_swapchain_queue_present(struct wsi_swapchain *wsi_chain,
wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0);
wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX);
- if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
+ if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
struct wl_callback *frame = wl_surface_frame(chain->surface);
wl_proxy_set_queue((struct wl_proxy *)frame, chain->queue);
wl_callback_add_listener(frame, &frame_listener, chain);
@@ -717,12 +717,12 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;
chain->base.queue_present = wsi_wl_swapchain_queue_present;
chain->base.image_fns = image_fns;
+ chain->base.present_mode = pCreateInfo->presentMode;
chain->surface = surface->surface;
chain->extent = pCreateInfo->imageExtent;
chain->vk_format = pCreateInfo->imageFormat;
chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, alpha);
- chain->present_mode = pCreateInfo->presentMode;
chain->fifo_ready = true;
chain->image_count = num_images;
diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c
index 09718eb..8e0043f 100644
--- a/src/vulkan/wsi/wsi_common_x11.c
+++ b/src/vulkan/wsi/wsi_common_x11.c
@@ -34,10 +34,12 @@
#include <errno.h>
#include <string.h>
+#include <poll.h>
#include "util/hash_table.h"
#include "wsi_common.h"
#include "wsi_common_x11.h"
+#include "wsi_common_queue.h"
#define typed_memcpy(dest, src, count) ({ \
static_assert(sizeof(*src) == sizeof(*dest), ""); \
@@ -142,7 +144,9 @@ static const VkSurfaceFormatKHR formats[] = {
};
static const VkPresentModeKHR present_modes[] = {
+ VK_PRESENT_MODE_IMMEDIATE_KHR,
VK_PRESENT_MODE_MAILBOX_KHR,
+ VK_PRESENT_MODE_FIFO_KHR,
};
static xcb_screen_t *
@@ -488,8 +492,15 @@ struct x11_swapchain {
xcb_present_event_t event_id;
xcb_special_event_t * special_event;
uint64_t send_sbc;
+ uint64_t last_present_msc;
uint32_t stamp;
+ bool threaded;
+ VkResult status;
+ struct wsi_queue present_queue;
+ struct wsi_queue acquire_queue;
+ pthread_t queue_manager;
+
struct x11_image images[0];
};
@@ -540,6 +551,8 @@ x11_handle_dri3_present_event(struct x11_swapchain *chain,
for (unsigned i = 0; i < chain->image_count; i++) {
if (chain->images[i].pixmap == idle->pixmap) {
chain->images[i].busy = false;
+ if (chain->threaded)
+ wsi_queue_push(&chain->acquire_queue, i);
break;
}
}
@@ -547,7 +560,13 @@ x11_handle_dri3_present_event(struct x11_swapchain *chain,
break;
}
- case XCB_PRESENT_COMPLETE_NOTIFY:
+ case XCB_PRESENT_EVENT_COMPLETE_NOTIFY: {
+ xcb_present_complete_notify_event_t *complete = (void *) event;
+ if (complete->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
+ chain->last_present_msc = complete->msc;
+ break;
+ }
+
default:
break;
}
@@ -555,14 +574,33 @@ x11_handle_dri3_present_event(struct x11_swapchain *chain,
return VK_SUCCESS;
}
-static VkResult
-x11_acquire_next_image(struct wsi_swapchain *anv_chain,
- uint64_t timeout,
- VkSemaphore semaphore,
- uint32_t *image_index)
+
+static uint64_t wsi_get_current_time(void)
{
- struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
+ uint64_t current_time;
+ struct timespec tv;
+
+ clock_gettime(CLOCK_MONOTONIC, &tv);
+ current_time = tv.tv_nsec + tv.tv_sec*1000000000ull;
+ return current_time;
+}
+
+static uint64_t wsi_get_absolute_timeout(uint64_t timeout)
+{
+ uint64_t current_time = wsi_get_current_time();
+
+ timeout = MIN2(UINT64_MAX - current_time, timeout);
+
+ return current_time + timeout;
+}
+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;
while (1) {
for (uint32_t i = 0; i < chain->image_count; i++) {
if (!chain->images[i].busy) {
@@ -575,10 +613,39 @@ x11_acquire_next_image(struct wsi_swapchain *anv_chain,
}
xcb_flush(chain->conn);
- xcb_generic_event_t *event =
- xcb_wait_for_special_event(chain->conn, chain->special_event);
- if (!event)
- return VK_ERROR_OUT_OF_DATE_KHR;
+
+ if (timeout == UINT64_MAX) {
+ event = xcb_wait_for_special_event(chain->conn, chain->special_event);
+ if (!event)
+ return 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 VK_NOT_READY;
+
+ atimeout = wsi_get_absolute_timeout(timeout);
+
+ pfds.fd = xcb_get_file_descriptor(chain->conn);
+ pfds.events = POLLIN;
+ ret = poll(&pfds, 1, timeout / 1000 / 1000);
+ if (ret == 0)
+ return VK_TIMEOUT;
+ if (ret == -1)
+ return VK_ERROR_OUT_OF_DATE_KHR;
+
+ /* If a non-special event happens, the fd will still
+ * poll. So recalculate the timeout now just in case.
+ */
+ uint64_t current_time = wsi_get_current_time();
+ if (atimeout > current_time)
+ timeout = atimeout - current_time;
+ else
+ timeout = 0;
+ continue;
+ }
+ }
VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
free(event);
@@ -588,21 +655,43 @@ x11_acquire_next_image(struct wsi_swapchain *anv_chain,
}
static VkResult
-x11_queue_present(struct wsi_swapchain *anv_chain,
- uint32_t image_index)
+x11_acquire_next_image_from_queue(struct x11_swapchain *chain,
+ uint32_t *image_index_out, uint64_t timeout)
+{
+ assert(chain->threaded);
+
+ uint32_t image_index;
+ VkResult result = wsi_queue_pull(&chain->acquire_queue,
+ &image_index, timeout);
+ if (result != VK_SUCCESS) {
+ return result;
+ } else if (chain->status != VK_SUCCESS) {
+ return chain->status;
+ }
+
+ assert(image_index < chain->image_count);
+ xshmfence_await(chain->images[image_index].shm_fence);
+
+ *image_index_out = image_index;
+
+ return VK_SUCCESS;
+}
+
+static VkResult
+x11_present_to_x11(struct x11_swapchain *chain, uint32_t image_index,
+ uint32_t target_msc)
{
- struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
struct x11_image *image = &chain->images[image_index];
assert(image_index < chain->image_count);
uint32_t options = XCB_PRESENT_OPTION_NONE;
- int64_t target_msc = 0;
int64_t divisor = 0;
int64_t remainder = 0;
- options |= XCB_PRESENT_OPTION_ASYNC;
+ if (chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR)
+ options |= XCB_PRESENT_OPTION_ASYNC;
xshmfence_reset(image->shm_fence);
@@ -632,6 +721,82 @@ x11_queue_present(struct wsi_swapchain *anv_chain,
}
static VkResult
+x11_acquire_next_image(struct wsi_swapchain *anv_chain,
+ uint64_t timeout,
+ VkSemaphore semaphore,
+ uint32_t *image_index)
+{
+ struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
+
+ if (chain->threaded) {
+ return x11_acquire_next_image_from_queue(chain, image_index, timeout);
+ } else {
+ return x11_acquire_next_image_poll_x11(chain, image_index, timeout);
+ }
+}
+
+static VkResult
+x11_queue_present(struct wsi_swapchain *anv_chain,
+ uint32_t image_index)
+{
+ struct x11_swapchain *chain = (struct x11_swapchain *)anv_chain;
+
+ if (chain->threaded) {
+ wsi_queue_push(&chain->present_queue, image_index);
+ return chain->status;
+ } else {
+ return x11_present_to_x11(chain, image_index, 0);
+ }
+}
+
+static void *
+x11_manage_fifo_queues(void *state)
+{
+ struct x11_swapchain *chain = state;
+ VkResult result;
+
+ assert(chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR);
+
+ while (chain->status == VK_SUCCESS) {
+ /* It should be safe to unconditionally block here. Later in the loop
+ * we blocks until the previous present has landed on-screen. At that
+ * point, we should have received IDLE_NOTIFY on all images presented
+ * before that point so the client should be able to acquire any image
+ * other than the currently presented one.
+ */
+ uint32_t image_index;
+ result = wsi_queue_pull(&chain->present_queue, &image_index, INT64_MAX);
+ if (result != VK_SUCCESS) {
+ goto fail;
+ } else if (chain->status != VK_SUCCESS) {
+ return NULL;
+ }
+
+ uint64_t target_msc = chain->last_present_msc + 1;
+ result = x11_present_to_x11(chain, image_index, target_msc);
+ if (result != VK_SUCCESS)
+ goto fail;
+
+ while (chain->last_present_msc < target_msc) {
+ xcb_generic_event_t *event =
+ xcb_wait_for_special_event(chain->conn, chain->special_event);
+ if (!event)
+ goto fail;
+
+ result = x11_handle_dri3_present_event(chain, (void *)event);
+ if (result != VK_SUCCESS)
+ goto fail;
+ }
+ }
+
+fail:
+ chain->status = result;
+ wsi_queue_push(&chain->acquire_queue, UINT32_MAX);
+
+ return NULL;
+}
+
+static VkResult
x11_image_init(VkDevice device_h, struct x11_swapchain *chain,
const VkSwapchainCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks* pAllocator,
@@ -729,6 +894,15 @@ x11_swapchain_destroy(struct wsi_swapchain *anv_chain,
for (uint32_t i = 0; i < chain->image_count; i++)
x11_image_finish(chain, pAllocator, &chain->images[i]);
+ if (chain->threaded) {
+ chain->status = VK_ERROR_OUT_OF_DATE_KHR;
+ /* Push a UINT32_MAX to wake up the manager */
+ wsi_queue_push(&chain->present_queue, UINT32_MAX);
+ pthread_join(chain->queue_manager, NULL);
+ wsi_queue_destroy(&chain->acquire_queue);
+ wsi_queue_destroy(&chain->present_queue);
+ }
+
xcb_unregister_for_special_event(chain->conn, chain->special_event);
vk_free(pAllocator, chain);
@@ -773,12 +947,16 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
chain->base.acquire_next_image = x11_acquire_next_image;
chain->base.queue_present = x11_queue_present;
chain->base.image_fns = image_fns;
+ chain->base.present_mode = pCreateInfo->presentMode;
chain->conn = conn;
chain->window = window;
chain->depth = geometry->depth;
chain->extent = pCreateInfo->imageExtent;
chain->image_count = num_images;
chain->send_sbc = 0;
+ chain->last_present_msc = 0;
+ chain->threaded = false;
+ chain->status = VK_SUCCESS;
free(geometry);
@@ -817,6 +995,37 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
goto fail_init_images;
}
+ if (chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR) {
+ chain->threaded = true;
+
+ /* Initialize our queues. We make them image_count + 1 because we will
+ * occasionally use UINT32_MAX to signal the other thread that an error
+ * has occurred and we don't want an overflow.
+ */
+ int ret;
+ ret = wsi_queue_init(&chain->acquire_queue, chain->image_count + 1);
+ if (ret) {
+ goto fail_init_images;
+ }
+
+ ret = wsi_queue_init(&chain->present_queue, chain->image_count + 1);
+ if (ret) {
+ wsi_queue_destroy(&chain->acquire_queue);
+ goto fail_init_images;
+ }
+
+ for (unsigned i = 0; i < chain->image_count; i++)
+ wsi_queue_push(&chain->acquire_queue, i);
+
+ ret = pthread_create(&chain->queue_manager, NULL,
+ x11_manage_fifo_queues, chain);
+ if (ret) {
+ wsi_queue_destroy(&chain->present_queue);
+ wsi_queue_destroy(&chain->acquire_queue);
+ goto fail_init_images;
+ }
+ }
+
*swapchain_out = &chain->base;
return VK_SUCCESS;