From: Charlotte Pabst <cpabst@codeweavers.com> --- dlls/mfplat/main.c | 172 +++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 93 deletions(-) diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 445a074a561..98d9b5cf8f1 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -8849,70 +8849,13 @@ HRESULT WINAPI CreatePropertyStore(IPropertyStore **store) return S_OK; } -struct d3d12_sync_object_async_release_params +struct d3d12_sync_object_release { - IUnknown IUnknown_iface; - LONG refcount; + struct list entry; ID3D12Fence *fence; HANDLE event; }; -static struct d3d12_sync_object_async_release_params *d3d12_sync_object_async_release_params_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct d3d12_sync_object_async_release_params, IUnknown_iface); -} - -static HRESULT WINAPI d3d12_sync_object_async_release_params_QueryInterface(IUnknown *iface, REFIID riid, void **obj) -{ - if (IsEqualIID(riid, &IID_IUnknown)) - { - *obj = iface; - IUnknown_AddRef(iface); - return S_OK; - } - - *obj = NULL; - WARN("Unsupported interface %s.\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI d3d12_sync_object_async_release_params_AddRef(IUnknown *iface) -{ - struct d3d12_sync_object_async_release_params *params = d3d12_sync_object_async_release_params_from_IUnknown(iface); - return InterlockedIncrement(¶ms->refcount); -} - -static ULONG WINAPI d3d12_sync_object_async_release_params_Release(IUnknown *iface) -{ - struct d3d12_sync_object_async_release_params *params = d3d12_sync_object_async_release_params_from_IUnknown(iface); - ULONG ref = InterlockedDecrement(¶ms->refcount); - if (!ref) - { - CloseHandle(params->event); - ID3D12Fence_Release(params->fence); - free(params); - } - return ref; -} - -static const IUnknownVtbl d3d12_sync_object_async_release_params_vtbl = -{ - d3d12_sync_object_async_release_params_QueryInterface, - d3d12_sync_object_async_release_params_AddRef, - d3d12_sync_object_async_release_params_Release, -}; - -static IUnknown *d3d12_sync_object_async_release_params_create(HANDLE event, ID3D12Fence *fence) -{ - struct d3d12_sync_object_async_release_params *params; - if (!(params = calloc(1, sizeof(*params)))) return NULL; - params->IUnknown_iface.lpVtbl = &d3d12_sync_object_async_release_params_vtbl; - params->refcount = 1; - params->event = event; - params->fence = fence; - return ¶ms->IUnknown_iface; -} - struct d3d12_sync_object { IMFD3D12SynchronizationObject IMFD3D12SynchronizationObject_iface; @@ -8920,10 +8863,13 @@ struct d3d12_sync_object IRtwqAsyncCallback async_release_iface; LONG refcount; CRITICAL_SECTION cs; + ID3D12Device *device; ID3D12Fence *ready_fence; UINT64 generation; unsigned int release_wait; HANDLE final_release_event; + struct list release_freelist; + struct list *release_freelist_cursor; }; static struct d3d12_sync_object *impl_from_IMFD3D12SynchronizationObject(IMFD3D12SynchronizationObject *iface) @@ -8981,6 +8927,18 @@ static ULONG WINAPI d3d12_sync_object_Release(IMFD3D12SynchronizationObject *ifa if (!refcount) { + struct d3d12_sync_object_release *cursor, *cursor2; + + LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &syncobj->release_freelist, + struct d3d12_sync_object_release, entry) + { + if (cursor->fence) + ID3D12Fence_Release(cursor->fence); + CloseHandle(cursor->event); + free(cursor); + } + + ID3D12Device_Release(syncobj->device); ID3D12Fence_Release(syncobj->ready_fence); DeleteCriticalSection(&syncobj->cs); free(syncobj); @@ -9016,7 +8974,10 @@ static HRESULT WINAPI d3d12_sync_object_Reset(IMFD3D12SynchronizationObject *ifa if (syncobj->release_wait) hr = MF_E_UNEXPECTED; else + { ++syncobj->generation; + syncobj->release_freelist_cursor = &syncobj->release_freelist; + } LeaveCriticalSection(&syncobj->cs); return hr; @@ -9079,62 +9040,83 @@ static HRESULT WINAPI d3d12_sync_object_commands_SignalEventOnResourceReady(IMFD return hr; } +static HRESULT d3d12_sync_object_create_release(struct d3d12_sync_object *syncobj, struct d3d12_sync_object_release **out) +{ + struct list *next; + struct d3d12_sync_object_release *relobj; + HRESULT hr; + + next = list_next(&syncobj->release_freelist, syncobj->release_freelist_cursor); + if (next) + { + relobj = LIST_ENTRY(next, struct d3d12_sync_object_release, entry); + } + else + { + relobj = calloc(1, sizeof(*relobj)); + if (!relobj) + return E_OUTOFMEMORY; + relobj->event = CreateEventA(NULL, FALSE, FALSE, NULL); + list_add_after(syncobj->release_freelist_cursor, &relobj->entry); + } + + if (!relobj->fence) + { + hr = ID3D12Device_CreateFence(syncobj->device, 0, D3D12_FENCE_FLAG_SHARED, &IID_ID3D12Fence, (void **) &relobj->fence); + if (FAILED(hr)) + return hr; + } + + *out = relobj; + return S_OK; +} + static HRESULT WINAPI d3d12_sync_object_commands_EnqueueResourceRelease(IMFD3D12SynchronizationObjectCommands *iface, ID3D12CommandQueue *consumer_queue) { struct d3d12_sync_object *syncobj = impl_from_IMFD3D12SynchronizationObjectCommands(iface); - HRESULT hr; - HANDLE event; - ID3D12Device *device; - ID3D12Fence *fence; - IUnknown *params; + struct d3d12_sync_object_release *relobj; IRtwqAsyncResult *result; + RTWQWORKITEM_KEY key; + HRESULT hr; TRACE("%p, %p.\n", iface, consumer_queue); - hr = ID3D12CommandQueue_GetDevice(consumer_queue, &IID_ID3D12Device, (void **) &device); + EnterCriticalSection(&syncobj->cs); + hr = d3d12_sync_object_create_release(syncobj, &relobj); if (FAILED(hr)) - return hr; + goto end; - hr = ID3D12Device_CreateFence(device, 0, 0, &IID_ID3D12Fence, (void **) &fence); - ID3D12Device_Release(device); + hr = RtwqCreateAsyncResult(NULL, &syncobj->async_release_iface, NULL, &result); if (FAILED(hr)) - return hr; + goto end; - hr = ID3D12CommandQueue_Signal(consumer_queue, fence, 1); + hr = RtwqPutWaitingWorkItem(relobj->event, 0, result, &key); + IRtwqAsyncResult_Release(result); if (FAILED(hr)) - { - ID3D12Fence_Release(fence); - return hr; - } + goto end; - event = CreateEventA(NULL, FALSE, FALSE, NULL); - params = d3d12_sync_object_async_release_params_create(event, fence); - if (!params) + hr = ID3D12CommandQueue_Signal(consumer_queue, relobj->fence, syncobj->generation); + if (FAILED(hr)) { - CloseHandle(event); - ID3D12Fence_Release(fence); - return E_OUTOFMEMORY; + RtwqCancelWorkItem(key); + goto end; } - hr = ID3D12Fence_SetEventOnCompletion(fence, 1, event); + hr = ID3D12Fence_SetEventOnCompletion(relobj->fence, syncobj->generation, relobj->event); if (FAILED(hr)) { - IUnknown_Release(params); - return hr; + RtwqCancelWorkItem(key); + /* can't re-use fence since queue might signal it */ + ID3D12Fence_Release(relobj->fence); + relobj->fence = NULL; + goto end; } - hr = RtwqCreateAsyncResult(NULL, &syncobj->async_release_iface, params, &result); - IUnknown_Release(params); - if (FAILED(hr)) - return hr; + ++syncobj->release_wait; + syncobj->release_freelist_cursor = &relobj->entry; - EnterCriticalSection(&syncobj->cs); - hr = RtwqPutWaitingWorkItem(event, 0, result, NULL); - IRtwqAsyncResult_Release(result); - if (SUCCEEDED(hr)) - ++syncobj->release_wait; +end: LeaveCriticalSection(&syncobj->cs); - return hr; } @@ -9240,7 +9222,11 @@ HRESULT WINAPI MFCreateD3D12SynchronizationObject(ID3D12Device *device, REFIID r syncobj->IMFD3D12SynchronizationObjectCommands_iface.lpVtbl = &d3d12_sync_object_commands_vtbl; syncobj->async_release_iface.lpVtbl = &d3d12_sync_object_async_release_vtbl; InitializeCriticalSection(&syncobj->cs); + ID3D12Device_AddRef(device); + syncobj->device = device; syncobj->generation = 1; + list_init(&syncobj->release_freelist); + syncobj->release_freelist_cursor = &syncobj->release_freelist; hr = IMFD3D12SynchronizationObject_QueryInterface(&syncobj->IMFD3D12SynchronizationObject_iface, riid, obj); IMFD3D12SynchronizationObject_Release(&syncobj->IMFD3D12SynchronizationObject_iface); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9777