Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/main.c | 26 ++++++-- dlls/mfplat/mfplat_private.h | 20 ++++++ dlls/mfplat/queue.c | 123 ++++++++++++++++++++++++++++------- include/mfapi.h | 8 +++ include/mfobjects.idl | 1 + 5 files changed, 150 insertions(+), 28 deletions(-) create mode 100644 dlls/mfplat/mfplat_private.h
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index a38c03b4d1..2d82589dfb 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -36,6 +36,8 @@ #include "wine/debug.h" #include "wine/unicode.h"
+#include "mfplat_private.h" + WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
static LONG platform_lock; @@ -465,11 +467,16 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags) #define MF_VERSION_XP MAKELONG( MF_API_VERSION, 1 ) #define MF_VERSION_WIN7 MAKELONG( MF_API_VERSION, 2 )
- FIXME("(%u, %u): stub\n", version, flags); + TRACE("%#x, %#x.\n", version, flags);
- if(version != MF_VERSION_XP && version != MF_VERSION_WIN7) + if (version != MF_VERSION_XP && version != MF_VERSION_WIN7) return MF_E_BAD_STARTUP_VERSION;
+ if (InterlockedIncrement(&platform_lock) == 1) + { + init_system_queues(); + } + return S_OK; }
@@ -478,7 +485,15 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags) */ HRESULT WINAPI MFShutdown(void) { - FIXME("(): stub\n"); + TRACE("\n"); + + if (platform_lock <= 0) + return S_OK; + + if (InterlockedExchangeAdd(&platform_lock, -1) == 1) + { + shutdown_system_queues(); + }
return S_OK; } @@ -498,7 +513,10 @@ HRESULT WINAPI MFLockPlatform(void) */ HRESULT WINAPI MFUnlockPlatform(void) { - InterlockedDecrement(&platform_lock); + if (InterlockedDecrement(&platform_lock) == 0) + { + shutdown_system_queues(); + }
return S_OK; } diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h new file mode 100644 index 0000000000..2d9e7d5906 --- /dev/null +++ b/dlls/mfplat/mfplat_private.h @@ -0,0 +1,20 @@ +/* + * Copyright 2019 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +extern void init_system_queues(void) DECLSPEC_HIDDEN; +extern void shutdown_system_queues(void) DECLSPEC_HIDDEN; diff --git a/dlls/mfplat/queue.c b/dlls/mfplat/queue.c index 7c8790b52c..9a3922fce2 100644 --- a/dlls/mfplat/queue.c +++ b/dlls/mfplat/queue.c @@ -26,33 +26,40 @@ #include "wine/debug.h" #include "wine/heap.h"
+#include "mfplat_private.h" + WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
#define FIRST_USER_QUEUE_HANDLE 5 #define MAX_USER_QUEUE_HANDLES 124
struct queue +{ + TP_POOL *pool; +}; + +struct queue_handle { void *obj; LONG refcount; WORD generation; };
-static struct queue user_queues[MAX_USER_QUEUE_HANDLES]; -static struct queue *next_free_user_queue; -static struct queue *next_unused_user_queue = user_queues; +static struct queue_handle user_queues[MAX_USER_QUEUE_HANDLES]; +static struct queue_handle *next_free_user_queue; +static struct queue_handle *next_unused_user_queue = user_queues; static WORD queue_generation;
-static CRITICAL_SECTION user_queues_section; -static CRITICAL_SECTION_DEBUG user_queues_critsect_debug = +static CRITICAL_SECTION queues_section; +static CRITICAL_SECTION_DEBUG queues_critsect_debug = { - 0, 0, &user_queues_section, - { &user_queues_critsect_debug.ProcessLocksList, &user_queues_critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": user_queues_section") } + 0, 0, &queues_section, + { &queues_critsect_debug.ProcessLocksList, &queues_critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": queues_section") } }; -static CRITICAL_SECTION user_queues_section = { &user_queues_critsect_debug, -1, 0, 0, 0, 0 }; +static CRITICAL_SECTION queues_section = { &queues_critsect_debug, -1, 0, 0, 0, 0 };
-static struct queue *get_queue_obj(DWORD handle) +static struct queue_handle *get_queue_obj(DWORD handle) { unsigned int idx = HIWORD(handle) - FIRST_USER_QUEUE_HANDLE;
@@ -65,12 +72,79 @@ static struct queue *get_queue_obj(DWORD handle) return NULL; }
-static HRESULT alloc_user_queue(DWORD *queue) +enum system_queue_index +{ + SYS_QUEUE_STANDARD = 0, + SYS_QUEUE_RT, + SYS_QUEUE_IO, + SYS_QUEUE_TIMER, + SYS_QUEUE_MULTITHREADED, + SYS_QUEUE_DO_NOT_USE, + SYS_QUEUE_LONG_FUNCTION, + SYS_QUEUE_COUNT, +}; + +static struct queue system_queues[SYS_QUEUE_COUNT]; + +static void init_work_queue(MFASYNC_WORKQUEUE_TYPE queue_type, struct queue *queue) +{ + queue->pool = CreateThreadpool(NULL); +} + +void init_system_queues(void) +{ + /* Always initialize standard queue, keep the rest lazy. */ + + EnterCriticalSection(&queues_section); + + if (system_queues[SYS_QUEUE_STANDARD].pool) + { + LeaveCriticalSection(&queues_section); + return; + } + + init_work_queue(MF_STANDARD_WORKQUEUE, &system_queues[SYS_QUEUE_STANDARD]); + + LeaveCriticalSection(&queues_section); +} + +static void shutdown_queue(struct queue *queue) +{ + if (!queue->pool) + return; + + CloseThreadpool(queue->pool); + queue->pool = NULL; +} + +void shutdown_system_queues(void) +{ + unsigned int i; + + EnterCriticalSection(&queues_section); + + for (i = 0; i < ARRAY_SIZE(system_queues); ++i) + { + shutdown_queue(&system_queues[i]); + } + + LeaveCriticalSection(&queues_section); +} + +static HRESULT alloc_user_queue(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue_id) { - struct queue *entry; + struct queue_handle *entry; + struct queue *queue; unsigned int idx;
- EnterCriticalSection(&user_queues_section); + *queue_id = MFASYNC_CALLBACK_QUEUE_UNDEFINED; + + queue = heap_alloc_zero(sizeof(*queue)); + if (!queue) + return E_OUTOFMEMORY; + init_work_queue(queue_type, queue); + + EnterCriticalSection(&queues_section);
entry = next_free_user_queue; if (entry) @@ -79,17 +153,18 @@ static HRESULT alloc_user_queue(DWORD *queue) entry = next_unused_user_queue++; else { - LeaveCriticalSection(&user_queues_section); + LeaveCriticalSection(&queues_section); return E_OUTOFMEMORY; }
entry->refcount = 1; - entry->obj = NULL; + entry->obj = queue; if (++queue_generation == 0xffff) queue_generation = 1; entry->generation = queue_generation; idx = entry - user_queues + FIRST_USER_QUEUE_HANDLE; - *queue = (idx << 16) | entry->generation; - LeaveCriticalSection(&user_queues_section); + *queue_id = (idx << 16) | entry->generation; + + LeaveCriticalSection(&queues_section);
return S_OK; } @@ -97,31 +172,31 @@ static HRESULT alloc_user_queue(DWORD *queue) static HRESULT lock_user_queue(DWORD queue) { HRESULT hr = MF_E_INVALID_WORKQUEUE; - struct queue *entry; + struct queue_handle *entry;
if (!(queue & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK)) return S_OK;
- EnterCriticalSection(&user_queues_section); + EnterCriticalSection(&queues_section); entry = get_queue_obj(queue); if (entry && entry->refcount) { entry->refcount++; hr = S_OK; } - LeaveCriticalSection(&user_queues_section); + LeaveCriticalSection(&queues_section); return hr; }
static HRESULT unlock_user_queue(DWORD queue) { HRESULT hr = MF_E_INVALID_WORKQUEUE; - struct queue *entry; + struct queue_handle *entry;
if (!(queue & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK)) return S_OK;
- EnterCriticalSection(&user_queues_section); + EnterCriticalSection(&queues_section); entry = get_queue_obj(queue); if (entry && entry->refcount) { @@ -132,7 +207,7 @@ static HRESULT unlock_user_queue(DWORD queue) } hr = S_OK; } - LeaveCriticalSection(&user_queues_section); + LeaveCriticalSection(&queues_section); return hr; }
@@ -309,7 +384,7 @@ HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue) { TRACE("%p.\n", queue);
- return alloc_user_queue(queue); + return alloc_user_queue(MF_STANDARD_WORKQUEUE, queue); }
/*********************************************************************** diff --git a/include/mfapi.h b/include/mfapi.h index 4b7d758488..ee5cf4c069 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -88,7 +88,15 @@ DEFINE_GUID(MFMediaType_Video, 0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0
typedef unsigned __int64 MFWORKITEM_KEY;
+typedef enum +{ + MF_STANDARD_WORKQUEUE, + MF_WINDOW_WORKQUEUE, + MF_MULTITHREADED_WORKQUEUE, +} MFASYNC_WORKQUEUE_TYPE; + HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue); +HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue); HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key); HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines); HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size); diff --git a/include/mfobjects.idl b/include/mfobjects.idl index 5ea26b2c67..3245d84d1b 100644 --- a/include/mfobjects.idl +++ b/include/mfobjects.idl @@ -431,6 +431,7 @@ cpp_quote("#define MFASYNC_CALLBACK_QUEUE_STANDARD 0x00000001") cpp_quote("#define MFASYNC_CALLBACK_QUEUE_RT 0x00000002") cpp_quote("#define MFASYNC_CALLBACK_QUEUE_IO 0x00000003") cpp_quote("#define MFASYNC_CALLBACK_QUEUE_TIMER 0x00000004") +cpp_quote("#define MFASYNC_CALLBACK_QUEUE_MULTITHREADED 0x00000005") cpp_quote("#define MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION 0x00000007") cpp_quote("#define MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK 0xffff0000") cpp_quote("#define MFASYNC_CALLBACK_QUEUE_ALL 0xffffffff")