The GetWorkItemCount implementation may look strange. It's done this way because of how WaitForAllItems is implemented. Alternative solution is to introduce separate counter for GetWorkItemCount.
-- v4: d3dx10/tests: Add D3DX10CreateThreadPump tests. d3dx10: Add ID3DX10ThreadPump:PurgeAllItems implementation. d3dx10: Add ID3DX10ThreadPump:GetQueueStatus implementation. d3dx10: Add ID3DX10ThreadPump:WaitForAllItems implementation. d3dx10: Add ID3DX10ThreadPump:ProcessDeviceWorkItems implementation. d3dx10: Add ID3DX10ThreadPump:GetWorkItemCount implementation. d3dx10: Add ID3DX10ThreadPump:AddWorkItem implementation. d3dx10: Add D3DX10CreateThreadPump stub. d3dx10/tests: Fix texture leak in check_resource_data.
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/tests/d3dx10.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index 1c28a62b700..d1c772197b9 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -1237,7 +1237,7 @@ static void check_resource_data(ID3D10Resource *resource, const struct test_imag ok_(__FILE__, line)(hr == S_OK, "Map failed, hr %#x.\n", hr); if (hr != S_OK) { - ID3D10Texture2D_Unmap(readback, 0); + ID3D10Texture2D_Release(readback); return; }
@@ -1253,6 +1253,7 @@ static void check_resource_data(ID3D10Resource *resource, const struct test_imag }
ID3D10Texture2D_Unmap(readback, 0); + ID3D10Texture2D_Release(readback); }
static void test_D3DX10UnsetAllDeviceObjects(void) @@ -2062,7 +2063,7 @@ static void test_D3DX10CreateAsyncTextureProcessor(void)
CoUninitialize();
- ID3D10Device_Release(device); + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); }
static void test_get_image_info(void) @@ -2417,7 +2418,7 @@ static void test_create_texture(void)
CoUninitialize();
- ID3D10Device_Release(device); + ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); }
#define check_rect(rect, left, top, right, bottom) _check_rect(__LINE__, rect, left, top, right, bottom)
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/async.c | 123 ++++++++++++++++++++++++++++++++++ dlls/d3dx10_43/d3dx10_43.spec | 2 +- include/d3dx10core.h | 1 + 3 files changed, 125 insertions(+), 1 deletion(-)
diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c index bb1cf30a217..7913f634c21 100644 --- a/dlls/d3dx10_43/async.c +++ b/dlls/d3dx10_43/async.c @@ -609,3 +609,126 @@ HRESULT WINAPI D3DX10PreprocessShaderFromMemory(const char *data, SIZE_T data_si
return E_NOTIMPL; } + +struct thread_pump +{ + ID3DX10ThreadPump ID3DX10ThreadPump_iface; + LONG refcount; +}; + +static inline struct thread_pump *impl_from_ID3DX10ThreadPump(ID3DX10ThreadPump *iface) +{ + return CONTAINING_RECORD(iface, struct thread_pump, ID3DX10ThreadPump_iface); +} + +static HRESULT WINAPI thread_pump_QueryInterface(ID3DX10ThreadPump *iface, REFIID riid, void **out) +{ + TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualGUID(riid, &IID_ID3DX10ThreadPump) + || IsEqualGUID(riid, &IID_IUnknown)) + { + ID3DX10ThreadPump_AddRef(iface); + *out = iface; + return S_OK; + } + + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI thread_pump_AddRef(ID3DX10ThreadPump *iface) +{ + struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface); + ULONG refcount = InterlockedIncrement(&thread_pump->refcount); + + TRACE("%p increasing refcount to %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI thread_pump_Release(ID3DX10ThreadPump *iface) +{ + struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface); + ULONG refcount = InterlockedDecrement(&thread_pump->refcount); + + TRACE("%p decreasing refcount to %lu.\n", iface, refcount); + + if (!refcount) + free(thread_pump); + + return refcount; +} + +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", + iface, loader, processor, result, object); + return E_NOTIMPL; +} + +static UINT WINAPI thread_pump_GetWorkItemCount(ID3DX10ThreadPump *iface) +{ + FIXME("iface %p stub!\n", iface); + return 0; +} + +static HRESULT WINAPI thread_pump_WaitForAllItems(ID3DX10ThreadPump *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI thread_pump_ProcessDeviceWorkItems(ID3DX10ThreadPump *iface, UINT count) +{ + FIXME("iface %p, count %u stub!\n", iface, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI thread_pump_PurgeAllItems(ID3DX10ThreadPump *iface) +{ + FIXME("iface %p stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI thread_pump_GetQueueStatus(ID3DX10ThreadPump *iface, + UINT *io_queue, UINT *process_queue, UINT *device_queue) +{ + FIXME("iface %p, io_queue %p, process_queue %p, device_queue %p stub!\n", + iface, io_queue, process_queue, device_queue); + return E_NOTIMPL; +} + +static const ID3DX10ThreadPumpVtbl thread_pump_vtbl = +{ + thread_pump_QueryInterface, + thread_pump_AddRef, + thread_pump_Release, + thread_pump_AddWorkItem, + thread_pump_GetWorkItemCount, + thread_pump_WaitForAllItems, + thread_pump_ProcessDeviceWorkItems, + thread_pump_PurgeAllItems, + thread_pump_GetQueueStatus +}; + +HRESULT WINAPI D3DX10CreateThreadPump(UINT io_threads, UINT proc_threads, ID3DX10ThreadPump **pump) +{ + struct thread_pump *object; + + 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)))) + return E_OUTOFMEMORY; + + object->ID3DX10ThreadPump_iface.lpVtbl = &thread_pump_vtbl; + object->refcount = 1; + + *pump = &object->ID3DX10ThreadPump_iface; + return S_OK; +} diff --git a/dlls/d3dx10_43/d3dx10_43.spec b/dlls/d3dx10_43/d3dx10_43.spec index 95160a067c5..2359c7c6f02 100644 --- a/dlls/d3dx10_43/d3dx10_43.spec +++ b/dlls/d3dx10_43/d3dx10_43.spec @@ -1,4 +1,4 @@ -@ stub D3DX10CreateThreadPump(long long ptr) +@ stdcall D3DX10CreateThreadPump(long long ptr) @ stdcall D3DX10CheckVersion(long long) @ stub D3DX10CompileFromFileA(str ptr ptr str str long long ptr ptr ptr ptr) @ stub D3DX10CompileFromFileW(wstr ptr ptr str str long long ptr ptr ptr ptr) diff --git a/include/d3dx10core.h b/include/d3dx10core.h index a9ba7854e90..cca9052cc13 100644 --- a/include/d3dx10core.h +++ b/include/d3dx10core.h @@ -298,3 +298,4 @@ HRESULT WINAPI D3DX10CreateFontW(ID3D10Device *device, INT height, UINT width, U UINT miplevels, BOOL italic, UINT charset, UINT precision, UINT quality, UINT pitchandfamily, const WCHAR *facename, ID3DX10Font **font); HRESULT WINAPI D3DX10CreateSprite(ID3D10Device *device, UINT size, ID3DX10Sprite **sprite); +HRESULT WINAPI D3DX10CreateThreadPump(UINT io_threads, UINT proc_threads, ID3DX10ThreadPump **pump);
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@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;
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/async.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c index a3d1014986b..33dd3ceca9a 100644 --- a/dlls/d3dx10_43/async.c +++ b/dlls/d3dx10_43/async.c @@ -636,6 +636,8 @@ struct thread_pump ID3DX10ThreadPump ID3DX10ThreadPump_iface; LONG refcount;
+ LONG processing_count; + SRWLOCK io_lock; CONDITION_VARIABLE io_cv; unsigned int io_count; @@ -758,6 +760,7 @@ static HRESULT WINAPI thread_pump_AddWorkItem(ID3DX10ThreadPump *iface, ID3DX10D if (object) *object = NULL;
+ InterlockedIncrement(&thread_pump->processing_count); AcquireSRWLockExclusive(&thread_pump->io_lock); ++thread_pump->io_count; list_add_tail(&thread_pump->io_queue, &work_item->entry); @@ -768,8 +771,15 @@ static HRESULT WINAPI thread_pump_AddWorkItem(ID3DX10ThreadPump *iface, ID3DX10D
static UINT WINAPI thread_pump_GetWorkItemCount(ID3DX10ThreadPump *iface) { - FIXME("iface %p stub!\n", iface); - return 0; + struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface); + UINT ret; + + TRACE("iface %p.\n", iface); + + AcquireSRWLockExclusive(&thread_pump->device_lock); + ret = thread_pump->processing_count + thread_pump->device_count; + ReleaseSRWLockExclusive(&thread_pump->device_lock); + return ret; }
static HRESULT WINAPI thread_pump_WaitForAllItems(ID3DX10ThreadPump *iface) @@ -842,6 +852,7 @@ static DWORD WINAPI io_thread(void *arg) if (work_item->result) *work_item->result = hr; work_item_free(work_item, FALSE); + InterlockedDecrement(&thread_pump->processing_count); continue; }
@@ -894,6 +905,7 @@ static DWORD WINAPI proc_thread(void *arg) if (work_item->result) *work_item->result = hr; work_item_free(work_item, FALSE); + InterlockedDecrement(&thread_pump->processing_count); continue; }
@@ -908,6 +920,7 @@ static DWORD WINAPI proc_thread(void *arg) if (work_item->result) *work_item->result = hr; work_item_free(work_item, FALSE); + InterlockedDecrement(&thread_pump->processing_count); continue; }
@@ -921,6 +934,7 @@ static DWORD WINAPI proc_thread(void *arg)
list_add_tail(&thread_pump->device_queue, &work_item->entry); ++thread_pump->device_count; + InterlockedDecrement(&thread_pump->processing_count); ReleaseSRWLockExclusive(&thread_pump->device_lock); } return 0;
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/async.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c index 33dd3ceca9a..10058eb5fba 100644 --- a/dlls/d3dx10_43/async.c +++ b/dlls/d3dx10_43/async.c @@ -790,8 +790,34 @@ static HRESULT WINAPI thread_pump_WaitForAllItems(ID3DX10ThreadPump *iface)
static HRESULT WINAPI thread_pump_ProcessDeviceWorkItems(ID3DX10ThreadPump *iface, UINT count) { - FIXME("iface %p, count %u stub!\n", iface, count); - return E_NOTIMPL; + struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface); + struct work_item *work_item; + HRESULT hr; + UINT i; + + TRACE("iface %p, count %u.\n", iface, count); + + for (i = 0; i < count; ++i) + { + AcquireSRWLockExclusive(&thread_pump->device_lock); + if (!thread_pump->device_count) + { + ReleaseSRWLockExclusive(&thread_pump->device_lock); + break; + } + + thread_pump->device_count--; + work_item = LIST_ENTRY(list_head(&thread_pump->device_queue), struct work_item, entry); + list_remove(&work_item->entry); + ReleaseSRWLockExclusive(&thread_pump->device_lock); + + hr = ID3DX10DataProcessor_CreateDeviceObject(work_item->processor, work_item->object); + if (work_item->result) + *work_item->result = hr; + work_item_free(work_item, FALSE); + } + + return S_OK; }
static HRESULT WINAPI thread_pump_PurgeAllItems(ID3DX10ThreadPump *iface)
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/async.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c index 10058eb5fba..585d71e05f1 100644 --- a/dlls/d3dx10_43/async.c +++ b/dlls/d3dx10_43/async.c @@ -21,6 +21,7 @@ #include "d3dx10.h" #include "d3dcompiler.h" #include "dxhelpers.h" +#include "winternl.h"
#include "wine/debug.h" #include "wine/list.h" @@ -784,8 +785,32 @@ static UINT WINAPI thread_pump_GetWorkItemCount(ID3DX10ThreadPump *iface)
static HRESULT WINAPI thread_pump_WaitForAllItems(ID3DX10ThreadPump *iface) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface); + HRESULT hr; + LONG v; + + TRACE("iface %p.\n", iface); + + for (;;) + { + if (FAILED((hr = ID3DX10ThreadPump_ProcessDeviceWorkItems(iface, UINT_MAX)))) + return hr; + + AcquireSRWLockExclusive(&thread_pump->device_lock); + if (thread_pump->device_count) + { + ReleaseSRWLockExclusive(&thread_pump->device_lock); + continue; + } + v = thread_pump->processing_count; + ReleaseSRWLockExclusive(&thread_pump->device_lock); + if (!v) + break; + + RtlWaitOnAddress(&thread_pump->processing_count, &v, sizeof(v), NULL); + } + + return S_OK; }
static HRESULT WINAPI thread_pump_ProcessDeviceWorkItems(ID3DX10ThreadPump *iface, UINT count) @@ -878,7 +903,8 @@ static DWORD WINAPI io_thread(void *arg) if (work_item->result) *work_item->result = hr; work_item_free(work_item, FALSE); - InterlockedDecrement(&thread_pump->processing_count); + if (!InterlockedDecrement(&thread_pump->processing_count)) + RtlWakeAddressAll(&thread_pump->processing_count); continue; }
@@ -931,7 +957,8 @@ static DWORD WINAPI proc_thread(void *arg) if (work_item->result) *work_item->result = hr; work_item_free(work_item, FALSE); - InterlockedDecrement(&thread_pump->processing_count); + if (!InterlockedDecrement(&thread_pump->processing_count)) + RtlWakeAddressAll(&thread_pump->processing_count); continue; }
@@ -946,7 +973,8 @@ static DWORD WINAPI proc_thread(void *arg) if (work_item->result) *work_item->result = hr; work_item_free(work_item, FALSE); - InterlockedDecrement(&thread_pump->processing_count); + if (!InterlockedDecrement(&thread_pump->processing_count)) + RtlWakeAddressAll(&thread_pump->processing_count); continue; }
@@ -961,6 +989,7 @@ static DWORD WINAPI proc_thread(void *arg) list_add_tail(&thread_pump->device_queue, &work_item->entry); ++thread_pump->device_count; InterlockedDecrement(&thread_pump->processing_count); + RtlWakeAddressAll(&thread_pump->processing_count); ReleaseSRWLockExclusive(&thread_pump->device_lock); } return 0;
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/async.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c index 585d71e05f1..746c8220cf2 100644 --- a/dlls/d3dx10_43/async.c +++ b/dlls/d3dx10_43/async.c @@ -854,9 +854,15 @@ static HRESULT WINAPI thread_pump_PurgeAllItems(ID3DX10ThreadPump *iface) static HRESULT WINAPI thread_pump_GetQueueStatus(ID3DX10ThreadPump *iface, UINT *io_queue, UINT *process_queue, UINT *device_queue) { - FIXME("iface %p, io_queue %p, process_queue %p, device_queue %p stub!\n", + struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface); + + TRACE("iface %p, io_queue %p, process_queue %p, device_queue %p.\n", iface, io_queue, process_queue, device_queue); - return E_NOTIMPL; + + *io_queue = thread_pump->io_count; + *process_queue = thread_pump->proc_count; + *device_queue = thread_pump->device_count; + return S_OK; }
static const ID3DX10ThreadPumpVtbl thread_pump_vtbl =
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/async.c | 46 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/dlls/d3dx10_43/async.c b/dlls/d3dx10_43/async.c index 746c8220cf2..fdcfc033f27 100644 --- a/dlls/d3dx10_43/async.c +++ b/dlls/d3dx10_43/async.c @@ -845,10 +845,52 @@ static HRESULT WINAPI thread_pump_ProcessDeviceWorkItems(ID3DX10ThreadPump *ifac return S_OK; }
+static void purge_list(struct list *list, LONG *count) +{ + struct work_item *work_item; + + while (!list_empty(list)) + { + work_item = LIST_ENTRY(list_head(list), struct work_item, entry); + list_remove(&work_item->entry); + work_item_free(work_item, TRUE); + + if (count && !InterlockedDecrement(count)) + RtlWakeAddressAll(count); + } +} + static HRESULT WINAPI thread_pump_PurgeAllItems(ID3DX10ThreadPump *iface) { - FIXME("iface %p stub!\n", iface); - return E_NOTIMPL; + struct thread_pump *thread_pump = impl_from_ID3DX10ThreadPump(iface); + LONG v; + + TRACE("iface %p.\n", iface); + + for (;;) + { + AcquireSRWLockExclusive(&thread_pump->io_lock); + purge_list(&thread_pump->io_queue, &thread_pump->processing_count); + thread_pump->io_count = 0; + ReleaseSRWLockExclusive(&thread_pump->io_lock); + + AcquireSRWLockExclusive(&thread_pump->proc_lock); + purge_list(&thread_pump->proc_queue, &thread_pump->processing_count); + thread_pump->proc_count = 0; + ReleaseSRWLockExclusive(&thread_pump->proc_lock); + + AcquireSRWLockExclusive(&thread_pump->device_lock); + purge_list(&thread_pump->device_queue, NULL); + thread_pump->device_count = 0; + v = thread_pump->processing_count; + ReleaseSRWLockExclusive(&thread_pump->device_lock); + if (!v) + break; + + RtlWaitOnAddress(&thread_pump->processing_count, &v, sizeof(v), NULL); + } + + return S_OK; }
static HRESULT WINAPI thread_pump_GetQueueStatus(ID3DX10ThreadPump *iface,
From: Piotr Caban piotr@codeweavers.com
Signed-off-by: Piotr Caban piotr@codeweavers.com --- dlls/d3dx10_43/tests/d3dx10.c | 357 ++++++++++++++++++++++++++++++++++ 1 file changed, 357 insertions(+)
diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index d1c772197b9..f5708e569ed 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -2066,6 +2066,362 @@ static void test_D3DX10CreateAsyncTextureProcessor(void) ok(!ID3D10Device_Release(device), "Unexpected refcount.\n"); }
+static DWORD main_tid; +static DWORD io_tid; + +struct data_object +{ + ID3DX10DataLoader ID3DX10DataLoader_iface; + ID3DX10DataProcessor ID3DX10DataProcessor_iface; + + HANDLE load_started; + HANDLE load_done; + HANDLE decompress_done; + HRESULT load_ret; + + DWORD process_tid; +}; + +static struct data_object *data_object_from_ID3DX10DataLoader(ID3DX10DataLoader *iface) +{ + return CONTAINING_RECORD(iface, struct data_object, ID3DX10DataLoader_iface); +} + +static LONG data_loader_load_count; +static WINAPI HRESULT data_loader_Load(ID3DX10DataLoader *iface) +{ + struct data_object *data_object = data_object_from_ID3DX10DataLoader(iface); + DWORD ret; + + ok(InterlockedDecrement(&data_loader_load_count) >= 0, "Got unexpected call.\n"); + + if (!io_tid) + io_tid = GetCurrentThreadId(); + ok(io_tid != main_tid, "Load called in main thread.\n"); + ok(io_tid == GetCurrentThreadId(), "Load called in wrong thread.\n"); + + SetEvent(data_object->load_started); + ret = WaitForSingleObject(data_object->load_done, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x.\n", ret); + return data_object->load_ret; +} + +static LONG data_loader_decompress_count; +static WINAPI HRESULT data_loader_Decompress(ID3DX10DataLoader *iface, void **data, SIZE_T *bytes) +{ + struct data_object *data_object = data_object_from_ID3DX10DataLoader(iface); + DWORD ret; + + ok(InterlockedDecrement(&data_loader_decompress_count) >= 0, "Got unexpected call.\n"); + ok(data != NULL, "Got unexpected data = NULL.\n"); + ok(bytes != NULL, "Got unexpected bytes = NULL.\n"); + + data_object->process_tid = GetCurrentThreadId(); + ok(data_object->process_tid != main_tid, "Decompress called in main thread.\n"); + ok(data_object->process_tid != io_tid, "Decompress called in IO thread.\n"); + + *data = (void*)0xdeadbeef; + *bytes = 0xdead; + ret = WaitForSingleObject(data_object->decompress_done, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x.\n", ret); + return S_OK; +} + +static LONG data_loader_destroy_count; +static WINAPI HRESULT data_loader_Destroy(ID3DX10DataLoader *iface) +{ + ok(InterlockedDecrement(&data_loader_destroy_count) >= 0, "Got unexpected call.\n"); + return S_OK; +} + +static ID3DX10DataLoaderVtbl D3DX10DataLoaderVtbl = +{ + data_loader_Load, + data_loader_Decompress, + data_loader_Destroy +}; + +static struct data_object* data_object_from_ID3DX10DataProcessor(ID3DX10DataProcessor *iface) +{ + return CONTAINING_RECORD(iface, struct data_object, ID3DX10DataProcessor_iface); +} + +static LONG data_processor_process_count; +static HRESULT WINAPI data_processor_Process(ID3DX10DataProcessor *iface, void *data, SIZE_T bytes) +{ + struct data_object *data_object = data_object_from_ID3DX10DataProcessor(iface); + + ok(InterlockedDecrement(&data_processor_process_count) >= 0, "Got unexpected call.\n"); + ok(data_object->process_tid == GetCurrentThreadId(), "Process called in wrong thread.\n"); + + ok(data == (void*)0xdeadbeef, "data = %p\n", data); + ok(bytes == 0xdead, "bytes = %lu\n", bytes); + return S_OK; +} + +static LONG data_processor_create_count; +static HRESULT WINAPI data_processor_CreateDeviceObject(ID3DX10DataProcessor *iface, void **object) +{ + ok(InterlockedDecrement(&data_processor_create_count) >= 0, "Got unexpected call.\n"); + ok(main_tid == GetCurrentThreadId(), "CreateDeviceObject not called in main thread.\n"); + + *object = (void*)0xdeadf00d; + return S_OK; +} + +static LONG data_processor_destroy_count; +static HRESULT WINAPI data_processor_Destroy(ID3DX10DataProcessor *iface) +{ + struct data_object *data_object = data_object_from_ID3DX10DataProcessor(iface); + + ok(InterlockedDecrement(&data_processor_destroy_count) >= 0, "Got unexpected call.\n"); + + CloseHandle(data_object->load_started); + CloseHandle(data_object->load_done); + CloseHandle(data_object->decompress_done); + free(data_object); + return S_OK; +} + +static ID3DX10DataProcessorVtbl D3DX10DataProcessorVtbl = +{ + data_processor_Process, + data_processor_CreateDeviceObject, + data_processor_Destroy +}; + +static struct data_object* create_data_object(HRESULT load_ret) +{ + struct data_object *data_object = malloc(sizeof(*data_object)); + + data_object->ID3DX10DataLoader_iface.lpVtbl = &D3DX10DataLoaderVtbl; + data_object->ID3DX10DataProcessor_iface.lpVtbl = &D3DX10DataProcessorVtbl; + + data_object->load_started = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(data_object->load_started != NULL, "CreateEvent failed, error %u.\n", GetLastError()); + data_object->load_done = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(data_object->load_done != NULL, "CreateEvent failed, error %u.\n", GetLastError()); + data_object->decompress_done = CreateEventW(NULL, FALSE, FALSE, NULL); + ok(data_object->decompress_done != NULL, "CreateEvent failed, error %u.\n", GetLastError()); + data_object->load_ret = load_ret; + + return data_object; +} + +static void test_D3DX10CreateThreadPump(void) +{ + UINT io_count, process_count, device_count, count; + struct data_object *data_object[2]; + ID3DX10DataProcessor *processor; + D3DX10_IMAGE_INFO image_info; + ID3DX10DataLoader *loader; + HRESULT hr, work_item_hr; + ID3D10Resource *resource; + ID3DX10ThreadPump *pump; + ID3D10Device *device; + SYSTEM_INFO info; + void *object; + DWORD ret; + int i; + + main_tid = GetCurrentThreadId(); + + hr = D3DX10CreateThreadPump(1024, 0, &pump); + ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr); + hr = D3DX10CreateThreadPump(0, 1024, &pump); + ok(hr == E_FAIL, "Got unexpected hr %#x.\n", hr); + + GetSystemInfo(&info); + if (info.dwNumberOfProcessors > 1) + hr = D3DX10CreateThreadPump(0, 0, &pump); + else + hr = D3DX10CreateThreadPump(0, 2, &pump); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + + count = ID3DX10ThreadPump_GetWorkItemCount(pump); + ok(!count, "GetWorkItemCount returned %u.\n", count); + hr = ID3DX10ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(!io_count, "Got unexpected io_count = %u.\n", io_count); + ok(!process_count, "Got unexpected process_count = %u.\n", process_count); + ok(!device_count, "Got unexpected device_count = %u.\n", device_count); + + data_object[0] = create_data_object(E_NOTIMPL); + data_object[1] = create_data_object(S_OK); + + data_loader_load_count = 1; + hr = ID3DX10ThreadPump_AddWorkItem(pump, &data_object[0]->ID3DX10DataLoader_iface, + &data_object[0]->ID3DX10DataProcessor_iface, &work_item_hr, NULL); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ret = WaitForSingleObject(data_object[0]->load_started, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x.\n", ret); + ok(!data_loader_load_count, "Got unexpected data_loader_load_count %d.\n", data_loader_load_count); + count = ID3DX10ThreadPump_GetWorkItemCount(pump); + ok(count == 1, "GetWorkItemCount returned %u.\n", count); + hr = ID3DX10ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(!io_count, "Got unexpected io_count = %u.\n", io_count); + ok(!process_count, "Got unexpected process_count = %u.\n", process_count); + ok(!device_count, "Got unexpected device_count = %u.\n", device_count); + + hr = ID3DX10ThreadPump_AddWorkItem(pump, &data_object[1]->ID3DX10DataLoader_iface, + &data_object[1]->ID3DX10DataProcessor_iface, NULL, &object); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ret = WaitForSingleObject(data_object[0]->load_started, 50); + ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %x.\n", ret); + count = ID3DX10ThreadPump_GetWorkItemCount(pump); + ok(count == 2, "GetWorkItemCount returned %u.\n", count); + hr = ID3DX10ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(io_count == 1, "Got unexpected io_count = %u.\n", io_count); + ok(!process_count, "Got unexpected process_count = %u.\n", process_count); + ok(!device_count, "Got unexpected device_count = %u.\n", device_count); + + data_loader_load_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + SetEvent(data_object[0]->load_done); + ret = WaitForSingleObject(data_object[1]->load_started, INFINITE); + ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %x.\n", ret); + ok(work_item_hr == E_NOTIMPL, "Got unexpected work_item_hr = %#x.\n", work_item_hr); + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %d.\n", data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %d.\n", + data_processor_destroy_count); + ok(!data_loader_load_count, "Got unexpected data_loader_load_count %d.\n", data_loader_load_count); + + data_loader_decompress_count = 1; + data_processor_process_count = 1; + SetEvent(data_object[1]->load_done); + SetEvent(data_object[1]->decompress_done); + + data_processor_create_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + hr = ID3DX10ThreadPump_WaitForAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(object == (void*)0xdeadf00d, "Got unexpected object = %p.\n", object); + ok(!data_loader_decompress_count, "Got unexpected data_loader_decompress_count %d.\n", data_loader_decompress_count); + ok(!data_processor_process_count, "Got unexpected data_processor_process_count %d.\n", data_processor_process_count); + ok(!data_processor_create_count, "Got unexpected data_processor_create_count %d.\n", data_processor_create_count); + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %d.\n", data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %d.\n", data_processor_destroy_count); + + data_object[0] = create_data_object(S_OK); + data_object[1] = create_data_object(S_OK); + SetEvent(data_object[0]->load_done); + SetEvent(data_object[1]->load_done); + SetEvent(data_object[1]->decompress_done); + + data_loader_load_count = 2; + data_loader_decompress_count = 2; + data_processor_process_count = 1; + hr = ID3DX10ThreadPump_AddWorkItem(pump, &data_object[0]->ID3DX10DataLoader_iface, + &data_object[0]->ID3DX10DataProcessor_iface, NULL, &object); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = ID3DX10ThreadPump_AddWorkItem(pump, &data_object[1]->ID3DX10DataLoader_iface, + &data_object[1]->ID3DX10DataProcessor_iface, NULL, &object); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + while(1) + { + hr = ID3DX10ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + if (hr != S_OK || device_count) + break; + Sleep(1); + } + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(!io_count, "Got unexpected io_count = %u.\n", io_count); + ok(!process_count, "Got unexpected process_count = %u.\n", process_count); + ok(device_count == 1, "Got unexpected device_count = %u.\n", device_count); + ok(!data_loader_load_count, "Got unexpected data_loader_load_count %d.\n", data_loader_load_count); + ok(!data_loader_decompress_count, "Got unexpected data_loader_decompress_count %d.\n", data_loader_decompress_count); + ok(!data_processor_process_count, "Got unexpected data_processor_process_count %d.\n", data_processor_process_count); + + hr = ID3DX10ThreadPump_ProcessDeviceWorkItems(pump, 0); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = ID3DX10ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(!io_count, "Got unexpected io_count = %u.\n", io_count); + ok(!process_count, "Got unexpected process_count = %u.\n", process_count); + ok(device_count == 1, "Got unexpected device_count = %u.\n", device_count); + + data_processor_create_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + hr = ID3DX10ThreadPump_ProcessDeviceWorkItems(pump, 1); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = ID3DX10ThreadPump_GetQueueStatus(pump, &io_count, &process_count, &device_count); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(!io_count, "Got unexpected io_count = %u.\n", io_count); + ok(!process_count, "Got unexpected process_count = %u.\n", process_count); + ok(!device_count, "Got unexpected device_count = %u.\n", device_count); + ok(!data_processor_create_count, "Got unexpected data_processor_create_count %d.\n", data_processor_create_count); + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %d.\n", data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %d.\n", data_processor_destroy_count); + + data_processor_process_count = 1; + data_loader_destroy_count = 1; + data_processor_destroy_count = 1; + SetEvent(data_object[0]->decompress_done); + hr = ID3DX10ThreadPump_PurgeAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + data_processor_process_count = 0; + ok(!data_loader_destroy_count, "Got unexpected data_loader_destroy_count %d.\n", data_loader_destroy_count); + ok(!data_processor_destroy_count, "Got unexpected data_processor_destroy_count %d.\n", data_processor_destroy_count); + + device = create_device(); + if (!device) + { + skip("Failed to create device, skipping tests.\n"); + ID3DX10ThreadPump_Release(pump); + return; + } + + for (i = 0; i < ARRAY_SIZE(test_image); ++i) + { + winetest_push_context("Test %u", i); + + hr = D3DX10CreateAsyncMemoryLoader(test_image[i].data, test_image[i].size, &loader); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = D3DX10CreateAsyncTextureInfoProcessor(&image_info, &processor); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = ID3DX10ThreadPump_AddWorkItem(pump, loader, processor, &work_item_hr, NULL); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = ID3DX10ThreadPump_WaitForAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + ok(work_item_hr == S_OK || (work_item_hr == E_FAIL + && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#x.\n", work_item_hr); + if (work_item_hr == S_OK) + check_image_info(&image_info, test_image + i, __LINE__); + + hr = D3DX10CreateAsyncMemoryLoader(test_image[i].data, test_image[i].size, &loader); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = D3DX10CreateAsyncTextureProcessor(device, NULL, &processor); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = ID3DX10ThreadPump_AddWorkItem(pump, loader, processor, &work_item_hr, (void **)&resource); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + hr = ID3DX10ThreadPump_WaitForAllItems(pump); + ok(hr == S_OK, "Got unexpected hr %#x.\n", hr); + todo_wine_if(test_image[i].expected_info.MiscFlags & D3D10_RESOURCE_MISC_TEXTURECUBE) + ok(work_item_hr == S_OK || (work_item_hr == E_FAIL + && test_image[i].expected_info.ImageFileFormat == D3DX10_IFF_WMP), + "Got unexpected hr %#x.\n", work_item_hr); + if (work_item_hr == S_OK) + { + check_resource_info(resource, test_image + i, __LINE__); + check_resource_data(resource, test_image + i, __LINE__); + ID3D10Resource_Release(resource); + } + + winetest_pop_context(); + } + + ok(!ID3D10Device_Release(device), "Got unexpected refcount.\n"); + + ret = ID3DX10ThreadPump_Release(pump); + ok(!ret, "Got unexpected refcount %u.\n", ret); +} + static void test_get_image_info(void) { static const WCHAR test_resource_name[] = L"resource.data"; @@ -3573,6 +3929,7 @@ START_TEST(d3dx10) test_D3DX10CreateAsyncResourceLoader(); test_D3DX10CreateAsyncTextureInfoProcessor(); test_D3DX10CreateAsyncTextureProcessor(); + test_D3DX10CreateThreadPump(); test_get_image_info(); test_create_texture(); test_font();