improve precision of gradients (disabled for now)
BUG=skia:2898 TBR=caryclark Review URL: https://codereview.chromium.org/815623004
This commit is contained in:
parent
695025fe1d
commit
caf7e9313b
@ -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',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
@ -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 @@ static int chop(int64_t x0, SkFixed edge, int64_t x1, int64_t dx, int count) {
|
||||
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::initFor1(SkFixed fx) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
|
||||
|
||||
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 @@ void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
|
||||
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 @@ void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
|
||||
|
||||
// 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 @@ void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
|
||||
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 @@ void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
|
||||
extraCount = originalCount - count;
|
||||
ex = fx + dx * count;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool doSwap = dx < 0;
|
||||
|
||||
@ -129,7 +141,7 @@ void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
|
||||
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 @@ void SkClampRange::init(SkFixed fx0, SkFixed dx0, int count, int v0, int v1) {
|
||||
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
|
||||
|
@ -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 @@ struct SkClampRange {
|
||||
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
|
||||
|
@ -104,7 +104,7 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext(
|
||||
|
||||
#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 @@ SkLinearGradient::LinearGradientContext::LinearGradientContext(
|
||||
|
||||
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 @@ void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
|
||||
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_clamp(TileProc proc, SkFixed dx, SkFixed fx,
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
|
||||
} 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 @@ void SkLinearGradient::LinearGradientContext::shadeSpan(int x, int y, SkPMColor*
|
||||
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 @@ static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
|
||||
|
||||
#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 @@ static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
|
||||
|
||||
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_clamp(TileProc proc, SkFixed dx, SkFixed fx,
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void shadeSpan16_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
|
||||
} 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 @@ void SkLinearGradient::LinearGradientContext::shadeSpan16(int x, int y,
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user