diff options
Diffstat (limited to 'chromium/third_party/skia/src/effects/gradients/SkSweepGradient.cpp')
-rw-r--r-- | chromium/third_party/skia/src/effects/gradients/SkSweepGradient.cpp | 295 |
1 files changed, 55 insertions, 240 deletions
diff --git a/chromium/third_party/skia/src/effects/gradients/SkSweepGradient.cpp b/chromium/third_party/skia/src/effects/gradients/SkSweepGradient.cpp index c38205b844a..154e3a2f138 100644 --- a/chromium/third_party/skia/src/effects/gradients/SkSweepGradient.cpp +++ b/chromium/third_party/skia/src/effects/gradients/SkSweepGradient.cpp @@ -9,8 +9,8 @@ #include "SkSweepGradient.h" SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, - const Descriptor& desc) - : SkGradientShaderBase(desc) + const Descriptor& desc, const SkMatrix* localMatrix) + : SkGradientShaderBase(desc, localMatrix) , fCenter(SkPoint::Make(cx, cy)) { fPtsToUnit.setTranslate(-cx, -cy); @@ -42,188 +42,29 @@ SkShader::GradientType SkSweepGradient::asAGradient(GradientInfo* info) const { return kSweep_GradientType; } -SkSweepGradient::SkSweepGradient(SkFlattenableReadBuffer& buffer) +SkSweepGradient::SkSweepGradient(SkReadBuffer& buffer) : INHERITED(buffer), fCenter(buffer.readPoint()) { } -void SkSweepGradient::flatten(SkFlattenableWriteBuffer& buffer) const { +void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); buffer.writePoint(fCenter); } -#ifndef SK_SCALAR_IS_FLOAT -#ifdef COMPUTE_SWEEP_TABLE -#define PI 3.14159265 -static bool gSweepTableReady; -static uint8_t gSweepTable[65]; - -/* Our table stores precomputed values for atan: [0...1] -> [0..PI/4] - We scale the results to [0..32] -*/ -static const uint8_t* build_sweep_table() { - if (!gSweepTableReady) { - const int N = 65; - const double DENOM = N - 1; - - for (int i = 0; i < N; i++) - { - double arg = i / DENOM; - double v = atan(arg); - int iv = (int)round(v * DENOM * 2 / PI); -// printf("[%d] atan(%g) = %g %d\n", i, arg, v, iv); - printf("%d, ", iv); - gSweepTable[i] = iv; - } - gSweepTableReady = true; - } - return gSweepTable; +size_t SkSweepGradient::contextSize() const { + return sizeof(SweepGradientContext); } -#else -static const uint8_t gSweepTable[] = { - 0, 1, 1, 2, 3, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9, 9, - 10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18, - 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, - 26, 27, 27, 27, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, - 32 -}; -static const uint8_t* build_sweep_table() { return gSweepTable; } -#endif -#endif - -// divide numer/denom, with a bias of 6bits. Assumes numer <= denom -// and denom != 0. Since our table is 6bits big (+1), this is a nice fit. -// Same as (but faster than) SkFixedDiv(numer, denom) >> 10 - -//unsigned div_64(int numer, int denom); -#ifndef SK_SCALAR_IS_FLOAT -static unsigned div_64(int numer, int denom) { - SkASSERT(numer <= denom); - SkASSERT(numer > 0); - SkASSERT(denom > 0); - - int nbits = SkCLZ(numer); - int dbits = SkCLZ(denom); - int bits = 6 - nbits + dbits; - SkASSERT(bits <= 6); - - if (bits < 0) { // detect underflow - return 0; - } - - denom <<= dbits - 1; - numer <<= nbits - 1; - - unsigned result = 0; - // do the first one - if ((numer -= denom) >= 0) { - result = 1; - } else { - numer += denom; - } - - // Now fall into our switch statement if there are more bits to compute - if (bits > 0) { - // make room for the rest of the answer bits - result <<= bits; - switch (bits) { - case 6: - if ((numer = (numer << 1) - denom) >= 0) - result |= 32; - else - numer += denom; - case 5: - if ((numer = (numer << 1) - denom) >= 0) - result |= 16; - else - numer += denom; - case 4: - if ((numer = (numer << 1) - denom) >= 0) - result |= 8; - else - numer += denom; - case 3: - if ((numer = (numer << 1) - denom) >= 0) - result |= 4; - else - numer += denom; - case 2: - if ((numer = (numer << 1) - denom) >= 0) - result |= 2; - else - numer += denom; - case 1: - default: // not strictly need, but makes GCC make better ARM code - if ((numer = (numer << 1) - denom) >= 0) - result |= 1; - else - numer += denom; - } - } - return result; +SkShader::Context* SkSweepGradient::onCreateContext(const ContextRec& rec, void* storage) const { + return SkNEW_PLACEMENT_ARGS(storage, SweepGradientContext, (*this, rec)); } -#endif - -// Given x,y in the first quadrant, return 0..63 for the angle [0..90] -#ifndef SK_SCALAR_IS_FLOAT -static unsigned atan_0_90(SkFixed y, SkFixed x) { -#ifdef SK_DEBUG - { - static bool gOnce; - if (!gOnce) { - gOnce = true; - SkASSERT(div_64(55, 55) == 64); - SkASSERT(div_64(128, 256) == 32); - SkASSERT(div_64(2326528, 4685824) == 31); - SkASSERT(div_64(753664, 5210112) == 9); - SkASSERT(div_64(229376, 4882432) == 3); - SkASSERT(div_64(2, 64) == 2); - SkASSERT(div_64(1, 64) == 1); - // test that we handle underflow correctly - SkASSERT(div_64(12345, 0x54321234) == 0); - } - } -#endif - - SkASSERT(y > 0 && x > 0); - const uint8_t* table = build_sweep_table(); - - unsigned result; - bool swap = (x < y); - if (swap) { - // first part of the atan(v) = PI/2 - atan(1/v) identity - // since our div_64 and table want v <= 1, where v = y/x - SkTSwap<SkFixed>(x, y); - } - - result = div_64(y, x); -#ifdef SK_DEBUG - { - unsigned result2 = SkDivBits(y, x, 6); - SkASSERT(result2 == result || - (result == 1 && result2 == 0)); - } -#endif - - SkASSERT(result < SK_ARRAY_COUNT(gSweepTable)); - result = table[result]; - - if (swap) { - // complete the atan(v) = PI/2 - atan(1/v) identity - result = 64 - result; - // pin to 63 - result -= result >> 6; - } - - SkASSERT(result <= 63); - return result; -} -#endif +SkSweepGradient::SweepGradientContext::SweepGradientContext( + const SkSweepGradient& shader, const ContextRec& rec) + : INHERITED(shader, rec) {} // returns angle in a circle [0..2PI) -> [0..255] -#ifdef SK_SCALAR_IS_FLOAT static unsigned SkATan2_255(float y, float x) { // static const float g255Over2PI = 255 / (2 * SK_ScalarPI); static const float g255Over2PI = 40.584510488433314f; @@ -239,68 +80,12 @@ static unsigned SkATan2_255(float y, float x) { SkASSERT(ir >= 0 && ir <= 255); return ir; } -#else -static unsigned SkATan2_255(SkFixed y, SkFixed x) { - if (x == 0) { - if (y == 0) { - return 0; - } - return y < 0 ? 192 : 64; - } - if (y == 0) { - return x < 0 ? 128 : 0; - } - - /* Find the right quadrant for x,y - Since atan_0_90 only handles the first quadrant, we rotate x,y - appropriately before calling it, and then add the right amount - to account for the real quadrant. - quadrant 0 : add 0 | x > 0 && y > 0 - quadrant 1 : add 64 (90 degrees) | x < 0 && y > 0 - quadrant 2 : add 128 (180 degrees) | x < 0 && y < 0 - quadrant 3 : add 192 (270 degrees) | x > 0 && y < 0 - - map x<0 to (1 << 6) - map y<0 to (3 << 6) - add = map_x ^ map_y - */ - int xsign = x >> 31; - int ysign = y >> 31; - int add = ((-xsign) ^ (ysign & 3)) << 6; - -#ifdef SK_DEBUG - if (0 == add) - SkASSERT(x > 0 && y > 0); - else if (64 == add) - SkASSERT(x < 0 && y > 0); - else if (128 == add) - SkASSERT(x < 0 && y < 0); - else if (192 == add) - SkASSERT(x > 0 && y < 0); - else - SkDEBUGFAIL("bad value for add"); -#endif - - /* This ^ trick makes x, y positive, and the swap<> handles quadrants - where we need to rotate x,y by 90 or -90 - */ - x = (x ^ xsign) - xsign; - y = (y ^ ysign) - ysign; - if (add & 64) { // quads 1 or 3 need to swap x,y - SkTSwap<SkFixed>(x, y); - } - - unsigned result = add + atan_0_90(y, x); - SkASSERT(result < 256); - return result; -} -#endif -void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, - int count) { +void SkSweepGradient::SweepGradientContext::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, + int count) { SkMatrix::MapXYProc proc = fDstToIndexProc; const SkMatrix& matrix = fDstToIndex; - const SkPMColor* SK_RESTRICT cache = this->getCache32(); + const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); int toggle = init_dither_toggle(x, y); SkPoint srcPt; @@ -338,11 +123,11 @@ void SkSweepGradient::shadeSpan(int x, int y, SkPMColor* SK_RESTRICT dstC, } } -void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, - int count) { +void SkSweepGradient::SweepGradientContext::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, + int count) { SkMatrix::MapXYProc proc = fDstToIndexProc; const SkMatrix& matrix = fDstToIndex; - const uint16_t* SK_RESTRICT cache = this->getCache16(); + const uint16_t* SK_RESTRICT cache = fCache->getCache16(); int toggle = init_dither_toggle16(x, y); SkPoint srcPt; @@ -389,6 +174,7 @@ void SkSweepGradient::shadeSpan16(int x, int y, uint16_t* SK_RESTRICT dstC, #if SK_SUPPORT_GPU #include "GrTBackendEffectFactory.h" +#include "SkGr.h" class GrGLSweepGradient : public GrGLGradientEffect { public: @@ -462,7 +248,10 @@ GrEffectRef* GrSweepGradient::TestCreate(SkRandom* random, SkAutoTUnref<SkShader> shader(SkGradientShader::CreateSweep(center.fX, center.fY, colors, stops, colorCount)); SkPaint paint; - return shader->asNewEffect(context, paint); + GrEffectRef* effect; + GrColor grColor; + shader->asNewEffect(context, paint, NULL, &grColor, &effect); + return effect; } ///////////////////////////////////////////////////////////////////// @@ -476,33 +265,59 @@ void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder, const TextureSamplerArray& samplers) { this->emitUniforms(builder, key); SkString coords2D = builder->ensureFSCoords2D(coords, 0); + const GrGLContextInfo ctxInfo = builder->ctxInfo(); SkString t; - t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords2D.c_str(), coords2D.c_str()); + // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi] + // On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int + // thus must us -1.0 * %s.x to work correctly + if (kIntel_GrGLVendor != ctxInfo.vendor()){ + t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", + coords2D.c_str(), coords2D.c_str()); + } else { + t.printf("atan(- %s.y, -1.0 * %s.x) * 0.1591549430918 + 0.5", + coords2D.c_str(), coords2D.c_str()); + } this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers); } ///////////////////////////////////////////////////////////////////// -GrEffectRef* SkSweepGradient::asNewEffect(GrContext* context, const SkPaint&) const { +bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint, + const SkMatrix* localMatrix, GrColor* grColor, + GrEffectRef** grEffect) const { + SkMatrix matrix; if (!this->getLocalMatrix().invert(&matrix)) { - return NULL; + return false; + } + if (localMatrix) { + SkMatrix inv; + if (!localMatrix->invert(&inv)) { + return false; + } + matrix.postConcat(inv); } matrix.postConcat(fPtsToUnit); - return GrSweepGradient::Create(context, *this, matrix); + + *grEffect = GrSweepGradient::Create(context, *this, matrix); + *grColor = SkColor2GrColorJustAlpha(paint.getColor()); + + return true; } #else -GrEffectRef* SkSweepGradient::asNewEffect(GrContext*, const SkPaint&) const { +bool SkSweepGradient::asNewEffect(GrContext* context, const SkPaint& paint, + const SkMatrix* localMatrix, GrColor* grColor, + GrEffectRef** grEffect) const { SkDEBUGFAIL("Should not call in GPU-less build"); - return NULL; + return false; } #endif -#ifdef SK_DEVELOPER +#ifndef SK_IGNORE_TO_STRING void SkSweepGradient::toString(SkString* str) const { str->append("SkSweepGradient: ("); |