[vulkan] Fix hang bug in CTS test.
Bug: 42086544
Change-Id: If2585bec444b4161f05f32b016d25ba4d719ca3e
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/mesa/+/1044103
Reviewed-by: Craig Stout <cstout@google.com>
Commit-Queue: John Rosasco <rosasco@google.com>
diff --git a/src/gallium/frontends/lavapipe/lvp_device.c b/src/gallium/frontends/lavapipe/lvp_device.c
index 40d3218..498cf4e 100644
--- a/src/gallium/frontends/lavapipe/lvp_device.c
+++ b/src/gallium/frontends/lavapipe/lvp_device.c
@@ -280,11 +280,12 @@
device->sync_timeline_type = vk_sync_timeline_get_type(&lvp_pipe_sync_type);
uint32_t st = 0;
#if VK_USE_PLATFORM_FUCHSIA
+ // TODO(rosasco): add emulated sync type ?
device->sync_types[st++] = &lvp_pipe_sync_fuchsia_type;
#else
device->sync_types[st++] = &lvp_pipe_sync_type;
-#endif
device->sync_types[st++] = &device->sync_timeline_type.sync;
+#endif
device->sync_types[st] = NULL;
assert(st < MAX_SYNC_TYPES);
device->vk.supported_sync_types = device->sync_types;
diff --git a/src/gallium/frontends/lavapipe/lvp_pipe_sync_fuchsia.c b/src/gallium/frontends/lavapipe/lvp_pipe_sync_fuchsia.c
index 317a51b..e6acaf3 100644
--- a/src/gallium/frontends/lavapipe/lvp_pipe_sync_fuchsia.c
+++ b/src/gallium/frontends/lavapipe/lvp_pipe_sync_fuchsia.c
@@ -34,33 +34,33 @@
#include "vk_log.h"
#include "vulkan/vulkan_core.h"
-#define ZX_STATUS_VK_RTN(status, device, message) \
- switch (status) { \
- case ZX_OK: \
- return VK_SUCCESS; \
- case ZX_ERR_BAD_HANDLE: \
- return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE, \
- "%s - Bad Zircon handle: %m", message); \
- case ZX_ERR_TIMED_OUT: \
- return VK_TIMEOUT; \
- default: \
- return vk_errorf(device, VK_ERROR_UNKNOWN, \
- "%s - Unknown Zircon error: %m", message); \
- }
+#define ZX_STATUS_VK_RTN(status, device, handle, message) \
+ switch (status) { \
+ case ZX_OK: \
+ return VK_SUCCESS; \
+ case ZX_ERR_BAD_HANDLE: \
+ return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE, \
+ "%s - Bad Zircon handle 0x%0x: %m", message, handle); \
+ case ZX_ERR_TIMED_OUT: \
+ return VK_TIMEOUT; \
+ default: \
+ return vk_errorf(device, VK_ERROR_UNKNOWN, \
+ "%s - Unknown Zircon error: %m", message); \
+ }
/* No-op when status == ZX_OK. */
-#define ZX_STATUS_VK_RTN_ERR(status, device, message) \
- switch (status) { \
- case ZX_OK: \
- break; \
- case ZX_ERR_BAD_HANDLE: \
- return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE, \
- "%s - Bad Zircon handle: %m", message); \
- case ZX_ERR_TIMED_OUT: \
- return VK_TIMEOUT; \
- default: \
- return vk_errorf(device, VK_ERROR_UNKNOWN, \
- "%s - Unknown Zircon error: %m", message); \
+#define ZX_STATUS_VK_RTN_ERR(status, device, handle, message) \
+ switch (status) { \
+ case ZX_OK: \
+ break; \
+ case ZX_ERR_BAD_HANDLE: \
+ return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE, \
+ "%s - Bad Zircon handl 0x%0x: %m", message, handle); \
+ case ZX_ERR_TIMED_OUT: \
+ return VK_TIMEOUT; \
+ default: \
+ return vk_errorf(device, VK_ERROR_UNKNOWN, \
+ "%s - Unknown Zircon error: %m", message); \
}
static bool is_signaled(zx_handle_t handle) {
@@ -68,16 +68,12 @@
return (status == ZX_OK);
}
-static void lvp_pipe_sync_fuchsia_validate(
- ASSERTED struct lvp_pipe_sync_fuchsia *sync) {
- if (is_signaled(sync->signaled)) assert(sync->fence == NULL);
-}
-
static VkResult lvp_pipe_sync_fuchsia_init(UNUSED struct vk_device *vk_device,
struct vk_sync *vk_sync,
uint64_t initial_value) {
struct lvp_pipe_sync_fuchsia *sync =
vk_sync_as_lvp_pipe_sync_fuchsia(vk_sync);
+ mtx_init(&sync->lock, mtx_plain);
zx_handle_t handle = (zx_handle_t)initial_value;
@@ -89,14 +85,14 @@
if (sync->signaled != ZX_HANDLE_INVALID) {
if (zx_handle_close(sync->signaled) != ZX_OK) {
return vk_errorf(vk_device, VK_ERROR_INVALID_EXTERNAL_HANDLE,
- "Init (close): %m");
+ "Init (close) bad handle 0x%x: %m", sync->signaled);
}
}
/* Duplicate and store |handle| into |sync->signaled|. */
zx_status_t status =
zx_handle_replace(handle, ZX_RIGHT_SAME_RIGHTS, &sync->signaled);
- ZX_STATUS_VK_RTN_ERR(status, vk_device, "Init (replace)");
+ ZX_STATUS_VK_RTN_ERR(status, vk_device, handle, "Init (replace)");
} else {
zx_status_t status = zx_event_create(0, &sync->signaled);
if (status != ZX_OK) {
@@ -107,7 +103,7 @@
if (initial_value == 1) {
zx_status_t status =
zx_object_signal(sync->signaled, 0u, ZX_EVENT_SIGNALED);
- ZX_STATUS_VK_RTN(status, vk_device, "Init (signal)");
+ ZX_STATUS_VK_RTN(status, vk_device, sync->signaled, "Init (signal)");
}
}
sync->fence = NULL;
@@ -121,42 +117,38 @@
struct lvp_pipe_sync_fuchsia *sync =
vk_sync_as_lvp_pipe_sync_fuchsia(vk_sync);
- lvp_pipe_sync_fuchsia_validate(sync);
+ mtx_lock(&sync->lock);
if (sync->fence)
device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
if (sync->signaled == ZX_HANDLE_INVALID) {
+ mtx_unlock(&sync->lock);
vk_logi(VK_LOG_OBJS(device), "Finish - invalid handle\n");
return;
}
zx_status_t status = zx_handle_close(sync->signaled);
- switch (status) {
- case ZX_OK:
- break;
- case ZX_ERR_BAD_HANDLE:
- vk_loge(VK_LOG_OBJS(device),
- "Finish - attempt to close bad Zircon event handle.\n");
- return;
- default:
- vk_loge(VK_LOG_OBJS(device), "Finish - Unknown error.\n");
- return;
+ if (status == ZX_OK) {
+ sync->signaled = ZX_HANDLE_INVALID;
+ mtx_unlock(&sync->lock);
+ mtx_destroy(&sync->lock);
+ return;
}
- sync->signaled = ZX_HANDLE_INVALID;
+ if (status == ZX_ERR_BAD_HANDLE) {
+ vk_loge(VK_LOG_OBJS(device), "Finish - attempt to close bad Zircon event handle: %u.\n",
+ sync->signaled);
+ } else {
+ vk_loge(VK_LOG_OBJS(device), "Finish - Unknown error.\n");
+ }
}
void lvp_pipe_sync_fuchsia_signal_with_fence(struct lvp_device *device,
struct lvp_pipe_sync_fuchsia *sync,
struct pipe_fence_handle *fence) {
- lvp_pipe_sync_fuchsia_validate(sync);
- if (fence == NULL) {
- if (zx_object_signal(sync->signaled, 0u, ZX_EVENT_SIGNALED) != ZX_OK) {
- mesa_loge("Signal with fence (== NULL) failed.");
- }
- } else {
- if (zx_object_signal(sync->signaled, ZX_EVENT_SIGNALED, 0u) != ZX_OK) {
- mesa_loge("Signal with fence (!= NULL) failed.");
- }
- }
+ mtx_lock(&sync->lock);
device->pscreen->fence_reference(device->pscreen, &sync->fence, fence);
+ if (zx_object_signal(sync->signaled, 0u, ZX_EVENT_SIGNALED) != ZX_OK) {
+ mesa_loge("Signal handle 0x%x with fence (== NULL) failed.", sync->signaled);
+ }
+ mtx_unlock(&sync->lock);
}
static VkResult lvp_pipe_sync_fuchsia_signal(struct vk_device *vk_device,
@@ -166,14 +158,13 @@
struct lvp_pipe_sync_fuchsia *sync =
vk_sync_as_lvp_pipe_sync_fuchsia(vk_sync);
- lvp_pipe_sync_fuchsia_validate(sync);
- zx_status_t status = zx_object_signal(sync->signaled, 0u, ZX_EVENT_SIGNALED);
- if (status == ZX_OK) {
- if (sync->fence)
- device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
- return VK_SUCCESS;
+ mtx_lock(&sync->lock);
+ if (sync->fence) {
+ device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
}
- ZX_STATUS_VK_RTN(status, vk_device, "Signal (signal)");
+ zx_status_t status = zx_object_signal(sync->signaled, 0u, ZX_EVENT_SIGNALED);
+ mtx_unlock(&sync->lock);
+ ZX_STATUS_VK_RTN(status, vk_device, sync->signaled, "Signal (signal)");
}
static VkResult lvp_pipe_sync_fuchsia_reset(struct vk_device *vk_device,
@@ -182,21 +173,27 @@
struct lvp_pipe_sync_fuchsia *sync =
vk_sync_as_lvp_pipe_sync_fuchsia(vk_sync);
- lvp_pipe_sync_fuchsia_validate(sync);
+ mtx_lock(&sync->lock);
if (sync->signaled == ZX_HANDLE_INVALID) {
+ mtx_unlock(&sync->lock);
return vk_errorf(
device, VK_ERROR_INVALID_EXTERNAL_HANDLE,
- "Reset - Attempt to reset invalid Zircon event handle: %m");
+ "Reset - Attempt to reset invalid handle: %m");
}
- zx_status_t status = zx_object_signal(sync->signaled, ZX_EVENT_SIGNALED, 0u);
- if (status == ZX_OK) {
- if (sync->fence)
- device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
+ if (sync->fence) {
+ device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
}
- ZX_STATUS_VK_RTN(status, vk_device, "Reset (signal)");
+ zx_status_t status = zx_object_signal(sync->signaled, ZX_EVENT_SIGNALED, 0u);
+ mtx_unlock(&sync->lock);
+ ZX_STATUS_VK_RTN(status, vk_device, sync->signaled, "Reset (signal)");
}
+#define DUAL_LOCK(a, b) mtx_lock(a); mtx_lock(b);
+#define DUAL_UNLOCK(a, b) mtx_unlock(a); mtx_unlock(b);
+
+/* This matches the lvp_pipe_sync move implementation. Unlike typical move semantics, */
+/* it's expected that vk_src->signaled will be used after this move. */
static VkResult lvp_pipe_sync_fuchsia_move(struct vk_device *vk_device,
struct vk_sync *vk_dst,
struct vk_sync *vk_src) {
@@ -204,23 +201,39 @@
struct lvp_pipe_sync_fuchsia *dst = vk_sync_as_lvp_pipe_sync_fuchsia(vk_dst);
struct lvp_pipe_sync_fuchsia *src = vk_sync_as_lvp_pipe_sync_fuchsia(vk_src);
+ DUAL_LOCK(&src->lock, &dst->lock);
if (src->signaled == ZX_HANDLE_INVALID) {
+ DUAL_UNLOCK(&src->lock, &dst->lock);
return vk_errorf(&device->vk, VK_ERROR_INVALID_EXTERNAL_HANDLE,
"Move - Unable to move invalid handle: %m");
}
- zx_handle_t handle_out = ZX_HANDLE_INVALID;
- zx_status_t status =
- zx_handle_replace(src->signaled, ZX_RIGHT_SAME_RIGHTS, &handle_out);
- ZX_STATUS_VK_RTN_ERR(status, &device->vk, "Move (replace)");
+ struct pipe_fence_handle *fence = src->fence;
+ src->fence = NULL;
+ if (dst->fence) {
+ device->pscreen->fence_reference(device->pscreen, &dst->fence, NULL);
+ }
+ dst->fence = fence;
- src->signaled = ZX_HANDLE_INVALID;
- *dst = *src;
- dst->signaled = handle_out;
+ zx_status_t status = ZX_ERR_BAD_STATE;
+ if(is_signaled(src->signaled)) {
+ status = zx_object_signal(dst->signaled, 0u, ZX_EVENT_SIGNALED);
+ } else {
+ status = zx_object_signal(dst->signaled, ZX_EVENT_SIGNALED, 0u);
+ }
+ if(status != ZX_OK) {
+ DUAL_UNLOCK(&src->lock, &dst->lock);
+ return vk_errorf(&device->vk, VK_ERROR_UNKNOWN,
+ "Move - unable to signal handle 0x%x: %m", dst->signaled);
+ }
+ status = zx_object_signal(src->signaled, ZX_EVENT_SIGNALED, 0u);
+ DUAL_UNLOCK(&src->lock, &dst->lock);
return VK_SUCCESS;
}
+/* The submit thread is force enabled even when requesting "immediate". A client's wait may */
+/* may begin before the submit thread calls signal_with_fence. */
static VkResult lvp_pipe_sync_fuchsia_wait(struct vk_device *vk_device,
struct vk_sync *vk_sync,
uint64_t wait_value,
@@ -229,26 +242,28 @@
struct lvp_device *device = container_of(vk_device, struct lvp_device, vk);
struct lvp_pipe_sync_fuchsia *sync =
vk_sync_as_lvp_pipe_sync_fuchsia(vk_sync);
-
assert(!(wait_flags & VK_SYNC_WAIT_ANY));
-
- lvp_pipe_sync_fuchsia_validate(sync);
-
zx_status_t status = ZX_OK;
zx_time_t now_ns = zx_clock_get_monotonic();
abs_timeout_ns =
(abs_timeout_ns > ZX_TIME_INFINITE) ? ZX_TIME_INFINITE : abs_timeout_ns;
+
+ mtx_lock(&sync->lock);
while (!is_signaled(sync->signaled) && !sync->fence) {
+ mtx_unlock(&sync->lock);
if (now_ns >= abs_timeout_ns) return VK_TIMEOUT;
status = zx_object_wait_one(sync->signaled, ZX_EVENT_SIGNALED,
(zx_time_t)abs_timeout_ns, NULL);
- ZX_STATUS_VK_RTN_ERR(status, device, "Wait (wait one)");
- lvp_pipe_sync_fuchsia_validate(sync);
+ ZX_STATUS_VK_RTN_ERR(status, device, sync->signaled, "Wait (wait one)");
+ mtx_lock(&sync->lock);
now_ns = zx_clock_get_monotonic();
}
- if (is_signaled(sync->signaled) || (wait_flags & VK_SYNC_WAIT_PENDING))
+ if ((!sync->fence && is_signaled(sync->signaled)) ||
+ (wait_flags & VK_SYNC_WAIT_PENDING)) {
+ mtx_unlock(&sync->lock);
return VK_SUCCESS;
+ }
/* Grab a reference before we drop the lock */
struct pipe_fence_handle *fence = NULL;
@@ -261,49 +276,58 @@
device->pscreen->fence_reference(device->pscreen, &fence, NULL);
- lvp_pipe_sync_fuchsia_validate(sync);
-
- if (!complete) return VK_TIMEOUT;
+ if (!complete) {
+ mtx_unlock(&sync->lock);
+ return VK_TIMEOUT;
+ }
if (sync->fence == fence) {
device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
status = zx_object_signal(sync->signaled, 0u, ZX_EVENT_SIGNALED);
- ZX_STATUS_VK_RTN_ERR(status, device, "Wait (signal)");
+ mtx_unlock(&sync->lock);
+ ZX_STATUS_VK_RTN_ERR(status, device, sync->signaled, "Wait (signal)");
}
+ mtx_unlock(&sync->lock);
return VK_SUCCESS;
}
static VkResult lvp_pipe_sync_fuchsia_import_zircon_handle(
- struct vk_device *device, struct vk_sync *sync, uint32_t handle) {
- struct lvp_pipe_sync_fuchsia *sobj = vk_sync_as_lvp_pipe_sync_fuchsia(sync);
+ struct vk_device *device, struct vk_sync *vk_sync, uint32_t handle) {
+ struct lvp_pipe_sync_fuchsia *sync = vk_sync_as_lvp_pipe_sync_fuchsia(vk_sync);
zx_handle_t semaphore = ZX_HANDLE_INVALID;
-
zx_status_t status =
zx_handle_replace(handle, ZX_RIGHT_SAME_RIGHTS, &semaphore);
- ZX_STATUS_VK_RTN_ERR(status, device, "Import (replace)");
- status = zx_handle_close(sobj->signaled);
+ ZX_STATUS_VK_RTN_ERR(status, device, handle, "Import (replace)");
+
+ mtx_lock(&sync->lock);
+ status = zx_handle_close(sync->signaled);
if (status == ZX_OK) {
- sobj->signaled = semaphore;
+ sync->signaled = semaphore;
+ mtx_unlock(&sync->lock);
return VK_SUCCESS;
}
zx_handle_close(semaphore);
- ZX_STATUS_VK_RTN(status, device, "Import (close - signaled)");
+ mtx_unlock(&sync->lock);
+ ZX_STATUS_VK_RTN(status, device, semaphore, "Import (close - signaled)");
}
static VkResult lvp_pipe_sync_fuchsia_export_zircon_handle(
- struct vk_device *device, struct vk_sync *sync, uint32_t *handle_out) {
- struct lvp_pipe_sync_fuchsia *sobj = vk_sync_as_lvp_pipe_sync_fuchsia(sync);
+ struct vk_device *device, struct vk_sync *vk_sync, uint32_t *handle_out) {
+ struct lvp_pipe_sync_fuchsia *sync = vk_sync_as_lvp_pipe_sync_fuchsia(vk_sync);
- if (sobj->signaled == ZX_HANDLE_INVALID) {
+ mtx_lock(&sync->lock);
+ if (sync->signaled == ZX_HANDLE_INVALID) {
+ mtx_unlock(&sync->lock);
return vk_errorf(
device, VK_ERROR_INVALID_EXTERNAL_HANDLE,
- "Export - Attempt to export invalid Zircon event handle: %m");
+ "Export - Attempt to export invalid handle: %m");
}
zx_status_t status =
- zx_handle_duplicate(sobj->signaled, ZX_RIGHT_SAME_RIGHTS, handle_out);
- ZX_STATUS_VK_RTN(status, device, "Export (duplicate)");
+ zx_handle_duplicate(sync->signaled, ZX_RIGHT_SAME_RIGHTS, handle_out);
+ mtx_unlock(&sync->lock);
+ ZX_STATUS_VK_RTN(status, device, sync->signaled, "Export (duplicate)");
}
const struct vk_sync_type lvp_pipe_sync_fuchsia_type = {
diff --git a/src/gallium/frontends/lavapipe/lvp_private.h b/src/gallium/frontends/lavapipe/lvp_private.h
index 88e08af..7ed6ab5 100644
--- a/src/gallium/frontends/lavapipe/lvp_private.h
+++ b/src/gallium/frontends/lavapipe/lvp_private.h
@@ -227,6 +227,7 @@
* |signaled| field below. */
zx_handle_t signaled;
+ mtx_t lock;
struct pipe_fence_handle *fence;
};