[PATCH v2] d2d1: Implement D2D1ConvertColorSpace.

Giovanni Mascellani gmascellani at codeweavers.com
Wed Mar 3 10:54:14 CST 2021


From: Giovanni Mascellani <wine at mascellani.eu>

Signed-off-by: Giovanni Mascellani <gmascellani at codeweavers.com>
---
 dlls/d2d1/d2d1.spec    |  2 +-
 dlls/d2d1/factory.c    | 69 ++++++++++++++++++++++++++++++++
 dlls/d2d1/tests/d2d1.c | 91 ++++++++++++++++++++++++++++++++++++++++++
 include/d2d1_1.idl     |  2 +
 4 files changed, 163 insertions(+), 1 deletion(-)

diff --git a/dlls/d2d1/d2d1.spec b/dlls/d2d1/d2d1.spec
index 0ae894109fb..3fa85a93bae 100644
--- a/dlls/d2d1/d2d1.spec
+++ b/dlls/d2d1/d2d1.spec
@@ -3,7 +3,7 @@
 @ stdcall D2D1MakeSkewMatrix(float float float float ptr)
 @ stdcall D2D1IsMatrixInvertible(ptr)
 @ stdcall D2D1InvertMatrix(ptr)
-@ stub D2D1ConvertColorSpace
+@ stdcall D2D1ConvertColorSpace(long long ptr)
 @ stdcall D2D1CreateDevice(ptr ptr ptr)
 @ stub D2D1CreateDeviceContext
 @ stdcall D2D1SinCos(float ptr ptr)
diff --git a/dlls/d2d1/factory.c b/dlls/d2d1/factory.c
index 6b6eab766c7..2e502003576 100644
--- a/dlls/d2d1/factory.c
+++ b/dlls/d2d1/factory.c
@@ -735,6 +735,75 @@ float WINAPI D2D1Vec3Length(float x, float y, float z)
     return sqrtf(x * x + y * y + z * z);
 }
 
+/* Formulae taken from IEC 61966-2-1:1999; see also
+   https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_sRGB.txt. */
+static float srgb_transfer_function(float x)
+{
+    if (x <= 0.0f)
+        return 0.0f;
+    else if (x >= 1.0f)
+        return 1.0f;
+    else if (x <= 0.0031308f)
+        return 12.92f * x;
+    else
+        return 1.055f * powf(x, 1.0f / 2.4f) - 0.055f;
+}
+
+static float srgb_inverse_transfer_function(float x)
+{
+    if (x <= 0.0f)
+        return 0.0f;
+    else if (x >= 1.0f)
+        return 1.0f;
+    else if (x <= 0.04045f)
+        return x / 12.92f;
+    else
+        return powf((x + 0.055f) / 1.055f, 2.4f);
+}
+
+D2D1_COLOR_F WINAPI D2D1ConvertColorSpace(D2D1_COLOR_SPACE source_color_space,
+        D2D1_COLOR_SPACE destination_color_space, const D2D1_COLOR_F *color)
+{
+    D2D1_COLOR_F ret;
+
+    if (source_color_space == D2D1_COLOR_SPACE_CUSTOM || destination_color_space == D2D1_COLOR_SPACE_CUSTOM)
+    {
+        ret.r = 0.0f;
+        ret.g = 0.0f;
+        ret.b = 0.0f;
+        ret.a = 0.0f;
+    }
+    else if (source_color_space == destination_color_space)
+    {
+        ret = *color;
+    }
+    else if (source_color_space == D2D1_COLOR_SPACE_SRGB && destination_color_space == D2D1_COLOR_SPACE_SCRGB)
+    {
+        ret.r = srgb_inverse_transfer_function(color->r);
+        ret.g = srgb_inverse_transfer_function(color->g);
+        ret.b = srgb_inverse_transfer_function(color->b);
+        ret.a = color->a;
+    }
+    else if (source_color_space == D2D1_COLOR_SPACE_SCRGB && destination_color_space == D2D1_COLOR_SPACE_SRGB)
+    {
+        ret.r = srgb_transfer_function(color->r);
+        ret.g = srgb_transfer_function(color->g);
+        ret.b = srgb_transfer_function(color->b);
+        ret.a = color->a;
+    }
+    else
+    {
+        FIXME("unknown combination source_color_space %#x, destination_color_space %#x!\n",
+                source_color_space, destination_color_space);
+        ret.r = 0.0f;
+        ret.g = 0.0f;
+        ret.b = 0.0f;
+        ret.a = 0.0f;
+    }
+
+    return ret;
+}
+
 static BOOL get_config_key_dword(HKEY default_key, HKEY application_key, const char *name, DWORD *value)
 {
     DWORD type, data, size;
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 8d584605819..b23ddaa767c 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -34,6 +34,8 @@ 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 D2D1_COLOR_F (WINAPI *pD2D1ConvertColorSpace)(D2D1_COLOR_SPACE source_color_space,
+        D2D1_COLOR_SPACE destination_color_space, const D2D1_COLOR_F *color);
 
 static BOOL use_mt = TRUE;
 
@@ -9466,6 +9468,93 @@ static void test_math(BOOL d3d11)
     }
 }
 
