Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/d2d1/factory.c | 102 ++++++++++++++++++++++++++++++++++++++++- dlls/d2d1/tests/d2d1.c | 59 ++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 2a9de448c6e..b65727d3a32 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -30,12 +30,15 @@ struct d2d_settings d2d_settings = struct d2d_factory { ID2D1Factory2 ID2D1Factory2_iface; + ID2D1Multithread ID2D1Multithread_iface; LONG refcount;
ID3D10Device1 *device;
float dpi_x; float dpi_y; + + CRITICAL_SECTION cs; };
static inline struct d2d_factory *impl_from_ID2D1Factory2(ID2D1Factory2 *iface) @@ -43,6 +46,11 @@ static inline struct d2d_factory *impl_from_ID2D1Factory2(ID2D1Factory2 *iface) return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Factory2_iface); }
+static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Multithread_iface); +} + static HRESULT d2d_factory_reload_sysmetrics(struct d2d_factory *factory) { HDC hdc; @@ -63,6 +71,8 @@ static HRESULT d2d_factory_reload_sysmetrics(struct d2d_factory *factory)
static HRESULT STDMETHODCALLTYPE d2d_factory_QueryInterface(ID2D1Factory2 *iface, REFIID iid, void **out) { + struct d2d_factory *factory = impl_from_ID2D1Factory2(iface); + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
if ((IsEqualGUID(iid, &IID_ID2D1Factory2) && d2d_settings.max_version_factory >= 2) @@ -74,6 +84,12 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_QueryInterface(ID2D1Factory2 *iface *out = iface; return S_OK; } + else if (IsEqualGUID(iid, &IID_ID2D1Multithread)) + { + ID2D1Factory2_AddRef(iface); + *out = &factory->ID2D1Multithread_iface; + return S_OK; + }
WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
@@ -102,6 +118,7 @@ static ULONG STDMETHODCALLTYPE d2d_factory_Release(ID2D1Factory2 *iface) { if (factory->device) ID3D10Device1_Release(factory->device); + DeleteCriticalSection(&factory->cs); heap_free(factory); }
@@ -593,17 +610,92 @@ static const struct ID2D1Factory2Vtbl d2d_factory_vtbl = d2d_factory_ID2D1Factory1_CreateDevice, };
+static HRESULT STDMETHODCALLTYPE d2d_factory_mt_QueryInterface(ID2D1Multithread *iface, REFIID iid, void **out) +{ + struct d2d_factory *factory = impl_from_ID2D1Multithread(iface); + return d2d_factory_QueryInterface(&factory->ID2D1Factory2_iface, iid, out); +} + +static ULONG STDMETHODCALLTYPE d2d_factory_mt_AddRef(ID2D1Multithread *iface) +{ + struct d2d_factory *factory = impl_from_ID2D1Multithread(iface); + return d2d_factory_AddRef(&factory->ID2D1Factory2_iface); +} + +static ULONG STDMETHODCALLTYPE d2d_factory_mt_Release(ID2D1Multithread *iface) +{ + struct d2d_factory *factory = impl_from_ID2D1Multithread(iface); + return d2d_factory_Release(&factory->ID2D1Factory2_iface); +} + +static BOOL STDMETHODCALLTYPE d2d_factory_mt_GetMultithreadProtected(ID2D1Multithread *iface) +{ + return TRUE; +} + +static void STDMETHODCALLTYPE d2d_factory_mt_Enter(ID2D1Multithread *iface) +{ + struct d2d_factory *factory = impl_from_ID2D1Multithread(iface); + + TRACE("%p.\n", iface); + + return EnterCriticalSection(&factory->cs); +} + +static void STDMETHODCALLTYPE d2d_factory_mt_Leave(ID2D1Multithread *iface) +{ + struct d2d_factory *factory = impl_from_ID2D1Multithread(iface); + + TRACE("%p.\n", iface); + + return LeaveCriticalSection(&factory->cs); +} + +static BOOL STDMETHODCALLTYPE d2d_factory_st_GetMultithreadProtected(ID2D1Multithread *iface) +{ + return FALSE; +} + +static void STDMETHODCALLTYPE d2d_factory_st_Enter(ID2D1Multithread *iface) +{ +} + +static void STDMETHODCALLTYPE d2d_factory_st_Leave(ID2D1Multithread *iface) +{ +} + +static const struct ID2D1MultithreadVtbl d2d_factory_multithread_vtbl = +{ + d2d_factory_mt_QueryInterface, + d2d_factory_mt_AddRef, + d2d_factory_mt_Release, + d2d_factory_mt_GetMultithreadProtected, + d2d_factory_mt_Enter, + d2d_factory_mt_Leave, +}; + +static const struct ID2D1MultithreadVtbl d2d_factory_multithread_noop_vtbl = +{ + d2d_factory_mt_QueryInterface, + d2d_factory_mt_AddRef, + d2d_factory_mt_Release, + d2d_factory_st_GetMultithreadProtected, + d2d_factory_st_Enter, + d2d_factory_st_Leave, +}; + static void d2d_factory_init(struct d2d_factory *factory, D2D1_FACTORY_TYPE factory_type, const D2D1_FACTORY_OPTIONS *factory_options) { - if (factory_type != D2D1_FACTORY_TYPE_SINGLE_THREADED) - FIXME("Ignoring factory type %#x.\n", factory_type); if (factory_options && factory_options->debugLevel != D2D1_DEBUG_LEVEL_NONE) WARN("Ignoring debug level %#x.\n", factory_options->debugLevel);
factory->ID2D1Factory2_iface.lpVtbl = &d2d_factory_vtbl; + factory->ID2D1Multithread_iface.lpVtbl = factory_type == D2D1_FACTORY_TYPE_SINGLE_THREADED ? + &d2d_factory_multithread_noop_vtbl : &d2d_factory_multithread_vtbl; factory->refcount = 1; d2d_factory_reload_sysmetrics(factory); + InitializeCriticalSection(&factory->cs); }
HRESULT WINAPI D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type, REFIID iid, @@ -615,6 +707,12 @@ HRESULT WINAPI D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type, REFIID iid, TRACE("factory_type %#x, iid %s, factory_options %p, factory %p.\n", factory_type, debugstr_guid(iid), factory_options, factory);
+ if (factory_type != D2D1_FACTORY_TYPE_SINGLE_THREADED && + factory_type != D2D1_FACTORY_TYPE_MULTI_THREADED) + { + return E_INVALIDARG; + } + if (!(object = heap_alloc_zero(sizeof(*object)))) return E_OUTOFMEMORY;
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index a046a21c7f6..8db2aad813e 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -9614,6 +9614,64 @@ static void test_geometry_group(BOOL d3d11) ID2D1Factory_Release(factory); }
+static DWORD WINAPI mt_factory_test_thread_func(void *param) +{ + ID2D1Multithread *multithread = param; + + ID2D1Multithread_Enter(multithread); + + return 0; +} + +static void test_mt_factory(BOOL d3d11) +{ + ID2D1Multithread *multithread; + ID2D1Factory *factory; + HANDLE thread; + HRESULT hr; + DWORD ret; + + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED + 1, &IID_ID2D1Factory, NULL, (void **)&factory); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, (void **)&factory); + ok(SUCCEEDED(hr), "Failed to create factory, hr %#x.\n", hr); + + hr = ID2D1Factory_QueryInterface(factory, &IID_ID2D1Multithread, (void **)&multithread); + ok(SUCCEEDED(hr), "Failed to get interface, hr %#x.\n", hr); + + ret = ID2D1Multithread_GetMultithreadProtected(multithread); + ok(!ret, "Unexpected return value.\n"); + + ID2D1Multithread_Enter(multithread); + thread = CreateThread(NULL, 0, mt_factory_test_thread_func, multithread, 0, NULL); + ok(!!thread, "Failed to create a thread.\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + ID2D1Multithread_Release(multithread); + ID2D1Factory_Release(factory); + + hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &IID_ID2D1Factory, NULL, (void **)&factory); + ok(SUCCEEDED(hr), "Failed to create factory, hr %#x.\n", hr); + + hr = ID2D1Factory_QueryInterface(factory, &IID_ID2D1Multithread, (void **)&multithread); + ok(SUCCEEDED(hr), "Failed to get interface, hr %#x.\n", hr); + + ret = ID2D1Multithread_GetMultithreadProtected(multithread); + ok(!!ret, "Unexpected return value.\n"); + + ID2D1Multithread_Enter(multithread); + thread = CreateThread(NULL, 0, mt_factory_test_thread_func, multithread, 0, NULL); + ok(!!thread, "Failed to create a thread.\n"); + ret = WaitForSingleObject(thread, 10); + ok(ret == WAIT_TIMEOUT, "Expected timeout.\n"); + CloseHandle(thread); + ID2D1Multithread_Release(multithread); + + ID2D1Factory_Release(factory); +} + START_TEST(d2d1) { HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); @@ -9674,6 +9732,7 @@ START_TEST(d2d1) queue_d3d10_test(test_math); queue_d3d10_test(test_colour_space); queue_test(test_geometry_group); + queue_test(test_mt_factory);
run_queued_tests(); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=88058
Your paranoid android.
=== w2008s64 (32 bit report) ===
d2d1: d2d1.c:9641: Test failed: Failed to get interface, hr 0x80004002. 0390:d2d1: unhandled exception c0000005 at 004019B7
=== w7u_el (32 bit report) ===
d2d1: 0a44:d2d1: unhandled exception c0000005 at 00000000
=== wvistau64 (64 bit report) ===
d2d1: d2d1.c:9641: Test failed: Failed to get interface, hr 0x80004002. 09f0:d2d1: unhandled exception c0000005 at 0000000000401917
=== w2008s64 (64 bit report) ===
d2d1: d2d1.c:9641: Test failed: Failed to get interface, hr 0x80004002. 0390:d2d1: unhandled exception c0000005 at 0000000000401917
=== w1064_2qxl (64 bit report) ===
d2d1: 096c:d2d1: unhandled exception c0000005 at 0000000000000000
=== w10pro64_he (64 bit report) ===
d2d1: 1d8c:d2d1: unhandled exception c0000005 at 0000000000000000
=== w10pro64_ja (64 bit report) ===
d2d1: 0fd4:d2d1: unhandled exception c0000005 at 0000000000000000
=== debiant2 (32 bit Japanese:Japan report) ===
d2d1: Unhandled exception: page fault on read access to 0x00000014 in 32-bit code (0x004014f8).