Fixes a specific game's crash on startup.
`d2d_device_context_draw` doesn't accept `D2D_TARGET_UNKNOWN` because `render_target->target.bitmap->rtv` isn't reliably set when calling `ID3D11DeviceContext1_OMSetRenderTargets`. Therefore, we check for that condition and return early.
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/d2d1/device.c | 9 +++++++ dlls/d2d1/tests/d2d1.c | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+)
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 4780acb3bec..d9494d4f90b 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -1858,6 +1858,15 @@ static void STDMETHODCALLTYPE d2d_device_context_Clear(ID2D1DeviceContext6 *ifac
TRACE("iface %p, colour %p.\n", iface, colour);
+ if (FAILED(context->error.code)) + return; + + if (context->target.type == D2D_TARGET_UNKNOWN) + { + d2d_device_context_set_error(context, D2DERR_WRONG_STATE); + return; + } + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_clear(context->target.command_list, colour); diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 997ebc81ceb..215e3f2bea7 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15715,6 +15715,60 @@ static void test_get_dxgi_device(BOOL d3d11) release_test_context(&ctx); }
+static void test_no_target(BOOL d3d11) +{ + struct d2d1_test_context ctx; + ID2D1DeviceContext *context; + D2D1_MATRIX_3X2_F matrix; + ID2D1RenderTarget *rt; + ID2D1Device *device; + D2D1_TAG t1, t2; + HRESULT hr; + + if (!init_test_context(&ctx, d3d11)) + return; + + if (!ctx.factory1) + { + win_skip("ID2D1Factory1 is not supported.\n"); + release_test_context(&ctx); + return; + } + + hr = ID2D1Factory1_CreateDevice(ctx.factory1, ctx.device, &device); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID2D1Device_CreateDeviceContext(device, D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &context); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1DeviceContext_SetTarget(context, NULL); + + hr = ID2D1DeviceContext_QueryInterface(context, &IID_ID2D1RenderTarget, (void **)&rt); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + /* Clear method */ + ID2D1RenderTarget_BeginDraw(rt); + + set_matrix_identity(&matrix); + ID2D1RenderTarget_SetTags(rt, 0x10, 0x10); + ID2D1RenderTarget_SetTransform(rt, &matrix); + + ID2D1RenderTarget_SetTags(rt, 0x10, 0x20); + ID2D1RenderTarget_Clear(rt, 0); + + ID2D1RenderTarget_SetTags(rt, 0x10, 0x30); + ID2D1RenderTarget_Clear(rt, 0); + + hr = ID2D1RenderTarget_EndDraw(rt, &t1, &t2); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + ok(t1 == 0x10 && t2 == 0x20, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2)); + + ID2D1RenderTarget_Release(rt); + ID2D1DeviceContext_Release(context); + ID2D1Device_Release(device); + release_test_context(&ctx); +} + START_TEST(d2d1) { HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); @@ -15812,6 +15866,7 @@ START_TEST(d2d1) queue_test(test_wic_target_format); queue_test(test_effect_blob_property); queue_test(test_get_dxgi_device); + queue_test(test_no_target);
run_queued_tests(); }
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/d2d1/device.c | 27 +++++++++++++++++++++++++++ dlls/d2d1/tests/d2d1.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+)
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index d9494d4f90b..f6ff44cd32c 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -1216,6 +1216,15 @@ static void STDMETHODCALLTYPE d2d_device_context_DrawBitmap(ID2D1DeviceContext6 TRACE("iface %p, bitmap %p, dst_rect %s, opacity %.8e, interpolation_mode %#x, src_rect %s.\n", iface, bitmap, debug_d2d_rect_f(dst_rect), opacity, interpolation_mode, debug_d2d_rect_f(src_rect));
+ if (FAILED(context->error.code)) + return; + + if (context->target.type == D2D_TARGET_UNKNOWN) + { + d2d_device_context_set_error(context, D2DERR_WRONG_STATE); + return; + } + if (interpolation_mode != D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR && interpolation_mode != D2D1_BITMAP_INTERPOLATION_MODE_LINEAR) { @@ -2559,6 +2568,15 @@ static void STDMETHODCALLTYPE d2d_device_context_DrawImage(ID2D1DeviceContext6 * iface, image, debug_d2d_point_2f(target_offset), debug_d2d_rect_f(image_rect), interpolation_mode, composite_mode);
+ if (FAILED(context->error.code)) + return; + + if (context->target.type == D2D_TARGET_UNKNOWN) + { + d2d_device_context_set_error(context, D2DERR_WRONG_STATE); + return; + } + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_draw_image(context->target.command_list, image, target_offset, image_rect, @@ -2598,6 +2616,15 @@ static void STDMETHODCALLTYPE d2d_device_context_ID2D1DeviceContext_DrawBitmap(I iface, bitmap, debug_d2d_rect_f(dst_rect), opacity, interpolation_mode, debug_d2d_rect_f(src_rect), perspective_transform);
+ if (FAILED(context->error.code)) + return; + + if (context->target.type == D2D_TARGET_UNKNOWN) + { + d2d_device_context_set_error(context, D2DERR_WRONG_STATE); + return; + } + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_draw_bitmap(context->target.command_list, bitmap, dst_rect, opacity, interpolation_mode, diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 215e3f2bea7..8e2faf47c42 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15717,11 +15717,14 @@ static void test_get_dxgi_device(BOOL d3d11)
static void test_no_target(BOOL d3d11) { + D2D1_BITMAP_PROPERTIES bitmap_desc; struct d2d1_test_context ctx; ID2D1DeviceContext *context; D2D1_MATRIX_3X2_F matrix; ID2D1RenderTarget *rt; + ID2D1Bitmap *bitmap; ID2D1Device *device; + D2D1_SIZE_U size; D2D1_TAG t1, t2; HRESULT hr;
@@ -15763,6 +15766,32 @@ static void test_no_target(BOOL d3d11) ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); ok(t1 == 0x10 && t2 == 0x20, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2));
+ /* DrawBitmap method */ + set_size_u(&size, 4, 4); + bitmap_desc.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; + bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_IGNORE; + bitmap_desc.dpiX = 96.0f; + bitmap_desc.dpiY = 96.0f; + hr = ID2D1RenderTarget_CreateBitmap(rt, size, NULL, 0, &bitmap_desc, &bitmap); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1RenderTarget_BeginDraw(rt); + + ID2D1DeviceContext_SetTags(context, 0x20, 0x10); + ID2D1DeviceContext_SetPrimitiveBlend(context, D2D1_PRIMITIVE_BLEND_SOURCE_OVER); + + ID2D1RenderTarget_SetTags(rt, 0x20, 0x20); + ID2D1RenderTarget_DrawBitmap(rt, bitmap, NULL, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, NULL); + + ID2D1RenderTarget_SetTags(rt, 0x20, 0x30); + ID2D1RenderTarget_DrawBitmap(rt, bitmap, NULL, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, NULL); + + hr = ID2D1RenderTarget_EndDraw(rt, &t1, &t2); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + ok(t1 == 0x20 && t2 == 0x20, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2)); + + ID2D1Bitmap_Release(bitmap); + ID2D1RenderTarget_Release(rt); ID2D1DeviceContext_Release(context); ID2D1Device_Release(device);
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/d2d1/device.c | 21 +++++++++++++++++++++ dlls/d2d1/tests/d2d1.c | 24 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index f6ff44cd32c..e06bbb32cb1 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -586,6 +586,9 @@ static void STDMETHODCALLTYPE d2d_device_context_DrawLine(ID2D1DeviceContext6 *i TRACE("iface %p, p0 %s, p1 %s, brush %p, stroke_width %.8e, stroke_style %p.\n", iface, debug_d2d_point_2f(&p0), debug_d2d_point_2f(&p1), brush, stroke_width, stroke_style);
+ if (FAILED(context->error.code)) + return; + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_draw_line(context->target.command_list, context, p0, p1, brush, stroke_width, stroke_style); @@ -626,6 +629,9 @@ static void STDMETHODCALLTYPE d2d_device_context_DrawRectangle(ID2D1DeviceContex TRACE("iface %p, rect %s, brush %p, stroke_width %.8e, stroke_style %p.\n", iface, debug_d2d_rect_f(rect), brush, stroke_width, stroke_style);
+ if (FAILED(context->error.code)) + return; + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_draw_rectangle(context->target.command_list, context, rect, brush, stroke_width, stroke_style); @@ -677,6 +683,9 @@ static void STDMETHODCALLTYPE d2d_device_context_DrawRoundedRectangle(ID2D1Devic TRACE("iface %p, rect %p, brush %p, stroke_width %.8e, stroke_style %p.\n", iface, rect, brush, stroke_width, stroke_style);
+ if (FAILED(render_target->error.code)) + return; + if (FAILED(hr = ID2D1Factory_CreateRoundedRectangleGeometry(render_target->factory, rect, &geometry))) { ERR("Failed to create geometry, hr %#lx.\n", hr); @@ -716,6 +725,9 @@ static void STDMETHODCALLTYPE d2d_device_context_DrawEllipse(ID2D1DeviceContext6 TRACE("iface %p, ellipse %p, brush %p, stroke_width %.8e, stroke_style %p.\n", iface, ellipse, brush, stroke_width, stroke_style);
+ if (FAILED(render_target->error.code)) + return; + if (FAILED(hr = ID2D1Factory_CreateEllipseGeometry(render_target->factory, ellipse, &geometry))) { ERR("Failed to create geometry, hr %#lx.\n", hr); @@ -961,6 +973,15 @@ static void STDMETHODCALLTYPE d2d_device_context_DrawGeometry(ID2D1DeviceContext TRACE("iface %p, geometry %p, brush %p, stroke_width %.8e, stroke_style %p.\n", iface, geometry, brush, stroke_width, stroke_style);
+ if (FAILED(context->error.code)) + return; + + if (context->target.type == D2D_TARGET_UNKNOWN) + { + d2d_device_context_set_error(context, D2DERR_WRONG_STATE); + return; + } + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_draw_geometry(context->target.command_list, context, geometry, brush, diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 8e2faf47c42..fe993d11ad1 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15719,12 +15719,15 @@ static void test_no_target(BOOL d3d11) { D2D1_BITMAP_PROPERTIES bitmap_desc; struct d2d1_test_context ctx; + ID2D1SolidColorBrush *brush; ID2D1DeviceContext *context; D2D1_MATRIX_3X2_F matrix; ID2D1RenderTarget *rt; ID2D1Bitmap *bitmap; ID2D1Device *device; + D2D1_COLOR_F color; D2D1_SIZE_U size; + D2D1_RECT_F rect; D2D1_TAG t1, t2; HRESULT hr;
@@ -15792,6 +15795,27 @@ static void test_no_target(BOOL d3d11)
ID2D1Bitmap_Release(bitmap);
+ /* DrawRectagnle method */ + set_color(&color, 0.0f, 0.0f, 0.0f, 0.0f); + hr = ID2D1RenderTarget_CreateSolidColorBrush(rt, &color, NULL, &brush); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + set_rect(&rect, 0.0f, 0.0f, 1.0f, 1.0f); + + ID2D1RenderTarget_BeginDraw(rt); + + ID2D1RenderTarget_SetTags(rt, 0x30, 0x10); + ID2D1RenderTarget_DrawRectangle(rt, &rect, (ID2D1Brush *)brush, 1.0f, NULL); + + ID2D1RenderTarget_SetTags(rt, 0x30, 0x20); + ID2D1RenderTarget_DrawRectangle(rt, &rect, (ID2D1Brush *)brush, 1.0f, NULL); + + hr = ID2D1RenderTarget_EndDraw(rt, &t1, &t2); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + ok(t1 == 0x30 && t2 == 0x10, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2)); + + ID2D1SolidColorBrush_Release(brush); + ID2D1RenderTarget_Release(rt); ID2D1DeviceContext_Release(context); ID2D1Device_Release(device);
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/d2d1/device.c | 8 ++++++++ dlls/d2d1/tests/d2d1.c | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+)
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index 4246b84979f..4a781033499 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -129,6 +129,8 @@ static void d2d_device_context_draw(struct d2d_device_context *render_target, en unsigned int offset; D3D11_VIEWPORT vp;
+ assert(render_target->target.type == D2D_TARGET_BITMAP); + vp.TopLeftX = 0; vp.TopLeftY = 0; vp.Width = render_target->pixel_size.width; @@ -1549,6 +1551,12 @@ static void d2d_device_context_draw_glyph_run(struct d2d_device_context *context if (FAILED(context->error.code)) return;
+ if (context->target.type == D2D_TARGET_UNKNOWN) + { + d2d_device_context_set_error(context, D2DERR_WRONG_STATE); + return; + } + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_draw_glyph_run(context->target.command_list, context, baseline_origin, glyph_run, diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index e7673a9dbeb..16285b104f9 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15718,6 +15718,8 @@ static void test_get_dxgi_device(BOOL d3d11) static void test_no_target(BOOL d3d11) { D2D1_BITMAP_PROPERTIES bitmap_desc; + IDWriteFactory *dwrite_factory; + IDWriteTextFormat *text_format; struct d2d1_test_context ctx; ID2D1SolidColorBrush *brush; ID2D1DeviceContext *context; @@ -15827,6 +15829,28 @@ static void test_no_target(BOOL d3d11) ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); ok(t1 == 0x40 && t2 == 0x10, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2));
+ /* DrawText method */ + hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, &IID_IDWriteFactory, (IUnknown **)&dwrite_factory); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDWriteFactory_CreateTextFormat(dwrite_factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, + DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"", &text_format); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + ID2D1RenderTarget_BeginDraw(rt); + + ID2D1RenderTarget_SetTags(rt, 0x50, 0x10); + ID2D1RenderTarget_DrawText(rt, L"Wine", 4, text_format, &rect, (ID2D1Brush *)brush, D2D1_DRAW_TEXT_OPTIONS_NONE, DWRITE_MEASURING_MODE_NATURAL); + + ID2D1RenderTarget_SetTags(rt, 0x50, 0x20); + ID2D1RenderTarget_DrawText(rt, L"Wine", 4, text_format, &rect, (ID2D1Brush *)brush, D2D1_DRAW_TEXT_OPTIONS_NONE, DWRITE_MEASURING_MODE_NATURAL); + + hr = ID2D1RenderTarget_EndDraw(rt, &t1, &t2); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + ok(t1 == 0x50 && t2 == 0x10, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2)); + + IDWriteTextFormat_Release(text_format); + IDWriteFactory_Release(dwrite_factory); + ID2D1SolidColorBrush_Release(brush);
ID2D1RenderTarget_Release(rt);
From: Akihiro Sagawa sagawa.aki@gmail.com
--- dlls/d2d1/device.c | 15 +++++++++++++++ dlls/d2d1/tests/d2d1.c | 13 +++++++++++++ 2 files changed, 28 insertions(+)
diff --git a/dlls/d2d1/device.c b/dlls/d2d1/device.c index e06bbb32cb1..4246b84979f 100644 --- a/dlls/d2d1/device.c +++ b/dlls/d2d1/device.c @@ -657,6 +657,9 @@ static void STDMETHODCALLTYPE d2d_device_context_FillRectangle(ID2D1DeviceContex
TRACE("iface %p, rect %s, brush %p.\n", iface, debug_d2d_rect_f(rect), brush);
+ if (FAILED(context->error.code)) + return; + if (context->target.type == D2D_TARGET_COMMAND_LIST) { d2d_command_list_fill_rectangle(context->target.command_list, context, rect, brush); @@ -705,6 +708,9 @@ static void STDMETHODCALLTYPE d2d_device_context_FillRoundedRectangle(ID2D1Devic
TRACE("iface %p, rect %p, brush %p.\n", iface, rect, brush);
+ if (FAILED(render_target->error.code)) + return; + if (FAILED(hr = ID2D1Factory_CreateRoundedRectangleGeometry(render_target->factory, rect, &geometry))) { ERR("Failed to create geometry, hr %#lx.\n", hr); @@ -747,6 +753,9 @@ static void STDMETHODCALLTYPE d2d_device_context_FillEllipse(ID2D1DeviceContext6
TRACE("iface %p, ellipse %p, brush %p.\n", iface, ellipse, brush);
+ if (FAILED(render_target->error.code)) + return; + if (FAILED(hr = ID2D1Factory_CreateEllipseGeometry(render_target->factory, ellipse, &geometry))) { ERR("Failed to create geometry, hr %#lx.\n", hr); @@ -1109,6 +1118,12 @@ static void STDMETHODCALLTYPE d2d_device_context_FillGeometry(ID2D1DeviceContext if (FAILED(context->error.code)) return;
+ if (context->target.type == D2D_TARGET_UNKNOWN) + { + d2d_device_context_set_error(context, D2DERR_WRONG_STATE); + return; + } + if (opacity_brush && brush_impl->type != D2D_BRUSH_TYPE_BITMAP) { d2d_device_context_set_error(context, D2DERR_INCOMPATIBLE_BRUSH_TYPES); diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index fe993d11ad1..e7673a9dbeb 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15814,6 +15814,19 @@ static void test_no_target(BOOL d3d11) ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); ok(t1 == 0x30 && t2 == 0x10, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2));
+ /* FillRectangle method */ + ID2D1RenderTarget_BeginDraw(rt); + + ID2D1RenderTarget_SetTags(rt, 0x40, 0x10); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)brush); + + ID2D1RenderTarget_SetTags(rt, 0x40, 0x20); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)brush); + + hr = ID2D1RenderTarget_EndDraw(rt, &t1, &t2); + ok(hr == D2DERR_WRONG_STATE, "Got unexpected hr %#lx.\n", hr); + ok(t1 == 0x40 && t2 == 0x10, "Unexpected tags %s:%s.\n", wine_dbgstr_longlong(t1), wine_dbgstr_longlong(t2)); + ID2D1SolidColorBrush_Release(brush);
ID2D1RenderTarget_Release(rt);