improve precision of gradients (disabled for now)
BUG=skia:2898
TBR=caryclark
Review URL: https://codereview.chromium.org/815623004
diff --git a/gyp/skia_for_chromium_defines.gypi b/gyp/skia_for_chromium_defines.gypi
index 6a9adf5..a214270 100644
--- a/gyp/skia_for_chromium_defines.gypi
+++ b/gyp/skia_for_chromium_defines.gypi
@@ -13,6 +13,7 @@
# If these become 'permanent', they should be moved into skia_common.gypi
#
'skia_for_chromium_defines': [
+ 'SK_SUPPORT_LEGACY_GRADIENT_PRECISION',
],
},
}
diff --git a/src/effects/gradients/SkClampRange.cpp b/src/effects/gradients/SkClampRange.cpp
index 398b024..cf302cd 100644
--- a/src/effects/gradients/SkClampRange.cpp
+++ b/src/effects/gradients/SkClampRange.cpp
@@ -13,7 +13,7 @@
* returns [0..count] for the number of steps (<= count) for which x0 <= edge
* given each step is followed by x0 += dx
*/
-static int chop(int64_t x0, SkFixed edge, int64_t x1, int64_t dx, int count) {
+static int chop(int64_t x0, SkGradFixed edge, int64_t x1, int64_t dx, int count) {
SkASSERT(dx > 0);
SkASSERT(count >= 0);
@@ -29,15 +29,17 @@
return (int)n;
}
-static bool overflows_fixed(int64_t x) {
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
+static bool overflows_gradfixed(int64_t x) {
return x < -SK_FixedMax || x > SK_FixedMax;
}
+#endif
-void SkClampRange::initFor1(SkFixed fx) {
+void SkClampRange::initFor1(SkGradFixed fx) {
fCount0 = fCount1 = fCount2 = 0;
if (fx <= 0) {
fCount0 = 1;
- } else if (fx < 0xFFFF) {
+ } else if (fx < kFracMax_SkGradFixed) {
fCount1 = 1;
fFx1 = fx;
} else {
@@ -45,7 +47,7 @@
}
}
-void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
+void SkClampRange::init(SkGradFixed fx0, SkGradFixed dx0, int count, int v0, int v1) {
SkASSERT(count > 0);
fV0 = v0;
@@ -60,10 +62,11 @@
int64_t fx = fx0;
int64_t dx = dx0;
+
// start with ex equal to the last computed value
int64_t ex = fx + (count - 1) * dx;
- if ((uint64_t)(fx | ex) <= 0xFFFF) {
+ if ((uint64_t)(fx | ex) <= kFracMax_SkGradFixed) {
fCount0 = fCount2 = 0;
fCount1 = count;
fFx1 = fx0;
@@ -74,7 +77,7 @@
fCount0 = count;
return;
}
- if (fx >= 0xFFFF && ex >= 0xFFFF) {
+ if (fx >= kFracMax_SkGradFixed && ex >= kFracMax_SkGradFixed) {
fCount0 = fCount1 = 0;
fCount2 = count;
return;
@@ -84,8 +87,10 @@
// now make ex be 1 past the last computed value
ex += dx;
+
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
// now check for over/under flow
- if (overflows_fixed(ex)) {
+ if (overflows_gradfixed(ex)) {
int originalCount = count;
int64_t ccount;
bool swap = dx < 0;
@@ -93,7 +98,13 @@
dx = -dx;
fx = -fx;
}
- ccount = (SK_FixedMax - fx + dx - 1) / dx;
+
+ int shift = 0;
+ if (sizeof(SkGradFixed) == 8) {
+ shift = 16;
+ }
+
+ ccount = ((SK_FixedMax << shift) - fx + dx - 1) / dx;
if (swap) {
dx = -dx;
fx = -fx;
@@ -113,6 +124,7 @@
extraCount = originalCount - count;
ex = fx + dx * count;
}
+#endif
bool doSwap = dx < 0;
@@ -129,7 +141,7 @@
fx += fCount0 * dx;
SkASSERT(fx >= 0);
SkASSERT(fCount0 == 0 || (fx - dx) < 0);
- fCount1 = chop(fx, 0xFFFF, ex, dx, count);
+ fCount1 = chop(fx, kFracMax_SkGradFixed, ex, dx, count);
count -= fCount1;
fCount2 = count;
@@ -137,9 +149,9 @@
fx += fCount1 * dx;
SkASSERT(fx <= ex);
if (fCount2 > 0) {
- SkASSERT(fx >= 0xFFFF);
+ SkASSERT(fx >= kFracMax_SkGradFixed);
if (fCount1 > 0) {
- SkASSERT(fx - dx < 0xFFFF);
+ SkASSERT(fx - dx < kFracMax_SkGradFixed);
}
}
#endif
diff --git a/src/effects/gradients/SkClampRange.h b/src/effects/gradients/SkClampRange.h
index 09386d7..a71009d 100644
--- a/src/effects/gradients/SkClampRange.h
+++ b/src/effects/gradients/SkClampRange.h
@@ -1,4 +1,3 @@
-
/*
* Copyright 2011 Google Inc.
*
@@ -6,14 +5,30 @@
* found in the LICENSE file.
*/
-
#ifndef SkClampRange_DEFINED
#define SkClampRange_DEFINED
#include "SkFixed.h"
+#include "SkScalar.h"
+
+#define SK_SUPPORT_LEGACY_GRADIENT_PRECISION
+
+#ifdef SK_SUPPORT_LEGACY_GRADIENT_PRECISION
+ #define SkGradFixed SkFixed
+ #define SkScalarToGradFixed SkScalarToFixed
+ #define SkFixedToGradFixed(x) (x)
+ #define SkGradFixedToFixed(x) (x)
+ #define kFracMax_SkGradFixed 0xFFFF
+#else
+ #define SkGradFixed SkFixed3232
+ #define SkScalarToGradFixed SkScalarToFixed3232
+ #define SkFixedToGradFixed SkFixedToFixed3232
+ #define SkGradFixedToFixed(x) (SkFixed)((x) >> 16)
+ #define kFracMax_SkGradFixed 0xFFFFFFFFLL
+#endif
/**
- * Iteration fixed fx by dx, clamping as you go to [0..0xFFFF], this class
+ * Iteration fixed fx by dx, clamping as you go to [0..kFracMax_SkGradFixed], this class
* computes the (up to) 3 spans there are:
*
* range0: use constant value V0
@@ -24,14 +39,14 @@
int fCount0; // count for fV0
int fCount1; // count for interpolating (fV0...fV1)
int fCount2; // count for fV1
- SkFixed fFx1; // initial fx value for the fCount1 range.
+ SkGradFixed fFx1; // initial fx value for the fCount1 range.
// only valid if fCount1 > 0
int fV0, fV1;
- void init(SkFixed fx, SkFixed dx, int count, int v0, int v1);
+ void init(SkGradFixed fx, SkGradFixed dx, int count, int v0, int v1);
private:
- void initFor1(SkFixed fx);
+ void initFor1(SkGradFixed fx);
};
#endif
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 4e7a6c7..885a1b5 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -104,7 +104,7 @@
#define NO_CHECK_ITER \
do { \
- unsigned fi = fx >> SkGradientShaderBase::kCache32Shift; \
+ unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache32Shift; \
SkASSERT(fi <= 0xFF); \
fx += dx; \
*dstC++ = cache[toggle + fi]; \
@@ -113,21 +113,21 @@
namespace {
-typedef void (*LinearShadeProc)(TileProc proc, SkFixed dx, SkFixed fx,
+typedef void (*LinearShadeProc)(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* dstC, const SkPMColor* cache,
int toggle, int count);
// Linear interpolation (lerp) is unnecessary if there are no sharp
// discontinuities in the gradient - which must be true if there are
// only 2 colors - but it's cheap.
-void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_vertical_lerp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache,
int toggle, int count) {
// We're a vertical gradient, so no change in a span.
// If colors change sharply across the gradient, dithering is
// insufficient (it subsamples the color space) and we need to lerp.
- unsigned fullIndex = proc(fx);
+ unsigned fullIndex = proc(SkGradFixedToFixed(fx));
unsigned fi = fullIndex >> SkGradientShaderBase::kCache32Shift;
unsigned remainder = fullIndex & ((1 << SkGradientShaderBase::kCache32Shift) - 1);
@@ -143,7 +143,7 @@
sk_memset32_dither(dstC, lerp, dlerp, count);
}
-void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache,
int toggle, int count) {
@@ -180,12 +180,12 @@
}
}
-void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = mirror_8bits(fx >> 8);
+ unsigned fi = mirror_8bits(SkGradFixedToFixed(fx) >> 8);
SkASSERT(fi <= 0xFF);
fx += dx;
*dstC++ = cache[toggle + fi];
@@ -193,12 +193,12 @@
} while (--count != 0);
}
-void shadeSpan_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
SkPMColor* SK_RESTRICT dstC,
const SkPMColor* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = repeat_8bits(fx >> 8);
+ unsigned fi = repeat_8bits(SkGradFixedToFixed(fx) >> 8);
SkASSERT(fi <= 0xFF);
fx += dx;
*dstC++ = cache[toggle + fi];
@@ -223,15 +223,16 @@
if (fDstToIndexClass != kPerspective_MatrixClass) {
dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+ SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX);
if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
SkFixed dxStorage[1];
(void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
- dx = dxStorage[0];
+ // todo: do we need a real/high-precision value for dx here?
+ dx = SkFixedToGradFixed(dxStorage[0]);
} else {
SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarToFixed(fDstToIndex.getScaleX());
+ dx = SkScalarToGradFixed(fDstToIndex.getScaleX());
}
LinearShadeProc shadeProc = shadeSpan_linear_repeat;
@@ -301,7 +302,7 @@
#define NO_CHECK_ITER_16 \
do { \
- unsigned fi = fx >> SkGradientShaderBase::kCache16Shift; \
+ unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift; \
SkASSERT(fi < SkGradientShaderBase::kCache16Count); \
fx += dx; \
*dstC++ = cache[toggle + fi]; \
@@ -310,22 +311,22 @@
namespace {
-typedef void (*LinearShade16Proc)(TileProc proc, SkFixed dx, SkFixed fx,
+typedef void (*LinearShade16Proc)(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* dstC, const uint16_t* cache,
int toggle, int count);
-void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_vertical(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
// we're a vertical gradient, so no change in a span
- unsigned fi = proc(fx) >> SkGradientShaderBase::kCache16Shift;
+ unsigned fi = proc(SkGradFixedToFixed(fx)) >> SkGradientShaderBase::kCache16Shift;
SkASSERT(fi < SkGradientShaderBase::kCache16Count);
dither_memset16(dstC, cache[toggle + fi],
cache[next_dither_toggle16(toggle) + fi], count);
}
-void shadeSpan16_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
@@ -362,12 +363,12 @@
}
}
-void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = mirror_bits(fx >> SkGradientShaderBase::kCache16Shift,
+ unsigned fi = mirror_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift,
SkGradientShaderBase::kCache16Bits);
SkASSERT(fi < SkGradientShaderBase::kCache16Count);
fx += dx;
@@ -376,12 +377,12 @@
} while (--count != 0);
}
-void shadeSpan16_linear_repeat(TileProc proc, SkFixed dx, SkFixed fx,
+void shadeSpan16_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx,
uint16_t* SK_RESTRICT dstC,
const uint16_t* SK_RESTRICT cache,
int toggle, int count) {
do {
- unsigned fi = repeat_bits(fx >> SkGradientShaderBase::kCache16Shift,
+ unsigned fi = repeat_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift,
SkGradientShaderBase::kCache16Bits);
SkASSERT(fi < SkGradientShaderBase::kCache16Count);
fx += dx;
@@ -410,19 +411,20 @@
if (fDstToIndexClass != kPerspective_MatrixClass) {
dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- SkFixed dx, fx = SkScalarToFixed(srcPt.fX);
+ SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX);
if (fDstToIndexClass == kFixedStepInX_MatrixClass) {
SkFixed dxStorage[1];
(void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, NULL);
- dx = dxStorage[0];
+ // todo: do we need a real/high-precision value for dx here?
+ dx = SkFixedToGradFixed(dxStorage[0]);
} else {
SkASSERT(fDstToIndexClass == kLinear_MatrixClass);
- dx = SkScalarToFixed(fDstToIndex.getScaleX());
+ dx = SkScalarToGradFixed(fDstToIndex.getScaleX());
}
LinearShade16Proc shadeProc = shadeSpan16_linear_repeat;
- if (fixed_nearly_zero(dx)) {
+ if (fixed_nearly_zero(SkGradFixedToFixed(dx))) {
shadeProc = shadeSpan16_linear_vertical;
} else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) {
shadeProc = shadeSpan16_linear_clamp;