From: Brendan McGrath bmcgrath@codeweavers.com
Ensures the Direct 2D lock is held before attempting to access Direct 2D exclusive resources.
This fixes periodic crashes in PowerPoint 365 --- dlls/d2d1/d2d1_private.h | 29 ++++++++++++++++++++++++++++- dlls/d2d1/device.c | 22 ++++++++++++++++++++++ dlls/d2d1/factory.c | 36 +++++++++++++++--------------------- dlls/d2d1/tests/d2d1.c | 2 +- 4 files changed, 66 insertions(+), 23 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 1dd5cdb0a39..8ca732322ae 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -171,6 +171,7 @@ struct d2d_device_context const struct d2d_device_context_ops *ops;
ID2D1Factory *factory; + CRITICAL_SECTION* cs; struct d2d_device *device; ID3D11Device1 *d3d_device; ID3DDeviceContextState *d3d_state; @@ -678,7 +679,33 @@ struct d2d_effect_registration struct d2d_effect_properties properties; };
-struct d2d_factory; +struct d2d_factory +{ + ID2D1Factory3 ID2D1Factory3_iface; + ID2D1Multithread ID2D1Multithread_iface; + LONG refcount; + + ID3D10Device1 *device; + + float dpi_x; + float dpi_y; + + struct list effects; + INIT_ONCE init_builtins; + + CRITICAL_SECTION cs; + D2D1_FACTORY_TYPE factory_type; +}; + +inline struct d2d_factory *unsafe_impl_from_ID2D1Factory(ID2D1Factory *iface) +{ + return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Factory3_iface); +} + +inline BOOL d2d_factory_is_multithreaded(struct d2d_factory *factory) { + return factory->factory_type == D2D1_FACTORY_TYPE_MULTI_THREADED; +} + void d2d_effects_init_builtins(struct d2d_factory *factory); struct d2d_effect_registration * d2d_factory_get_registered_effect(ID2D1Factory *factory, const GUID *effect_id); diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index e5548878ee9..90f4d76b698 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -115,6 +115,16 @@ static void d2d_clip_stack_pop(struct d2d_clip_stack *stack) --stack->count; }
+static inline void d2d_device_context_enter_cs(struct d2d_device_context *context) +{ + if (context->cs) EnterCriticalSection(context->cs); +} + +static inline void d2d_device_context_leave_cs(struct d2d_device_context *context) +{ + if (context->cs) LeaveCriticalSection(context->cs); +} + static void d2d_device_context_draw(struct d2d_device_context *render_target, enum d2d_shape_type shape_type, ID3D11Buffer *ib, unsigned int index_count, ID3D11Buffer *vb, unsigned int vb_stride, struct d2d_brush *brush, struct d2d_brush *opacity_brush) @@ -135,6 +145,8 @@ static void d2d_device_context_draw(struct d2d_device_context *render_target, en vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f;
+ d2d_device_context_enter_cs(render_target); + ID3D11Device1_GetImmediateContext1(device, &context); ID3D11DeviceContext1_SwapDeviceContextState(context, render_target->d3d_state, &prev_state);
@@ -188,6 +200,8 @@ static void d2d_device_context_draw(struct d2d_device_context *render_target, en ID3D11DeviceContext1_SwapDeviceContextState(context, prev_state, NULL); ID3D11DeviceContext1_Release(context); ID3DDeviceContextState_Release(prev_state); + + d2d_device_context_leave_cs(render_target); }
static void d2d_device_context_set_error(struct d2d_device_context *context, HRESULT code) @@ -3196,6 +3210,7 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, IDWriteFactory *dwrite_factory; D3D11_RASTERIZER_DESC rs_desc; D3D11_BUFFER_DESC buffer_desc; + struct d2d_factory *factory; unsigned int i; HRESULT hr;
@@ -4256,6 +4271,13 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, render_target->device = device; ID2D1Device1_AddRef(&render_target->device->ID2D1Device1_iface);
+ factory = unsafe_impl_from_ID2D1Factory(render_target->factory); + if (d2d_factory_is_multithreaded(factory)) { + render_target->cs = &factory->cs; + } else { + render_target->cs = NULL; + } + render_target->outer_unknown = outer_unknown ? outer_unknown : &render_target->IUnknown_iface; render_target->ops = ops;
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 3b2b1f5e4ec..4eccbf2967b 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -36,36 +36,19 @@ static void d2d_effect_registration_cleanup(struct d2d_effect_registration *reg) free(reg); }
-struct d2d_factory -{ - ID2D1Factory3 ID2D1Factory3_iface; - ID2D1Multithread ID2D1Multithread_iface; - LONG refcount; - - ID3D10Device1 *device; - - float dpi_x; - float dpi_y; - - struct list effects; - INIT_ONCE init_builtins; - - CRITICAL_SECTION cs; -}; - static inline struct d2d_factory *impl_from_ID2D1Factory3(ID2D1Factory3 *iface) { return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Factory3_iface); }
-static inline struct d2d_factory *unsafe_impl_from_ID2D1Factory(ID2D1Factory *iface) +static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *iface) { - return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Factory3_iface); + return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Multithread_iface); }
-static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *iface) +struct d2d_factory *d2d_factory_from_ID2D1Multithread(ID2D1Multithread *iface) { - return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Multithread_iface); + return impl_from_ID2D1Multithread(iface); }
static BOOL WINAPI d2d_factory_builtins_initonce(INIT_ONCE *once, void *param, void **context) @@ -1173,6 +1156,16 @@ static void STDMETHODCALLTYPE d2d_factory_mt_Leave(ID2D1Multithread *iface) LeaveCriticalSection(&factory->cs); }
+void d2d_factory_enter_cs(struct d2d_factory *factory) +{ + EnterCriticalSection(&factory->cs); +} + +void d2d_factory_leave_cs(struct d2d_factory *factory) +{ + LeaveCriticalSection(&factory->cs); +} + static BOOL STDMETHODCALLTYPE d2d_factory_st_GetMultithreadProtected(ID2D1Multithread *iface) { return FALSE; @@ -1215,6 +1208,7 @@ static void d2d_factory_init(struct d2d_factory *factory, D2D1_FACTORY_TYPE fact factory->ID2D1Factory3_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->factory_type = factory_type; factory->refcount = 1; d2d_factory_reload_sysmetrics(factory); list_init(&factory->effects); diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 3a8d97162fa..0a4d81fe857 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -10777,7 +10777,7 @@ static void test_mt_factory(BOOL d3d11) thread = CreateThread(NULL, 0, mt_factory_test_thread_draw_func, ctx.rt, 0, NULL); ok(!!thread, "Failed to create a thread.\n"); ret = WaitForSingleObject(thread, 1000); - todo_wine ok(ret == WAIT_TIMEOUT, "Expected timeout.\n"); + ok(ret == WAIT_TIMEOUT, "Expected timeout.\n"); ID2D1Multithread_Leave(multithread); WaitForSingleObject(thread, INFINITE); CloseHandle(thread);