lavapipe: Switch to the common sync framework
authorJason Ekstrand <jason.ekstrand@collabora.com>
Tue, 29 Mar 2022 19:07:18 +0000 (14:07 -0500)
committerMarge Bot <emma+marge@anholt.net>
Wed, 6 Apr 2022 00:38:22 +0000 (00:38 +0000)
The common Vulkan sync framework will do most of the queueing for us.
It will even sort out timeline semaphore dependencies and ensure
everything executes in-order.  All we have to do is make sure our
vk_sync type implements VK_SYNC_FEATURE_WAIT_PENDING.  This lets us get
rid of a big pile of code.

Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15651>

src/gallium/frontends/lavapipe/ci/lvp-asan-fails.txt
src/gallium/frontends/lavapipe/lvp_device.c
src/gallium/frontends/lavapipe/lvp_pipe_sync.c [new file with mode: 0644]
src/gallium/frontends/lavapipe/lvp_private.h
src/gallium/frontends/lavapipe/lvp_query.c
src/gallium/frontends/lavapipe/lvp_wsi.c
src/gallium/frontends/lavapipe/meson.build

index 6d45c95..61448dc 100644 (file)
@@ -24,9 +24,6 @@ dEQP-VK.memory_model.message_passing.ext.u32.noncoherent.atomic_atomic.atomicwri
 dEQP-VK.memory_model.write_after_read.ext.u32.noncoherent.fence_fence.atomicwrite.device.payload_local.buffer.guard_local.image.vert,Fail
 dEQP-VK.synchronization.op.single_queue.event.write_image_fragment_read_image_tess_eval.image_128x128_r16_uint,Fail
 dEQP-VK.synchronization2.op.single_queue.timeline_semaphore.write_image_geometry_read_copy_image.image_128x128_r8g8b8a8_unorm,Fail
-dEQP-VK.synchronization2.timeline_semaphore.device_host.write_image_vertex_read_image_compute.image_128x128_r32g32b32a32_sfloat,Fail
-dEQP-VK.synchronization2.timeline_semaphore.one_to_n.write_image_tess_control_read_image_tess_eval.image_128_r32_uint,Fail
-dEQP-VK.synchronization2.timeline_semaphore.wait_before_signal.write_image_tess_eval_read_copy_image.image_128x128_r8g8b8a8_unorm,Fail
 
 # Direct leak of 24 byte(s) in 1 object(s) allocated from:
 #     #0 0x7f29a36d1e8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
@@ -69,22 +66,5 @@ dEQP-VK.synchronization.op.single_queue.binary_semaphore.write_image_fragment_re
 dEQP-VK.synchronization.op.single_queue.event.write_image_fragment_read_image_tess_control.image_128x128_r8_unorm,Fail
 dEQP-VK.synchronization.op.single_queue.timeline_semaphore.write_image_vertex_read_copy_image.image_128x128_r16_uint,Fail
 dEQP-VK.synchronization.op.single_queue.timeline_semaphore.write_image_vertex_read_copy_image_to_buffer.image_128x128_r8_unorm,Fail
-dEQP-VK.synchronization.timeline_semaphore.one_to_n.write_copy_buffer_to_image_read_copy_image_to_buffer.image_64x64x8_r32_sfloat,Fail
 dEQP-VK.synchronization.timeline_semaphore.wait_before_signal.write_copy_buffer_to_image_read_image_fragment.image_128x128_r16g16b16a16_uint,Fail
-dEQP-VK.synchronization.timeline_semaphore.wait_before_signal.write_copy_buffer_to_image_read_image_geometry.image_128x128_r8g8b8a8_unorm,Fail
 dEQP-VK.synchronization2.op.single_queue.timeline_semaphore.write_image_geometry_read_blit_image.image_128x128_r16g16b16a16_uint,Fail
-dEQP-VK.synchronization2.timeline_semaphore.device_host.write_image_vertex_read_image_compute_indirect.image_64x64x8_r32_sfloat,Fail
-dEQP-VK.synchronization2.timeline_semaphore.one_to_n.write_image_tess_control_read_image_geometry.image_128x128_r8_unorm,Fail
-dEQP-VK.synchronization2.timeline_semaphore.wait_before_signal.write_image_tess_eval_read_blit_image.image_128x128_r16g16b16a16_uint,Fail
-
-# Direct leak of 336 byte(s) in 3 object(s) allocated from:
-#     #0 0x7fec1b280037 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
-#     #1 0x7fec162e5da9 in lp_fence_create ../src/gallium/drivers/llvmpipe/lp_fence.c:48
-#     #2 0x7fec16318536 in lp_setup_flush ../src/gallium/drivers/llvmpipe/lp_setup.c:409
-#     #3 0x7fec16318536 in lp_setup_flush ../src/gallium/drivers/llvmpipe/lp_setup.c:400
-#     #4 0x7fec15cc432f in thread_flush ../src/gallium/frontends/lavapipe/lvp_device.c:1358
-#     #5 0x7fec15cc5c75 in queue_thread ../src/gallium/frontends/lavapipe/lvp_device.c:1576
-#     #6 0x7fec15d6df01 in util_queue_thread_func ../src/util/u_queue.c:313
-#     #7 0x7fec15d6d26b in impl_thrd_routine ../include/c11/threads_posix.h:87
-#     #8 0x7fec1af4dea6 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x8ea6)
-dEQP-VK.synchronization.timeline_semaphore.one_to_n.write_copy_buffer_to_image_read_copy_image.image_128x128_r16g16b16a16_uint,Fail
index 0aa2490..6b90aa8 100644 (file)
@@ -26,6 +26,7 @@
 #include "pipe-loader/pipe_loader.h"
 #include "git_sha1.h"
 #include "vk_cmd_enqueue_entrypoints.h"
+#include "vk_sync_dummy.h"
 #include "vk_util.h"
 #include "pipe/p_config.h"
 #include "pipe/p_defines.h"
