Giovanni Mascellani (@giomasce) commented about dlls/mfplat/main.c:
+ EnterCriticalSection(&syncobj->cs); + hr = ID3D12CommandQueue_Wait(consumer_queue, syncobj->ready_fence, syncobj->generation); + LeaveCriticalSection(&syncobj->cs); + + return hr; +} + +static HRESULT WINAPI d3d12_sync_object_commands_SignalEventOnResourceReady(IMFD3D12SynchronizationObjectCommands *iface, HANDLE event) +{ + struct d3d12_sync_object *syncobj = impl_from_IMFD3D12SynchronizationObjectCommands(iface); + HRESULT hr; + + TRACE("%p, %p.\n", iface, event); + + EnterCriticalSection(&syncobj->cs); + hr = ID3D12Fence_SetEventOnCompletion(syncobj->ready_fence, syncobj->generation, event); `SetEventOnCompletion()` has a special behavior when passed a NULL event: it just waits for the fence to be completed. It would probably be good to check whether this behavior is expected for `SignalEventOnResourceReady()` and either check that the event is not NULL if it's not or implement it without holding the critical section forever if it is.
(relatedly, other APIs might return with `E_POINTER` when passed a NULL pointer, rather than crashing) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9777#note_137215