[PATCH v4 3/9] d3dx10: Add ID3DX10ThreadPump:AddWorkItem implementation.
Piotr Caban
wine at gitlab.winehq.org
Sun Jun 26 11:09:22 CDT 2022
From: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
---
dlls/d3dx10_43/async.c | 248 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 245 insertions(+), 3 deletions(-)
diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c
index 7913f634c21..a3d1014986b 100644
--- a/dlls/d3dx10_43/async.c
+++ b/dlls/d3dx10_43/async.c
@@ -23,6 +23,7 @@
#include "dxhelpers.h"
#include "wine/debug.h"
+#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
@@ -610,10 +611,47 @@ HRESULT WINAPI D3DX10PreprocessShaderFromMemory(const char *data, SIZE_T data_si
return E_NOTIMPL;
}
+struct work_item
+{
+ struct list entry;
+
+ ID3DX10DataLoader *loader;
+ ID3DX10DataProcessor *processor;
+ HRESULT *result;
+ void **object;
+};
+
+static inline void work_item_free(struct work_item *work_item, BOOL cancel)
+{
+ ID3DX10DataLoader_Destroy(work_item->loader);
+ ID3DX10DataProcessor_Destroy(work_item->processor);
+ if (cancel && work_item->result)
+ *work_item->result = S_FALSE;
+ free(work_item);
+}
+
+#define THREAD_PUMP_EXITING UINT_MAX
struct thread_pump
{
ID3DX10ThreadPump ID3DX10ThreadPump_iface;
LONG refcount;
+
+ SRWLOCK io_lock;
+ CONDITION_VARIABLE io_cv;
+ unsigned int io_count;
+ struct list io_queue;
+
+ SRWLOCK proc_lock;
+ CONDITION_VARIABLE proc_cv;
+ unsigned int proc_count;
+ struct list proc_queue;
+
+ SRWLOCK device_lock;
+ unsigned int device_count;
+ struct list device_queue;
+
+ unsigned int thread_count;
+ HANDLE threads[1];
};
static inline struct thread_pump *impl_from_ID3DX10ThreadPump(ID3DX10ThreadPump *iface)
@@ -652,11 +690,49 @@ static ULONG WINAPI thread_pump_Release(ID3DX10ThreadPump *iface)
{
struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
ULONG refcount = InterlockedDecrement(&thread_pump->refcount);
+ struct work_item *item, *next;
+ struct list list;
+ unsigned int i;
TRACE("%p decreasing refcount to %lu.\n", iface, refcount);
if (!refcount)
+ {
+ AcquireSRWLockExclusive(&thread_pump->io_lock);
+ thread_pump->io_count = THREAD_PUMP_EXITING;
+ ReleaseSRWLockExclusive(&thread_pump->io_lock);
+ WakeAllConditionVariable(&thread_pump->io_cv);
+
+ AcquireSRWLockExclusive(&thread_pump->proc_lock);
+ thread_pump->proc_count = THREAD_PUMP_EXITING;
+ ReleaseSRWLockExclusive(&thread_pump->proc_lock);
+ WakeAllConditionVariable(&thread_pump->proc_cv);
+
+ AcquireSRWLockExclusive(&thread_pump->device_lock);
+ thread_pump->device_count = THREAD_PUMP_EXITING;
+ ReleaseSRWLockExclusive(&thread_pump->device_lock);
+
+ for (i = 0; i < thread_pump->thread_count; ++i)
+ {
+ if (!thread_pump->threads[i])
+ continue;
+
+ WaitForSingleObject(thread_pump->threads[i], INFINITE);
+ CloseHandle(thread_pump->threads[i]);
+ }
+
+ list_init(&list);
+ list_move_tail(&list, &thread_pump->io_queue);
+ list_move_tail(&list, &thread_pump->proc_queue);
+ list_move_tail(&list, &thread_pump->device_queue);
+ LIST_FOR_EACH_ENTRY_SAFE(item, next, &list, struct work_item, entry)
+ {
+ list_remove(&item->entry);
+ work_item_free(item, TRUE);
+ }
+
free(thread_pump);
+ }
return refcount;
}
@@ -664,9 +740,30 @@ static ULONG WINAPI thread_pump_Release(ID3DX10ThreadPump *iface)
static HRESULT WINAPI thread_pump_AddWorkItem(ID3DX10ThreadPump *iface, ID3DX10DataLoader *loader,
ID3DX10DataProcessor *processor, HRESULT *result, void **object)
{
- FIXME("iface %p, loader %p, processor %p, result %p, object %p stub!\n",
+ struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface);
+ struct work_item *work_item;
+
+ TRACE("iface %p, loader %p, processor %p, result %p, object %p.\n",
iface, loader, processor, result, object);
- return E_NOTIMPL;
+
+ work_item = malloc(sizeof(*work_item));
+ if (!work_item)
+ return E_OUTOFMEMORY;
+
+ work_item->loader = loader;
+ work_item->processor = processor;
+ work_item->result = result;
+ work_item->object = object;
+
+ if (object)
+ *object = NULL;
+
+ AcquireSRWLockExclusive(&thread_pump->io_lock);
+ ++thread_pump->io_count;
+ list_add_tail(&thread_pump->io_queue, &work_item->entry);
+ ReleaseSRWLockExclusive(&thread_pump->io_lock);
+ WakeConditionVariable(&thread_pump->io_cv);
+ return S_OK;
}
static UINT WINAPI thread_pump_GetWorkItemCount(ID3DX10ThreadPump *iface)
@@ -714,20 +811,165 @@ static const ID3DX10ThreadPumpVtbl thread_pump_vtbl =
thread_pump_GetQueueStatus
};
+static DWORD WINAPI io_thread(void *arg)
+{
+ struct thread_pump *thread_pump = arg;
+ struct work_item *work_item;
+ HRESULT hr;
+
+ TRACE("%p thread started.\n", thread_pump);
+
+ for (;;)
+ {
+ AcquireSRWLockExclusive(&thread_pump->io_lock);
+
+ while (!thread_pump->io_count)
+ SleepConditionVariableSRW(&thread_pump->io_cv, &thread_pump->io_lock, INFINITE, 0);
+
+ if (thread_pump->io_count == THREAD_PUMP_EXITING)
+ {
+ ReleaseSRWLockExclusive(&thread_pump->io_lock);
+ return 0;
+ }
+
+ thread_pump->io_count--;
+ work_item = LIST_ENTRY(list_head(&thread_pump->io_queue), struct work_item, entry);
+ list_remove(&work_item->entry);
+ ReleaseSRWLockExclusive(&thread_pump->io_lock);
+
+ if (FAILED(hr = ID3DX10DataLoader_Load(work_item->loader)))
+ {
+ if (work_item->result)
+ *work_item->result = hr;
+ work_item_free(work_item, FALSE);
+ continue;
+ }
+
+ AcquireSRWLockExclusive(&thread_pump->proc_lock);
+ if (thread_pump->proc_count == THREAD_PUMP_EXITING)
+ {
+ ReleaseSRWLockExclusive(&thread_pump->proc_lock);
+ work_item_free(work_item, TRUE);
+ return 0;
+ }
+
+ list_add_tail(&thread_pump->proc_queue, &work_item->entry);
+ ++thread_pump->proc_count;
+ ReleaseSRWLockExclusive(&thread_pump->proc_lock);
+ WakeConditionVariable(&thread_pump->proc_cv);
+ }
+ return 0;
+}
+
+static DWORD WINAPI proc_thread(void *arg)
+{
+ struct thread_pump *thread_pump = arg;
+ struct work_item *work_item;
+ SIZE_T size;
+ void *data;
+ HRESULT hr;
+
+ TRACE("%p thread started.\n", thread_pump);
+
+ for (;;)
+ {
+ AcquireSRWLockExclusive(&thread_pump->proc_lock);
+
+ while (!thread_pump->proc_count)
+ SleepConditionVariableSRW(&thread_pump->proc_cv, &thread_pump->proc_lock, INFINITE, 0);
+
+ if (thread_pump->proc_count == THREAD_PUMP_EXITING)
+ {
+ ReleaseSRWLockExclusive(&thread_pump->proc_lock);
+ return 0;
+ }
+
+ thread_pump->proc_count--;
+ work_item = LIST_ENTRY(list_head(&thread_pump->proc_queue), struct work_item, entry);
+ list_remove(&work_item->entry);
+ ReleaseSRWLockExclusive(&thread_pump->proc_lock);
+
+ if (FAILED(hr = ID3DX10DataLoader_Decompress(work_item->loader, &data, &size)))
+ {
+ if (work_item->result)
+ *work_item->result = hr;
+ work_item_free(work_item, FALSE);
+ continue;
+ }
+
+ if (thread_pump->device_count == THREAD_PUMP_EXITING)
+ {
+ work_item_free(work_item, TRUE);
+ return 0;
+ }
+
+ if (FAILED(hr = ID3DX10DataProcessor_Process(work_item->processor, data, size)))
+ {
+ if (work_item->result)
+ *work_item->result = hr;
+ work_item_free(work_item, FALSE);
+ continue;
+ }
+
+ AcquireSRWLockExclusive(&thread_pump->device_lock);
+ if (thread_pump->device_count == THREAD_PUMP_EXITING)
+ {
+ ReleaseSRWLockExclusive(&thread_pump->device_lock);
+ work_item_free(work_item, TRUE);
+ return 0;
+ }
+
+ list_add_tail(&thread_pump->device_queue, &work_item->entry);
+ ++thread_pump->device_count;
+ ReleaseSRWLockExclusive(&thread_pump->device_lock);
+ }
+ return 0;
+}
+
HRESULT WINAPI D3DX10CreateThreadPump(UINT io_threads, UINT proc_threads, ID3DX10ThreadPump **pump)
{
struct thread_pump *object;
+ int i;
TRACE("io_threads %u, proc_threads %u, pump %p.\n", io_threads, proc_threads, pump);
if (io_threads >= 1024 || proc_threads >= 1024)
return E_FAIL;
- if (!(object = calloc(1, sizeof(*object))))
+ if (!io_threads)
+ io_threads = 1;
+ if (!proc_threads)
+ {
+ SYSTEM_INFO info;
+
+ GetSystemInfo(&info);
+ proc_threads = info.dwNumberOfProcessors;
+ }
+
+ if (!(object = calloc(1, FIELD_OFFSET(struct thread_pump, threads[io_threads + proc_threads]))))
return E_OUTOFMEMORY;
object->ID3DX10ThreadPump_iface.lpVtbl = &thread_pump_vtbl;
object->refcount = 1;
+ InitializeSRWLock(&object->io_lock);
+ InitializeConditionVariable(&object->io_cv);
+ list_init(&object->io_queue);
+ InitializeSRWLock(&object->proc_lock);
+ InitializeConditionVariable(&object->proc_cv);
+ list_init(&object->proc_queue);
+ InitializeSRWLock(&object->device_lock);
+ list_init(&object->device_queue);
+ object->thread_count = io_threads + proc_threads;
+
+ for (i = 0; i < object->thread_count; ++i)
+ {
+ object->threads[i] = CreateThread(NULL, 0, i < io_threads ? io_thread : proc_thread, object, 0, NULL);
+ if (!object->threads[i])
+ {
+ ID3DX10ThreadPump_Release(&object->ID3DX10ThreadPump_iface);
+ return E_FAIL;
+ }
+ }
*pump = &object->ID3DX10ThreadPump_iface;
return S_OK;
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/272
More information about the wine-devel
mailing list