GrUnrolledBinaryGradientColorizer.fp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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. // Unrolled gradient code supporting up to 8 intervals that produces code
  8. // targeting a specific interval count.
  9. // Assumed to be between 1 and 8.
  10. layout(key) in int intervalCount;
  11. // With the current hardstop detection threshold of 0.00024, the maximum scale and bias values
  12. // will be on the order of 4k (since they divide by dt). That is well outside the precision
  13. // capabilities of half floats, which can lead to inaccurate gradient calculations
  14. layout(ctype=SkPMColor4f) in uniform float4 scale0_1;
  15. layout(ctype=SkPMColor4f, when=intervalCount > 1) in uniform float4 scale2_3;
  16. layout(ctype=SkPMColor4f, when=intervalCount > 2) in uniform float4 scale4_5;
  17. layout(ctype=SkPMColor4f, when=intervalCount > 3) in uniform float4 scale6_7;
  18. layout(ctype=SkPMColor4f, when=intervalCount > 4) in uniform float4 scale8_9;
  19. layout(ctype=SkPMColor4f, when=intervalCount > 5) in uniform float4 scale10_11;
  20. layout(ctype=SkPMColor4f, when=intervalCount > 6) in uniform float4 scale12_13;
  21. layout(ctype=SkPMColor4f, when=intervalCount > 7) in uniform float4 scale14_15;
  22. layout(ctype=SkPMColor4f) in uniform float4 bias0_1;
  23. layout(ctype=SkPMColor4f, when=intervalCount > 1) in uniform float4 bias2_3;
  24. layout(ctype=SkPMColor4f, when=intervalCount > 2) in uniform float4 bias4_5;
  25. layout(ctype=SkPMColor4f, when=intervalCount > 3) in uniform float4 bias6_7;
  26. layout(ctype=SkPMColor4f, when=intervalCount > 4) in uniform float4 bias8_9;
  27. layout(ctype=SkPMColor4f, when=intervalCount > 5) in uniform float4 bias10_11;
  28. layout(ctype=SkPMColor4f, when=intervalCount > 6) in uniform float4 bias12_13;
  29. layout(ctype=SkPMColor4f, when=intervalCount > 7) in uniform float4 bias14_15;
  30. // The 7 threshold positions that define the boundaries of the 8 intervals (excluding t = 0, and t =
  31. // 1) are packed into two half4's instead of having up to 7 separate scalar uniforms. For low
  32. // interval counts, the extra components are ignored in the shader, but the uniform simplification
  33. // is worth it. It is assumed thresholds are provided in increasing value, mapped as:
  34. // - thresholds1_7.x = boundary between (0,1) and (2,3) -> 1_2
  35. // - .y = boundary between (2,3) and (4,5) -> 3_4
  36. // - .z = boundary between (4,5) and (6,7) -> 5_6
  37. // - .w = boundary between (6,7) and (8,9) -> 7_8
  38. // - thresholds9_13.x = boundary between (8,9) and (10,11) -> 9_10
  39. // - .y = boundary between (10,11) and (12,13) -> 11_12
  40. // - .z = boundary between (12,13) and (14,15) -> 13_14
  41. // - .w = unused
  42. in uniform half4 thresholds1_7;
  43. in uniform half4 thresholds9_13;
  44. void main() {
  45. half t = sk_InColor.x;
  46. float4 scale, bias;
  47. // Explicit binary search for the proper interval that t falls within. The interval count
  48. // checks are converted into constant expressions in the C++ generated SkSL, which are then
  49. // optimized to the minimal number of branches for the specific interval count.
  50. // thresholds1_7.w is mid point for intervals (0,7) and (8,15)
  51. if (intervalCount <= 4 || t < thresholds1_7.w) {
  52. // thresholds1_7.y is mid point for intervals (0,3) and (4,7)
  53. if (intervalCount <= 2 || t < thresholds1_7.y) {
  54. // thresholds1_7.x is mid point for intervals (0,1) and (2,3)
  55. if (intervalCount <= 1 || t < thresholds1_7.x) {
  56. scale = scale0_1;
  57. bias = bias0_1;
  58. } else {
  59. scale = scale2_3;
  60. bias = bias2_3;
  61. }
  62. } else {
  63. // thresholds1_7.z is mid point for intervals (4,5) and (6,7)
  64. if (intervalCount <= 3 || t < thresholds1_7.z) {
  65. scale = scale4_5;
  66. bias = bias4_5;
  67. } else {
  68. scale = scale6_7;
  69. bias = bias6_7;
  70. }
  71. }
  72. } else {
  73. // thresholds9_13.y is mid point for intervals (8,11) and (12,15)
  74. if (intervalCount <= 6 || t < thresholds9_13.y) {
  75. // thresholds9_13.x is mid point for intervals (8,9) and (10,11)
  76. if (intervalCount <= 5 || t < thresholds9_13.x) {
  77. // interval 8-9
  78. scale = scale8_9;
  79. bias = bias8_9;
  80. } else {
  81. // interval 10-11
  82. scale = scale10_11;
  83. bias = bias10_11;
  84. }
  85. } else {
  86. // thresholds9_13.z is mid point for intervals (12,13) and (14,15)
  87. if (intervalCount <= 7 || t < thresholds9_13.z) {
  88. // interval 12-13
  89. scale = scale12_13;
  90. bias = bias12_13;
  91. } else {
  92. // interval 14-15
  93. scale = scale14_15;
  94. bias = bias14_15;
  95. }
  96. }
  97. }
  98. sk_OutColor = half4(t * scale + bias);
  99. }
  100. //////////////////////////////////////////////////////////////////////////////
  101. @class {
  102. static const int kMaxColorCount = 16;
  103. }
  104. @make {
  105. static std::unique_ptr<GrFragmentProcessor> Make(const SkPMColor4f* colors,
  106. const SkScalar* positions,
  107. int count);
  108. }
  109. @cppEnd {
  110. static const int kMaxIntervals = 8;
  111. std::unique_ptr<GrFragmentProcessor> GrUnrolledBinaryGradientColorizer::Make(
  112. const SkPMColor4f* colors, const SkScalar* positions, int count) {
  113. // Depending on how the positions resolve into hard stops or regular stops, the number of
  114. // intervals specified by the number of colors/positions can change. For instance, a plain
  115. // 3 color gradient is two intervals, but a 4 color gradient with a hard stop is also
  116. // two intervals. At the most extreme end, an 8 interval gradient made entirely of hard
  117. // stops has 16 colors.
  118. if (count > kMaxColorCount) {
  119. // Definitely cannot represent this gradient configuration
  120. return nullptr;
  121. }
  122. // The raster implementation also uses scales and biases, but since they must be calculated
  123. // after the dst color space is applied, it limits our ability to cache their values.
  124. SkPMColor4f scales[kMaxIntervals];
  125. SkPMColor4f biases[kMaxIntervals];
  126. SkScalar thresholds[kMaxIntervals];
  127. int intervalCount = 0;
  128. for (int i = 0; i < count - 1; i++) {
  129. if (intervalCount >= kMaxIntervals) {
  130. // Already reached kMaxIntervals, and haven't run out of color stops so this
  131. // gradient cannot be represented by this shader.
  132. return nullptr;
  133. }
  134. SkScalar t0 = positions[i];
  135. SkScalar t1 = positions[i + 1];
  136. SkScalar dt = t1 - t0;
  137. // If the interval is empty, skip to the next interval. This will automatically create
  138. // distinct hard stop intervals as needed. It also protects against malformed gradients
  139. // that have repeated hard stops at the very beginning that are effectively unreachable.
  140. if (SkScalarNearlyZero(dt)) {
  141. continue;
  142. }
  143. auto c0 = Sk4f::Load(colors[i].vec());
  144. auto c1 = Sk4f::Load(colors[i + 1].vec());
  145. auto scale = (c1 - c0) / dt;
  146. auto bias = c0 - t0 * scale;
  147. scale.store(scales + intervalCount);
  148. bias.store(biases + intervalCount);
  149. thresholds[intervalCount] = t1;
  150. intervalCount++;
  151. }
  152. // For isEqual to make sense, set the unused values to something consistent
  153. for (int i = intervalCount; i < kMaxIntervals; i++) {
  154. scales[i] = SK_PMColor4fTRANSPARENT;
  155. biases[i] = SK_PMColor4fTRANSPARENT;
  156. thresholds[i] = 0.0;
  157. }
  158. return std::unique_ptr<GrFragmentProcessor>(new GrUnrolledBinaryGradientColorizer(
  159. intervalCount, scales[0], scales[1], scales[2], scales[3], scales[4], scales[5],
  160. scales[6], scales[7], biases[0], biases[1], biases[2], biases[3], biases[4],
  161. biases[5], biases[6], biases[7],
  162. SkRect::MakeLTRB(thresholds[0], thresholds[1], thresholds[2], thresholds[3]),
  163. SkRect::MakeLTRB(thresholds[4], thresholds[5], thresholds[6], 0.0)));
  164. }
  165. }