aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-02-04 18:21:23 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-02-04 18:21:23 +0000
commit60040292be58ac553298209fb2e0684a4cb17dcc (patch)
tree6cfc2e2a1ccde64fd438978f49b036ae11ac1aa7 /src/effects
parent73349aa33277889d79e3e8bd8cef89cdf0310288 (diff)
Go from a 1x2 to a 2x2 dither cell, and change/simplify the logic for how we
compute the "dithered" version of a color to just a graduated fixed-point-round. Also, add this new dither to conical and sweep, which before had no dithering. Disabled for now using SK_IGNORE_GRADIENT_DITHER_FIX. Will enable this and and rebaseline skia. http://code.google.com/p/skia/issues/detail?id=1098 Review URL: https://codereview.appspot.com/7248046 git-svn-id: http://skia.googlecode.com/svn/trunk@7549 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/gradients/SkGradientShader.cpp43
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h11
-rw-r--r--src/effects/gradients/SkLinearGradient.cpp5
-rw-r--r--src/effects/gradients/SkRadialGradient.cpp3
-rw-r--r--src/effects/gradients/SkSweepGradient.cpp15
-rw-r--r--src/effects/gradients/SkTwoPointConicalGradient.cpp46
6 files changed, 103 insertions, 20 deletions
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index de9ae9e48b..aa03ecb208 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright 2006 The Android Open Source Project
*
@@ -327,18 +326,54 @@ void SkGradientShaderBase::Build32bitCache(SkPMColor cache[], SkColor c0, SkColo
SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
a = SkIntToFixed(a) + 0x8000;
r = SkIntToFixed(r) + 0x8000;
g = SkIntToFixed(g) + 0x8000;
b = SkIntToFixed(b) + 0x8000;
+#else
+ a = SkIntToFixed(a);
+ r = SkIntToFixed(r);
+ g = SkIntToFixed(g);
+ b = SkIntToFixed(b);
+#endif
do {
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
cache[0] = SkPremultiplyARGBInline(a >> 16, r >> 16, g >> 16, b >> 16);
cache[kCache32Count] =
SkPremultiplyARGBInline(dither_ceil_fixed_to_8(a),
dither_fixed_to_8(r),
dither_fixed_to_8(g),
dither_fixed_to_8(b));
+#else
+ /*
+ * Our dither-cell (spatially) is
+ * 0 2
+ * 3 1
+ * Where
+ * [0] -> [-1/8 ... 1/8 ) values near 0
+ * [1] -> [ 1/8 ... 3/8 ) values near 1/4
+ * [2] -> [ 3/8 ... 5/8 ) values near 1/2
+ * [3] -> [ 5/8 ... 7/8 ) values near 3/4
+ */
+ cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0x2000) >> 16,
+ (r + 0x2000) >> 16,
+ (g + 0x2000) >> 16,
+ (b + 0x2000) >> 16);
+ cache[kCache32Count*3] = SkPremultiplyARGBInline((a + 0x6000) >> 16,
+ (r + 0x6000) >> 16,
+ (g + 0x6000) >> 16,
+ (b + 0x6000) >> 16);
+ cache[kCache32Count*1] = SkPremultiplyARGBInline((a + 0xA000) >> 16,
+ (r + 0xA000) >> 16,
+ (g + 0xA000) >> 16,
+ (b + 0xA000) >> 16);
+ cache[kCache32Count*2] = SkPremultiplyARGBInline((a + 0xE000) >> 16,
+ (r + 0xE000) >> 16,
+ (g + 0xE000) >> 16,
+ (b + 0xE000) >> 16);
+#endif
cache += 1;
a += da;
r += dr;
@@ -410,7 +445,7 @@ const uint16_t* SkGradientShaderBase::getCache16() const {
const SkPMColor* SkGradientShaderBase::getCache32() const {
if (fCache32 == NULL) {
// double the count for dither entries
- const int entryCount = kCache32Count * 2;
+ const int entryCount = kCache32Count * 4;
const size_t allocSize = sizeof(SkPMColor) * entryCount;
if (NULL == fCache32PixelRef) {
@@ -446,6 +481,10 @@ const SkPMColor* SkGradientShaderBase::getCache32() const {
int index = map->mapUnit16((i << 8) | i) >> 8;
mapped[i] = linear[index];
mapped[i + kCache32Count] = linear[index + kCache32Count];
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ mapped[i + kCache32Count*2] = linear[index + kCache32Count*2];
+ mapped[i + kCache32Count*3] = linear[index + kCache32Count*3];
+#endif
}
fCache32PixelRef->unref();
fCache32PixelRef = newPR;
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 4d14dc6a07..82535de5d3 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -1,4 +1,3 @@
-
/*
* Copyright 2012 Google Inc.
*
@@ -20,6 +19,8 @@
#include "SkBitmapCache.h"
#include "SkShader.h"
+#define SK_IGNORE_GRADIENT_DITHER_FIX
+
#ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
#define USE_DITHER_32BIT_GRADIENT
#endif
@@ -108,7 +109,7 @@ public:
/// Seems like enough for visual accuracy. TODO: if pos[] deserves
/// it, use a larger cache.
kCache32Bits = 8,
- kCache32Count = (1 << kCache32Bits),
+ kCache32Count = (1 << kCache32Bits),
kCache32Shift = 16 - kCache32Bits,
kSqrt32Shift = 8 - kCache32Bits,
@@ -176,7 +177,13 @@ private:
};
static inline int init_dither_toggle(int x, int y) {
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride32;
+#else
+ x &= 1;
+ y = (y & 1) << 1;
+ return (x | y) * SkGradientShaderBase::kDitherStride32;
+#endif
}
static inline int next_dither_toggle(int toggle) {
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 03393f726a..059cc93493 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -94,7 +94,11 @@ bool SkLinearGradient::setContext(const SkBitmap& device, const SkPaint& paint,
unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
if ((fDstToIndex.getType() & ~mask) == 0) {
+#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
fFlags |= SkShader::kConstInY32_Flag;
+#else
+ // when we dither, we are (usually) not const-in-Y
+#endif
if ((fFlags & SkShader::kHasSpan16_Flag) && !paint.isDither()) {
// only claim this if we do have a 16bit mode (i.e. none of our
// colors have alpha), and if we are not dithering (which obviously
@@ -328,7 +332,6 @@ void shadeSpan16_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
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,
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 328fe76e51..fdca340f3a 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -335,8 +335,7 @@ void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx,
if (count) {
UNPINNED_RADIAL_STEP;
}
- }
- else {
+ } else {
// Specializing for dy == 0 gains us 25% on Skia benchmarks
if (dy == 0) {
unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1);
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index db18521066..458ddbc590 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -298,6 +298,11 @@ void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
SkMatrix::MapXYProc proc = fDstToIndexProc;
const SkMatrix& matrix = fDstToIndex;
const SkPMColor* SK_RESTRICT cache = this->getCache32();
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ int toggle = init_dither_toggle(x, y);
+#else
+ int toggle = 0;
+#endif
SkPoint srcPt;
if (fDstToIndexClass != kPerspective_MatrixClass) {
@@ -319,15 +324,21 @@ void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC,
}
for (; count > 0; --count) {
- *dstC++ = cache[SkATan2_255(fy, fx)];
+ *dstC++ = cache[toggle + SkATan2_255(fy, fx)];
fx += dx;
fy += dy;
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ toggle = next_dither_toggle(toggle);
+#endif
}
} else { // perspective case
for (int stop = x + count; x < stop; x++) {
proc(matrix, SkIntToScalar(x) + SK_ScalarHalf,
SkIntToScalar(y) + SK_ScalarHalf, &srcPt);
- *dstC++ = cache[SkATan2_255(srcPt.fY, srcPt.fX)];
+ *dstC++ = cache[toggle + SkATan2_255(srcPt.fY, srcPt.fX)];
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ toggle = next_dither_toggle(toggle);
+#endif
}
}
}
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index e23953005b..f1acd551cc 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -113,11 +113,12 @@ SkFixed TwoPtRadial::nextT() {
return SkFloatToFixed(t);
}
-typedef void (*TwoPointRadialProc)(TwoPtRadial* rec, SkPMColor* dstC,
- const SkPMColor* cache, int count);
+typedef void (*TwoPointConicalProc)(TwoPtRadial* rec, SkPMColor* dstC,
+ const SkPMColor* cache, int toggle, int count);
static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache, int count) {
+ const SkPMColor* SK_RESTRICT cache, int toggle,
+ int count) {
for (; count > 0; --count) {
SkFixed t = rec->nextT();
if (TwoPtRadial::DontDrawT(t)) {
@@ -125,13 +126,18 @@ static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
} else {
SkFixed index = SkClampMax(t, 0xFFFF);
SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+ *dstC++ = cache[toggle +
+ (index >> SkGradientShaderBase::kCache32Shift)];
}
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ toggle = next_dither_toggle(toggle);
+#endif
}
}
static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache, int count) {
+ const SkPMColor* SK_RESTRICT cache, int toggle,
+ int count) {
for (; count > 0; --count) {
SkFixed t = rec->nextT();
if (TwoPtRadial::DontDrawT(t)) {
@@ -139,13 +145,18 @@ static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
} else {
SkFixed index = repeat_tileproc(t);
SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+ *dstC++ = cache[toggle +
+ (index >> SkGradientShaderBase::kCache32Shift)];
}
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ toggle = next_dither_toggle(toggle);
+#endif
}
}
static void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
- const SkPMColor* SK_RESTRICT cache, int count) {
+ const SkPMColor* SK_RESTRICT cache, int toggle,
+ int count) {
for (; count > 0; --count) {
SkFixed t = rec->nextT();
if (TwoPtRadial::DontDrawT(t)) {
@@ -153,8 +164,12 @@ static void twopoint_mirror(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
} else {
SkFixed index = mirror_tileproc(t);
SkASSERT(index <= 0xFFFF);
- *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+ *dstC++ = cache[toggle +
+ (index >> SkGradientShaderBase::kCache32Shift)];
}
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ toggle = next_dither_toggle(toggle);
+#endif
}
}
@@ -183,6 +198,12 @@ SkTwoPointConicalGradient::SkTwoPointConicalGradient(
void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
int count) {
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ int toggle = init_dither_toggle(x, y);
+#else
+ int toggle = 0;
+#endif
+
SkASSERT(count > 0);
SkPMColor* SK_RESTRICT dstC = dstCParam;
@@ -191,7 +212,7 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
const SkPMColor* SK_RESTRICT cache = this->getCache32();
- TwoPointRadialProc shadeProc = twopoint_repeat;
+ TwoPointConicalProc shadeProc = twopoint_repeat;
if (SkShader::kClamp_TileMode == fTileMode) {
shadeProc = twopoint_clamp;
} else if (SkShader::kMirror_TileMode == fTileMode) {
@@ -219,7 +240,7 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
}
fRec.setup(fx, fy, dx, dy);
- (*shadeProc)(&fRec, dstC, cache, count);
+ (*shadeProc)(&fRec, dstC, cache, toggle, count);
} else { // perspective case
SkScalar dstX = SkIntToScalar(x);
SkScalar dstY = SkIntToScalar(y);
@@ -229,7 +250,10 @@ void SkTwoPointConicalGradient::shadeSpan(int x, int y, SkPMColor* dstCParam,
dstX += SK_Scalar1;
fRec.setup(srcPt.fX, srcPt.fY, 0, 0);
- (*shadeProc)(&fRec, dstC, cache, 1);
+ (*shadeProc)(&fRec, dstC, cache, toggle, 1);
+#ifndef SK_IGNORE_GRADIENT_DITHER_FIX
+ toggle = next_dither_toggle(toggle);
+#endif
}
}
}