Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(252)

Side by Side Diff: tests/ColorSpaceXformTest.cpp

Issue 2449243003: Initial implementation of a SkColorSpace_A2B xform (Closed)
Patch Set: updated implementation to use SkRasterPipeline Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "Resources.h" 8 #include "Resources.h"
9 #include "SkCodec.h" 9 #include "SkCodec.h"
10 #include "SkCodecPriv.h" 10 #include "SkCodecPriv.h"
11 #include "SkColorPriv.h" 11 #include "SkColorPriv.h"
12 #include "SkColorSpace.h" 12 #include "SkColorSpace.h"
13 #include "SkColorSpace_A2B.h"
13 #include "SkColorSpace_Base.h" 14 #include "SkColorSpace_Base.h"
14 #include "SkColorSpace_XYZ.h" 15 #include "SkColorSpace_XYZ.h"
15 #include "SkColorSpaceXform_Base.h" 16 #include "SkColorSpaceXform_Base.h"
16 #include "Test.h" 17 #include "Test.h"
17 18
18 class ColorSpaceXformTest { 19 class ColorSpaceXformTest {
19 public: 20 public:
20 static std::unique_ptr<SkColorSpaceXform> CreateIdentityXform(const sk_sp<Sk Gammas>& gammas) { 21 static std::unique_ptr<SkColorSpaceXform> CreateIdentityXform(const sk_sp<Sk Gammas>& gammas) {
21 // Logically we can pass any matrix here. For simplicty, pass I(), i.e. D50 XYZ gamut. 22 // Logically we can pass any matrix here. For simplicty, pass I(), i.e. D50 XYZ gamut.
22 sk_sp<SkColorSpace> space(new SkColorSpace_XYZ( 23 sk_sp<SkColorSpace> space(new SkColorSpace_XYZ(
23 kNonStandard_SkGammaNamed, gammas, SkMatrix::I(), nullptr)); 24 kNonStandard_SkGammaNamed, gammas, SkMatrix::I(), nullptr));
24 25
25 // Use special testing entry point, so we don't skip the xform, even tho ugh src == dst. 26 // Use special testing entry point, so we don't skip the xform, even tho ugh src == dst.
26 return SlowIdentityXform(static_cast<SkColorSpace_XYZ*>(space.get())); 27 return SlowIdentityXform(static_cast<SkColorSpace_XYZ*>(space.get()));
27 } 28 }
29
30 static std::unique_ptr<SkColorSpaceXform> CreateIdentityXform_A2B(
31 SkGammaNamed gammaNamed, const sk_sp<SkGammas>& gammas) {
32 std::vector<SkColorSpace_A2B::Element> srcElements;
33 const float values[16] = {
34 1.0f, 0.3f, -0.6f, 0.0f,
35 0.5f, -0.8f, 3.2f, 0.0f,
36 -0.5f, 1.3f, -0.7f, 0.0f,
37 0.0f, 0.0f, 0.0f, 1.0f
38 };
39 SkMatrix44 arbitraryMatrix{SkMatrix44::kUninitialized_Constructor};
40 arbitraryMatrix.setRowMajorf(values);
41 if (kNonStandard_SkGammaNamed == gammaNamed) {
42 srcElements.push_back(SkColorSpace_A2B::Element(gammas));
43 }
44 else {
45 srcElements.push_back(SkColorSpace_A2B::Element(gammaNamed));
46 }
47 srcElements.push_back(SkColorSpace_A2B::Element(arbitraryMatrix));
48 auto srcSpace = ColorSpaceXformTest::CreateA2BSpace(SkColorSpace_A2B::PC S::kXYZ,
49 std::move(srcElement s));
50 sk_sp<SkColorSpace> dstSpace(new SkColorSpace_XYZ(gammaNamed, gammas, ar bitraryMatrix,
51 nullptr));
52
53 return SkColorSpaceXform::New(static_cast<SkColorSpace_A2B*>(srcSpace.ge t()),
54 static_cast<SkColorSpace_XYZ*>(dstSpace.ge t()));
55 }
56
57 static sk_sp<SkColorSpace> CreateA2BSpace(SkColorSpace_A2B::PCS pcs,
58 std::vector<SkColorSpace_A2B::Elem ent> elements) {
59 return sk_sp<SkColorSpace>(new SkColorSpace_A2B(pcs, nullptr, std::move( elements)));
60 }
28 }; 61 };
29 62
30 static bool almost_equal(int x, int y) { 63 static bool almost_equal(int x, int y) {
31 return SkTAbs(x - y) <= 1; 64 const auto diff = SkTAbs(x - y);
65 return diff <= 1 || (x <= 3 && y <= 3 && diff <= 3);
32 } 66 }
33 67
34 static void test_identity_xform(skiatest::Reporter* r, const sk_sp<SkGammas>& ga mmas, 68 static void test_identity_xform(skiatest::Reporter* r, const sk_sp<SkGammas>& ga mmas,
35 bool repeat) { 69 bool repeat) {
36 // Arbitrary set of 10 pixels 70 // Arbitrary set of 10 pixels
37 constexpr int width = 10; 71 constexpr int width = 10;
38 constexpr uint32_t srcPixels[width] = { 72 constexpr uint32_t srcPixels[width] = {
39 0xFFABCDEF, 0xFF146829, 0xFF382759, 0xFF184968, 0xFFDE8271, 73 0xFFABCDEF, 0xFF146829, 0xFF382759, 0xFF184968, 0xFFDE8271,
40 0xFF32AB52, 0xFF0383BC, 0xFF000102, 0xFFFFFFFF, 0xFFDDEEFF, }; 74 0xFF32AB52, 0xFF0383BC, 0xFF000102, 0xFFFFFFFF, 0xFFDDEEFF, };
41 uint32_t dstPixels[width]; 75 uint32_t dstPixels[width];
(...skipping 18 matching lines...) Expand all
60 SkGetPackedA32(dstPixels[i]))); 94 SkGetPackedA32(dstPixels[i])));
61 } 95 }
62 96
63 if (repeat) { 97 if (repeat) {
64 // We should cache part of the transform after the run. So it is intere sting 98 // We should cache part of the transform after the run. So it is intere sting
65 // to make sure it still runs correctly the second time. 99 // to make sure it still runs correctly the second time.
66 test_identity_xform(r, gammas, false); 100 test_identity_xform(r, gammas, false);
67 } 101 }
68 } 102 }
69 103
104 static void test_identity_xform_A2B(skiatest::Reporter* r, SkGammaNamed gammaNam ed,
105 const sk_sp<SkGammas>& gammas, bool repeat) {
106 // Arbitrary set of 10 pixels
107 constexpr int width = 10;
108 constexpr uint32_t srcPixels[width] = {
109 0xFFABCDEF, 0xFF146829, 0xFF382759, 0xFF184968, 0xFFDE8271,
110 0xFF32AB52, 0xFF0383BC, 0xFF000102, 0xFFFFFFFF, 0xFFDDEEFF, };
111 uint32_t dstPixels[width];
112
113 // Create and perform an identity xform.
114 auto xform = ColorSpaceXformTest::CreateIdentityXform_A2B(gammaNamed, gammas );
115 bool result = xform->apply(select_xform_format(kN32_SkColorType), dstPixels,
116 SkColorSpaceXform::kBGRA_8888_ColorFormat, srcPix els, width,
117 kOpaque_SkAlphaType);
118 REPORTER_ASSERT(r, result);
119
120 // Since the src->dst matrix is the identity, and the gamma curves match,
121 // the pixels should be unchanged.
122 for (int i = 0; i < width; i++) {
123 REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 0) & 0xFF),
124 SkGetPackedB32(dstPixels[i])));
125 REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 8) & 0xFF),
126 SkGetPackedG32(dstPixels[i])));
127 REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 16) & 0xFF),
128 SkGetPackedR32(dstPixels[i])));
129 REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 24) & 0xFF),
130 SkGetPackedA32(dstPixels[i])));
131 }
132
133 if (repeat) {
134 // We should cache part of the transform after the run. So it is intere sting
135 // to make sure it still runs correctly the second time.
136 test_identity_xform_A2B(r, gammaNamed, gammas, false);
137 }
138 }
139
70 DEF_TEST(ColorSpaceXform_TableGamma, r) { 140 DEF_TEST(ColorSpaceXform_TableGamma, r) {
71 // Lookup-table based gamma curves 141 // Lookup-table based gamma curves
72 constexpr size_t tableSize = 10; 142 constexpr size_t tableSize = 10;
73 void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize) ; 143 void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize) ;
74 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas()); 144 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
75 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kTable_Type; 145 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kTable_Type;
76 gammas->fRedData.fTable.fSize = gammas->fGreenData.fTable.fSize = 146 gammas->fRedData.fTable.fSize = gammas->fGreenData.fTable.fSize =
77 gammas->fBlueData.fTable.fSize = tableSize; 147 gammas->fBlueData.fTable.fSize = tableSize;
78 gammas->fRedData.fTable.fOffset = gammas->fGreenData.fTable.fOffset = 148 gammas->fRedData.fTable.fOffset = gammas->fGreenData.fTable.fOffset =
79 gammas->fBlueData.fTable.fOffset = 0; 149 gammas->fBlueData.fTable.fOffset = 0;
80 float* table = SkTAddOffset<float>(memory, sizeof(SkGammas)); 150 float* table = SkTAddOffset<float>(memory, sizeof(SkGammas));
81 151
82 table[0] = 0.00f; 152 table[0] = 0.00f;
83 table[1] = 0.05f; 153 table[1] = 0.05f;
84 table[2] = 0.10f; 154 table[2] = 0.10f;
85 table[3] = 0.15f; 155 table[3] = 0.15f;
86 table[4] = 0.25f; 156 table[4] = 0.25f;
87 table[5] = 0.35f; 157 table[5] = 0.35f;
88 table[6] = 0.45f; 158 table[6] = 0.45f;
89 table[7] = 0.60f; 159 table[7] = 0.60f;
90 table[8] = 0.75f; 160 table[8] = 0.75f;
91 table[9] = 1.00f; 161 table[9] = 1.00f;
92 test_identity_xform(r, gammas, true); 162 test_identity_xform(r, gammas, true);
163 test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
93 } 164 }
94 165
95 DEF_TEST(ColorSpaceXform_ParametricGamma, r) { 166 DEF_TEST(ColorSpaceXform_ParametricGamma, r) {
96 // Parametric gamma curves 167 // Parametric gamma curves
97 void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransfe rFn)); 168 void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransfe rFn));
98 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas()); 169 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
99 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kParam_Type; 170 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kParam_Type;
100 gammas->fRedData.fParamOffset = gammas->fGreenData.fParamOffset = 171 gammas->fRedData.fParamOffset = gammas->fGreenData.fParamOffset =
101 gammas->fBlueData.fParamOffset = 0; 172 gammas->fBlueData.fParamOffset = 0;
102 SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn> 173 SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn>
103 (memory, sizeof(SkGammas)); 174 (memory, sizeof(SkGammas));
104 175
105 // Interval, switch xforms at 0.0031308f 176 // Interval, switch xforms at 0.0031308f
106 params->fD = 0.04045f; 177 params->fD = 0.04045f;
107 178
108 // First equation: 179 // First equation:
109 params->fE = 1.0f / 12.92f; 180 params->fE = 1.0f / 12.92f;
110 params->fF = 0.0f; 181 params->fF = 0.0f;
111 182
112 // Second equation: 183 // Second equation:
113 // Note that the function is continuous (it's actually sRGB). 184 // Note that the function is continuous (it's actually sRGB).
114 params->fA = 1.0f / 1.055f; 185 params->fA = 1.0f / 1.055f;
115 params->fB = 0.055f / 1.055f; 186 params->fB = 0.055f / 1.055f;
116 params->fC = 0.0f; 187 params->fC = 0.0f;
117 params->fG = 2.4f; 188 params->fG = 2.4f;
118 test_identity_xform(r, gammas, true); 189 test_identity_xform(r, gammas, true);
190 test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
119 } 191 }
120 192
121 DEF_TEST(ColorSpaceXform_ExponentialGamma, r) { 193 DEF_TEST(ColorSpaceXform_ExponentialGamma, r) {
122 // Exponential gamma curves 194 // Exponential gamma curves
123 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas()); 195 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas());
124 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kValue_Type; 196 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kValue_Type;
125 gammas->fRedData.fValue = gammas->fGreenData.fValue = gammas->fBlueData.fVal ue = 1.4f; 197 gammas->fRedData.fValue = gammas->fGreenData.fValue = gammas->fBlueData.fVal ue = 1.4f;
126 test_identity_xform(r, gammas, true); 198 test_identity_xform(r, gammas, true);
199 test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
127 } 200 }
128 201
129 DEF_TEST(ColorSpaceXform_NamedGamma, r) { 202 DEF_TEST(ColorSpaceXform_NamedGamma, r) {
130 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas()); 203 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new SkGammas());
131 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kNamed_Type; 204 gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type:: kNamed_Type;
132 gammas->fRedData.fNamed = kSRGB_SkGammaNamed; 205 gammas->fRedData.fNamed = kSRGB_SkGammaNamed;
133 gammas->fGreenData.fNamed = k2Dot2Curve_SkGammaNamed; 206 gammas->fGreenData.fNamed = k2Dot2Curve_SkGammaNamed;
134 gammas->fBlueData.fNamed = kLinear_SkGammaNamed; 207 gammas->fBlueData.fNamed = kLinear_SkGammaNamed;
135 test_identity_xform(r, gammas, true); 208 test_identity_xform(r, gammas, true);
209 test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
210 test_identity_xform_A2B(r, kSRGB_SkGammaNamed, nullptr, true);
211 test_identity_xform_A2B(r, k2Dot2Curve_SkGammaNamed, nullptr, true);
212 test_identity_xform_A2B(r, kLinear_SkGammaNamed, nullptr, true);
136 } 213 }
137 214
138 DEF_TEST(ColorSpaceXform_NonMatchingGamma, r) { 215 DEF_TEST(ColorSpaceXform_NonMatchingGamma, r) {
139 constexpr size_t tableSize = 10; 216 constexpr size_t tableSize = 10;
140 void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize + 217 void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize +
141 sizeof(SkColorSpaceTransferFn)); 218 sizeof(SkColorSpaceTransferFn));
142 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas()); 219 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
143 220
144 float* table = SkTAddOffset<float>(memory, sizeof(SkGammas)); 221 float* table = SkTAddOffset<float>(memory, sizeof(SkGammas));
145 table[0] = 0.00f; 222 table[0] = 0.00f;
(...skipping 21 matching lines...) Expand all
167 gammas->fRedData.fValue = 1.2f; 244 gammas->fRedData.fValue = 1.2f;
168 245
169 gammas->fGreenType = SkGammas::Type::kTable_Type; 246 gammas->fGreenType = SkGammas::Type::kTable_Type;
170 gammas->fGreenData.fTable.fSize = tableSize; 247 gammas->fGreenData.fTable.fSize = tableSize;
171 gammas->fGreenData.fTable.fOffset = 0; 248 gammas->fGreenData.fTable.fOffset = 0;
172 249
173 gammas->fBlueType = SkGammas::Type::kParam_Type; 250 gammas->fBlueType = SkGammas::Type::kParam_Type;
174 gammas->fBlueData.fParamOffset = sizeof(float) * tableSize; 251 gammas->fBlueData.fParamOffset = sizeof(float) * tableSize;
175 252
176 test_identity_xform(r, gammas, true); 253 test_identity_xform(r, gammas, true);
254 test_identity_xform_A2B(r, kNonStandard_SkGammaNamed, gammas, true);
177 } 255 }
178 256
257 DEF_TEST(ColorSpaceXform_A2BCLUT, r) {
258 constexpr int inputChannels = 3;
259 constexpr int gp = 4; // # grid points
260
261 constexpr int numEntries = gp*gp*gp*3;
262 uint8_t gridPoints[3] = {gp, gp, gp};
263 void* memory = sk_malloc_throw(sizeof(SkColorLookUpTable) + sizeof(float) * numEntries);
264 sk_sp<SkColorLookUpTable> colorLUT(new (memory) SkColorLookUpTable(inputChan nels, gridPoints));
265 // make a CLUT that rotates R, G, and B ie R->G, G->B, B->R
266 float* table = SkTAddOffset<float>(memory, sizeof(SkColorLookUpTable));
267 for (int r = 0; r < gp; ++r) {
268 for (int g = 0; g < gp; ++g) {
269 for (int b = 0; b < gp; ++b) {
270 table[3*(gp*gp*r + gp*g + b) + 0] = g * (1.f / (gp - 1.f));
271 table[3*(gp*gp*r + gp*g + b) + 1] = b * (1.f / (gp - 1.f));
272 table[3*(gp*gp*r + gp*g + b) + 2] = r * (1.f / (gp - 1.f));
273 }
274 }
275 }
276
277 // build an even distribution of pixels every (7 / 255) steps
278 // to test the xform on
279 constexpr int pixelgp = 7;
280 constexpr int numPixels = pixelgp*pixelgp*pixelgp;
281 SkAutoTMalloc<uint32_t> srcPixels(numPixels);
282 int srcIndex = 0;
283 for (int r = 0; r < pixelgp; ++r) {
284 for (int g = 0; g < pixelgp; ++g) {
285 for (int b = 0; b < pixelgp; ++b) {
286 const int red = (int) (r * (255.f / (pixelgp - 1.f)));
287 const int green = (int) (g * (255.f / (pixelgp - 1.f)));
288 const int blue = (int) (b * (255.f / (pixelgp - 1.f)));
289 srcPixels[srcIndex] = SkColorSetRGB(red, green, blue);
290 ++srcIndex;
291 }
292 }
293 }
294 SkAutoTMalloc<uint32_t> dstPixels(numPixels);
295
296 // src space is identity besides CLUT
297 std::vector<SkColorSpace_A2B::Element> srcElements;
298 srcElements.push_back(SkColorSpace_A2B::Element(std::move(colorLUT)));
299 auto srcSpace = ColorSpaceXformTest::CreateA2BSpace(SkColorSpace_A2B::PCS::k XYZ,
300 std::move(srcElements));
301 // dst space is entirely identity
302 auto dstSpace = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamm a, SkMatrix44::I());
303 auto xform = SkColorSpaceXform::New(srcSpace.get(), dstSpace.get());
304 bool result = xform->apply(SkColorSpaceXform::kRGBA_8888_ColorFormat, dstPix els.get(),
305 SkColorSpaceXform::kRGBA_8888_ColorFormat, srcPix els.get(),
306 numPixels, kOpaque_SkAlphaType);
307 REPORTER_ASSERT(r, result);
308
309 for (int i = 0; i < numPixels; ++i) {
310 REPORTER_ASSERT(r, almost_equal(SkColorGetR(srcPixels[i]),
311 SkColorGetG(dstPixels[i])));
312 REPORTER_ASSERT(r, almost_equal(SkColorGetG(srcPixels[i]),
313 SkColorGetB(dstPixels[i])));
314 REPORTER_ASSERT(r, almost_equal(SkColorGetB(srcPixels[i]),
315 SkColorGetR(dstPixels[i])));
316 }
317 }
318
OLDNEW
« src/opts/SkRasterPipeline_opts.h ('K') | « src/opts/SkRasterPipeline_opts.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698