[PATCH vkd3d 7/8] vkd3d: Implement d3d12_command_queue_Wait().

Józef Kucia joseph.kucia at gmail.com
Thu May 2 09:02:41 CDT 2019


From: Józef Kucia <jkucia at codeweavers.com>

Waiting before the signal is not supported yet.

Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---

The emulation of ID3D12Fence with a Vulkan semaphore per fence value
isn't very pretty, but the wait before signal emulation is expected to
be even worse...

---
 libs/vkd3d/command.c       | 164 ++++++++++++++++++++++++++++++++++++-
 libs/vkd3d/vkd3d_private.h |   1 +
 2 files changed, 162 insertions(+), 3 deletions(-)

diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index 2febca67e1ce..c8e23e1fd2ab 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -524,11 +524,12 @@ static void d3d12_fence_garbage_collect_vk_semaphores_locked(struct d3d12_fence
 
         /* The semaphore doesn't have a pending signal operation if the fence
          * was signaled. */
-        if (current->vk_fence && !destroy_all)
+        if ((current->vk_fence || current->is_acquired) && !destroy_all)
             continue;
 
         if (current->vk_fence)
             WARN("Destroying potentially pending semaphore.\n");
+        assert(!current->is_acquired);
 
         VK_CALL(vkDestroySemaphore(device->vk_device, current->vk_semaphore, NULL));
         list_remove(&current->entry);
@@ -568,6 +569,83 @@ static void d3d12_fence_destroy_vk_objects(struct d3d12_fence *fence)
     pthread_mutex_unlock(&fence->mutex);
 }
 
