From 9222f5e5b1c54dfc763aec57372a2f4c397ef23f Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Tue, 29 Apr 2025 21:03:25 +0200 Subject: [PATCH] vkd3d: Handle multiple fence ALL waits in d3d12_device_SetEventOnMultipleFenceCompletion(). --- libs/vkd3d/command.c | 4 +- libs/vkd3d/device.c | 77 +++++++++++++++++++++++++++++++++++++- libs/vkd3d/vkd3d_private.h | 3 ++ tests/d3d12.c | 12 +++--- 4 files changed, 86 insertions(+), 10 deletions(-) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 31c3ccdb7..1399494ef 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -1076,7 +1076,7 @@ static UINT64 STDMETHODCALLTYPE d3d12_fence_GetCompletedValue(ID3D12Fence1 *ifac return completed_value; } -static bool d3d12_fence_add_waiting_event(struct d3d12_fence *fence, +bool d3d12_fence_add_waiting_event(struct d3d12_fence *fence, HANDLE event, PFN_vkd3d_signal_event signal, uint64_t value) { struct vkd3d_waiting_event *e; @@ -1205,7 +1205,7 @@ static const struct ID3D12Fence1Vtbl d3d12_fence_vtbl = d3d12_fence_GetCreationFlags, }; -static struct d3d12_fence *unsafe_impl_from_ID3D12Fence(ID3D12Fence *iface) +struct d3d12_fence *unsafe_impl_from_ID3D12Fence(ID3D12Fence *iface) { ID3D12Fence1 *iface1; diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index bf32e0bf9..1d58d2ef0 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -4901,11 +4901,38 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_CreatePipelineLibrary(ID3D12Device return DXGI_ERROR_UNSUPPORTED; } +struct waiting_event_semaphore +{ + HANDLE event; + PFN_vkd3d_signal_event signal; + uint32_t value; +}; + +static HRESULT waiting_event_semaphore_signal(HANDLE h) +{ + struct waiting_event_semaphore *s = h; + + if (vkd3d_atomic_decrement_u32(&s->value)) + return S_OK; + + if (s->event) + s->signal(s->event); + vkd3d_free(s); + + return S_OK; +} + static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion(ID3D12Device9 *iface, ID3D12Fence *const *fences, const UINT64 *values, UINT fence_count, D3D12_MULTIPLE_FENCE_WAIT_FLAGS flags, HANDLE event) { - FIXME("iface %p, fences %p, values %p, fence_count %u, flags %#x, event %p partial stub!\n", + struct d3d12_device *device = impl_from_ID3D12Device9(iface); + struct waiting_event_semaphore *s; + struct d3d12_fence *fence; + HRESULT hr = S_OK; + unsigned int i; + + TRACE("iface %p, fences %p, values %p, fence_count %u, flags %#x, event %p.\n", iface, fences, values, fence_count, flags, event); if (flags & ~D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY) @@ -4920,7 +4947,53 @@ static HRESULT STDMETHODCALLTYPE d3d12_device_SetEventOnMultipleFenceCompletion( if (fence_count == 1) return ID3D12Fence_SetEventOnCompletion(fences[0], values[0], event); - return E_NOTIMPL; + if (flags) + { + FIXME("Unhandled flags %#x.\n", flags); + return E_NOTIMPL; + } + + if (!event) + { + FIXME("Unhandled NULL event.\n"); + return E_NOTIMPL; + } + + if (!(s = vkd3d_malloc(sizeof(*s)))) + { + WARN("Failed to allocate semaphore memory.\n"); + return E_OUTOFMEMORY; + } + + s->event = event; + s->signal = device->signal_event; + s->value = fence_count; + + for (i = 0; i < fence_count; ++i) + { + fence = unsafe_impl_from_ID3D12Fence(fences[i]); + + vkd3d_mutex_lock(&fence->mutex); + + if (values[i] <= fence->value) + { + vkd3d_mutex_unlock(&fence->mutex); + waiting_event_semaphore_signal(s); + continue; + } + + if (!d3d12_fence_add_waiting_event(fence, s, waiting_event_semaphore_signal, values[i])) + { + WARN("Failed to add event.\n"); + s->event = NULL; + waiting_event_semaphore_signal(s); + hr = E_OUTOFMEMORY; + } + + vkd3d_mutex_unlock(&fence->mutex); + } + + return hr; } static HRESULT STDMETHODCALLTYPE d3d12_device_SetResidencyPriority(ID3D12Device9 *iface, diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 29f02e472..ac232fb04 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -410,8 +410,11 @@ struct d3d12_fence struct vkd3d_private_store private_store; }; +bool d3d12_fence_add_waiting_event(struct d3d12_fence *fence, + HANDLE event, PFN_vkd3d_signal_event signal, uint64_t value); HRESULT d3d12_fence_create(struct d3d12_device *device, uint64_t initial_value, D3D12_FENCE_FLAGS flags, struct d3d12_fence **fence); +struct d3d12_fence *unsafe_impl_from_ID3D12Fence(ID3D12Fence *iface); VkResult vkd3d_create_timeline_semaphore(const struct d3d12_device *device, uint64_t initial_value, VkSemaphore *timeline_semaphore); diff --git a/tests/d3d12.c b/tests/d3d12.c index ba3462ed4..3b60d4490 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -39055,9 +39055,9 @@ static void test_multi_fence_event(void) ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret); hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences, fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL, 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); - 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, fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ANY, NULL); todo ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -39075,7 +39075,7 @@ static void test_multi_fence_event(void) fence_values[2] = 34; hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences, fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL, 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); ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret); hr = ID3D12Fence_Signal(fences[2], 34); @@ -39089,7 +39089,7 @@ static void test_multi_fence_event(void) hr = ID3D12Fence_Signal(fences[1], 33); ok(hr == S_OK, "Got hr %#x.\n", hr); 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); fence_values[0] = 40; fence_values[1] = 41; @@ -39175,13 +39175,13 @@ static void test_multi_fence_event(void) ok(hr == S_OK, "Got hr %#x.\n", hr); hr = ID3D12Device1_SetEventOnMultipleFenceCompletion(device1, fences, fence_values, 3, D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL, 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); ok(ret == WAIT_TIMEOUT, "Got ret %#x.\n", ret); hr = ID3D12Fence_Signal(fences[1], 65); ok(hr == S_OK, "Got hr %#x.\n", hr); 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); fence_values[1] = 67; thread_data.flags = D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL;