Nikolay Sivov : d2d1: Implement ID2D1Multithread.

Alexandre Julliard julliard at winehq.org
Mon Apr 5 16:28:24 CDT 2021


Module: wine
Branch: master
Commit: 27fed4a5209cf1a32870cbba229711b64925d7e4
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=27fed4a5209cf1a32870cbba229711b64925d7e4

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Fri Apr  2 18:06:39 2021 +0300

d2d1: Implement ID2D1Multithread.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/d2d1/factory.c    | 102 ++++++++++++++++++++++++++++++++++++++++++++++++-
 dlls/d2d1/tests/d2d1.c |  68 +++++++++++++++++++++++++++++++++
 2 files changed, 168 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..8dbad9c5ecc 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -9614,6 +9614,73 @@ 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);
+    if (hr == E_NOINTERFACE)
+    {
+        win_skip("ID2D1Multithread is not supported.\n");
+        ID2D1Factory_Release(factory);
+        return;
+    }
+    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");
+    ID2D1Multithread_Leave(multithread);
+    WaitForSingleObject(thread, INFINITE);
+    CloseHandle(thread);
+
+    ID2D1Multithread_Release(multithread);
+
+    ID2D1Factory_Release(factory);
+}
+
 START_TEST(d2d1)
 {
     HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll");
@@ -9674,6 +9741,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();
 }




More information about the wine-cvs mailing list