From 97918ff4ae2fbbfbd621491a2ed73bcac9e487f4 Mon Sep 17 00:00:00 2001 From: Mike Klein Date: Fri, 25 May 2018 12:55:58 -0400 Subject: 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 Commit-Queue: Mike Klein --- tests/SkColorSpaceXformStepsTest.cpp | 270 ++++++++++++++--------------------- 1 file changed, 108 insertions(+), 162 deletions(-) (limited to 'tests/SkColorSpaceXformStepsTest.cpp') 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 -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 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<