@@ -223,6 +224,12 @@ lvp_physical_device_init(struct lvp_physical_device *device,
    if (!device->pscreen)
       return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
 
+   device->sync_timeline_type = vk_sync_timeline_get_type(&lvp_pipe_sync_type);
+   device->sync_types[0] = &lvp_pipe_sync_type;
+   device->sync_types[1] = &device->sync_timeline_type.sync;
+   device->sync_types[2] = NULL;
+   device->vk.supported_sync_types = device->sync_types;
+
    device->max_images = device->pscreen->get_shader_param(device->pscreen, PIPE_SHADER_FRAGMENT, PIPE_SHADER_CAP_MAX_SHADER_IMAGES);
    device->vk.supported_extensions = lvp_device_extensions_supported;
 
@@ -1370,241 +1377,35 @@ VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vk_icdGetPhysicalDeviceProcAddr(
    return vk_instance_get_physical_device_proc_addr(&instance->vk, pName);
 }
 
-static void
-set_last_fence(struct lvp_device *device, struct pipe_fence_handle *handle, uint64_t timeline)
+static VkResult
+lvp_queue_submit(struct vk_queue *vk_queue,
+                 struct vk_queue_submit *submit)
 {
-   simple_mtx_lock(&device->queue.last_lock);
-   device->queue.last_fence_timeline = timeline;
-   device->pscreen->fence_reference(device->pscreen, &device->queue.last_fence, handle);
-   simple_mtx_unlock(&device->queue.last_lock);
-}
-
-static void
-thread_flush(struct lvp_device *device, struct lvp_fence *fence, uint64_t timeline,
-             unsigned num_signal_semaphores, struct lvp_semaphore **semaphores,
-             unsigned num_timelines, struct lvp_semaphore_timeline **timelines)
-{
-   struct pipe_fence_handle *handle = NULL;
-   device->queue.ctx->flush(device->queue.ctx, &handle, 0);
-   if (fence)
-      device->pscreen->fence_reference(device->pscreen, &fence->handle, handle);
-   for (unsigned i = 0; i < num_signal_semaphores; i++) {
-      struct lvp_semaphore *sema = semaphores[i];
-      if (!sema->is_timeline) {
-         simple_mtx_lock(&sema->lock);
-         device->pscreen->fence_reference(device->pscreen, &sema->handle, handle);
-         simple_mtx_unlock(&sema->lock);
-      }
-   }
-   set_last_fence(device, handle, timeline);
-   /* this is the array of signaling timeline semaphore links */
-   for (unsigned i = 0; i < num_timelines; i++)
-      device->pscreen->fence_reference(device->pscreen, &timelines[i]->fence, handle);
-
-   device->pscreen->fence_reference(device->pscreen, &handle, NULL);
-}
-
-/* get a new timeline link for creating a new signal event
- * sema->lock MUST be locked before calling
- */
-static struct lvp_semaphore_timeline *
-get_semaphore_link(struct lvp_semaphore *sema)
-{
-   if (!util_dynarray_num_elements(&sema->links, struct lvp_semaphore_timeline*)) {
-#define NUM_LINKS 50
-      /* bucket allocate using the ralloc ctx because I like buckets */
-      struct lvp_semaphore_timeline *link = ralloc_array(sema->mem, struct lvp_semaphore_timeline, NUM_LINKS);
-      for (unsigned i = 0; i < NUM_LINKS; i++) {
-         link[i].next = NULL;
-         link[i].fence = NULL;
-         util_dynarray_append(&sema->links, struct lvp_semaphore_timeline*, &link[i]);
-      }
-   }
-   struct lvp_semaphore_timeline *tl = util_dynarray_pop(&sema->links, struct lvp_semaphore_timeline*);
-   if (sema->timeline)
-      sema->latest->next = tl;
-   else
-      sema->timeline = tl;
-   sema->latest = tl;
-   return tl;
-}
+   struct lvp_queue *queue = container_of(vk_queue, struct lvp_queue, vk);
 
-static bool
-fence_finish(struct lvp_device *device,
-             struct pipe_fence_handle *fence, uint64_t timeout)
-{
-   return fence && device->pscreen->fence_finish(device->pscreen, NULL, fence, timeout);
-}
+   VkResult result = vk_sync_wait_many(&queue->device->vk,
+                                       submit->wait_count, submit->waits,
+                                       VK_SYNC_WAIT_COMPLETE, UINT64_MAX);
+   if (result != VK_SUCCESS)
+      return result;
 
-/* prune any timeline links which are older than the current device timeline id
- * sema->lock MUST be locked before calling
- */
-static void
-prune_semaphore_links(struct lvp_device *device,
-                      struct lvp_semaphore *sema, uint64_t timeline)
-{
-   if (!timeline)
-      /* zero isn't a valid id to prune with */
-      return;
-   struct lvp_semaphore_timeline *tl = sema->timeline;
-   /* walk the timeline links and pop all the ones that are old */
-   while (tl && ((tl->timeline <= timeline) || (tl->signal <= sema->current))) {
-      struct lvp_semaphore_timeline *cur = tl;
-      /* only update current timeline id if the update is monotonic */
-      if (sema->current < tl->signal)
-         sema->current = tl->signal;
-      util_dynarray_append(&sema->links, struct lvp_semaphore_timeline*, tl);
-      tl = tl->next;
-      cur->next = NULL;
-      device->pscreen->fence_reference(device->pscreen, &cur->fence, NULL);
-   }
-   /* this is now the current timeline link */
-   sema->timeline = tl;
-}
+   for (uint32_t i = 0; i < submit->command_buffer_count; i++) {
+      struct lvp_cmd_buffer *cmd_buffer =
+         container_of(submit->command_buffers[i], struct lvp_cmd_buffer, vk);
 
-/* find a timeline id that can be waited on to satisfy the signal condition
- * sema->lock MUST be locked before calling
- */
-static struct lvp_semaphore_timeline *
-find_semaphore_timeline(struct lvp_semaphore *sema, uint64_t signal)
-{
-   for (struct lvp_semaphore_timeline *tl = sema->timeline; tl; tl = tl->next) {
-      if (tl->signal >= signal)
-         return tl;
+      lvp_execute_cmds(queue->device, queue, cmd_buffer);
    }
-   /* never submitted or is completed */
-   return NULL;
-}
-
-struct timeline_wait {
-   bool done;
-   struct lvp_semaphore_timeline *tl;
-};
 
-static VkResult wait_semaphores(struct lvp_device *device,
-    const VkSemaphoreWaitInfo*                  pWaitInfo,
-    uint64_t                                    timeout)
-{
-   /* build array of timeline links to poll */
-   VkResult ret = VK_TIMEOUT;
-   bool any = (pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT) == VK_SEMAPHORE_WAIT_ANY_BIT;
-   unsigned num_remaining = any ? 1 : pWaitInfo->semaphoreCount;
-   /* just allocate an array for simplicity */
-   struct timeline_wait *tl_array = calloc(pWaitInfo->semaphoreCount, sizeof(struct timeline_wait));
+   if (submit->command_buffer_count > 0)
+      queue->ctx->flush(queue->ctx, &queue->last_fence, 0);
 
-   int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
-   /* UINT64_MAX will always overflow, so special case it
-    * otherwise, calculate ((timeout / num_semaphores) / 10) to allow waiting 10 times on every semaphore
-    */
-   uint64_t wait_interval = timeout == UINT64_MAX ? 5000 : timeout / pWaitInfo->semaphoreCount / 10;
-   while (num_remaining) {
-      for (unsigned i = 0; num_remaining && i < pWaitInfo->semaphoreCount; i++) {
-         if (tl_array[i].done) //completed
-            continue;
-         if (timeout && timeout != UINT64_MAX) {
-            /* update remaining timeout on every loop */
-            int64_t time_ns = os_time_get_nano();
-            if (abs_timeout <= time_ns)
-               goto end;
-            timeout = abs_timeout > time_ns ? abs_timeout - time_ns : 0;
-         }
-         const uint64_t waitval = pWaitInfo->pValues[i];
-         LVP_FROM_HANDLE(lvp_semaphore, sema, pWaitInfo->pSemaphores[i]);
-
-         if (!sema->is_timeline) {
-            simple_mtx_lock(&sema->lock);
-            if (fence_finish(device, sema->handle, wait_interval)) {
-               tl_array[i].done = true;
-               num_remaining--;
-            }
-            simple_mtx_unlock(&sema->lock);
-            continue;
-         }
-         if (sema->current >= waitval) {
-            tl_array[i].done = true;
-            num_remaining--;
-            continue;
-         }
-         if (!tl_array[i].tl) {
-            /* no timeline link was available yet: try to find one */
-            simple_mtx_lock(&sema->lock);
-            /* always prune first to update current timeline id */
-            prune_semaphore_links(device, sema, device->queue.last_finished);
-            tl_array[i].tl = find_semaphore_timeline(sema, waitval);
-            if (timeout && !tl_array[i].tl) {
-               /* still no timeline link available:
-                * try waiting on the conditional for a broadcast instead of melting the cpu
-                */
-               mtx_lock(&sema->submit_lock);
-               struct timespec t;
-               t.tv_nsec = wait_interval % 1000000000u;
-               t.tv_sec = (wait_interval - t.tv_nsec) / 1000000000u;
-               cnd_timedwait(&sema->submit, &sema->submit_lock, &t);
-               mtx_unlock(&sema->submit_lock);
-               tl_array[i].tl = find_semaphore_timeline(sema, waitval);
-            }
-            simple_mtx_unlock(&sema->lock);
-         }
-         /* mark semaphore as done if:
-          * - timeline id comparison passes
-          * - fence for timeline id exists and completes
-          */
-         if (sema->current >= waitval ||
-             (tl_array[i].tl &&
-              fence_finish(device, tl_array[i].tl->fence, wait_interval))) {
-            tl_array[i].done = true;
-            num_remaining--;
-         }
-      }
-      if (!timeout)
-         break;
+   for (uint32_t i = 0; i < submit->signal_count; i++) {
+      struct lvp_pipe_sync *sync =
+         vk_sync_as_lvp_pipe_sync(submit->signals[i].sync);
+      lvp_pipe_sync_signal_with_fence(queue->device, sync, queue->last_fence);
    }
-   if (!num_remaining)
-      ret = VK_SUCCESS;
-
-end:
-   free(tl_array);
-   return ret;
-}
-
-void
-queue_thread_noop(void *data, void *gdata, int thread_index)
-{
-   struct lvp_device *device = gdata;
-   struct lvp_queue_noop *noop = data;
-
-   struct lvp_fence *fence = noop->fence;
-   struct lvp_semaphore *semaphore = noop->sema;
-
-   thread_flush(device, fence, fence ? fence->timeline : 0, semaphore ? 1 : 0, &semaphore, 0, NULL);
-   free(noop);
-}
 
-static void
-queue_thread(void *data, void *gdata, int thread_index)
-{
-   struct lvp_queue_work *task = data;
-   struct lvp_device *device = gdata;
-   struct lvp_queue *queue = &device->queue;
-
-   if (task->wait_count) {
-      /* identical to WaitSemaphores */
-      VkSemaphoreWaitInfo wait;
-      wait.flags = 0; //wait on all semaphores
-      wait.semaphoreCount = task->wait_count;
-      wait.pSemaphores = task->waits;
-      wait.pValues = task->wait_vals;
-      //wait
-      wait_semaphores(device, &wait, UINT64_MAX);
-   }
-
-   //execute
-   for (unsigned i = 0; i < task->cmd_buffer_count; i++) {
-      lvp_execute_cmds(queue->device, queue, task->cmd_buffers[i]);
-   }
-
-   thread_flush(device, task->fence, task->timeline, task->signal_count, task->signals, task->timeline_count, task->timelines);
-   free(task);
+   return VK_SUCCESS;
 }
 
 static VkResult
@@ -1617,29 +1418,29 @@ lvp_queue_init(struct lvp_device *device, struct lvp_queue *queue,
    if (result != VK_SUCCESS)
       return result;
 
+   result = vk_queue_enable_submit_thread(&queue->vk);
+   if (result != VK_SUCCESS) {
+      vk_queue_finish(&queue->vk);
+      return result;
+   }
+
    queue->device = device;
 
-   simple_mtx_init(&queue->last_lock, mtx_plain);
-   queue->timeline = 0;
    queue->ctx = device->pscreen->context_create(device->pscreen, NULL, PIPE_CONTEXT_ROBUST_BUFFER_ACCESS);
    queue->cso = cso_create_context(queue->ctx, CSO_NO_VBUF);
-   util_queue_init(&queue->queue, "lavapipe", 8, 1, UTIL_QUEUE_INIT_RESIZE_IF_FULL, device);
-   p_atomic_set(&queue->count, 0);
    queue->uploader = u_upload_create(queue->ctx, 1024 * 1024, PIPE_BIND_CONSTANT_BUFFER, PIPE_USAGE_STREAM, 0);
 
+   queue->vk.driver_submit = lvp_queue_submit;
+
    return VK_SUCCESS;
 }
 
 static void
 lvp_queue_finish(struct lvp_queue *queue)
 {
-   util_queue_finish(&queue->queue);
-   util_queue_destroy(&queue->queue);
-
    u_upload_destroy(queue->uploader);
    cso_destroy_context(queue->cso);
    queue->ctx->destroy(queue->ctx);
-   simple_mtx_destroy(&queue->last_lock);
 
    vk_queue_finish(&queue->vk);
 }
@@ -1661,6 +1462,15 @@ unref_pipeline_layout(struct vk_device *vk_device, VkPipelineLayout _layout)
    lvp_pipeline_layout_unref(device, layout);
 }
 
+static VkResult
+lvp_create_sync_for_memory(struct vk_device *device,
+                           VkDeviceMemory memory,
+                           bool signal_memory,
+                           struct vk_sync **sync_out)
+{
+   return vk_sync_create(device, &vk_sync_dummy_type, 0, 1, sync_out);
+}
+
 VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateDevice(
    VkPhysicalDevice                            physicalDevice,
    const VkDeviceCreateInfo*                   pCreateInfo,
@@ -1700,9 +1510,12 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateDevice(
       return result;
    }
 
+   vk_device_enable_threaded_submit(&device->vk);
+
    device->instance = (struct lvp_instance *)physical_device->vk.instance;
    device->physical_device = physical_device;
 
+   device->vk.create_sync_for_memory = lvp_create_sync_for_memory;
    device->vk.ref_pipeline_layout = ref_pipeline_layout;
    device->vk.unref_pipeline_layout = unref_pipeline_layout;
 
@@ -1771,138 +1584,6 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_EnumerateDeviceLayerProperties(
    return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
 }
 
-VKAPI_ATTR VkResult VKAPI_CALL lvp_QueueSubmit2KHR(
-    VkQueue                                     _queue,
-    uint32_t                                    submitCount,
-    const VkSubmitInfo2*                        pSubmits,
-    VkFence                                     _fence)
-{
-   LVP_FROM_HANDLE(lvp_queue, queue, _queue);
-   LVP_FROM_HANDLE(lvp_fence, fence, _fence);
-
-   /* each submit is a separate job to simplify/streamline semaphore waits */
-   for (uint32_t i = 0; i < submitCount; i++) {
-      uint64_t timeline = ++queue->timeline;
-      struct lvp_queue_work *task = malloc(sizeof(struct lvp_queue_work) +
-                                           pSubmits[i].commandBufferInfoCount * sizeof(struct lvp_cmd_buffer *) +
-                                           pSubmits[i].signalSemaphoreInfoCount * (sizeof(struct lvp_semaphore_timeline*) + sizeof(struct lvp_semaphore *)) +
-                                           pSubmits[i].waitSemaphoreInfoCount * (sizeof(VkSemaphore) + sizeof(uint64_t)));
-      task->cmd_buffer_count = pSubmits[i].commandBufferInfoCount;
-      task->timeline_count = pSubmits[i].signalSemaphoreInfoCount;
-      task->signal_count = pSubmits[i].signalSemaphoreInfoCount;
-      task->wait_count = pSubmits[i].waitSemaphoreInfoCount;
-      task->fence = fence;
-      task->timeline = timeline;
-      task->cmd_buffers = (struct lvp_cmd_buffer **)(task + 1);
-      task->timelines = (struct lvp_semaphore_timeline**)((uint8_t*)task->cmd_buffers + pSubmits[i].commandBufferInfoCount * sizeof(struct lvp_cmd_buffer *));
-      task->signals = (struct lvp_semaphore **)((uint8_t*)task->timelines + pSubmits[i].signalSemaphoreInfoCount * sizeof(struct lvp_semaphore_timeline *));
-      task->waits = (VkSemaphore*)((uint8_t*)task->signals + pSubmits[i].signalSemaphoreInfoCount * sizeof(struct lvp_semaphore *));
-      task->wait_vals = (uint64_t*)((uint8_t*)task->waits + pSubmits[i].waitSemaphoreInfoCount * sizeof(VkSemaphore));
-
-      unsigned c = 0;
-      for (uint32_t j = 0; j < pSubmits[i].commandBufferInfoCount; j++) {
-         task->cmd_buffers[c++] = lvp_cmd_buffer_from_handle(pSubmits[i].pCommandBufferInfos[j].commandBuffer);
-      }
-      unsigned s = 0;
-      for (unsigned j = 0; j < pSubmits[i].signalSemaphoreInfoCount; j++) {
-         const VkSemaphoreSubmitInfo *info = &pSubmits[i].pSignalSemaphoreInfos[j];
-         LVP_FROM_HANDLE(lvp_semaphore, sema, info->semaphore);
-         task->signals[j] = sema;
-         if (!sema->is_timeline) {
-            task->timeline_count--;
-            continue;
-         }
-         simple_mtx_lock(&sema->lock);
-         /* always prune first to make links available and update timeline id */
-         prune_semaphore_links(queue->device, sema, queue->last_finished);
-         if (sema->current < info->value) {
-            /* only signal semaphores if the new id is >= the current one */
-            struct lvp_semaphore_timeline *tl = get_semaphore_link(sema);
-            tl->signal = info->value;
-            tl->timeline = timeline;
-            task->timelines[s] = tl;
-            s++;
-         } else
-            task->timeline_count--;
-         simple_mtx_unlock(&sema->lock);
-      }
-      unsigned w = 0;
-      for (unsigned j = 0; j < pSubmits[i].waitSemaphoreInfoCount; j++) {
-         const VkSemaphoreSubmitInfo *info = &pSubmits[i].pWaitSemaphoreInfos[j];
-         LVP_FROM_HANDLE(lvp_semaphore, sema, info->semaphore);
-         if (!sema->is_timeline) {
-            task->waits[w] = info->semaphore;
-            task->wait_vals[w] = 0;
-            w++;
-            continue;
-         }
-         simple_mtx_lock(&sema->lock);
-         /* always prune first to update timeline id */
-         prune_semaphore_links(queue->device, sema, queue->last_finished);
-         if (info->value &&
-             info->stageMask &&
-             sema->current < info->value) {
-            /* only wait on semaphores if the new id is > the current one and a wait mask is set
-             * 
-             * technically the mask could be used to check whether there's gfx/compute ops on a cmdbuf and no-op,
-             * but probably that's not worth the complexity
-             */
-            task->waits[w] = info->semaphore;
-            task->wait_vals[w] = info->value;
-            w++;
-         } else
-            task->wait_count--;
-         simple_mtx_unlock(&sema->lock);
-      }
-      if (fence && i == submitCount - 1) {
-         /* u_queue fences should only be signaled for the last submit, as this is the one that
-          * the vk fence represents
-          */
-         fence->timeline = timeline;
-         util_queue_add_job(&queue->queue, task, &fence->fence, queue_thread, NULL, 0);
-      } else
-         util_queue_add_job(&queue->queue, task, NULL, queue_thread, NULL, 0);
-   }
-   if (!submitCount && fence) {
-      /* special case where a fence is created to use as a synchronization point */
-      fence->timeline = p_atomic_inc_return(&queue->timeline);
-      struct lvp_queue_noop *noop = malloc(sizeof(struct lvp_queue_noop));
-      if (!noop)
-         return VK_ERROR_OUT_OF_HOST_MEMORY;
-      noop->fence = fence;
-      noop->sema = NULL;
-      util_queue_add_job(&queue->queue, noop, &fence->fence, queue_thread_noop, NULL, 0);
-   }
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_QueueWaitIdle(
-   VkQueue                                     _queue)
-{
-   LVP_FROM_HANDLE(lvp_queue, queue, _queue);
-
-   util_queue_finish(&queue->queue);
-   simple_mtx_lock(&queue->last_lock);
-   uint64_t timeline = queue->last_fence_timeline;
-   if (fence_finish(queue->device, queue->last_fence, PIPE_TIMEOUT_INFINITE)) {
-      queue->device->pscreen->fence_reference(queue->device->pscreen, &queue->device->queue.last_fence, NULL);
-      if (timeline > queue->last_finished)
-         queue->last_finished = timeline;
-   }
-   simple_mtx_unlock(&queue->last_lock);
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_DeviceWaitIdle(
-   VkDevice                                    _device)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-
-   lvp_QueueWaitIdle(lvp_queue_to_handle(&device->queue));
-
-   return VK_SUCCESS;
-}
-
 VKAPI_ATTR VkResult VKAPI_CALL lvp_AllocateMemory(
    VkDevice                                    _device,
    const VkMemoryAllocateInfo*                 pAllocateInfo,
@@ -2359,270 +2040,6 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_QueueBindSparse(
    stub_return(VK_ERROR_INCOMPATIBLE_DRIVER);
 }
 
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateFence(
-   VkDevice                                    _device,
-   const VkFenceCreateInfo*                    pCreateInfo,
-   const VkAllocationCallbacks*                pAllocator,
-   VkFence*                                    pFence)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   struct lvp_fence *fence;
-
-   fence = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*fence), 8,
-                     VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-   if (fence == NULL)
-      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
-   vk_object_base_init(&device->vk, &fence->base, VK_OBJECT_TYPE_FENCE);
-   util_queue_fence_init(&fence->fence);
-   fence->signalled = (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) == VK_FENCE_CREATE_SIGNALED_BIT;
-
-   fence->handle = NULL;
-   fence->timeline = 0;
-   *pFence = lvp_fence_to_handle(fence);
-
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR void VKAPI_CALL lvp_DestroyFence(
-   VkDevice                                    _device,
-   VkFence                                     _fence,
-   const VkAllocationCallbacks*                pAllocator)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   LVP_FROM_HANDLE(lvp_fence, fence, _fence);
-
-   if (!_fence)
-      return;
-   /* evade annoying destroy assert */
-   util_queue_fence_init(&fence->fence);
-   util_queue_fence_destroy(&fence->fence);
-   if (fence->handle)
-      device->pscreen->fence_reference(device->pscreen, &fence->handle, NULL);
-
-   vk_object_base_finish(&fence->base);
-   vk_free2(&device->vk.alloc, pAllocator, fence);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_ResetFences(
-   VkDevice                                    _device,
-   uint32_t                                    fenceCount,
-   const VkFence*                              pFences)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   for (unsigned i = 0; i < fenceCount; i++) {
-      struct lvp_fence *fence = lvp_fence_from_handle(pFences[i]);
-      /* ensure u_queue doesn't explode when submitting a completed lvp_fence
-       * which has not yet signalled its u_queue fence
-       */
-      util_queue_fence_wait(&fence->fence);
-
-      if (fence->handle) {
-         simple_mtx_lock(&device->queue.last_lock);
-         if (fence->handle == device->queue.last_fence)
-            device->pscreen->fence_reference(device->pscreen, &device->queue.last_fence, NULL);
-         simple_mtx_unlock(&device->queue.last_lock);
-         device->pscreen->fence_reference(device->pscreen, &fence->handle, NULL);
-      }
-      fence->signalled = false;
-   }
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_GetFenceStatus(
-   VkDevice                                    _device,
-   VkFence                                     _fence)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   LVP_FROM_HANDLE(lvp_fence, fence, _fence);
-
-   if (fence->signalled)
-      return VK_SUCCESS;
-
-   if (!util_queue_fence_is_signalled(&fence->fence) || !fence_finish(device, fence->handle, 0))
-      return VK_NOT_READY;
-
-   fence->signalled = true;
-   simple_mtx_lock(&device->queue.last_lock);
-   if (fence->handle == device->queue.last_fence) {
-      device->pscreen->fence_reference(device->pscreen, &device->queue.last_fence, NULL);
-      if (fence->timeline > device->queue.last_finished)
-         device->queue.last_finished = fence->timeline;
-   }
-   simple_mtx_unlock(&device->queue.last_lock);
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_WaitForFences(
-   VkDevice                                    _device,
-   uint32_t                                    fenceCount,
-   const VkFence*                              pFences,
-   VkBool32                                    waitAll,
-   uint64_t                                    timeout)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   struct lvp_fence *fence = NULL;
-
-   /* lavapipe is completely synchronous, so only one fence needs to be waited on */
-   if (waitAll) {
-      /* find highest timeline id */
-      for (unsigned i = 0; i < fenceCount; i++) {
-         struct lvp_fence *f = lvp_fence_from_handle(pFences[i]);
-
-         /* this is an unsubmitted fence: immediately bail out */
-         if (!f->timeline && !f->signalled)
-            return VK_TIMEOUT;
-         if (!fence || f->timeline > fence->timeline)
-            fence = f;
-      }
-   } else {
-      /* find lowest timeline id */
-      for (unsigned i = 0; i < fenceCount; i++) {
-         struct lvp_fence *f = lvp_fence_from_handle(pFences[i]);
-         if (f->signalled)
-            return VK_SUCCESS;
-         if (f->timeline && (!fence || f->timeline < fence->timeline))
-            fence = f;
-      }
-   }
-   if (!fence)
-      return VK_TIMEOUT;
-   if (fence->signalled)
-      return VK_SUCCESS;
-
-   if (!util_queue_fence_is_signalled(&fence->fence)) {
-      int64_t abs_timeout = os_time_get_absolute_timeout(timeout);
-      if (!util_queue_fence_wait_timeout(&fence->fence, abs_timeout))
-         return VK_TIMEOUT;
-
-      if (timeout != OS_TIMEOUT_INFINITE) {
-         int64_t time_ns = os_time_get_nano();
-         timeout = abs_timeout > time_ns ? abs_timeout - time_ns : 0;
-      }
-   }
-
-   if (!fence_finish(device, fence->handle, timeout))
-      return VK_TIMEOUT;
-   simple_mtx_lock(&device->queue.last_lock);
-   if (fence->handle == device->queue.last_fence) {
-      device->pscreen->fence_reference(device->pscreen, &device->queue.last_fence, NULL);
-      if (fence->timeline > device->queue.last_finished)
-         device->queue.last_finished = fence->timeline;
-   }
-   simple_mtx_unlock(&device->queue.last_lock);
-   fence->signalled = true;
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateSemaphore(
-   VkDevice                                    _device,
-   const VkSemaphoreCreateInfo*                pCreateInfo,
-   const VkAllocationCallbacks*                pAllocator,
-   VkSemaphore*                                pSemaphore)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-
-   struct lvp_semaphore *sema = vk_alloc2(&device->vk.alloc, pAllocator,
-                                          sizeof(*sema), 8,
-                                          VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
-
-   if (!sema)
-      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
-   vk_object_base_init(&device->vk, &sema->base,
-                       VK_OBJECT_TYPE_SEMAPHORE);
-
-   const VkSemaphoreTypeCreateInfo *info = vk_find_struct_const(pCreateInfo->pNext, SEMAPHORE_TYPE_CREATE_INFO);
-   sema->is_timeline = info && info->semaphoreType == VK_SEMAPHORE_TYPE_TIMELINE;
-   simple_mtx_init(&sema->lock, mtx_plain);
-   sema->handle = NULL;
-   if (sema->is_timeline) {
-      sema->is_timeline = true;
-      sema->timeline = NULL;
-      sema->current = info->initialValue;
-      sema->mem = ralloc_context(NULL);
-      util_dynarray_init(&sema->links, sema->mem);
-
-      mtx_init(&sema->submit_lock, mtx_plain);
-      cnd_init(&sema->submit);
-   }
-
-   *pSemaphore = lvp_semaphore_to_handle(sema);
-
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR void VKAPI_CALL lvp_DestroySemaphore(
-   VkDevice                                    _device,
-   VkSemaphore                                 _semaphore,
-   const VkAllocationCallbacks*                pAllocator)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   LVP_FROM_HANDLE(lvp_semaphore, sema, _semaphore);
-
-   if (!_semaphore)
-      return;
-   if (sema->is_timeline) {
-      ralloc_free(sema->mem);
-      simple_mtx_destroy(&sema->lock);
-      mtx_destroy(&sema->submit_lock);
-      cnd_destroy(&sema->submit);
-   }
-   if (sema->handle)
-      device->pscreen->fence_reference(device->pscreen, &sema->handle, NULL);
-   vk_object_base_finish(&sema->base);
-   vk_free2(&device->vk.alloc, pAllocator, sema);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_WaitSemaphores(
-    VkDevice                                    _device,
-    const VkSemaphoreWaitInfo*                  pWaitInfo,
-    uint64_t                                    timeout)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   /* same mechanism as used by queue submit */
-   return wait_semaphores(device, pWaitInfo, timeout);
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_GetSemaphoreCounterValue(
-    VkDevice                                    _device,
-    VkSemaphore                                 _semaphore,
-    uint64_t*                                   pValue)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   LVP_FROM_HANDLE(lvp_semaphore, sema, _semaphore);
-   simple_mtx_lock(&sema->lock);
-   prune_semaphore_links(device, sema, device->queue.last_finished);
-   struct lvp_semaphore_timeline *tl = find_semaphore_timeline(sema, sema->current);
-   if (tl && fence_finish(device, tl->fence, 0)) {
-      simple_mtx_lock(&device->queue.last_lock);
-      if (tl->timeline > device->queue.last_finished)
-         device->queue.last_finished = tl->timeline;
-      simple_mtx_unlock(&device->queue.last_lock);
-      *pValue = tl->signal;
-   } else {
-      *pValue = sema->current;
-   }
-   simple_mtx_unlock(&sema->lock);
-   return VK_SUCCESS;
-}
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_SignalSemaphore(
-    VkDevice                                    _device,
-    const VkSemaphoreSignalInfo*                pSignalInfo)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   LVP_FROM_HANDLE(lvp_semaphore, sema, pSignalInfo->semaphore);
-
-   /* try to remain monotonic */
-   if (sema->current < pSignalInfo->value)
-      sema->current = pSignalInfo->value;
-   cnd_broadcast(&sema->submit);
-   simple_mtx_lock(&sema->lock);
-   prune_semaphore_links(device, sema, device->queue.last_finished);
-   simple_mtx_unlock(&sema->lock);
-   return VK_SUCCESS;
-}
-
 VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateEvent(
    VkDevice                                    _device,
    const VkEventCreateInfo*                    pCreateInfo,
diff --git a/src/gallium/frontends/lavapipe/lvp_pipe_sync.c b/src/gallium/frontends/lavapipe/lvp_pipe_sync.c
new file mode 100644 (file)
index 0000000..20924a6
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright © 2022 Collabora Ltd.
+ *
+ * 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.
+ */
+
+#include "lvp_private.h"
+#include "util/timespec.h"
+
+static void
+lvp_pipe_sync_validate(ASSERTED struct lvp_pipe_sync *sync)
+{
+   if (sync->signaled)
+      assert(sync->fence == NULL);
+}
+
+static VkResult
+lvp_pipe_sync_init(UNUSED struct vk_device *vk_device,
+                   struct vk_sync *vk_sync,
+                   uint64_t initial_value)
+{
+   struct lvp_pipe_sync *sync = vk_sync_as_lvp_pipe_sync(vk_sync);
+
+   mtx_init(&sync->lock, mtx_plain);
+   cnd_init(&sync->changed);
+   sync->signaled = (initial_value != 0);
+   sync->fence = NULL;
+
+   return VK_SUCCESS;
+}
+
+static void
+lvp_pipe_sync_finish(struct vk_device *vk_device,
+                     struct vk_sync *vk_sync)
+{
+   struct lvp_device *device = container_of(vk_device, struct lvp_device, vk);
+   struct lvp_pipe_sync *sync = vk_sync_as_lvp_pipe_sync(vk_sync);
+
+   lvp_pipe_sync_validate(sync);
+   if (sync->fence)
+      device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
+   cnd_destroy(&sync->changed);
+   mtx_destroy(&sync->lock);
+}
+
+void
+lvp_pipe_sync_signal_with_fence(struct lvp_device *device,
+                                struct lvp_pipe_sync *sync,
+                                struct pipe_fence_handle *fence)
+{
+   mtx_lock(&sync->lock);
+   lvp_pipe_sync_validate(sync);
+   sync->signaled = fence == NULL;
+   device->pscreen->fence_reference(device->pscreen, &sync->fence, fence);
+   cnd_broadcast(&sync->changed);
+   mtx_unlock(&sync->lock);
+}
+
+static VkResult
+lvp_pipe_sync_signal(struct vk_device *vk_device,
+                     struct vk_sync *vk_sync,
+                     uint64_t value)
+{
+   struct lvp_device *device = container_of(vk_device, struct lvp_device, vk);
+   struct lvp_pipe_sync *sync = vk_sync_as_lvp_pipe_sync(vk_sync);
+
+   mtx_lock(&sync->lock);
+   lvp_pipe_sync_validate(sync);
+   sync->signaled = true;
+   if (sync->fence)
+      device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
+   cnd_broadcast(&sync->changed);
+   mtx_unlock(&sync->lock);
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+lvp_pipe_sync_reset(struct vk_device *vk_device,
+                    struct vk_sync *vk_sync)
+{
+   struct lvp_device *device = container_of(vk_device, struct lvp_device, vk);
+   struct lvp_pipe_sync *sync = vk_sync_as_lvp_pipe_sync(vk_sync);
+
+   mtx_lock(&sync->lock);
+   lvp_pipe_sync_validate(sync);
+   sync->signaled = false;
+   if (sync->fence)
+      device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
+   cnd_broadcast(&sync->changed);
+   mtx_unlock(&sync->lock);
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+lvp_pipe_sync_move(struct vk_device *vk_device,
+                   struct vk_sync *vk_dst,
+                   struct vk_sync *vk_src)
+{
+   struct lvp_device *device = container_of(vk_device, struct lvp_device, vk);
+   struct lvp_pipe_sync *dst = vk_sync_as_lvp_pipe_sync(vk_dst);
+   struct lvp_pipe_sync *src = vk_sync_as_lvp_pipe_sync(vk_src);
+
+   /* Pull the fence out of the source */
+   mtx_lock(&src->lock);
+   struct pipe_fence_handle *fence = src->fence;
+   bool signaled = src->signaled;
+   src->fence = NULL;
+   src->signaled = false;
+   cnd_broadcast(&src->changed);
+   mtx_unlock(&src->lock);
+
+   mtx_lock(&dst->lock);
+   if (dst->fence)
+      device->pscreen->fence_reference(device->pscreen, &dst->fence, NULL);
+   dst->fence = fence;
+   dst->signaled = signaled;
+   cnd_broadcast(&dst->changed);
+   mtx_unlock(&dst->lock);
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+lvp_pipe_sync_wait_locked(struct lvp_device *device,
+                          struct lvp_pipe_sync *sync,
+                          uint64_t wait_value,
+                          enum vk_sync_wait_flags wait_flags,
+                          uint64_t abs_timeout_ns)
+{
+   assert(!(wait_flags & VK_SYNC_WAIT_ANY));
+
+   lvp_pipe_sync_validate(sync);
+
+   uint64_t now_ns = os_time_get_nano();
+   while (!sync->signaled && !sync->fence) {
+      if (now_ns >= abs_timeout_ns)
+         return VK_TIMEOUT;
+
+      int ret;
+      if (abs_timeout_ns >= INT64_MAX) {
+         /* Common infinite wait case */
+         ret = cnd_wait(&sync->changed, &sync->lock);
+      } else {
+         /* This is really annoying.  The C11 threads API uses CLOCK_REALTIME
+          * while all our absolute timeouts are in CLOCK_MONOTONIC.  Best
+          * thing we can do is to convert and hope the system admin doesn't
+          * change the time out from under us.
+          */
+         uint64_t rel_timeout_ns = abs_timeout_ns - now_ns;
+
+         struct timespec now_ts, abs_timeout_ts;
+         timespec_get(&now_ts, TIME_UTC);
+         if (timespec_add_nsec(&abs_timeout_ts, &now_ts, rel_timeout_ns)) {
+            /* Overflowed; may as well be infinite */
+            ret = cnd_wait(&sync->changed, &sync->lock);
+         } else {
+            ret = cnd_timedwait(&sync->changed, &sync->lock, &abs_timeout_ts);
+         }
+      }
+      if (ret == thrd_error)
+         return vk_errorf(device, VK_ERROR_UNKNOWN, "cnd_timedwait failed");
+
+      lvp_pipe_sync_validate(sync);
+
+      /* We don't trust the timeout condition on cnd_timedwait() because of
+       * the potential clock issues caused by using CLOCK_REALTIME.  Instead,
+       * update now_ns, go back to the top of the loop, and re-check.
+       */
+      now_ns = os_time_get_nano();
+   }
+
+   if (sync->signaled || (wait_flags & VK_SYNC_WAIT_PENDING))
+      return VK_SUCCESS;
+
+   /* Grab a reference before we drop the lock */
+   struct pipe_fence_handle *fence = NULL;
+   device->pscreen->fence_reference(device->pscreen, &fence, sync->fence);
+
+   mtx_unlock(&sync->lock);
+
+   uint64_t rel_timeout_ns =
+      now_ns >= abs_timeout_ns ? 0 : abs_timeout_ns - now_ns;
+   bool complete = device->pscreen->fence_finish(device->pscreen, NULL,
+                                                 fence, rel_timeout_ns);
+
+   device->pscreen->fence_reference(device->pscreen, &fence, NULL);
+
+   mtx_lock(&sync->lock);
+
+   lvp_pipe_sync_validate(sync);
+
+   if (!complete)
+      return VK_TIMEOUT;
+
+   if (sync->fence == fence) {
+      device->pscreen->fence_reference(device->pscreen, &sync->fence, NULL);
+      sync->signaled = true;
+   }
+
+   return VK_SUCCESS;
+}
+
+static VkResult
+lvp_pipe_sync_wait(struct vk_device *vk_device,
+                   struct vk_sync *vk_sync,
+                   uint64_t wait_value,
+                   enum vk_sync_wait_flags wait_flags,
+                   uint64_t abs_timeout_ns)
+{
+   struct lvp_device *device = container_of(vk_device, struct lvp_device, vk);
+   struct lvp_pipe_sync *sync = vk_sync_as_lvp_pipe_sync(vk_sync);
+
+   mtx_lock(&sync->lock);
+
+   VkResult result = lvp_pipe_sync_wait_locked(device, sync, wait_value,
+                                               wait_flags, abs_timeout_ns);
+
+   mtx_unlock(&sync->lock);
+
+   return result;
+}
+
+const struct vk_sync_type lvp_pipe_sync_type = {
+   .size = sizeof(struct lvp_pipe_sync),
+   .features = VK_SYNC_FEATURE_BINARY |
+               VK_SYNC_FEATURE_GPU_WAIT |
+               VK_SYNC_FEATURE_GPU_MULTI_WAIT |
+               VK_SYNC_FEATURE_CPU_WAIT |
+               VK_SYNC_FEATURE_CPU_RESET |
+               VK_SYNC_FEATURE_CPU_SIGNAL |
+               VK_SYNC_FEATURE_WAIT_PENDING,
+   .init = lvp_pipe_sync_init,
+   .finish = lvp_pipe_sync_finish,
+   .signal = lvp_pipe_sync_signal,
+   .reset = lvp_pipe_sync_reset,
+   .move = lvp_pipe_sync_move,
+   .wait = lvp_pipe_sync_wait,
+};
index 5e8c8a4..51957c1 100644 (file)
@@ -66,6 +66,8 @@ typedef uint32_t xcb_window_t;
 #include "vk_command_buffer.h"
 #include "vk_command_pool.h"
 #include "vk_queue.h"
+#include "vk_sync.h"
+#include "vk_sync_timeline.h"
 
 #include "wsi_common.h"
 
@@ -137,6 +139,9 @@ struct lvp_physical_device {
    struct pipe_screen *pscreen;
    uint32_t max_images;
 
+   struct vk_sync_timeline_type sync_timeline_type;
+   const struct vk_sync_type *sync_types[3];
+
    VkPhysicalDeviceLimits device_limits;
 
    struct wsi_device                       wsi_device;
@@ -167,37 +172,10 @@ struct lvp_queue {
    struct pipe_context *ctx;
    struct cso_context *cso;
    struct u_upload_mgr *uploader;
-   bool shutdown;
-   uint64_t timeline;
-   struct util_queue queue;
-   simple_mtx_t last_lock;
-   uint64_t last_finished;
-   uint64_t last_fence_timeline;
    struct pipe_fence_handle *last_fence;
-   volatile int count;
    void *state;
 };
 
-struct lvp_semaphore_wait {
-   struct lvp_semaphore *sema;
-   uint64_t wait;
-};
-
-struct lvp_queue_work {
-   struct list_head list;
-   uint32_t cmd_buffer_count;
-   uint32_t timeline_count;
-   uint32_t wait_count;
-   uint32_t signal_count;
-   uint64_t timeline;
-   struct lvp_fence *fence;
-   struct lvp_cmd_buffer **cmd_buffers;
-   struct lvp_semaphore_timeline **timelines;
-   struct lvp_semaphore **signals;
-   VkSemaphore *waits;
-   uint64_t *wait_vals;
-};
-
 struct lvp_pipeline_cache {
    struct vk_object_base                        base;
    struct lvp_device *                          device;
@@ -232,6 +210,29 @@ struct lvp_device_memory {
    int                                          backed_fd;
 };
 
+struct lvp_pipe_sync {
+   struct vk_sync base;
+
+   mtx_t lock;
+   cnd_t changed;
+
+   bool signaled;
+   struct pipe_fence_handle *fence;
+};
+
+extern const struct vk_sync_type lvp_pipe_sync_type;
+
+void lvp_pipe_sync_signal_with_fence(struct lvp_device *device,
+                                     struct lvp_pipe_sync *sync,
+                                     struct pipe_fence_handle *fence);
+
+static inline struct lvp_pipe_sync *
+vk_sync_as_lvp_pipe_sync(struct vk_sync *sync)
+{
+   assert(sync->type == &lvp_pipe_sync_type);
+   return container_of(sync, struct lvp_pipe_sync, base);
+}
+
 struct lvp_image {
    struct vk_image vk;
    VkDeviceSize size;
@@ -470,40 +471,6 @@ struct lvp_event {
    volatile uint64_t event_storage;
 };
 
-struct lvp_fence {
-   struct vk_object_base base;
-   uint64_t timeline;
-   struct util_queue_fence fence;
-   struct pipe_fence_handle *handle;
-   bool signalled;
-};
-
-struct lvp_semaphore_timeline {
-   struct lvp_semaphore_timeline *next;
-   uint64_t signal; //api
-   uint64_t timeline; //queue
-   struct pipe_fence_handle *fence;
-};
-
-struct lvp_semaphore {
-   struct vk_object_base base;
-   bool is_timeline;
-   uint64_t current;
-   simple_mtx_t lock;
-   mtx_t submit_lock;
-   cnd_t submit;
-   void *mem;
-   struct util_dynarray links;
-   struct lvp_semaphore_timeline *timeline;
-   struct lvp_semaphore_timeline *latest;
-   struct pipe_fence_handle *handle;
-};
-
-struct lvp_queue_noop {
-   struct lvp_fence *fence;
-   struct lvp_semaphore *sema;
-};
-
 struct lvp_buffer {
    struct vk_object_base base;
 
@@ -604,9 +571,6 @@ VK_DEFINE_NONDISP_HANDLE_CASTS(lvp_query_pool, base, VkQueryPool,
                                VK_OBJECT_TYPE_QUERY_POOL)
 VK_DEFINE_NONDISP_HANDLE_CASTS(lvp_sampler, base, VkSampler,
                                VK_OBJECT_TYPE_SAMPLER)
-VK_DEFINE_NONDISP_HANDLE_CASTS(lvp_fence, base, VkFence, VK_OBJECT_TYPE_FENCE);
-VK_DEFINE_NONDISP_HANDLE_CASTS(lvp_semaphore, base, VkSemaphore,
-                               VK_OBJECT_TYPE_SEMAPHORE);
 
 struct lvp_write_descriptor {
    uint32_t dst_binding;
index f85afdd..aa987b8 100644 (file)
@@ -104,7 +104,7 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_GetQueryPoolResults(
    LVP_FROM_HANDLE(lvp_query_pool, pool, queryPool);
    VkResult vk_result = VK_SUCCESS;
 
-   lvp_DeviceWaitIdle(_device);
+   device->vk.dispatch_table.DeviceWaitIdle(_device);
 
    for (unsigned i = firstQuery; i < firstQuery + queryCount; i++) {
       uint8_t *dptr = (uint8_t *)((char *)pData + (stride * (i - firstQuery)));
index a1f7493..39d4f82 100644 (file)
@@ -55,32 +55,3 @@ lvp_finish_wsi(struct lvp_physical_device *physical_device)
    wsi_device_finish(&physical_device->wsi_device,
                      &physical_device->vk.instance->alloc);
 }
-
-VKAPI_ATTR VkResult VKAPI_CALL lvp_AcquireNextImage2KHR(
-   VkDevice                                     _device,
-   const VkAcquireNextImageInfoKHR*             pAcquireInfo,
-   uint32_t*                                    pImageIndex)
-{
-   LVP_FROM_HANDLE(lvp_device, device, _device);
-   struct lvp_physical_device *pdevice = device->physical_device;
-
-   VkResult result = wsi_common_acquire_next_image2(&pdevice->wsi_device,
-                                                    _device,
-                                                    pAcquireInfo,
-                                                    pImageIndex);
-
-   LVP_FROM_HANDLE(lvp_fence, fence, pAcquireInfo->fence);
-   LVP_FROM_HANDLE(lvp_semaphore, semaphore, pAcquireInfo->semaphore);
-   if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) {
-      struct lvp_queue_noop *noop = malloc(sizeof(struct lvp_queue_noop));
-      if (!noop) {
-         return VK_ERROR_OUT_OF_HOST_MEMORY;
-      }
-      noop->fence = fence;
-      noop->sema = semaphore;
-      if (fence)
-         fence->timeline = p_atomic_inc_return(&device->queue.timeline);
-      util_queue_add_job(&device->queue.queue, noop, fence ? &fence->fence : NULL, queue_thread_noop, NULL, 0);
-   }
-   return result;
-}
index d416a81..3eba970 100644 (file)
@@ -21,6 +21,7 @@ liblvp_files = files(
     'lvp_lower_vulkan_resource.c',
     'lvp_lower_vulkan_resource.h',
     'lvp_lower_input_attachments.c',
+    'lvp_pipe_sync.c',
     'lvp_pipeline.c',
     'lvp_pipeline_cache.c',
     'lvp_query.c',