Index: src/core/SkSRGB.h |
diff --git a/src/core/SkSRGB.h b/src/core/SkSRGB.h |
index 08ba860e4a5df9aeb545d95165a62b37dc969728..31fd4aec5e2d31f005121fc03caddb491ce385b0 100644 |
--- a/src/core/SkSRGB.h |
+++ b/src/core/SkSRGB.h |
@@ -28,14 +28,15 @@ static inline Sk4f sk_clamp_0_255(const Sk4f& x) { |
return Sk4f::Min(Sk4f::Max(x, 0.0f), 255.0f); |
} |
-static inline Sk4i sk_linear_to_srgb(const Sk4f& x) { |
+// This should probably only be called from sk_linear_to_srgb() or sk_linear_to_srgb_noclamp(). |
+// It generally doesn't make sense to work with sRGB floats. |
+static inline Sk4f sk_linear_to_srgb_needs_trunc(const Sk4f& x) { |
// Approximation of the sRGB gamma curve (within 1 when scaled to 8-bit pixels). |
// |
- // Tuned by brute force to minimize the number of bytes that fail to round trip, |
- // here 0 (of 256), and then to minimize the number of points halfway between bytes |
- // (in linear space) that fail to hit the right byte, here 131 (of 255), and to |
- // minimize the number of monotonicity regressions over the range [0,1], here 0. |
- |
+ // Constants tuned by brute force to minimize (in order of importance) after truncation: |
+ // 1) the number of bytes that fail to round trip (0 of 256); |
+ // 2) the number of points in [FLT_MIN, 1.0f] that are non-monotonic (0 of ~1 billion); |
+ // 3) the number of points halfway between bytes that hit the wrong byte (131 of 255). |
auto rsqrt = x.rsqrt(), |
sqrt = rsqrt.invert(), |
ftrt = rsqrt.rsqrt(); |
@@ -45,8 +46,20 @@ static inline Sk4i sk_linear_to_srgb(const Sk4f& x) { |
auto hi = (-0.0974983f * 255.0f) |
+ (+0.687999f * 255.0f) * sqrt |
+ (+0.412999f * 255.0f) * ftrt; |
+ return (x < 0.0048f).thenElse(lo, hi); |
+} |
+ |
+static inline Sk4i sk_linear_to_srgb(const Sk4f& x) { |
+ Sk4f f = sk_linear_to_srgb_needs_trunc(x); |
+ return SkNx_cast<int>(sk_clamp_0_255(f)); |
+} |
- return SkNx_cast<int>(sk_clamp_0_255((x < 0.0048f).thenElse(lo, hi))); |
+static inline Sk4i sk_linear_to_srgb_noclamp(const Sk4f& x) { |
+ Sk4f f = sk_linear_to_srgb_needs_trunc(x); |
+ for (int i = 0; i < 4; i++) { |
+ SkASSERTF(0.0f <= f[i] && f[i] < 256.0f, "f[%d] was %g, outside [0,256)\n", i, f[i]); |
+ } |
+ return SkNx_cast<int>(f); |
} |
#endif//SkSRGB_DEFINED |