skia2/tests/SkColorSpaceXformStepsTest.cpp
Brian Osman f018b7d607 SkColorSpaceXformSteps improvements and tests
Added some helper functions and put the booleans in a nested struct
(this is motivated by upcoming changes). Added a unit test of steps
against skcms, with round-tripping in both combinations.

Change-Id: Iea3d60cd52edb5259b5576b1422ed6f856cde815
Reviewed-on: https://skia-review.googlesource.com/134660
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
2018-06-14 11:30:47 +00:00

141 lines
6.5 KiB
C++

/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkColorSpacePriv.h"
#include "SkColorSpaceXformSteps.h"
#include "Test.h"
DEF_TEST(SkColorSpaceXformSteps, r) {
auto srgb = SkColorSpace::MakeSRGB(),
adobe = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace::kAdobeRGB_Gamut),
srgb22 = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace:: kSRGB_Gamut),
srgb1 = srgb ->makeLinearGamma(),
adobe1 = adobe->makeLinearGamma();
struct {
sk_sp<SkColorSpace> src, dst;
SkAlphaType srcAT;
bool unpremul;
bool linearize;
bool gamut_transform;
bool encode;
bool premul;
} tests[] = {
// The general case is converting between two color spaces with different gamuts
// and different transfer functions. There's no optimization possible here.
{ adobe, srgb, kPremul_SkAlphaType,
true, // src is encoded as f(s)*a,a, so we unpremul to f(s),a before linearizing.
true, // linearize to s,a
true, // transform s to dst gamut, s'
true, // encode with dst transfer function, g(s'), a
true, // premul to g(s')*a, a
},
// All the same going the other direction.
{ srgb, adobe, kPremul_SkAlphaType, true,true,true,true,true },
// If the src alpha type is unpremul, we'll not need that initial unpremul step.
{ adobe, srgb, kUnpremul_SkAlphaType, false,true,true,true,true },
{ srgb, adobe, kUnpremul_SkAlphaType, false,true,true,true,true },
// If opaque, we need neither the initial unpremul, nor the premul later.
{ adobe, srgb, kOpaque_SkAlphaType, false,true,true,true,false },
{ srgb, adobe, kOpaque_SkAlphaType, false,true,true,true,false },
// Now let's go between sRGB and sRGB with a 2.2 gamma, the gamut staying the same.
{ srgb, srgb22, kPremul_SkAlphaType,
true, // we need to linearize, so we need to unpremul
true, // we need to encode to 2.2 gamma, so we need to get linear
false, // no need to change gamut
true, // linear -> gamma 2.2
true, // premul going into the blend
},
// Same sort of logic in the other direction.
{ srgb22, srgb, kPremul_SkAlphaType, true,true,false,true,true },
// As in the general case, when we change the alpha type unpremul and premul steps drop out.
{ srgb, srgb22, kUnpremul_SkAlphaType, false,true,false,true,true },
{ srgb22, srgb, kUnpremul_SkAlphaType, false,true,false,true,true },
{ srgb, srgb22, kOpaque_SkAlphaType, false,true,false,true,false },
{ srgb22, srgb, kOpaque_SkAlphaType, false,true,false,true,false },
// Let's look at the special case of completely matching color spaces.
// We should be ready to go into the blend without any fuss.
{ srgb, srgb, kPremul_SkAlphaType, false,false,false,false,false },
{ srgb, srgb, kUnpremul_SkAlphaType, false,false,false,false,true },
{ srgb, srgb, kOpaque_SkAlphaType, false,false,false,false,false },
// We can drop out the linearize step when the source is already linear.
{ srgb1, adobe, kPremul_SkAlphaType, true,false,true,true,true },
{ srgb1, srgb, kPremul_SkAlphaType, true,false,false,true,true },
// And we can drop the encode step when the destination is linear.
{ adobe, srgb1, kPremul_SkAlphaType, true,true,true,false,true },
{ srgb, srgb1, kPremul_SkAlphaType, true,true,false,false,true },
// Here's an interesting case where only gamut transform is needed.
{ adobe1, srgb1, kPremul_SkAlphaType, false,false,true,false,false },
{ adobe1, srgb1, kOpaque_SkAlphaType, false,false,true,false,false },
{ adobe1, srgb1, kUnpremul_SkAlphaType, false,false,true,false, true },
// Just finishing up with something to produce each other possible output.
// Nothing terribly interesting in these eight.
{ srgb, srgb1, kOpaque_SkAlphaType, false, true,false,false,false },
{ srgb, srgb1, kUnpremul_SkAlphaType, false, true,false,false, true },
{ srgb, adobe1, kOpaque_SkAlphaType, false, true, true,false,false },
{ srgb, adobe1, kUnpremul_SkAlphaType, false, true, true,false, true },
{ srgb1, srgb, kOpaque_SkAlphaType, false,false,false, true,false },
{ srgb1, srgb, kUnpremul_SkAlphaType, false,false,false, true, true },
{ srgb1, adobe, kOpaque_SkAlphaType, false,false, true, true,false },
{ srgb1, adobe, kUnpremul_SkAlphaType, false,false, true, true, true },
};
uint32_t tested = 0x00000000;
for (auto t : tests) {
SkColorSpaceXformSteps steps{t.src.get(), t.srcAT, t.dst.get()};
REPORTER_ASSERT(r, steps.flags.unpremul == t.unpremul);
REPORTER_ASSERT(r, steps.flags.linearize == t.linearize);
REPORTER_ASSERT(r, steps.flags.gamut_transform == t.gamut_transform);
REPORTER_ASSERT(r, steps.flags.encode == t.encode);
REPORTER_ASSERT(r, steps.flags.premul == t.premul);
uint32_t bits = (uint32_t)t.unpremul << 0
| (uint32_t)t.linearize << 1
| (uint32_t)t.gamut_transform << 2
| (uint32_t)t.encode << 3
| (uint32_t)t.premul << 4;
tested |= (1<<bits);
}
// We'll check our test cases cover all 2^5 == 32 possible outputs.
for (uint32_t t = 0; t < 32; t++) {
if (tested & (1<<t)) {
continue;
}
// There a a few impossible outputs, so consider those bits tested.
// No way to need an unpremul but not premul later, ruling out all true,?,?,?,false.
if ((t & 1) == 1 && (t & 16) == 0) {
continue;
}
// Unpremul then premul should be optimized away to a noop, so 0b10001 isn't possible.
// A gamut transform in the middle is fine too, so 0b10101 isn't possible either.
if (t == 0b10001 || t == 0b10101) {
continue;
}
ERRORF(r, "{ xxx, yyy, at, %s,%s,%s,%s,%s }, not covered",
(t& 1) ? " true" : "false",
(t& 2) ? " true" : "false",
(t& 4) ? " true" : "false",
(t& 8) ? " true" : "false",
(t&16) ? " true" : "false");
}
}