Module: wine Branch: master Commit: 0ad6d68873bf3d70955f62a2fe2d98221f586ef9 URL: https://gitlab.winehq.org/wine/wine/-/commit/0ad6d68873bf3d70955f62a2fe2d982...
Author: Zebediah Figura zfigura@codeweavers.com Date: Thu Nov 17 20:03:17 2022 -0600
quartz: Use a single message thread for all filter graphs.
This matches native, as the test shows, but was motivated by bug 50779, which it may alleviate.
---
dlls/quartz/filtergraph.c | 68 ++++++++++++++++++++++++----------------- dlls/quartz/quartz_private.h | 7 +++++ dlls/quartz/tests/filtergraph.c | 16 ++++++++-- 3 files changed, 61 insertions(+), 30 deletions(-)
diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c index 1849174cf97..437691b5553 100644 --- a/dlls/quartz/filtergraph.c +++ b/dlls/quartz/filtergraph.c @@ -42,6 +42,19 @@
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
+DECLARE_CRITICAL_SECTION(message_cs); + +struct filter_create_params +{ + HRESULT hr; + IMoniker *moniker; + IBaseFilter *filter; +}; + +static HANDLE message_thread, message_thread_ret; +static DWORD message_thread_id; +static unsigned int message_thread_refcount; + struct media_event { struct list entry; @@ -132,9 +145,6 @@ struct filter_graph IUnknown *pSite; LONG version;
- HANDLE message_thread, message_thread_ret; - DWORD message_thread_id; - /* Respectively: the last timestamp at which we started streaming, and the * current offset within the stream. */ REFERENCE_TIME stream_start, stream_elapsed; @@ -142,6 +152,7 @@ struct filter_graph LONGLONG current_pos;
unsigned int needs_async_run : 1; + unsigned int threaded : 1; };
struct enum_filters @@ -465,14 +476,17 @@ static ULONG WINAPI FilterGraphInner_Release(IUnknown *iface) flush_media_events(This); CloseHandle(This->media_event_handle);
- This->cs.DebugInfo->Spare[0] = 0; - if (This->message_thread) + EnterCriticalSection(&message_cs); + if (This->threaded && !--message_thread_refcount) { - PostThreadMessageW(This->message_thread_id, WM_USER + 1, 0, 0); - WaitForSingleObject(This->message_thread, INFINITE); - CloseHandle(This->message_thread); - CloseHandle(This->message_thread_ret); + PostThreadMessageW(message_thread_id, WM_USER + 1, 0, 0); + WaitForSingleObject(message_thread, INFINITE); + CloseHandle(message_thread); + CloseHandle(message_thread_ret); } + LeaveCriticalSection(&message_cs); + + This->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->event_cs); DeleteCriticalSection(&This->cs); free(This); @@ -1012,21 +1026,13 @@ static HRESULT WINAPI FilterGraph2_SetDefaultSyncSource(IFilterGraph2 *iface) return hr; }
-struct filter_create_params -{ - HRESULT hr; - IMoniker *moniker; - IBaseFilter *filter; -}; - static DWORD WINAPI message_thread_run(void *ctx) { - struct filter_graph *graph = ctx; MSG msg;
/* Make sure we have a message queue. */ PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE); - SetEvent(graph->message_thread_ret); + SetEvent(message_thread_ret);
CoInitializeEx(NULL, COINIT_MULTITHREADED);
@@ -1040,7 +1046,7 @@ static DWORD WINAPI message_thread_run(void *ctx)
params->hr = IMoniker_BindToObject(params->moniker, NULL, NULL, &IID_IBaseFilter, (void **)¶ms->filter); - SetEvent(graph->message_thread_ret); + SetEvent(message_thread_ret); } else if (!msg.hwnd && msg.message == WM_USER + 1) { @@ -1059,13 +1065,17 @@ static DWORD WINAPI message_thread_run(void *ctx)
static HRESULT create_filter(struct filter_graph *graph, IMoniker *moniker, IBaseFilter **filter) { - if (graph->message_thread) + if (graph->threaded) { struct filter_create_params params;
params.moniker = moniker; - PostThreadMessageW(graph->message_thread_id, WM_USER, (WPARAM)¶ms, 0); - WaitForSingleObject(graph->message_thread_ret, INFINITE); + + EnterCriticalSection(&message_cs); + PostThreadMessageW(message_thread_id, WM_USER, (WPARAM)¶ms, 0); + WaitForSingleObject(message_thread_ret, INFINITE); + LeaveCriticalSection(&message_cs); + *filter = params.filter; return params.hr; } @@ -5654,14 +5664,16 @@ static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL object->name_index = 1; object->timeformatseek = TIME_FORMAT_MEDIA_TIME;
- if (threaded) + object->threaded = !!threaded; + + EnterCriticalSection(&message_cs); + if (threaded && !message_thread_refcount++) { - object->message_thread_ret = CreateEventW(NULL, FALSE, FALSE, NULL); - object->message_thread = CreateThread(NULL, 0, message_thread_run, object, 0, &object->message_thread_id); - WaitForSingleObject(object->message_thread_ret, INFINITE); + message_thread_ret = CreateEventW(NULL, FALSE, FALSE, NULL); + message_thread = CreateThread(NULL, 0, message_thread_run, object, 0, &message_thread_id); + WaitForSingleObject(message_thread_ret, INFINITE); } - else - object->message_thread = NULL; + LeaveCriticalSection(&message_cs);
TRACE("Created %sthreaded filter graph %p.\n", threaded ? "" : "non-", object); *out = &object->IUnknown_inner; diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index c706d906a26..6414cd4a988 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -37,6 +37,13 @@ #include "wine/strmbase.h" #include "wine/list.h"
+#define DECLARE_CRITICAL_SECTION(cs) \ + static CRITICAL_SECTION cs; \ + static CRITICAL_SECTION_DEBUG cs##_debug = \ + { 0, 0, &cs, { &cs##_debug.ProcessLocksList, &cs##_debug.ProcessLocksList }, \ + 0, 0, { (DWORD_PTR)(__FILE__ ": " # cs) }}; \ + static CRITICAL_SECTION cs = { &cs##_debug, -1, 0, 0, 0, 0 }; + static inline const char *debugstr_time(REFERENCE_TIME time) { ULONGLONG abstime = time >= 0 ? time : -time; diff --git a/dlls/quartz/tests/filtergraph.c b/dlls/quartz/tests/filtergraph.c index 2c07dc49356..c06041b422f 100644 --- a/dlls/quartz/tests/filtergraph.c +++ b/dlls/quartz/tests/filtergraph.c @@ -5213,10 +5213,11 @@ static void test_window_threading(void) }; WCHAR *filename = load_resource(L"test.avi"); IFilterGraph2 *graph = create_graph(); + HWND hwnd, hwnd2, parent; + IFilterGraph2 *graph2; IVideoWindow *window; - HWND hwnd, parent; + DWORD tid, tid2; HRESULT hr; - DWORD tid; ULONG ref; BOOL ret;
@@ -5253,6 +5254,17 @@ static void test_window_threading(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); IVideoWindow_Release(window); ok(!(GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_NOPARENTNOTIFY), "Window has WS_EX_NOPARENTNOTIFY.\n"); + + graph2 = create_graph(); + hr = IFilterGraph2_RenderFile(graph2, filename, NULL); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hwnd2 = get_renderer_hwnd(graph); + ok(!!hwnd2, "Failed to get renderer window.\n"); + tid2 = GetWindowThreadProcessId(hwnd, NULL); + ok(tid2 == tid, "Expected thread to be shared.\n"); + + ref = IFilterGraph2_Release(graph2); + ok(!ref, "Got outstanding refcount %ld.\n", ref); } else skip("Could not find renderer window.\n");