Index: src/effects/gradients/SkLinearGradient.cpp |
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp |
index a249ae4ac82c2195ce2e559978cf057ce0a8377a..d631d942d932363fb28e8dd1d4cc5dcf01bdd2cf 100644 |
--- a/src/effects/gradients/SkLinearGradient.cpp |
+++ b/src/effects/gradients/SkLinearGradient.cpp |
@@ -525,25 +525,62 @@ find_backward(const SkLinearGradient::LinearGradientContext::Rec rec[], float ti |
return rec; |
} |
-template <bool apply_alpha> SkPMColor trunc_from_255(const Sk4f& x) { |
+// As an optimization, we can apply the dither bias before interpolation -- but only when |
+// operating in premul space (apply_alpha == false). When apply_alpha == true, we must |
+// defer the bias application until after premul. |
+// |
+// The following two helpers encapsulate this logic: pre_bias is called before interpolation, |
+// and effects the bias when apply_alpha == false, while post_bias is called after premul and |
+// effects the bias for the apply_alpha == true case. |
+ |
+template <bool apply_alpha> |
+Sk4f pre_bias(const Sk4f& x, const Sk4f& bias) { |
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PREMUL |
+ return x + bias; |
+#else |
+ return apply_alpha ? x : x + bias; |
+#endif |
+} |
+ |
+template <bool apply_alpha> |
+Sk4f post_bias(const Sk4f& x, const Sk4f& bias) { |
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PREMUL |
+ return x; |
+#else |
+ return apply_alpha ? x + bias : x; |
+#endif |
+} |
+ |
+template <bool apply_alpha> SkPMColor trunc_from_255(const Sk4f& x, const Sk4f& bias) { |
SkPMColor c; |
+ |
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PREMUL |
SkNx_cast<uint8_t>(x).store(&c); |
if (apply_alpha) { |
c = SkPreMultiplyARGB(SkGetPackedA32(c), SkGetPackedR32(c), |
SkGetPackedG32(c), SkGetPackedB32(c)); |
} |
+#else |
+ Sk4f c4f255 = x; |
+ if (apply_alpha) { |
+ const float scale = x[SkPM4f::A] * (1 / 255.f); |
+ c4f255 *= Sk4f(scale, scale, scale, 1); |
+ } |
+ SkNx_cast<uint8_t>(post_bias<apply_alpha>(c4f255, bias)).store(&c); |
+#endif |
return c; |
} |
template <bool apply_alpha> void fill(SkPMColor dst[], int count, |
- const Sk4f& c4, const Sk4f& c4other) { |
- sk_memset32_dither(dst, trunc_from_255<apply_alpha>(c4), |
- trunc_from_255<apply_alpha>(c4other), count); |
+ const Sk4f& c4, const Sk4f& bias0, const Sk4f& bias1) { |
+ const SkPMColor c0 = trunc_from_255<apply_alpha>(pre_bias<apply_alpha>(c4, bias0), bias0); |
+ const SkPMColor c1 = trunc_from_255<apply_alpha>(pre_bias<apply_alpha>(c4, bias1), bias1); |
+ sk_memset32_dither(dst, c0, c1, count); |
} |
template <bool apply_alpha> void fill(SkPMColor dst[], int count, const Sk4f& c4) { |
// Assumes that c4 does not need to be dithered. |
- sk_memset32(dst, trunc_from_255<apply_alpha>(c4), count); |
+ sk_memset32(dst, trunc_from_255<apply_alpha>(c4, 0), count); |
} |
/* |
@@ -573,8 +610,8 @@ template <bool apply_alpha> void ramp(SkPMColor dstC[], int n, const Sk4f& c, co |
const Sk4f& dither0, const Sk4f& dither1) { |
Sk4f dc2 = dc + dc; |
Sk4f dc4 = dc2 + dc2; |
- Sk4f cd0 = c + dither0; |
- Sk4f cd1 = c + dc + dither1; |
+ Sk4f cd0 = pre_bias<apply_alpha>(c , dither0); |
+ Sk4f cd1 = pre_bias<apply_alpha>(c + dc, dither1); |
Sk4f cd2 = cd0 + dc2; |
Sk4f cd3 = cd1 + dc2; |
while (n >= 4) { |
@@ -582,10 +619,10 @@ template <bool apply_alpha> void ramp(SkPMColor dstC[], int n, const Sk4f& c, co |
Sk4f_ToBytes((uint8_t*)dstC, cd0, cd1, cd2, cd3); |
dstC += 4; |
} else { |
- *dstC++ = trunc_from_255<apply_alpha>(cd0); |
- *dstC++ = trunc_from_255<apply_alpha>(cd1); |
- *dstC++ = trunc_from_255<apply_alpha>(cd2); |
- *dstC++ = trunc_from_255<apply_alpha>(cd3); |
+ *dstC++ = trunc_from_255<apply_alpha>(cd0, dither0); |
+ *dstC++ = trunc_from_255<apply_alpha>(cd1, dither1); |
+ *dstC++ = trunc_from_255<apply_alpha>(cd2, dither0); |
+ *dstC++ = trunc_from_255<apply_alpha>(cd3, dither1); |
} |
cd0 = cd0 + dc4; |
cd1 = cd1 + dc4; |
@@ -594,12 +631,12 @@ template <bool apply_alpha> void ramp(SkPMColor dstC[], int n, const Sk4f& c, co |
n -= 4; |
} |
if (n & 2) { |
- *dstC++ = trunc_from_255<apply_alpha>(cd0); |
- *dstC++ = trunc_from_255<apply_alpha>(cd1); |
+ *dstC++ = trunc_from_255<apply_alpha>(cd0, dither0); |
+ *dstC++ = trunc_from_255<apply_alpha>(cd1, dither1); |
cd0 = cd0 + dc2; |
} |
if (n & 1) { |
- *dstC++ = trunc_from_255<apply_alpha>(cd0); |
+ *dstC++ = trunc_from_255<apply_alpha>(cd0, dither0); |
} |
} |
@@ -746,9 +783,9 @@ void SkLinearGradient::LinearGradientContext::shade4_clamp(int x, int y, SkPMCol |
const float pinFx = SkTPin(fx, 0.0f, 1.0f); |
Sk4f c = lerp_color(pinFx, find_forward(fRecs.begin(), pinFx)); |
if (fApplyAlphaAfterInterp) { |
- fill<true>(dstC, count, c + dither0, c + dither1); |
+ fill<true>(dstC, count, c, dither0, dither1); |
} else { |
- fill<false>(dstC, count, c + dither0, c + dither1); |
+ fill<false>(dstC, count, c, dither0, dither1); |
} |
return; |
} |