+static void test_color_space(BOOL d3d11)
+{
+    D2D1_COLOR_SPACE srcS, dstS;
+    unsigned i, j;
+
+    static struct {
+        D2D1_COLOR_F srgb;
+        D2D1_COLOR_F scrgb;
+    }
+    const test_data[] =
+    {
+        {{0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f}},
+        {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 1.0f}},
+        {{1.0f, 1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}},
+        /* Samples in the non-linear region. */
+        {{0.2f, 0.4f, 0.6f, 0.8f}, {0.0331047624f, 0.132868335f, 0.318546832f, 0.8f}},
+        {{0.3f, 0.5f, 0.7f, 0.9f}, {0.0732389688f, 0.214041144f, 0.447988421f, 0.9f}},
+        /* Samples in the linear region. */
+        {{0.0002f, 0.0004f, 0.0006f, 0.0008f}, {1.54798763e-005f, 3.09597526e-005f, 4.64396289e-005f, 0.0008f}},
+        {{0.0003f, 0.0005f, 0.0007f, 0.0009f}, {2.32198145e-005f, 3.86996908e-005f, 5.41795634e-005f, 0.0009f}},
+    };
+
+    if (!pD2D1ConvertColorSpace)
+    {
+        win_skip("D2D1ConvertColorSpace not available, skipping test.\n");
+        return;
+    }
+
+    for (srcS = 0; srcS < 3; srcS++)
+        for (dstS = 0; dstS < 3; dstS++)
+            for (i = 0; i < ARRAY_SIZE(test_data); i++)
+                for (j = 0; j < 3; j++)
+                {
+                    D2D1_COLOR_F src = test_data[i].srgb, dst, expect;
+                    BOOL change_expect = TRUE;
+
+                    if (srcS == D2D1_COLOR_SPACE_SCRGB)
+                        src = test_data[i].scrgb;
+                    if (srcS == D2D1_COLOR_SPACE_CUSTOM || dstS == D2D1_COLOR_SPACE_CUSTOM)
+                    {
+                        expect.r = 0.0f;
+                        expect.g = 0.0f;
+                        expect.b = 0.0f;
+                        expect.a = 0.0f;
+                        change_expect = FALSE;
+                    }
+                    else if (srcS == dstS)
+                        expect = src;
+                    else if (dstS == D2D1_COLOR_SPACE_SRGB)
+                        expect = test_data[i].srgb;
+                    else if (dstS == D2D1_COLOR_SPACE_SCRGB)
+                        expect = test_data[i].scrgb;
+                    else
+                        ok(0, "Should not arrive here.\n");
+
+                    /* Test underflowing or overflowing some components. */
+                    if (j == 1)
+                    {
+                        src.r = -0.5f;
+                        src.a = -0.7f;
+                        if (change_expect)
+                        {
+                            expect.r = srcS == dstS ? src.r : 0.0f;
+                            expect.a = src.a;
+                        }
+                    }
+                    else if (j == 2)
+                    {
+                        src.g = 1.5f;
+                        src.a = 1.7f;
+                        if (change_expect)
+                        {
+                            expect.g = srcS == dstS ? src.g : 1.0f;
+                            expect.a = src.a;
+                        }
+                    }
+
+                    dst = pD2D1ConvertColorSpace(srcS, dstS, &src);
+                    ok(compare_float(dst.r, expect.r, 1) && compare_float(dst.g, expect.g, 1)
+                            && compare_float(dst.b, expect.b, 1) && compare_float(dst.a, expect.a, 1),
+                            "Unexpected value {%.8e, %.8e, %.8e, %.8e} -> {%.8e, %.8e, %.8e, %.8e}, "
+                            "expected {%.8e, %.8e, %.8e, %.8e}, while converting %#x -> %#x.\n",
+                            src.r, src.g, src.b, src.a, dst.r, dst.g, dst.b, dst.a,
+                            expect.r, expect.g, expect.b, expect.a, srcS, dstS);
+            }
+}
+
 START_TEST(d2d1)
 {
     HMODULE d2d1_dll = GetModuleHandleA("d2d1.dll");
@@ -9476,6 +9565,7 @@ START_TEST(d2d1)
     pD2D1SinCos = (void *)GetProcAddress(d2d1_dll, "D2D1SinCos");
     pD2D1Tan = (void *)GetProcAddress(d2d1_dll, "D2D1Tan");
     pD2D1Vec3Length = (void *)GetProcAddress(d2d1_dll, "D2D1Vec3Length");
+    pD2D1ConvertColorSpace = (void *)GetProcAddress(d2d1_dll, "D2D1ConvertColorSpace");
 
     use_mt = !getenv("WINETEST_NO_MT_D3D");
 
@@ -9523,6 +9613,7 @@ START_TEST(d2d1)
     queue_test(test_dpi);
     queue_test(test_wic_bitmap_format);
     queue_d3d10_test(test_math);
+    queue_d3d10_test(test_color_space);
 
     run_queued_tests();
 }
diff --git a/include/d2d1_1.idl b/include/d2d1_1.idl
index 1bcadab01d5..1a2ddcb90fb 100644
--- a/include/d2d1_1.idl
+++ b/include/d2d1_1.idl
@@ -962,3 +962,5 @@ interface ID2D1Multithread : IUnknown
 [local] void __stdcall D2D1SinCos(float angle, float *s, float *c);
 [local] float __stdcall D2D1Tan(float angle);
 [local] float __stdcall D2D1Vec3Length(float x, float y, float z);
+[local] D2D1_COLOR_F __stdcall D2D1ConvertColorSpace(D2D1_COLOR_SPACE source_color_space,
+        D2D1_COLOR_SPACE destination_color_space, const D2D1_COLOR_F *color);
-- 
2.30.1




More information about the wine-devel mailing list