Flutter Engine
The Flutter Engine
SkColorSpaceXformStepsTest.cpp
Go to the documentation of this file.
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
12#include "tests/Test.h"
13
14#include <cstdint>
15
17 auto srgb = SkColorSpace::MakeSRGB(),
20 srgb1 = srgb ->makeLinearGamma(),
21 adobe1 = adobe->makeLinearGamma();
22
24 opaque = kOpaque_SkAlphaType,
25 unpremul = kUnpremul_SkAlphaType;
26
27 struct Test {
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}
static BlurTest tests[]
Definition: BlurTest.cpp:84
kUnpremul_SkAlphaType
SkAlphaType
Definition: SkAlphaType.h:26
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
DEF_TEST(SkColorSpaceXformSteps, r)
static void encode(uint8_t output[16], const uint32_t input[4])
Definition: SkMD5.cpp:240
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
#define ERRORF(r,...)
Definition: Test.h:293
static uint32_t premul(uint32_t color)
sk_sp< SkColorSpace > makeLinearGamma() const
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static constexpr skcms_Matrix3x3 kSRGB
Definition: SkColorSpace.h:67
static constexpr skcms_Matrix3x3 kAdobeRGB
Definition: SkColorSpace.h:77
static constexpr skcms_TransferFunction k2Dot2
Definition: SkColorSpace.h:48
dst
Definition: cp.py:12