Commit 27fed4a5 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

d2d1: Implement ID2D1Multithread.

parent b918aa07
...@@ -30,12 +30,15 @@ struct d2d_settings d2d_settings = ...@@ -30,12 +30,15 @@ struct d2d_settings d2d_settings =
struct d2d_factory struct d2d_factory
{ {
ID2D1Factory2 ID2D1Factory2_iface; ID2D1Factory2 ID2D1Factory2_iface;
ID2D1Multithread ID2D1Multithread_iface;
LONG refcount; LONG refcount;
ID3D10Device1 *device; ID3D10Device1 *device;
float dpi_x; float dpi_x;
float dpi_y; float dpi_y;
CRITICAL_SECTION cs;
}; };
static inline struct d2d_factory *impl_from_ID2D1Factory2(ID2D1Factory2 *iface) static inline struct d2d_factory *impl_from_ID2D1Factory2(ID2D1Factory2 *iface)
...@@ -43,6 +46,11 @@ 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); 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) static HRESULT d2d_factory_reload_sysmetrics(struct d2d_factory *factory)
{ {
HDC hdc; HDC hdc;
...@@ -63,6 +71,8 @@ static HRESULT d2d_factory_reload_sysmetrics(struct d2d_factory *factory) ...@@ -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) 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); TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
if ((IsEqualGUID(iid, &IID_ID2D1Factory2) && d2d_settings.max_version_factory >= 2) if ((IsEqualGUID(iid, &IID_ID2D1Factory2) && d2d_settings.max_version_factory >= 2)
...@@ -74,6 +84,12 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_QueryInterface(ID2D1Factory2 *iface ...@@ -74,6 +84,12 @@ static HRESULT STDMETHODCALLTYPE d2d_factory_QueryInterface(ID2D1Factory2 *iface
*out = iface; *out = iface;
return S_OK; 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)); WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
...@@ -102,6 +118,7 @@ static ULONG STDMETHODCALLTYPE d2d_factory_Release(ID2D1Factory2 *iface) ...@@ -102,6 +118,7 @@ static ULONG STDMETHODCALLTYPE d2d_factory_Release(ID2D1Factory2 *iface)
{ {
if (factory->device) if (factory->device)
ID3D10Device1_Release(factory->device); ID3D10Device1_Release(factory->device);
DeleteCriticalSection(&factory->cs);
heap_free(factory); heap_free(factory);
} }
...@@ -593,17 +610,92 @@ static const struct ID2D1Factory2Vtbl d2d_factory_vtbl = ...@@ -593,17 +610,92 @@ static const struct ID2D1Factory2Vtbl d2d_factory_vtbl =
d2d_factory_ID2D1Factory1_CreateDevice, 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, static void d2d_factory_init(struct d2d_factory *factory, D2D1_FACTORY_TYPE factory_type,
const D2D1_FACTORY_OPTIONS *factory_options) 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) if (factory_options && factory_options->debugLevel != D2D1_DEBUG_LEVEL_NONE)
WARN("Ignoring debug level %#x.\n", factory_options->debugLevel); WARN("Ignoring debug level %#x.\n", factory_options->debugLevel);
factory->ID2D1Factory2_iface.lpVtbl = &d2d_factory_vtbl; 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; factory->refcount = 1;
d2d_factory_reload_sysmetrics(factory); d2d_factory_reload_sysmetrics(factory);
InitializeCriticalSection(&factory->cs);
} }
HRESULT WINAPI D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type, REFIID iid, HRESULT WINAPI D2D1CreateFactory(D2D1_FACTORY_TYPE factory_type, REFIID iid,
...@@ -615,6 +707,12 @@ 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", TRACE("factory_type %#x, iid %s, factory_options %p, factory %p.\n",
factory_type, debugstr_guid(iid), factory_options, factory); 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)))) if (!(object = heap_alloc_zero(sizeof(*object))))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
......
...@@ -9614,6 +9614,73 @@ static void test_geometry_group(BOOL d3d11) ...@@ -9614,6 +9614,73 @@ static void test_geometry_group(BOOL d3d11)
ID2D1Factory_Release(factory); 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) START_TEST(d2d1)
{ {
HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll");
...@@ -9674,6 +9741,7 @@ START_TEST(d2d1) ...@@ -9674,6 +9741,7 @@ START_TEST(d2d1)
queue_d3d10_test(test_math); queue_d3d10_test(test_math);
queue_d3d10_test(test_colour_space); queue_d3d10_test(test_colour_space);
queue_test(test_geometry_group); queue_test(test_geometry_group);
queue_test(test_mt_factory);
run_queued_tests(); run_queued_tests();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment