From: Henri Verbeet Subject: [PATCH 8/9] d2d1: Bitmap values are always premultiplied in practice. Message-Id: <1437672732-31707-8-git-send-email-hverbeet@codeweavers.com> Date: Thu, 23 Jul 2015 19:32:11 +0200 Since creating bitmaps with D2D1_ALPHA_MODE_UNKNOWN or D2D1_ALPHA_MODE_STRAIGHT is not possible, and D2D1_ALPHA_MODE_IGNORE behaves as if alpha == 1.0f. --- dlls/d2d1/brush.c | 3 ++ dlls/d2d1/render_target.c | 17 +++--- dlls/d2d1/tests/d2d1.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 9 deletions(-) diff --git a/dlls/d2d1/brush.c b/dlls/d2d1/brush.c index b968a65..36d0a51 100644 --- a/dlls/d2d1/brush.c +++ b/dlls/d2d1/brush.c @@ -746,6 +746,9 @@ HRESULT d2d_brush_get_ps_cb(struct d2d_brush *brush, struct d2d_d3d_render_targe { color = brush->u.solid.color; color.a *= brush->opacity; + color.r *= color.a; + color.g *= color.a; + color.b *= color.a; buffer_desc.ByteWidth = sizeof(color); buffer_data.pSysMem = &color; diff --git a/dlls/d2d1/render_target.c b/dlls/d2d1/render_target.c index 1122446..925db33 100644 --- a/dlls/d2d1/render_target.c +++ b/dlls/d2d1/render_target.c @@ -1133,6 +1133,7 @@ static void STDMETHODCALLTYPE d2d_d3d_render_target_PopAxisAlignedClip(ID2D1Rend static void STDMETHODCALLTYPE d2d_d3d_render_target_Clear(ID2D1RenderTarget *iface, const D2D1_COLOR_F *color) { struct d2d_d3d_render_target *render_target = impl_from_ID2D1RenderTarget(iface); + D2D1_COLOR_F c = {0.0f, 0.0f, 0.0f, 0.0f}; D3D10_SUBRESOURCE_DATA buffer_data; D3D10_BUFFER_DESC buffer_desc; ID3D10Buffer *vs_cb, *ps_cb; @@ -1579,16 +1580,14 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, texcoord.x = position.x * transform._11 + position.y * transform._21 + transform._31; texcoord.y = position.x * transform._12 + position.y * transform._22 + transform._32; - ret = t.Sample(s, texcoord); + ret = t.Sample(s, texcoord) * opacity; if (ignore_alpha) ret.a = opacity; - else - ret.a *= opacity; return ret; } #endif - 0x43425844, 0xf2e9967c, 0xad1d1ac2, 0x865274b8, 0x6ab4c5ca, 0x00000001, 0x000001fc, 0x00000003, + 0x43425844, 0xf5bb1e01, 0xe3386963, 0xcaa095bd, 0xea2887de, 0x00000001, 0x000001fc, 0x00000003, 0x0000002c, 0x00000060, 0x00000094, 0x4e475349, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000001, 0x00000003, 0x00000000, 0x0000030f, 0x505f5653, 0x5449534f, 0x004e4f49, 0x4e47534f, 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, 0x00000003, @@ -1600,10 +1599,10 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, 0x0010000a, 0x00000000, 0x0020802a, 0x00000000, 0x00000000, 0x0800000f, 0x00100042, 0x00000000, 0x00101046, 0x00000000, 0x00208046, 0x00000000, 0x00000001, 0x08000000, 0x00100022, 0x00000000, 0x0010002a, 0x00000000, 0x0020802a, 0x00000000, 0x00000001, 0x09000045, 0x001000f2, 0x00000000, - 0x00100046, 0x00000000, 0x00107e46, 0x00000000, 0x00106000, 0x00000000, 0x08000038, 0x00100082, - 0x00000000, 0x0010003a, 0x00000000, 0x0020803a, 0x00000000, 0x00000001, 0x05000036, 0x00102072, - 0x00000000, 0x00100246, 0x00000000, 0x0b000037, 0x00102082, 0x00000000, 0x0020800a, 0x00000000, - 0x00000002, 0x0020803a, 0x00000000, 0x00000001, 0x0010003a, 0x00000000, 0x0100003e, + 0x00100046, 0x00000000, 0x00107e46, 0x00000000, 0x00106000, 0x00000000, 0x08000038, 0x001000f2, + 0x00000000, 0x00100e46, 0x00000000, 0x00208ff6, 0x00000000, 0x00000001, 0x0b000037, 0x00102082, + 0x00000000, 0x0020800a, 0x00000000, 0x00000002, 0x0020803a, 0x00000000, 0x00000001, 0x0010003a, + 0x00000000, 0x05000036, 0x00102072, 0x00000000, 0x00100246, 0x00000000, 0x0100003e, }; /* The basic idea here is to evaluate the implicit form of the curve in * texture space. "t.z" determines which side of the curve is shaded. */ @@ -1792,7 +1791,7 @@ HRESULT d2d_d3d_render_target_init(struct d2d_d3d_render_target *render_target, memset(&blend_desc, 0, sizeof(blend_desc)); blend_desc.BlendEnable[0] = TRUE; - blend_desc.SrcBlend = D3D10_BLEND_SRC_ALPHA; + blend_desc.SrcBlend = D3D10_BLEND_ONE; blend_desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA; blend_desc.BlendOp = D3D10_BLEND_OP_ADD; blend_desc.SrcBlendAlpha = D3D10_BLEND_ZERO; diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index 4c10df9..1119754 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -1627,6 +1627,140 @@ static void test_bitmap_formats(void) DestroyWindow(window); } +static void test_alpha_mode(void) +{ + D2D1_BITMAP_PROPERTIES bitmap_desc; + ID2D1SolidColorBrush *color_brush; + ID2D1BitmapBrush *bitmap_brush; + IDXGISwapChain *swapchain; + ID2D1RenderTarget *rt; + ID3D10Device1 *device; + IDXGISurface *surface; + ID2D1Bitmap *bitmap; + D2D1_COLOR_F color; + D2D1_RECT_F rect; + D2D1_SIZE_U size; + ULONG refcount; + HWND window; + HRESULT hr; + BOOL match; + + static const DWORD bitmap_data[] = + { + 0x7f7f0000, 0x7f7f7f00, 0x7f007f00, 0x7f007f7f, + 0x7f00007f, 0x7f7f007f, 0x7f000000, 0x7f404040, + 0x7f7f7f7f, 0x7f7f7f7f, 0x7f7f7f7f, 0x7f000000, + 0x7f7f7f7f, 0x7f000000, 0x7f000000, 0x7f000000, + }; + + if (!(device = create_device())) + { + skip("Failed to create device, skipping tests.\n"); + return; + } + window = CreateWindowA("static", "d2d1_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, 640, 480, NULL, NULL, NULL, NULL); + swapchain = create_swapchain(device, window, TRUE); + hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface, (void **)&surface); + ok(SUCCEEDED(hr), "Failed to get buffer, hr %#x.\n", hr); + rt = create_render_target(surface); + ok(!!rt, "Failed to create render target.\n"); + + ID2D1RenderTarget_SetAntialiasMode(rt, D2D1_ANTIALIAS_MODE_ALIASED); + + 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 / 40.0f; + bitmap_desc.dpiY = 96.0f / 30.0f; + hr = ID2D1RenderTarget_CreateBitmap(rt, size, bitmap_data, 4 * sizeof(*bitmap_data), &bitmap_desc, &bitmap); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + + hr = ID2D1RenderTarget_CreateBitmapBrush(rt, bitmap, NULL, NULL, &bitmap_brush); + ok(SUCCEEDED(hr), "Failed to create brush, hr %#x.\n", hr); + ID2D1BitmapBrush_SetInterpolationMode(bitmap_brush, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); + ID2D1BitmapBrush_SetExtendModeX(bitmap_brush, D2D1_EXTEND_MODE_WRAP); + ID2D1BitmapBrush_SetExtendModeY(bitmap_brush, D2D1_EXTEND_MODE_WRAP); + + set_color(&color, 0.0f, 1.0f, 0.0f, 0.75f); + hr = ID2D1RenderTarget_CreateSolidColorBrush(rt, &color, NULL, &color_brush); + ok(SUCCEEDED(hr), "Failed to create brush, hr %#x.\n", hr); + + ID2D1RenderTarget_BeginDraw(rt); + ID2D1RenderTarget_Clear(rt, NULL); + hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr); + match = compare_surface(surface, "b44510bf2d2e61a8d7c0ad862de49a471f1fd13f"); + ok(match, "Surface does not match.\n"); + + ID2D1RenderTarget_BeginDraw(rt); + set_color(&color, 1.0f, 0.0f, 0.0f, 0.25f); + ID2D1RenderTarget_Clear(rt, &color); + hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr); + match = compare_surface(surface, "2184f4a9198fc1de09ac85301b7a03eebadd9b81"); + ok(match, "Surface does not match.\n"); + + ID2D1RenderTarget_BeginDraw(rt); + set_color(&color, 0.0f, 0.0f, 1.0f, 0.75f); + ID2D1RenderTarget_Clear(rt, &color); + hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr); + match = compare_surface(surface, "6527ec83b4039c895b50f9b3e144fe0cf90d1889"); + ok(match, "Surface does not match.\n"); + + ID2D1RenderTarget_BeginDraw(rt); + + set_rect(&rect, 0.0f, 0.0f, 160.0f, 120.0f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)bitmap_brush); + set_rect(&rect, 160.0f, 0.0f, 320.0f, 120.0f); + ID2D1BitmapBrush_SetOpacity(bitmap_brush, 0.75f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)bitmap_brush); + set_rect(&rect, 320.0f, 0.0f, 480.0f, 120.0f); + ID2D1BitmapBrush_SetOpacity(bitmap_brush, 0.25f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)bitmap_brush); + + ID2D1Bitmap_Release(bitmap); + bitmap_desc.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; + hr = ID2D1RenderTarget_CreateBitmap(rt, size, bitmap_data, 4 * sizeof(*bitmap_data), &bitmap_desc, &bitmap); + ok(SUCCEEDED(hr), "Failed to create bitmap, hr %#x.\n", hr); + ID2D1BitmapBrush_SetBitmap(bitmap_brush, bitmap); + + set_rect(&rect, 0.0f, 120.0f, 160.0f, 240.0f); + ID2D1BitmapBrush_SetOpacity(bitmap_brush, 1.0f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)bitmap_brush); + set_rect(&rect, 160.0f, 120.0f, 320.0f, 240.0f); + ID2D1BitmapBrush_SetOpacity(bitmap_brush, 0.75f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)bitmap_brush); + set_rect(&rect, 320.0f, 120.0f, 480.0f, 240.0f); + ID2D1BitmapBrush_SetOpacity(bitmap_brush, 0.25f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)bitmap_brush); + + set_rect(&rect, 0.0f, 240.0f, 160.0f, 360.0f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)color_brush); + set_rect(&rect, 160.0f, 240.0f, 320.0f, 360.0f); + ID2D1SolidColorBrush_SetOpacity(color_brush, 0.75f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)color_brush); + set_rect(&rect, 320.0f, 240.0f, 480.0f, 360.0f); + ID2D1SolidColorBrush_SetOpacity(color_brush, 0.25f); + ID2D1RenderTarget_FillRectangle(rt, &rect, (ID2D1Brush *)color_brush); + + hr = ID2D1RenderTarget_EndDraw(rt, NULL, NULL); + ok(SUCCEEDED(hr), "Failed to end draw, hr %#x.\n", hr); + match = compare_surface(surface, "465f5a3190d7bde408b3206b4be939fb22f8a3d6"); + ok(match, "Surface does not match.\n"); + + refcount = ID2D1Bitmap_Release(bitmap); + ok(refcount == 1, "Bitmap has %u references left.\n", refcount); + ID2D1SolidColorBrush_Release(color_brush); + ID2D1BitmapBrush_Release(bitmap_brush); + ID2D1RenderTarget_Release(rt); + IDXGISurface_Release(surface); + IDXGISwapChain_Release(swapchain); + ID3D10Device1_Release(device); + DestroyWindow(window); +} + START_TEST(d2d1) { test_clip(); @@ -1635,4 +1769,5 @@ START_TEST(d2d1) test_bitmap_brush(); test_path_geometry(); test_bitmap_formats(); + test_alpha_mode(); } -- 2.1.4