vkd3d: Handle NULL event handles in ID3D12Fence::SetEventOnCompletion().

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>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Conor McCarthy 2022-01-18 15:54:11 +10:00 committed by Alexandre Julliard
parent de87352f77
commit c965b7b213
2 changed files with 39 additions and 2 deletions

View File

@ -806,6 +806,7 @@ static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkF
{ {
struct d3d12_device *device = fence->device; struct d3d12_device *device = fence->device;
struct vkd3d_signaled_semaphore *current; struct vkd3d_signaled_semaphore *current;
bool signal_null_event_cond = false;
unsigned int i, j; unsigned int i, j;
int rc; int rc;
@ -822,10 +823,18 @@ static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkF
struct vkd3d_waiting_event *current = &fence->events[i]; struct vkd3d_waiting_event *current = &fence->events[i];
if (current->value <= value) if (current->value <= value)
{
if (current->event)
{ {
fence->device->signal_event(current->event); fence->device->signal_event(current->event);
} }
else else
{
current->latch = true;
signal_null_event_cond = true;
}
}
else
{ {
if (i != j) if (i != j)
fence->events[j] = *current; fence->events[j] = *current;
@ -834,6 +843,9 @@ static HRESULT d3d12_fence_signal(struct d3d12_fence *fence, uint64_t value, VkF
} }
fence->event_count = j; fence->event_count = j;
if (signal_null_event_cond)
pthread_cond_broadcast(&fence->null_event_cond);
if (vk_fence) if (vk_fence)
{ {
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; 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); vkd3d_free(fence->events);
if ((rc = pthread_mutex_destroy(&fence->mutex))) if ((rc = pthread_mutex_destroy(&fence->mutex)))
ERR("Failed to destroy mutex, error %d.\n", rc); ERR("Failed to destroy mutex, error %d.\n", rc);
pthread_cond_destroy(&fence->null_event_cond);
vkd3d_free(fence); vkd3d_free(fence);
d3d12_device_release(device); d3d12_device_release(device);
@ -997,6 +1010,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *i
{ {
struct d3d12_fence *fence = impl_from_ID3D12Fence(iface); struct d3d12_fence *fence = impl_from_ID3D12Fence(iface);
unsigned int i; unsigned int i;
bool *latch;
int rc; int rc;
TRACE("iface %p, value %#"PRIx64", event %p.\n", iface, value, event); TRACE("iface %p, value %#"PRIx64", event %p.\n", iface, value, event);
@ -1009,6 +1023,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_fence_SetEventOnCompletion(ID3D12Fence *i
if (value <= fence->value) if (value <= fence->value)
{ {
if (event)
fence->device->signal_event(event); fence->device->signal_event(event);
pthread_mutex_unlock(&fence->mutex); pthread_mutex_unlock(&fence->mutex);
return S_OK; 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].value = value;
fence->events[fence->event_count].event = event; fence->events[fence->event_count].event = event;
fence->events[fence->event_count].latch = false;
latch = &fence->events[fence->event_count].latch;
++fence->event_count; ++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); pthread_mutex_unlock(&fence->mutex);
return S_OK; return S_OK;
} }
@ -1095,6 +1122,13 @@ static HRESULT d3d12_fence_init(struct d3d12_fence *fence, struct d3d12_device *
return hresult_from_errno(rc); 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) if (flags)
FIXME("Ignoring flags %#x.\n", 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))) if (FAILED(hr = vkd3d_private_store_init(&fence->private_store)))
{ {
pthread_mutex_destroy(&fence->mutex); pthread_mutex_destroy(&fence->mutex);
pthread_cond_destroy(&fence->null_event_cond);
return hr; return hr;
} }

View File

@ -367,11 +367,13 @@ struct d3d12_fence
uint64_t value; uint64_t value;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t null_event_cond;
struct vkd3d_waiting_event struct vkd3d_waiting_event
{ {
uint64_t value; uint64_t value;
HANDLE event; HANDLE event;
bool latch;
} *events; } *events;
size_t events_size; size_t events_size;
size_t event_count; size_t event_count;