-- v5: d2d1: Implement D2D1ComputeMaximumScaleFactor().
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d2d1/d2d1.spec | 1 + dlls/d2d1/factory.c | 21 +++++++++++++++ dlls/d2d1/tests/d2d1.c | 61 ++++++++++++++++++++++++++++++++++++++++++ include/d2d1_2.idl | 2 ++ 4 files changed, 85 insertions(+)
diff --git a/dlls/d2d1/d2d1.spec b/dlls/d2d1/d2d1.spec index 3fa85a93bae..b44d7114044 100644 --- a/dlls/d2d1/d2d1.spec +++ b/dlls/d2d1/d2d1.spec @@ -9,3 +9,4 @@ @ stdcall D2D1SinCos(float ptr ptr) @ stdcall D2D1Tan(float) @ stdcall D2D1Vec3Length(float float float) +@ stdcall D2D1ComputeMaximumScaleFactor(ptr) diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c index 1294d8c8fa3..62cbeeb51dd 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -1445,6 +1445,27 @@ BOOL WINAPI D2D1InvertMatrix(D2D1_MATRIX_3X2_F *matrix) return d2d_matrix_invert(matrix, &m); }
+float WINAPI D2D1ComputeMaximumScaleFactor(const D2D1_MATRIX_3X2_F *matrix) +{ + const float (*m)[2] = matrix->m; + float a1, a2, c; + + TRACE("matrix %p.\n", matrix); + + /* 2x2 matrix, _31 and _32 are ignored. */ + a1 = m[0][0] * m[0][0] + m[1][0] * m[1][0]; + a2 = m[0][1] * m[0][1] + m[1][1] * m[1][1]; + c = m[0][0] * m[0][1] + m[1][0] * m[1][1]; + + /* Maximum scale factor of matrix M refers to maximum value of |Mv|/|v| over all vectors v, where |.| is + * vector length. That is defined as matrix spectral norm. Spectral norm equals to the maximum of the + * singular values s1, s2 for 2x2 matrix M. + * s_i^2 = e_i where e_i (e1, e2) are eigenvalues of (transpose(M) * M) + * e1 + e2 = trace(transpose(M) * M) = a1 + a2 + * e1 * e2 = det(transpose(M) * M) = a1 * a2 - c ^ 2. */ + return sqrtf(0.5f * (a1 + a2 + sqrtf((a1 - a2) * (a1 - a2) + 4 * c * c))); +} + HRESULT WINAPI D2D1CreateDevice(IDXGIDevice *dxgi_device, const D2D1_CREATION_PROPERTIES *properties, ID2D1Device **device) { diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index f971d6dfe7d..12c199e2377 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -297,6 +297,7 @@ static HRESULT (WINAPI *pD2D1CreateDevice)(IDXGIDevice *dxgi_device, static void (WINAPI *pD2D1SinCos)(float angle, float *s, float *c); static float (WINAPI *pD2D1Tan)(float angle); static float (WINAPI *pD2D1Vec3Length)(float x, float y, float z); +static float (WINAPI *pD2D1ComputeMaximumScaleFactor)(const D2D1_MATRIX_3X2_F *matrix); static D2D1_COLOR_F (WINAPI *pD2D1ConvertColorSpace)(D2D1_COLOR_SPACE src_colour_space, D2D1_COLOR_SPACE dst_colour_space, const D2D1_COLOR_F *colour);
@@ -10689,6 +10690,52 @@ static void test_math(BOOL d3d11) {1.0f, 2.0f, 3.0f, 3.74165750f}, };
+ static const struct + { + D2D1_MATRIX_3X2_F mat; + float res; + } + scale_factor_tests[] = + { + { + .mat = {.m = + {{0.0f, 0.0f}, + {0.0f, 0.0f}, + {0.0f, 0.0f}, + }}, + 0.0f, + }, + { + .mat = {.m = + {{-3.0f, 0.0f}, + { 0.0f, 2.0f}, + { 2.0f, 1.0f}, + }}, + 3.0f, + }, + { + .mat = {.m = + {{-3.0f, 1.0f}, + { 2.0f, 2.0f}, + }}, + 3.62258267f, + }, + { + .mat = {.m = + {{1.0f, -1.0f}, + {1.0f, 1.0f}, + }}, + 1.41421354f, + }, + { + .mat = {.m = + {{0.0f, 1.0f}, + {2.0f, 0.0f}, + }}, + 2.0f, + }, + }; + if (!pD2D1SinCos || !pD2D1Tan || !pD2D1Vec3Length) { win_skip("D2D1SinCos/D2D1Tan/D2D1Vec3Length not available, skipping test.\n"); @@ -10717,6 +10764,19 @@ static void test_math(BOOL d3d11) ok(compare_float(l, l_data[i].l, 0), "Test %u: Got unexpected length %.8e, expected %.8e.\n", i, l, l_data[i].l); } + + if (!pD2D1ComputeMaximumScaleFactor) + { + win_skip(" D2D1ComputeMaximumScaleFactor not available, skipping test.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(scale_factor_tests); ++i) + { + s = pD2D1ComputeMaximumScaleFactor(&scale_factor_tests[i].mat); + ok(compare_float(s, scale_factor_tests[i].res, 1), + "Test %u: Got unexpected factor %.8e, expected %.8e.\n", i, s, scale_factor_tests[i].res); + } }
static void test_colour_space(BOOL d3d11) @@ -15864,6 +15924,7 @@ START_TEST(d2d1) pD2D1Tan = (void *)GetProcAddress(d2d1_dll, "D2D1Tan"); pD2D1Vec3Length = (void *)GetProcAddress(d2d1_dll, "D2D1Vec3Length"); pD2D1ConvertColorSpace = (void *)GetProcAddress(d2d1_dll, "D2D1ConvertColorSpace"); + pD2D1ComputeMaximumScaleFactor = (void *)GetProcAddress(d2d1_dll, "D2D1ComputeMaximumScaleFactor");
use_mt = !getenv("WINETEST_NO_MT_D3D"); /* Some host drivers (MacOS, Mesa radeonsi) never unmap memory even when diff --git a/include/d2d1_2.idl b/include/d2d1_2.idl index 982131667df..c4cb06e4300 100644 --- a/include/d2d1_2.idl +++ b/include/d2d1_2.idl @@ -101,3 +101,5 @@ interface ID2D1CommandSink1 : ID2D1CommandSink [in] D2D1_PRIMITIVE_BLEND primitive_blend ); } + +[local] float __stdcall D2D1ComputeMaximumScaleFactor(const D2D1_MATRIX_3X2_F *matrix);
This merge request was approved by Nikolay Sivov.