aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@chromium.org>2018-05-25 12:55:58 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-05-29 16:03:46 +0000
commit97918ff4ae2fbbfbd621491a2ed73bcac9e487f4 (patch)
treeebf8f5fa5f54dc122fa319ae6bf716e4f51bb133
parent616f1cb4564229322944234ee20fc96ab5716464 (diff)
wouldn't it be nice?
Here's our drawing pipeline if we always blend as encoded. I think it's very intuitive. Change-Id: I0e531c5da1f6279d0da1f19b84d6317d99942da3 Reviewed-on: https://skia-review.googlesource.com/130131 Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Mike Klein <mtklein@chromium.org>
-rw-r--r--src/core/SkColorSpaceXformSteps.cpp88
-rw-r--r--src/core/SkColorSpaceXformSteps.h19
-rw-r--r--tests/SkColorSpaceXformStepsTest.cpp270
3 files changed, 128 insertions, 249 deletions
diff --git a/src/core/SkColorSpaceXformSteps.cpp b/src/core/SkColorSpaceXformSteps.cpp
index e4b465e6cf..d2ca81e753 100644
--- a/src/core/SkColorSpaceXformSteps.cpp
+++ b/src/core/SkColorSpaceXformSteps.cpp
@@ -7,27 +7,7 @@
#include "SkColorSpaceXformSteps.h"
-// Our logical flow modulo any optimization is:
-// For source colors:
-// 1) get colors into linear, unpremul format
-// 2) transform to dst gamut
-// 3) encode with dst transfer function if dst has non-linear blending
-// 4) premul so we can blend
-//
-// For destination colors:
-// a) Linearize if dst has linear blending
-// b) (Presumably all destinations are already premul, but logically, premul here)
-//
-// Now the source and destination pipelines unify:
-// I) blend the src and dst colors, which are encoded the same way in the same gamut
-// II) if dst has linear blending, encode using dst transfer function
-//
-// Step 1) is represented by three bits:
-// - early_unpremul, converting f(s)*a,a to f(s),a if src has non-linear blending
-// - linearize_src, converting f(s),a to s,a _or_ f(s*a),a to s*a,a
-// - late_unpremul, converting s*a,a to s,a if src has linear blending
-// So we'll either early_unpremul and linearize_src, or linearize_src and late_unpremul.
-//
+// TODO: explain
SkColorSpaceXformSteps::SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType srcAT,
SkColorSpace* dst) {
@@ -35,29 +15,13 @@ SkColorSpaceXformSteps::SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType sr
memset(this, 0, sizeof(*this));
// We have some options about what to do with null src or dst here.
-#if 1
SkASSERT(src && dst);
-#else
- // If either the source or destination color space is unspecified,
- // treat it as non-linearly-blended sRGB ("legacy").
- sk_sp<SkColorSpace> sRGB_NL;
- if (!src || !dst) {
- sRGB_NL = SkColorSpace::MakeSRGB()->makeNonlinearBlending();
- if (!src) { src = sRGB_NL.get(); }
- if (!dst) { dst = sRGB_NL.get(); }
- }
-#endif
-
- bool srcNL = src->nonlinearBlending(),
- dstNL = dst->nonlinearBlending();
-
- // Step 1) get source colors into linear, unpremul format
- this->early_unpremul = srcNL && srcAT == kPremul_SkAlphaType;
- this->linearize_src = true;
- this->late_unpremul = !srcNL && srcAT == kPremul_SkAlphaType;
- // Step 2) transform source colors into destination gamut
- this->gamut_transform = (src->toXYZD50Hash() != dst->toXYZD50Hash());
+ this->unpremul = srcAT == kPremul_SkAlphaType;
+ this->linearize = !src->gammaIsLinear();
+ this->gamut_transform = src->toXYZD50Hash() != dst->toXYZD50Hash();
+ this->encode = !dst->gammaIsLinear();
+ this->premul = srcAT != kOpaque_SkAlphaType;
if (this->gamut_transform && src->toXYZD50() && dst->fromXYZD50()) {
auto xform = SkMatrix44(*src->toXYZD50(), *dst->fromXYZD50());
@@ -72,52 +36,30 @@ SkColorSpaceXformSteps::SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType sr
}
}
- // Step 3) encode with dst transfer function if dst has non-linear blending
- this->early_encode = dstNL;
-
- // Step 4) premul so we can blend
- this->premul = srcAT != kOpaque_SkAlphaType;
-
- // Step a) linearize if dst has linear blending
- this->linearize_dst = !dstNL;
-
- // Step II) if dst has linear blending, encode back using dst transfer function before storing
- this->late_encode = !dstNL;
-
// Fill out all the transfer functions we'll use:
SkColorSpaceTransferFn srcTF, dstTF;
SkAssertResult(src->isNumericalTransferFn(&srcTF));
SkAssertResult(dst->isNumericalTransferFn(&dstTF));
this->srcTFInv = srcTF.invert();
this->dstTF = dstTF;
- this->dstTFInv = dstTF.invert();
// If we linearize then immediately reencode with the same transfer function, skip both.
- if ( this->linearize_src &&
- !this->late_unpremul &&
+ if ( this->linearize &&
!this->gamut_transform &&
- this->early_encode &&
+ this->encode &&
0 == memcmp(&srcTF, &dstTF, sizeof(SkColorSpaceTransferFn)))
{
- this->linearize_src = false;
- this->early_encode = false;
+ this->linearize = false;
+ this->encode = false;
}
// Skip unpremul...premul if there are no non-linear operations between.
- if ( this->early_unpremul &&
- !this->linearize_src &&
- !this->early_encode &&
- this->premul)
- {
- this->early_unpremul = false;
- this->premul = false;
- }
-
- if ( this->late_unpremul &&
- !this->early_encode &&
+ if ( this->unpremul &&
+ !this->linearize &&
+ !this->encode &&
this->premul)
{
- this->late_unpremul = false;
- this->premul = false;
+ this->unpremul = false;
+ this->premul = false;
}
}
diff --git a/src/core/SkColorSpaceXformSteps.h b/src/core/SkColorSpaceXformSteps.h
index 090d88fe47..e4b97cd378 100644
--- a/src/core/SkColorSpaceXformSteps.h
+++ b/src/core/SkColorSpaceXformSteps.h
@@ -15,23 +15,14 @@ struct SkColorSpaceXformSteps {
SkColorSpaceXformSteps(SkColorSpace* src, SkAlphaType srcAT,
SkColorSpace* dst);
- // Source pipeline steps, pre-blend.
- bool early_unpremul;
- bool linearize_src;
- bool late_unpremul;
+ bool unpremul;
+ bool linearize;
bool gamut_transform;
- bool early_encode;
+ bool encode;
bool premul;
- // Destination pipeline steps, pre-blend.
- bool linearize_dst;
-
- // Post-blend steps.
- bool late_encode;
-
- SkColorSpaceTransferFn srcTFInv, // Apply for linearize_src.
- dstTFInv, // Apply for linearize_dst.
- dstTF; // Apply for early_encode or late_encode.
+ SkColorSpaceTransferFn srcTFInv, // Apply for linearize.
+ dstTF; // Apply for encode.
float src_to_dst_matrix[9]; // Apply this 3x3 row-major matrix for gamut_transform.
};
diff --git a/tests/SkColorSpaceXformStepsTest.cpp b/tests/SkColorSpaceXformStepsTest.cpp
index 6b2cf46203..9fdd21e7c0 100644
--- a/tests/SkColorSpaceXformStepsTest.cpp
+++ b/tests/SkColorSpaceXformStepsTest.cpp
@@ -9,186 +9,132 @@
#include "SkColorSpaceXformSteps.h"
#include "Test.h"
-template <typename T>
-static void check_eq(skiatest::Reporter* r, SkColorSpaceXformSteps steps, T baseline) {
- REPORTER_ASSERT(r, steps.early_unpremul == baseline.early_unpremul);
- REPORTER_ASSERT(r, steps.linearize_src == baseline.linearize_src);
- REPORTER_ASSERT(r, steps.late_unpremul == baseline.late_unpremul);
- REPORTER_ASSERT(r, steps.gamut_transform == baseline.gamut_transform);
- REPORTER_ASSERT(r, steps.early_encode == baseline.early_encode);
- REPORTER_ASSERT(r, steps.premul == baseline.premul);
- REPORTER_ASSERT(r, steps.linearize_dst == baseline.linearize_dst);
- REPORTER_ASSERT(r, steps.late_encode == baseline.late_encode);
-
- // A couple (redundant) sanity checks that cover impossible states.
- // At most one of the early/late options should happen, possibly neither.
- REPORTER_ASSERT(r, !(steps.early_unpremul && steps.late_unpremul));
- REPORTER_ASSERT(r, !(steps.early_encode && steps.late_encode));
-}
-
DEF_TEST(SkColorSpaceXformSteps, r) {
- auto srgb_L = SkColorSpace::MakeSRGB(),
- adobe_L = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace::kAdobeRGB_Gamut),
- srgb22_L = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace:: kSRGB_Gamut),
- srgb_N = srgb_L->makeNonlinearBlending(),
- adobe_N = adobe_L->makeNonlinearBlending(),
- srgb22_N = srgb22_L->makeNonlinearBlending();
+ 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 early_unpremul;
- bool linearize_src;
- bool late_unpremul;
-
+ bool unpremul;
+ bool linearize;
bool gamut_transform;
- bool early_encode;
+ bool encode;
bool premul;
- bool linearize_dst;
- bool late_encode;
} tests[] = {
- // The first eight cases we test are back and forth between two color spaces with
- // different gamuts and transfer functions. There's not much optimization possible here.
-
- { adobe_N, srgb_N, 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.
- false,
-
- true, // Gamut transform.
- true, // Non-linear blending, so we encode to sRGB g(s),a early.
- true, // Premul to g(s)*a,a
-
- false, // Non-linear blending, so no need to linearize dst.
- false, // Non-linear blending, so the output of our blend function is what we want.
+ // 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
},
- { srgb_N, adobe_N, kPremul_SkAlphaType, true,true,false, true,true,true, false,false },
+ // All the same going the other direction.
+ { srgb, adobe, kPremul_SkAlphaType, true,true,true,true,true },
- { adobe_L, srgb_L, kPremul_SkAlphaType,
- false, // src is encoded as f(s*a),a, so we linearize before unpremul.
- true, // Linearize,
- false, // then unpremul, but we can skip this here.
+ // 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 },
- true, // Gamut transform.
- false, // We're doing linear blending, so we don't encode to sRGB yet.
- false, // Premul so we can blend, but skipped because we never unpremulled.
-
- true, // We're doing linear blending, so we need to linearize dst.
- true, // Once blending is done, finally encode to sRGB.
- },
- { srgb_L, adobe_L, kPremul_SkAlphaType, false,true,false, true,false,false, 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 },
- { adobe_L, srgb_N, kPremul_SkAlphaType,
- false, // src is encoded as f(s*a),a, so we linearize before unpremul.
- true, // Linearize,
- true, // then unpremul.
- true, // Gamut transform
- true, // We're doing non-linear blending, so encode to sRGB now.
- true, // (non-linear) premul
-
- false, // We're doing non-linear blending, so dst is already ready to blend.
- false, // The output of the blend is just what we want.
+ // 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
},
- { srgb_L, adobe_N, kPremul_SkAlphaType, false,true,true, true,true,true, false,false },
-
- { adobe_N, srgb_L, 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.
- false,
-
- true, // Gamut transform
- false, // We're doing linear blending, so we don't encode to sRGB yet.
- true, // (linear) premul
-
- true, // We're doing linear blending, so we need to linearize dst.
- true, // Once blending is done, finally encode to sRGB.
- },
- { srgb_N, adobe_L, kPremul_SkAlphaType, true,true,false, true,false,true, true,true },
-
- // These next 16 are the previous 8 with opaque and unpremul srcs.
- // Generally, the steps that change are the early_unpremul, late_unpremul, and premul steps,
- // but optimizations can sometimes make more steps drop out.
- { adobe_N, srgb_N, kOpaque_SkAlphaType, false,true,false, true,true,false, false,false },
- { adobe_N, srgb_N, kUnpremul_SkAlphaType, false,true,false, true,true,true, false,false },
- { srgb_N, adobe_N, kOpaque_SkAlphaType, false,true,false, true,true,false, false,false },
- { srgb_N, adobe_N, kUnpremul_SkAlphaType, false,true,false, true,true,true, false,false },
-
- { adobe_L, srgb_L, kOpaque_SkAlphaType, false,true,false, true,false,false, true,true },
- { adobe_L, srgb_L, kUnpremul_SkAlphaType, false,true,false, true,false,true, true,true },
- { srgb_L, adobe_L, kOpaque_SkAlphaType, false,true,false, true,false,false, true,true },
- { srgb_L, adobe_L, kUnpremul_SkAlphaType, false,true,false, true,false,true, true,true },
-
- { adobe_L, srgb_N, kOpaque_SkAlphaType, false,true,false, true,true,false, false,false },
- { adobe_L, srgb_N, kUnpremul_SkAlphaType, false,true,false, true,true,true, false,false },
- { srgb_L, adobe_N, kOpaque_SkAlphaType, false,true,false, true,true,false, false,false },
- { srgb_L, adobe_N, kUnpremul_SkAlphaType, false,true,false, true,true,true, false,false },
-
- { adobe_N, srgb_L, kOpaque_SkAlphaType, false,true,false, true,false,false, true,true },
- { adobe_N, srgb_L, kUnpremul_SkAlphaType, false,true,false, true,false,true, true,true },
- { srgb_N, adobe_L, kOpaque_SkAlphaType, false,true,false, true,false,false, true,true },
- { srgb_N, adobe_L, kUnpremul_SkAlphaType, false,true,false, true,false,true, true,true },
-
- // These eight cases transform between color spaces with different
- // transfer functions and the same gamut. Optimization here is limited
- // to skipping the gamut_transform step: |
- // This column v has all become false.
- { srgb_N, srgb22_N, kPremul_SkAlphaType, true,true,false, false,true,true, false,false },
- { srgb22_N, srgb_N, kPremul_SkAlphaType, true,true,false, false,true,true, false,false },
-
- { srgb_L, srgb22_L, kPremul_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb22_L, srgb_L, kPremul_SkAlphaType, false,true,false, false,false,false, true,true },
-
- { srgb_L, srgb22_N, kPremul_SkAlphaType, false,true,true, false,true,true, false,false },
- { srgb22_L, srgb_N, kPremul_SkAlphaType, false,true,true, false,true,true, false,false },
-
- { srgb_N, srgb22_L, kPremul_SkAlphaType, true,true,false, false,false,true, true,true },
- { srgb22_N, srgb_L, kPremul_SkAlphaType, true,true,false, false,false,true, true,true },
-
- // Same deal, the next 16 are the previous 8 in opaque and unpremul.
- { srgb_N, srgb22_N, kOpaque_SkAlphaType, false,true,false, false,true,false, false,false},
- { srgb_N, srgb22_N, kUnpremul_SkAlphaType, false,true,false, false,true,true, false,false},
- { srgb22_N, srgb_N, kOpaque_SkAlphaType, false,true,false, false,true,false, false,false},
- { srgb22_N, srgb_N, kUnpremul_SkAlphaType, false,true,false, false,true,true, false,false},
-
- { srgb_L, srgb22_L, kOpaque_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb_L, srgb22_L, kUnpremul_SkAlphaType, false,true,false, false,false,true, true,true },
- { srgb22_L, srgb_L, kOpaque_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb22_L, srgb_L, kUnpremul_SkAlphaType, false,true,false, false,false,true, true,true },
-
- { srgb_L, srgb22_N, kOpaque_SkAlphaType, false,true,false, false,true,false, false,false},
- { srgb_L, srgb22_N, kUnpremul_SkAlphaType, false,true,false, false,true,true, false,false},
- { srgb22_L, srgb_N, kOpaque_SkAlphaType, false,true,false, false,true,false, false,false},
- { srgb22_L, srgb_N, kUnpremul_SkAlphaType, false,true,false, false,true,true, false,false},
-
- { srgb_N, srgb22_L, kOpaque_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb_N, srgb22_L, kUnpremul_SkAlphaType, false,true,false, false,false,true, true,true },
- { srgb22_N, srgb_L, kOpaque_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb22_N, srgb_L, kUnpremul_SkAlphaType, false,true,false, false,false,true, true,true },
-
- // These four test cases test drawing in the same color space.
- // There is lots of room for optimization here.
- { srgb_N, srgb_N, kPremul_SkAlphaType, false,false,false, false,false,false, false,false},
- { srgb_L, srgb_L, kPremul_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb_L, srgb_N, kPremul_SkAlphaType, false,true,true, false,true,true, false,false},
- { srgb_N, srgb_L, kPremul_SkAlphaType, true,true,false, false,false,true, true,true },
-
- // And the usual variants for opaque + unpremul sources.
- { srgb_N, srgb_N, kOpaque_SkAlphaType, false,false,false, false,false,false, false,false},
- { srgb_N, srgb_N, kUnpremul_SkAlphaType, false,false,false, false,false,true, false,false},
- { srgb_L, srgb_L, kOpaque_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb_L, srgb_L, kUnpremul_SkAlphaType, false,true,false, false,false,true, true,true },
- { srgb_L, srgb_N, kOpaque_SkAlphaType, false,false,false, false,false,false, false,false},
- { srgb_L, srgb_N, kUnpremul_SkAlphaType, false,false,false, false,false,true, false,false},
- { srgb_N, srgb_L, kOpaque_SkAlphaType, false,true,false, false,false,false, true,true },
- { srgb_N, srgb_L, kUnpremul_SkAlphaType, false,true,false, false,false,true, true,true },
-
- // TODO: versions of above crossing in linear transfer functions
+ // 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) {
- check_eq(r, SkColorSpaceXformSteps(t.src.get(), t.srcAT, t.dst.get()), t);
+ SkColorSpaceXformSteps steps{t.src.get(), t.srcAT, t.dst.get()};
+ REPORTER_ASSERT(r, steps.unpremul == t.unpremul);
+ REPORTER_ASSERT(r, steps.linearize == t.linearize);
+ REPORTER_ASSERT(r, steps.gamut_transform == t.gamut_transform);
+ REPORTER_ASSERT(r, steps.encode == t.encode);
+ REPORTER_ASSERT(r, steps.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 == 17 || t == 21) {
+ 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");
}
}