-- v3: d2d1: Implement D2D1ComputeMaximumScaleFactor().
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d2d1/tests/d2d1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c index f971d6dfe7d..1cded691d6c 100644 --- a/dlls/d2d1/tests/d2d1.c +++ b/dlls/d2d1/tests/d2d1.c @@ -15855,7 +15855,7 @@ static void test_no_target(BOOL d3d11)
START_TEST(d2d1) { - HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll"); + HMODULE d2d1_dll = LoadLibraryA("d2d1.dll"); unsigned int argc, i; char **argv;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/d2d1/d2d1.spec | 1 + dlls/d2d1/factory.c | 22 +++++++++++++++ dlls/d2d1/tests/d2d1.c | 61 ++++++++++++++++++++++++++++++++++++++++++ include/d2d1_2.idl | 2 ++ 4 files changed, 86 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..0487c3b1dfb 100644 --- a/dlls/d2d1/factory.c +++ b/dlls/d2d1/factory.c @@ -1445,6 +1445,28 @@ 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 refers to maximum value of |Mv|/|v| over all vectors, where |.| is vector length. + * That is defined as matrix spectral norm (see https://en.wikipedia.org/wiki/Matrix_norm, 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. + * (see https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors) */ + 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 1cded691d6c..fb322ab447c 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);
v3: - Remove 'stub' in TRACE; - Move function to other matrix functions; - Move prototype to d2d1_2.idl; - Update comment and add references to related Wikipedia articles.
Nikolay Sivov (@nsivov) commented about dlls/d2d1/tests/d2d1.c:
START_TEST(d2d1) {
- HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll");
- HMODULE d2d1_dll = LoadLibraryA("d2d1.dll"); unsigned int argc, i;
Why do we need this? We do import D2D1CreateFactory() and I do see any skips on Windows. Module pointer is not null on both Wine and Windows.
Nikolay Sivov (@nsivov) commented about dlls/d2d1/factory.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 refers to maximum value of |Mv|/|v| over all vectors, where |.| is vector length.
- That is defined as matrix spectral norm (see https://en.wikipedia.org/wiki/Matrix_norm, 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)));
Sorry, I missed that it's been said already that this is based on singular values. We don't really need any references for common characteristics like that, mentioning what it's based on is enough information to look up details. Formulas are fine to keep of course, but let's remove the links. Sorry for the noise.