Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 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 | |
| 8 | #include "SkColorSpacePriv.h" |
| 9 | #include "SkColorSpaceXformSteps.h" |
| 10 | #include "Test.h" |
| 11 | |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 12 | DEF_TEST(SkColorSpaceXformSteps, r) { |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 13 | auto srgb = SkColorSpace::MakeSRGB(), |
Brian Osman | 82ebe04 | 2019-01-04 17:03:00 -0500 | [diff] [blame] | 14 | adobe = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB), |
| 15 | srgb22 = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kSRGB), |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 16 | srgb1 = srgb ->makeLinearGamma(), |
| 17 | adobe1 = adobe->makeLinearGamma(); |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 18 | |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 19 | auto premul = kPremul_SkAlphaType, |
| 20 | opaque = kOpaque_SkAlphaType, |
| 21 | unpremul = kUnpremul_SkAlphaType; |
| 22 | |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 23 | struct { |
| 24 | sk_sp<SkColorSpace> src, dst; |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 25 | SkAlphaType srcAT, dstAT; |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 26 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 27 | bool unpremul; |
| 28 | bool linearize; |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 29 | bool gamut_transform; |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 30 | bool encode; |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 31 | bool premul; |
| 32 | |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 33 | } tests[] = { |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 34 | // The general case is converting between two color spaces with different gamuts |
| 35 | // and different transfer functions. There's no optimization possible here. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 36 | { adobe, srgb, premul, premul, |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 37 | true, // src is encoded as f(s)*a,a, so we unpremul to f(s),a before linearizing. |
| 38 | true, // linearize to s,a |
| 39 | true, // transform s to dst gamut, s' |
| 40 | true, // encode with dst transfer function, g(s'), a |
| 41 | true, // premul to g(s')*a, a |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 42 | }, |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 43 | // All the same going the other direction. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 44 | { srgb, adobe, premul, premul, true,true,true,true,true }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 45 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 46 | // If the src alpha type is unpremul, we'll not need that initial unpremul step. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 47 | { adobe, srgb, unpremul, premul, false,true,true,true,true }, |
| 48 | { srgb, adobe, unpremul, premul, false,true,true,true,true }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 49 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 50 | // If opaque, we need neither the initial unpremul, nor the premul later. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 51 | { adobe, srgb, opaque, premul, false,true,true,true,false }, |
| 52 | { srgb, adobe, opaque, premul, false,true,true,true,false }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 53 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 54 | |
| 55 | // Now let's go between sRGB and sRGB with a 2.2 gamma, the gamut staying the same. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 56 | { srgb, srgb22, premul, premul, |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 57 | true, // we need to linearize, so we need to unpremul |
| 58 | true, // we need to encode to 2.2 gamma, so we need to get linear |
| 59 | false, // no need to change gamut |
| 60 | true, // linear -> gamma 2.2 |
| 61 | true, // premul going into the blend |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 62 | }, |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 63 | // Same sort of logic in the other direction. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 64 | { srgb22, srgb, premul, premul, true,true,false,true,true }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 65 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 66 | // As in the general case, when we change the alpha type unpremul and premul steps drop out. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 67 | { srgb, srgb22, unpremul, premul, false,true,false,true,true }, |
| 68 | { srgb22, srgb, unpremul, premul, false,true,false,true,true }, |
| 69 | { srgb, srgb22, opaque, premul, false,true,false,true,false }, |
| 70 | { srgb22, srgb, opaque, premul, false,true,false,true,false }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 71 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 72 | // Let's look at the special case of completely matching color spaces. |
| 73 | // We should be ready to go into the blend without any fuss. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 74 | { srgb, srgb, premul, premul, false,false,false,false,false }, |
| 75 | { srgb, srgb, unpremul, premul, false,false,false,false,true }, |
| 76 | { srgb, srgb, opaque, premul, false,false,false,false,false }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 77 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 78 | // We can drop out the linearize step when the source is already linear. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 79 | { srgb1, adobe, premul, premul, true,false,true,true,true }, |
| 80 | { srgb1, srgb, premul, premul, true,false,false,true,true }, |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 81 | // And we can drop the encode step when the destination is linear. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 82 | { adobe, srgb1, premul, premul, true,true,true,false,true }, |
| 83 | { srgb, srgb1, premul, premul, true,true,false,false,true }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 84 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 85 | // Here's an interesting case where only gamut transform is needed. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 86 | { adobe1, srgb1, premul, premul, false,false,true,false,false }, |
| 87 | { adobe1, srgb1, opaque, premul, false,false,true,false,false }, |
| 88 | { adobe1, srgb1, unpremul, premul, false,false,true,false, true }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 89 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 90 | // Just finishing up with something to produce each other possible output. |
| 91 | // Nothing terribly interesting in these eight. |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 92 | { srgb, srgb1, opaque, premul, false, true,false,false,false }, |
| 93 | { srgb, srgb1, unpremul, premul, false, true,false,false, true }, |
| 94 | { srgb, adobe1, opaque, premul, false, true, true,false,false }, |
| 95 | { srgb, adobe1, unpremul, premul, false, true, true,false, true }, |
| 96 | { srgb1, srgb, opaque, premul, false,false,false, true,false }, |
| 97 | { srgb1, srgb, unpremul, premul, false,false,false, true, true }, |
| 98 | { srgb1, adobe, opaque, premul, false,false, true, true,false }, |
| 99 | { srgb1, adobe, unpremul, premul, false,false, true, true, true }, |
| 100 | |
| 101 | // Now test non-premul outputs. |
| 102 | { srgb , srgb , premul, unpremul, true,false,false,false,false }, |
| 103 | { srgb , srgb1 , premul, unpremul, true, true,false,false,false }, |
| 104 | { srgb1, adobe1, premul, unpremul, true,false, true,false,false }, |
| 105 | { srgb , adobe1, premul, unpremul, true, true, true,false,false }, |
| 106 | { srgb1, srgb , premul, unpremul, true,false,false, true,false }, |
| 107 | { srgb , srgb22, premul, unpremul, true, true,false, true,false }, |
| 108 | { srgb1, adobe , premul, unpremul, true,false, true, true,false }, |
| 109 | { srgb , adobe , premul, unpremul, true, true, true, true,false }, |
Mike Klein | b85fc3b | 2018-08-21 12:51:02 -0400 | [diff] [blame] | 110 | |
| 111 | // Opaque outputs are treated as the same alpha type as the source input. |
| 112 | // TODO: we'd really like to have a good way of explaining why we think this is useful. |
| 113 | { srgb , srgb , premul, opaque, false,false,false,false,false }, |
| 114 | { srgb , srgb1 , premul, opaque, true, true,false,false, true }, |
| 115 | { srgb1, adobe1, premul, opaque, false,false, true,false,false }, |
| 116 | { srgb , adobe1, premul, opaque, true, true, true,false, true }, |
| 117 | { srgb1, srgb , premul, opaque, true,false,false, true, true }, |
| 118 | { srgb , srgb22, premul, opaque, true, true,false, true, true }, |
| 119 | { srgb1, adobe , premul, opaque, true,false, true, true, true }, |
| 120 | { srgb , adobe , premul, opaque, true, true, true, true, true }, |
| 121 | |
| 122 | { srgb , srgb , unpremul, opaque, false,false,false,false,false }, |
| 123 | { srgb , srgb1 , unpremul, opaque, false, true,false,false,false }, |
| 124 | { srgb1, adobe1, unpremul, opaque, false,false, true,false,false }, |
| 125 | { srgb , adobe1, unpremul, opaque, false, true, true,false,false }, |
| 126 | { srgb1, srgb , unpremul, opaque, false,false,false, true,false }, |
| 127 | { srgb , srgb22, unpremul, opaque, false, true,false, true,false }, |
| 128 | { srgb1, adobe , unpremul, opaque, false,false, true, true,false }, |
| 129 | { srgb , adobe , unpremul, opaque, false, true, true, true,false }, |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 130 | }; |
| 131 | |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 132 | uint32_t tested = 0x00000000; |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 133 | for (auto t : tests) { |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 134 | SkColorSpaceXformSteps steps{t.src.get(), t.srcAT, |
| 135 | t.dst.get(), t.dstAT}; |
Brian Osman | f018b7d | 2018-06-13 17:21:19 -0400 | [diff] [blame] | 136 | REPORTER_ASSERT(r, steps.flags.unpremul == t.unpremul); |
| 137 | REPORTER_ASSERT(r, steps.flags.linearize == t.linearize); |
| 138 | REPORTER_ASSERT(r, steps.flags.gamut_transform == t.gamut_transform); |
| 139 | REPORTER_ASSERT(r, steps.flags.encode == t.encode); |
| 140 | REPORTER_ASSERT(r, steps.flags.premul == t.premul); |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 141 | |
| 142 | uint32_t bits = (uint32_t)t.unpremul << 0 |
| 143 | | (uint32_t)t.linearize << 1 |
| 144 | | (uint32_t)t.gamut_transform << 2 |
| 145 | | (uint32_t)t.encode << 3 |
| 146 | | (uint32_t)t.premul << 4; |
| 147 | tested |= (1<<bits); |
| 148 | } |
| 149 | |
| 150 | // We'll check our test cases cover all 2^5 == 32 possible outputs. |
| 151 | for (uint32_t t = 0; t < 32; t++) { |
| 152 | if (tested & (1<<t)) { |
| 153 | continue; |
| 154 | } |
| 155 | |
Mike Klein | 8f3d36c | 2018-08-14 10:28:05 -0400 | [diff] [blame] | 156 | // There are a couple impossible outputs, so consider those bits tested. |
| 157 | // |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 158 | // Unpremul then premul should be optimized away to a noop, so 0b10001 isn't possible. |
| 159 | // A gamut transform in the middle is fine too, so 0b10101 isn't possible either. |
Mike Klein | a23436c | 2018-05-31 10:59:52 -0400 | [diff] [blame] | 160 | if (t == 0b10001 || t == 0b10101) { |
Mike Klein | 97918ff | 2018-05-25 12:55:58 -0400 | [diff] [blame] | 161 | continue; |
| 162 | } |
| 163 | |
| 164 | ERRORF(r, "{ xxx, yyy, at, %s,%s,%s,%s,%s }, not covered", |
| 165 | (t& 1) ? " true" : "false", |
| 166 | (t& 2) ? " true" : "false", |
| 167 | (t& 4) ? " true" : "false", |
| 168 | (t& 8) ? " true" : "false", |
| 169 | (t&16) ? " true" : "false"); |
Mike Klein | 6968f9c | 2018-05-24 12:33:23 -0400 | [diff] [blame] | 170 | } |
| 171 | } |