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 | 7 ++++++- dlls/d2d1/device.c | 21 +++++++++++++++++++++ dlls/d2d1/factory.c | 14 +++++++++++++- dlls/d2d1/tests/d2d1.c | 2 +- 4 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/dlls/d2d1/d2d1_private.h b/dlls/d2d1/d2d1_private.h index 1dd5cdb0a39..6a780c6334f 100644 --- a/dlls/d2d1/d2d1_private.h +++ b/dlls/d2d1/d2d1_private.h @@ -159,6 +159,8 @@ enum d2d_device_context_target_type D2D_TARGET_COMMAND_LIST, };
+struct d2d_factory; + struct d2d_device_context { ID2D1DeviceContext1 ID2D1DeviceContext1_iface; @@ -171,6 +173,7 @@ struct d2d_device_context const struct d2d_device_context_ops *ops;
ID2D1Factory *factory; + struct d2d_factory *factory_impl; struct d2d_device *device; ID3D11Device1 *d3d_device; ID3DDeviceContextState *d3d_state; @@ -678,12 +681,14 @@ struct d2d_effect_registration struct d2d_effect_properties properties; };
-struct d2d_factory; void d2d_effects_init_builtins(struct d2d_factory *factory); struct d2d_effect_registration * d2d_factory_get_registered_effect(ID2D1Factory *factory, const GUID *effect_id); void d2d_factory_register_effect(struct d2d_factory *factory, struct d2d_effect_registration *effect); +struct d2d_factory *d2d_factory_from_ID2D1Multithread(ID2D1Multithread *iface); +void d2d_factory_enter_cs(struct d2d_factory *factory); +void d2d_factory_leave_cs(struct d2d_factory *factory);
struct d2d_transform_graph { diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index e5548878ee9..75ac3a5b7c1 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -115,6 +115,14 @@ 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->factory_impl) d2d_factory_enter_cs(context->factory_impl); +} + +static inline void d2d_device_context_leave_cs(struct d2d_device_context *context) { + if (context->factory_impl) d2d_factory_leave_cs(context->factory_impl); +} + 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 +143,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 +198,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 +3208,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; + ID2D1Multithread *multithread; unsigned int i; HRESULT hr;
@@ -4256,6 +4269,14 @@ static HRESULT d2d_device_context_init(struct d2d_device_context *render_target, render_target->device = device; ID2D1Device1_AddRef(&render_target->device->ID2D1Device1_iface);
+ ID2D1Factory_QueryInterface(render_target->factory, &IID_ID2D1Multithread, (void **)&multithread); + if (ID2D1Multithread_GetMultithreadProtected(multithread)) { + render_target->factory_impl = d2d_factory_from_ID2D1Multithread(multithread); + } else { + render_target->factory_impl = NULL; + } + ID2D1Multithread_Release(multithread); + 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..f35bfe51ea1 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -63,11 +63,15 @@ static inline struct d2d_factory *unsafe_impl_from_ID2D1Factory(ID2D1Factory *if return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Factory3_iface); }
-static inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *iface) +inline struct d2d_factory *impl_from_ID2D1Multithread(ID2D1Multithread *iface) { return CONTAINING_RECORD(iface, struct d2d_factory, ID2D1Multithread_iface); }
+struct d2d_factory *d2d_factory_from_ID2D1Multithread(ID2D1Multithread *iface) { + return impl_from_ID2D1Multithread(iface); +} + static BOOL WINAPI d2d_factory_builtins_initonce(INIT_ONCE *once, void *param, void **context) { d2d_effects_init_builtins(param); @@ -1173,6 +1177,14 @@ 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; diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index f0e6f1ffb38..3b7b59ef49f 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -10778,7 +10778,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);