The D3D12 documentation states: "If hEvent is a null handle, then this API will not return until the specified fence value(s) have been reached."
Based on a vkd3d-proton patch by Hans-Kristian Arntzen.
Signed-off-by: Conor McCarthy cmccarthy@codeweavers.com --- libs/vkd3d/command.c | 39 ++++++++++++++++++++++++++++++++++++-- libs/vkd3d/vkd3d_private.h | 2 ++ 2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 6ad4fa18..a800e8ec 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -806,6 +806,7 @@ static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkF { struct d3d12_device *device = fence->device; struct vkd3d_signaled_semaphore *current; + bool signal_null_event_cond = false; unsigned int i, j; int rc;
@@ -823,7 +824,15 @@ static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkF
if (current->value <= value) { - fence->device->signal_event(current->event); + if (current->event) + { + fence->device->signal_event(current->event); + } + else + { + current->latch = true; + signal_null_event_cond = true; + } } else { @@ -834,6 +843,9 @@ static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkF } fence->event_count = j;
+ if (signal_null_event_cond) + pthread_cond_broadcast(&fence->null_event_cond); + if (vk_fence) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; @@ -916,6 +928,7 @@ static ULONG STDMETHODCALLTYPE d3d12_fence_Release(ID3D12Fence *iface) vkd3d_free(fence->events); if ((rc = pthread_mutex_destroy(&fence->mutex))) ERR("Failed to destroy mutex, error %d.\n", rc); + pthread_cond_destroy(&fence->null_event_cond); vkd3d_free(fence);
d3d12_device_release(device); @@ -997,6 +1010,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *i { struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); unsigned int i; + bool volatile *latch; int rc;
TRACE("iface %p, value %#"PRIx64", event %p.\n", iface, value, event); @@ -1009,7 +1023,8 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *i
if (value <= fence->value) { - fence->device->signal_event(event); + if (event) + fence->device->signal_event(event); pthread_mutex_unlock(&fence->mutex); return S_OK; } @@ -1036,8 +1051,20 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *i
fence->events[fence->event_count].value = value; fence->events[fence->event_count].event = event; + fence->events[fence->event_count].latch = false; + latch = &fence->events[fence->event_count].latch; ++fence->event_count;
+ /* If event is NULL, we need to block until the fence value completes. + * Implement this in a uniform way where we pretend we have a dummy event. + * A NULL fence->events[].event means that we should set latch to true + * and signal a condition variable instead of calling external signal_event callback. */ + if (!event) + { + while (!*latch) + pthread_cond_wait(&fence->null_event_cond, &fence->mutex); + } + pthread_mutex_unlock(&fence->mutex); return S_OK; } @@ -1095,6 +1122,13 @@ static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device * return hresult_from_errno(rc); }
+ if ((rc = pthread_cond_init(&fence->null_event_cond, NULL))) + { + ERR("Failed to initialize cond variable, error %d.\n", rc); + pthread_mutex_destroy(&fence->mutex); + return hresult_from_errno(rc); + } + if (flags) FIXME("Ignoring flags %#x.\n", flags);
@@ -1112,6 +1146,7 @@ static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device * if (FAILED(hr = vkd3d_private_store_init(&fence->private_store))) { pthread_mutex_destroy(&fence->mutex); + pthread_cond_destroy(&fence->null_event_cond); return hr; }
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 1bccb35d..e129681b 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -361,11 +361,13 @@ struct d3d12_fence
uint64_t value; pthread_mutex_t mutex; + pthread_cond_t null_event_cond;
struct vkd3d_waiting_event { uint64_t value; HANDLE event; + bool volatile latch; } *events; size_t events_size; size_t event_count;