SkColorSpaceXformStepsTest.cpp 8.4 KB

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