vkd3d: Handle multiple fence ANY waits in d3d12_device_SetEventOnMultipleFenceCompletion().

This commit is contained in:
Henri Verbeet
2025-04-29 21:03:25 +02:00
parent 9222f5e5b1
commit 3fabac3f70
Notes: Henri Verbeet 2025-05-06 19:05:21 +02:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1476
2 changed files with 41 additions and 17 deletions

View File

@@ -4922,12 +4922,34 @@ static HRESULT waiting_event_semaphore_signal(HANDLE h)
return S_OK; return S_OK;
} }
static HRESULT waiting_event_semaphore_signal_first(HANDLE h)
{
struct waiting_event_semaphore *s = h;
HANDLE event;
if ((event = vkd3d_atomic_exchange_ptr(&s->event, NULL)))
s->signal(event);
return waiting_event_semaphore_signal(h);
}
static bool waiting_event_semaphore_cancel(struct waiting_event_semaphore *s)
{
bool ret;
ret = !vkd3d_atomic_exchange_ptr(&s->event, NULL);
waiting_event_semaphore_signal(s);
return ret;
}
static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(ID3D12Device9 *iface, static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(ID3D12Device9 *iface,
ID3D12Fence *const *fences, const UINT64 *values, UINT fence_count, ID3D12Fence *const *fences, const UINT64 *values, UINT fence_count,
D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags, HANDLE event) D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags, HANDLE event)
{ {
struct d3d12_device *device = impl_from_ID3D12Device9(iface); struct d3d12_device *device = impl_from_ID3D12Device9(iface);
struct waiting_event_semaphore *s; struct waiting_event_semaphore *s;
PFN_vkd3d_signal_event signal;
struct d3d12_fence *fence; struct d3d12_fence *fence;
HRESULT hr = S_OK; HRESULT hr = S_OK;
unsigned int i; unsigned int i;
@@ -4947,12 +4969,6 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(
if (fence_count == 1) if (fence_count == 1)
return ID3D12Fence_SetEventOnCompletion(fences[0], values[0], event); return ID3D12Fence_SetEventOnCompletion(fences[0], values[0], event);
if (flags)
{
FIXME("Unhandled flags %#x.\n", flags);
return E_NOTIMPL;
}
if (!event) if (!event)
{ {
FIXME("Unhandled NULL event.\n"); FIXME("Unhandled NULL event.\n");
@@ -4969,6 +4985,11 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(
s->signal = device->signal_event; s->signal = device->signal_event;
s->value = fence_count; s->value = fence_count;
if (flags & D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY)
signal = waiting_event_semaphore_signal_first;
else
signal = waiting_event_semaphore_signal;
for (i = 0; i < fence_count; ++i) for (i = 0; i < fence_count; ++i)
{ {
fence = unsafe_impl_from_ID3D12Fence(fences[i]); fence = unsafe_impl_from_ID3D12Fence(fences[i]);
@@ -4978,16 +4999,19 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(
if (values[i] <= fence->value) if (values[i] <= fence->value)
{ {
vkd3d_mutex_unlock(&fence->mutex); vkd3d_mutex_unlock(&fence->mutex);
waiting_event_semaphore_signal(s); signal(s);
continue; continue;
} }
if (!d3d12_fence_add_waiting_event(fence, s, waiting_event_semaphore_signal, values[i])) if (!d3d12_fence_add_waiting_event(fence, s, signal, values[i]))
{ {
WARN("Failed to add event.\n"); WARN("Failed to add event.\n");
s->event = NULL; /* If the event was already signalled, we don't need to fail here.
waiting_event_semaphore_signal(s); * Note that cancel() will also return "true" for any subsequent
hr = E_OUTOFMEMORY; * cancel() calls; that's fine, because we already failed in that
* case. */
if (!waiting_event_semaphore_cancel(s))
hr = E_OUTOFMEMORY;
} }
vkd3d_mutex_unlock(&fence->mutex); vkd3d_mutex_unlock(&fence->mutex);

View File

@@ -39065,9 +39065,9 @@ static void test_multi_fence_event(void)
ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret); ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret);
hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences, hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences,
fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, event); fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, event);
todo ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ret = wait_event(event, 0); ret = wait_event(event, 0);
todo ok(ret == WAIT_OBJECT_0, "Got ret %#x.\n", ret); ok(ret == WAIT_OBJECT_0, "Got ret %#x.\n", ret);
/* No fences signalled yet. */ /* No fences signalled yet. */
fence_values[0] = 32; fence_values[0] = 32;
@@ -39130,13 +39130,13 @@ static void test_multi_fence_event(void)
fence_values[2] = 50; fence_values[2] = 50;
hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences, hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences,
fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, event); fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, event);
todo ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ret = wait_event(event, 0); ret = wait_event(event, 0);
ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret); ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret);
hr = ID3D12Fence_Signal(fences[2], 50); hr = ID3D12Fence_Signal(fences[2], 50);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ret = wait_event(event, 0); ret = wait_event(event, 0);
todo ok(ret == WAIT_OBJECT_0, "Got ret %#x.\n", ret); ok(ret == WAIT_OBJECT_0, "Got ret %#x.\n", ret);
hr = ID3D12Fence_Signal(fences[0], 48); hr = ID3D12Fence_Signal(fences[0], 48);
ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ret = wait_event(event, 0); ret = wait_event(event, 0);
@@ -39205,9 +39205,9 @@ static void test_multi_fence_event(void)
ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret); ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret);
hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences, hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences,
fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, event); fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, event);
todo ok(hr == S_OK, "Got hr %#x.\n", hr); ok(hr == S_OK, "Got hr %#x.\n", hr);
ret = wait_event(event, 0); ret = wait_event(event, 0);
todo ok(ret == WAIT_OBJECT_0, "Got ret %#x.\n", ret); ok(ret == WAIT_OBJECT_0, "Got ret %#x.\n", ret);
hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences, hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences,
fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, NULL); fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, NULL);