xref: /aosp_15_r20/external/skia/tests/SkColorSpaceXformStepsTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkColorSpace.h"
10 #include "include/core/SkRefCnt.h"
11 #include "src/core/SkColorSpaceXformSteps.h"
12 #include "tests/Test.h"
13 
14 #include <cstdint>
15 
DEF_TEST(SkColorSpaceXformSteps,r)16 DEF_TEST(SkColorSpaceXformSteps, r) {
17     auto srgb   = SkColorSpace::MakeSRGB(),
18          adobe  = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB),
19          srgb22 = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kSRGB),
20          srgb1  = srgb ->makeLinearGamma(),
21          adobe1 = adobe->makeLinearGamma();
22 
23     auto premul =   kPremul_SkAlphaType,
24          opaque =   kOpaque_SkAlphaType,
25        unpremul = kUnpremul_SkAlphaType;
26 
27     struct Test {
28         sk_sp<SkColorSpace> src, dst;
29         SkAlphaType         srcAT, dstAT;
30 
31         bool unpremul;
32         bool linearize;
33         bool gamut_transform;
34         bool encode;
35         bool premul;
36 
37     };
38     Test tests[] = {
39         // The general case is converting between two color spaces with different gamuts
40         // and different transfer functions.  There's no optimization possible here.
41         { adobe, srgb, premul, premul,
42             true,  // src is encoded as f(s)*a,a, so we unpremul to f(s),a before linearizing.
43             true,  // linearize to s,a
44             true,  // transform s to dst gamut, s'
45             true,  // encode with dst transfer function, g(s'), a
46             true,  // premul to g(s')*a, a
47         },
48         // All the same going the other direction.
49         { srgb, adobe, premul, premul,  true,true,true,true,true },
50 
51         // If the src alpha type is unpremul, we'll not need that initial unpremul step.
52         { adobe, srgb, unpremul, premul, false,true,true,true,true },
53         { srgb, adobe, unpremul, premul, false,true,true,true,true },
54 
55         // If opaque, we need neither the initial unpremul, nor the premul later.
56         { adobe, srgb, opaque, premul, false,true,true,true,false },
57         { srgb, adobe, opaque, premul, false,true,true,true,false },
58 
59 
60         // Now let's go between sRGB and sRGB with a 2.2 gamma, the gamut staying the same.
61         { srgb, srgb22, premul, premul,
62             true,  // we need to linearize, so we need to unpremul
63             true,  // we need to encode to 2.2 gamma, so we need to get linear
64             false, // no need to change gamut
65             true,  // linear -> gamma 2.2
66             true,  // premul going into the blend
67         },
68         // Same sort of logic in the other direction.
69         { srgb22, srgb, premul, premul,  true,true,false,true,true },
70 
71         // As in the general case, when we change the alpha type unpremul and premul steps drop out.
72         { srgb, srgb22, unpremul, premul, false,true,false,true,true },
73         { srgb22, srgb, unpremul, premul, false,true,false,true,true },
74         { srgb, srgb22,   opaque, premul, false,true,false,true,false },
75         { srgb22, srgb,   opaque, premul, false,true,false,true,false },
76 
77         // Let's look at the special case of completely matching color spaces.
78         // We should be ready to go into the blend without any fuss.
79         { srgb, srgb,   premul, premul, false,false,false,false,false },
80         { srgb, srgb, unpremul, premul, false,false,false,false,true },
81         { srgb, srgb,   opaque, premul, false,false,false,false,false },
82 
83         // We can drop out the linearize step when the source is already linear.
84         { srgb1, adobe,   premul, premul, true,false,true,true,true },
85         { srgb1,  srgb,   premul, premul, true,false,false,true,true },
86         // And we can drop the encode step when the destination is linear.
87         { adobe, srgb1,   premul, premul, true,true,true,false,true },
88         {  srgb, srgb1,   premul, premul, true,true,false,false,true },
89 
90         // Here's an interesting case where only gamut transform is needed.
91         { adobe1, srgb1,   premul, premul, false,false,true,false,false },
92         { adobe1, srgb1,   opaque, premul, false,false,true,false,false },
93         { adobe1, srgb1, unpremul, premul, false,false,true,false, true },
94 
95         // Just finishing up with something to produce each other possible output.
96         // Nothing terribly interesting in these eight.
97         { srgb,  srgb1,   opaque, premul, false, true,false,false,false },
98         { srgb,  srgb1, unpremul, premul, false, true,false,false, true },
99         { srgb, adobe1,   opaque, premul, false, true, true,false,false },
100         { srgb, adobe1, unpremul, premul, false, true, true,false, true },
101         { srgb1,  srgb,   opaque, premul, false,false,false, true,false },
102         { srgb1,  srgb, unpremul, premul, false,false,false, true, true },
103         { srgb1, adobe,   opaque, premul, false,false, true, true,false },
104         { srgb1, adobe, unpremul, premul, false,false, true, true, true },
105 
106         // Now test non-premul outputs.
107         { srgb , srgb  , premul, unpremul, true,false,false,false,false },
108         { srgb , srgb1 , premul, unpremul, true, true,false,false,false },
109         { srgb1, adobe1, premul, unpremul, true,false, true,false,false },
110         { srgb , adobe1, premul, unpremul, true, true, true,false,false },
111         { srgb1, srgb  , premul, unpremul, true,false,false, true,false },
112         { srgb , srgb22, premul, unpremul, true, true,false, true,false },
113         { srgb1, adobe , premul, unpremul, true,false, true, true,false },
114         { srgb , adobe , premul, unpremul, true, true, true, true,false },
115 
116         // Opaque outputs are treated as the same alpha type as the source input.
117         // TODO: we'd really like to have a good way of explaining why we think this is useful.
118         { srgb , srgb  , premul, opaque, false,false,false,false,false },
119         { srgb , srgb1 , premul, opaque,  true, true,false,false, true },
120         { srgb1, adobe1, premul, opaque, false,false, true,false,false },
121         { srgb , adobe1, premul, opaque,  true, true, true,false, true },
122         { srgb1, srgb  , premul, opaque,  true,false,false, true, true },
123         { srgb , srgb22, premul, opaque,  true, true,false, true, true },
124         { srgb1, adobe , premul, opaque,  true,false, true, true, true },
125         { srgb , adobe , premul, opaque,  true, true, true, true, true },
126 
127         { srgb , srgb  , unpremul, opaque, false,false,false,false,false },
128         { srgb , srgb1 , unpremul, opaque, false, true,false,false,false },
129         { srgb1, adobe1, unpremul, opaque, false,false, true,false,false },
130         { srgb , adobe1, unpremul, opaque, false, true, true,false,false },
131         { srgb1, srgb  , unpremul, opaque, false,false,false, true,false },
132         { srgb , srgb22, unpremul, opaque, false, true,false, true,false },
133         { srgb1, adobe , unpremul, opaque, false,false, true, true,false },
134         { srgb , adobe , unpremul, opaque, false, true, true, true,false },
135     };
136 
137     uint32_t tested = 0x00000000;
138     for (const Test& t : tests) {
139         SkColorSpaceXformSteps steps{t.src.get(), t.srcAT,
140                                      t.dst.get(), t.dstAT};
141         REPORTER_ASSERT(r, steps.flags.unpremul        == t.unpremul);
142         REPORTER_ASSERT(r, steps.flags.linearize       == t.linearize);
143         REPORTER_ASSERT(r, steps.flags.gamut_transform == t.gamut_transform);
144         REPORTER_ASSERT(r, steps.flags.encode          == t.encode);
145         REPORTER_ASSERT(r, steps.flags.premul          == t.premul);
146 
147         uint32_t bits = (uint32_t)t.unpremul        << 0
148                       | (uint32_t)t.linearize       << 1
149                       | (uint32_t)t.gamut_transform << 2
150                       | (uint32_t)t.encode          << 3
151                       | (uint32_t)t.premul          << 4;
152         tested |= (1<<bits);
153     }
154 
155     // We'll check our test cases cover all 2^5 == 32 possible outputs.
156     for (uint32_t t = 0; t < 32; t++) {
157         if (tested & (1<<t)) {
158             continue;
159         }
160 
161         // There are a couple impossible outputs, so consider those bits tested.
162         //
163         // Unpremul then premul should be optimized away to a noop, so 0b10001 isn't possible.
164         // A gamut transform in the middle is fine too, so 0b10101 isn't possible either.
165         if (t == 0b10001 || t == 0b10101) {
166             continue;
167         }
168 
169         ERRORF(r, "{ xxx, yyy, at, %s,%s,%s,%s,%s }, not covered",
170                 (t& 1) ? " true" : "false",
171                 (t& 2) ? " true" : "false",
172                 (t& 4) ? " true" : "false",
173                 (t& 8) ? " true" : "false",
174                 (t&16) ? " true" : "false");
175     }
176 }
177