+static struct vkd3d_signaled_semaphore *d3d12_fence_acquire_vk_semaphore(struct d3d12_fence *fence,
+        uint64_t value, uint64_t *completed_value)
+{
+    struct vkd3d_signaled_semaphore *semaphore;
+    struct vkd3d_signaled_semaphore *current;
+    uint64_t semaphore_value;
+    int rc;
+
+    TRACE("fence %p, value %#"PRIx64".\n", fence, value);
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return VK_NULL_HANDLE;
+    }
+
+    semaphore = NULL;
+    semaphore_value = ~(uint64_t)0;
+
+    LIST_FOR_EACH_ENTRY(current, &fence->semaphores, struct vkd3d_signaled_semaphore, entry)
+    {
+        /* Prefer a semaphore with the smallest value. */
+        if (!current->is_acquired && current->value >= value && semaphore_value >= current->value)
+        {
+            semaphore = current;
+            semaphore_value = current->value;
+        }
+        if (semaphore_value == value)
+            break;
+    }
+
+    if (semaphore)
+        semaphore->is_acquired = true;
+
+    *completed_value = fence->value;
+
+    pthread_mutex_unlock(&fence->mutex);
+
+    return semaphore;
+}
+
+static void d3d12_fence_remove_vk_semaphore(struct d3d12_fence *fence, struct vkd3d_signaled_semaphore *semaphore)
+{
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    assert(semaphore->is_acquired);
+
+    list_remove(&semaphore->entry);
+    vkd3d_free(semaphore);
+
+    --fence->semaphore_count;
+
+    pthread_mutex_unlock(&fence->mutex);
+}
+
+static void d3d12_fence_release_vk_semaphore(struct d3d12_fence *fence, struct vkd3d_signaled_semaphore *semaphore)
+{
+    int rc;
+
+    if ((rc = pthread_mutex_lock(&fence->mutex)))
+    {
+        ERR("Failed to lock mutex, error %d.\n", rc);
+        return;
+    }
+
+    assert(semaphore->is_acquired);
+    semaphore->is_acquired = false;
+
+    pthread_mutex_unlock(&fence->mutex);
+}
+
 static HRESULT d3d12_fence_add_vk_semaphore(struct d3d12_fence *fence,
         VkSemaphore vk_semaphore, VkFence vk_fence, uint64_t value)
 {
@@ -595,6 +673,7 @@ static HRESULT d3d12_fence_add_vk_semaphore(struct d3d12_fence *fence,
     semaphore->value = value;
     semaphore->vk_semaphore = vk_semaphore;
     semaphore->vk_fence = vk_fence;
+    semaphore->is_acquired = false;
 
     list_add_tail(&fence->semaphores, &semaphore->entry);
     ++fence->semaphore_count;
@@ -5271,11 +5350,90 @@ fail:
 }
 
 static HRESULT STDMETHODCALLTYPE d3d12_command_queue_Wait(ID3D12CommandQueue *iface,
-        ID3D12Fence *fence, UINT64 value)
+        ID3D12Fence *fence_iface, UINT64 value)
 {
-    FIXME("iface %p, fence %p, value %#"PRIx64" stub!\n", iface, fence, value);
+    static const VkPipelineStageFlagBits wait_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+    struct d3d12_command_queue *command_queue = impl_from_ID3D12CommandQueue(iface);
+    const struct vkd3d_vk_device_procs *vk_procs;
+    struct vkd3d_signaled_semaphore *semaphore;
+    VkQueue vk_queue = VK_NULL_HANDLE;
+    uint64_t completed_value = 0;
+    struct vkd3d_queue *queue;
+    struct d3d12_fence *fence;
+    VkSubmitInfo submit_info;
+    VkResult vr;
+    HRESULT hr;
+
+    TRACE("iface %p, fence %p, value %#"PRIx64".\n", iface, fence_iface, value);
+
+    vk_procs = &command_queue->device->vk_procs;
+    queue = command_queue->vkd3d_queue;
+
+    fence = unsafe_impl_from_ID3D12Fence(fence_iface);
+
+    if (!(semaphore = d3d12_fence_acquire_vk_semaphore(fence, value, &completed_value)))
+    {
+        if (completed_value >= value)
+        {
+            TRACE("Already signaled %p, value %#"PRIx64".\n", fence, completed_value);
+        }
+        else
+        {
+            FIXME("Failed to acquire Vulkan semaphore for fence %p, value %#"PRIx64", completed value %#"PRIx64".\n",
+                    fence, value, completed_value);
+        }
+
+        return S_OK;
+    }
+
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.pNext = NULL;
+    submit_info.waitSemaphoreCount = 1;
+    submit_info.pWaitSemaphores = &semaphore->vk_semaphore;
+    submit_info.pWaitDstStageMask = &wait_stage_mask;
+    submit_info.commandBufferCount = 0;
+    submit_info.pCommandBuffers = NULL;
+    submit_info.signalSemaphoreCount = 0;
+    submit_info.pSignalSemaphores = NULL;
+
+    if (!(vk_queue = vkd3d_queue_acquire(queue)))
+    {
+        ERR("Failed to acquire queue %p.\n", queue);
+        hr = E_FAIL;
+        goto fail;
+    }
+
+    if (!vkd3d_array_reserve((void **)&queue->semaphores, &queue->semaphores_size,
+            queue->semaphore_count + 1, sizeof(*queue->semaphores)))
+    {
+        ERR("Failed to allocate memory for semaphore.\n");
+        vkd3d_queue_release(queue);
+        hr = E_OUTOFMEMORY;
+        goto fail;
+    }
 
+    if ((vr = VK_CALL(vkQueueSubmit(vk_queue, 1, &submit_info, VK_NULL_HANDLE))) >= 0)
+    {
+        queue->semaphores[queue->semaphore_count].vk_semaphore = semaphore->vk_semaphore;
+        queue->semaphores[queue->semaphore_count].sequence_number = queue->submitted_sequence_number + 1;
+        ++queue->semaphore_count;
+    }
+
+    vkd3d_queue_release(queue);
+
+    if (vr < 0)
+    {
+        WARN("Failed to submit wait operation, vr %d.\n", vr);
+        hr = hresult_from_vk_result(vr);
+        goto fail;
+    }
+
+    d3d12_fence_remove_vk_semaphore(fence, semaphore);
     return S_OK;
+
+fail:
+    d3d12_fence_release_vk_semaphore(fence, semaphore);
+    return hr;
 }
 
 static HRESULT STDMETHODCALLTYPE d3d12_command_queue_GetTimestampFrequency(ID3D12CommandQueue *iface,
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index f934d0ba9154..349591ddfe04 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -287,6 +287,7 @@ struct vkd3d_signaled_semaphore
     uint64_t value;
     VkSemaphore vk_semaphore;
     VkFence vk_fence;
+    bool is_acquired;
 };
 
 /* ID3D12Fence */
-- 
2.21.0




More information about the wine-devel mailing list