1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/effects/gradients/SkRadialGradient.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,582 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2012 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkRadialGradient.h" 1.13 +#include "SkRadialGradient_Table.h" 1.14 + 1.15 +#define kSQRT_TABLE_BITS 11 1.16 +#define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) 1.17 + 1.18 +#if 0 1.19 + 1.20 +#include <stdio.h> 1.21 + 1.22 +void SkRadialGradient_BuildTable() { 1.23 + // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table 1.24 + 1.25 + FILE* file = ::fopen("SkRadialGradient_Table.h", "w"); 1.26 + SkASSERT(file); 1.27 + ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n"); 1.28 + 1.29 + for (int i = 0; i < kSQRT_TABLE_SIZE; i++) { 1.30 + if ((i & 15) == 0) { 1.31 + ::fprintf(file, "\t"); 1.32 + } 1.33 + 1.34 + uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8); 1.35 + 1.36 + ::fprintf(file, "0x%02X", value); 1.37 + if (i < kSQRT_TABLE_SIZE-1) { 1.38 + ::fprintf(file, ", "); 1.39 + } 1.40 + if ((i & 15) == 15) { 1.41 + ::fprintf(file, "\n"); 1.42 + } 1.43 + } 1.44 + ::fprintf(file, "};\n"); 1.45 + ::fclose(file); 1.46 +} 1.47 + 1.48 +#endif 1.49 + 1.50 +namespace { 1.51 + 1.52 +// GCC doesn't like using static functions as template arguments. So force these to be non-static. 1.53 +inline SkFixed mirror_tileproc_nonstatic(SkFixed x) { 1.54 + return mirror_tileproc(x); 1.55 +} 1.56 + 1.57 +inline SkFixed repeat_tileproc_nonstatic(SkFixed x) { 1.58 + return repeat_tileproc(x); 1.59 +} 1.60 + 1.61 +void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, 1.62 + SkMatrix* matrix) { 1.63 + SkScalar inv = SkScalarInvert(radius); 1.64 + 1.65 + matrix->setTranslate(-center.fX, -center.fY); 1.66 + matrix->postScale(inv, inv); 1.67 +} 1.68 + 1.69 +typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx, 1.70 + SkScalar sfy, SkScalar sdy, 1.71 + uint16_t* dstC, const uint16_t* cache, 1.72 + int toggle, int count); 1.73 + 1.74 +void shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx, 1.75 + SkScalar sfy, SkScalar sdy, 1.76 + uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 1.77 + int toggle, int count) { 1.78 + const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; 1.79 + 1.80 + /* knock these down so we can pin against +- 0x7FFF, which is an 1.81 + immediate load, rather than 0xFFFF which is slower. This is a 1.82 + compromise, since it reduces our precision, but that appears 1.83 + to be visually OK. If we decide this is OK for all of our cases, 1.84 + we could (it seems) put this scale-down into fDstToIndex, 1.85 + to avoid having to do these extra shifts each time. 1.86 + */ 1.87 + SkFixed fx = SkScalarToFixed(sfx) >> 1; 1.88 + SkFixed dx = SkScalarToFixed(sdx) >> 1; 1.89 + SkFixed fy = SkScalarToFixed(sfy) >> 1; 1.90 + SkFixed dy = SkScalarToFixed(sdy) >> 1; 1.91 + // might perform this check for the other modes, 1.92 + // but the win will be a smaller % of the total 1.93 + if (dy == 0) { 1.94 + fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 1.95 + fy *= fy; 1.96 + do { 1.97 + unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 1.98 + unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS); 1.99 + fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 1.100 + fx += dx; 1.101 + *dstC++ = cache[toggle + 1.102 + (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; 1.103 + toggle = next_dither_toggle16(toggle); 1.104 + } while (--count != 0); 1.105 + } else { 1.106 + do { 1.107 + unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 1.108 + unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 1.109 + fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); 1.110 + fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 1.111 + fx += dx; 1.112 + fy += dy; 1.113 + *dstC++ = cache[toggle + 1.114 + (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; 1.115 + toggle = next_dither_toggle16(toggle); 1.116 + } while (--count != 0); 1.117 + } 1.118 +} 1.119 + 1.120 +template <SkFixed (*TileProc)(SkFixed)> 1.121 +void shadeSpan16_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 1.122 + uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 1.123 + int toggle, int count) { 1.124 + do { 1.125 + const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); 1.126 + const unsigned fi = TileProc(dist); 1.127 + SkASSERT(fi <= 0xFFFF); 1.128 + *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache16Shift)]; 1.129 + toggle = next_dither_toggle16(toggle); 1.130 + fx += dx; 1.131 + fy += dy; 1.132 + } while (--count != 0); 1.133 +} 1.134 + 1.135 +void shadeSpan16_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 1.136 + uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 1.137 + int toggle, int count) { 1.138 + shadeSpan16_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, toggle, count); 1.139 +} 1.140 + 1.141 +void shadeSpan16_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 1.142 + uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 1.143 + int toggle, int count) { 1.144 + shadeSpan16_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, toggle, count); 1.145 +} 1.146 + 1.147 +} // namespace 1.148 + 1.149 +///////////////////////////////////////////////////////////////////// 1.150 + 1.151 +SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, 1.152 + const Descriptor& desc) 1.153 + : SkGradientShaderBase(desc), 1.154 + fCenter(center), 1.155 + fRadius(radius) 1.156 +{ 1.157 + // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE 1.158 + SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE); 1.159 + 1.160 + rad_to_unit_matrix(center, radius, &fPtsToUnit); 1.161 +} 1.162 + 1.163 +void SkRadialGradient::shadeSpan16(int x, int y, uint16_t* dstCParam, 1.164 + int count) { 1.165 + SkASSERT(count > 0); 1.166 + 1.167 + uint16_t* SK_RESTRICT dstC = dstCParam; 1.168 + 1.169 + SkPoint srcPt; 1.170 + SkMatrix::MapXYProc dstProc = fDstToIndexProc; 1.171 + TileProc proc = fTileProc; 1.172 + const uint16_t* SK_RESTRICT cache = this->getCache16(); 1.173 + int toggle = init_dither_toggle16(x, y); 1.174 + 1.175 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.176 + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 1.177 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.178 + 1.179 + SkScalar sdx = fDstToIndex.getScaleX(); 1.180 + SkScalar sdy = fDstToIndex.getSkewY(); 1.181 + 1.182 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.183 + SkFixed storage[2]; 1.184 + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), 1.185 + &storage[0], &storage[1]); 1.186 + sdx = SkFixedToScalar(storage[0]); 1.187 + sdy = SkFixedToScalar(storage[1]); 1.188 + } else { 1.189 + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 1.190 + } 1.191 + 1.192 + RadialShade16Proc shadeProc = shadeSpan16_radial_repeat; 1.193 + if (SkShader::kClamp_TileMode == fTileMode) { 1.194 + shadeProc = shadeSpan16_radial_clamp; 1.195 + } else if (SkShader::kMirror_TileMode == fTileMode) { 1.196 + shadeProc = shadeSpan16_radial_mirror; 1.197 + } else { 1.198 + SkASSERT(SkShader::kRepeat_TileMode == fTileMode); 1.199 + } 1.200 + (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, 1.201 + cache, toggle, count); 1.202 + } else { // perspective case 1.203 + SkScalar dstX = SkIntToScalar(x); 1.204 + SkScalar dstY = SkIntToScalar(y); 1.205 + do { 1.206 + dstProc(fDstToIndex, dstX, dstY, &srcPt); 1.207 + unsigned fi = proc(SkScalarToFixed(srcPt.length())); 1.208 + SkASSERT(fi <= 0xFFFF); 1.209 + 1.210 + int index = fi >> (16 - kCache16Bits); 1.211 + *dstC++ = cache[toggle + index]; 1.212 + toggle = next_dither_toggle16(toggle); 1.213 + 1.214 + dstX += SK_Scalar1; 1.215 + } while (--count != 0); 1.216 + } 1.217 +} 1.218 + 1.219 +SkShader::BitmapType SkRadialGradient::asABitmap(SkBitmap* bitmap, 1.220 + SkMatrix* matrix, SkShader::TileMode* xy) const { 1.221 + if (bitmap) { 1.222 + this->getGradientTableBitmap(bitmap); 1.223 + } 1.224 + if (matrix) { 1.225 + matrix->setScale(SkIntToScalar(kCache32Count), 1.226 + SkIntToScalar(kCache32Count)); 1.227 + matrix->preConcat(fPtsToUnit); 1.228 + } 1.229 + if (xy) { 1.230 + xy[0] = fTileMode; 1.231 + xy[1] = kClamp_TileMode; 1.232 + } 1.233 + return kRadial_BitmapType; 1.234 +} 1.235 + 1.236 +SkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const { 1.237 + if (info) { 1.238 + commonAsAGradient(info); 1.239 + info->fPoint[0] = fCenter; 1.240 + info->fRadius[0] = fRadius; 1.241 + } 1.242 + return kRadial_GradientType; 1.243 +} 1.244 + 1.245 +SkRadialGradient::SkRadialGradient(SkReadBuffer& buffer) 1.246 + : INHERITED(buffer), 1.247 + fCenter(buffer.readPoint()), 1.248 + fRadius(buffer.readScalar()) { 1.249 +} 1.250 + 1.251 +void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { 1.252 + this->INHERITED::flatten(buffer); 1.253 + buffer.writePoint(fCenter); 1.254 + buffer.writeScalar(fRadius); 1.255 +} 1.256 + 1.257 +namespace { 1.258 + 1.259 +inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) { 1.260 + // fast, overly-conservative test: checks unit square instead 1.261 + // of unit circle 1.262 + bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || 1.263 + (fx <= -SK_FixedHalf && dx <= 0); 1.264 + bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || 1.265 + (fy <= -SK_FixedHalf && dy <= 0); 1.266 + 1.267 + return xClamped || yClamped; 1.268 +} 1.269 + 1.270 +// Return true if (fx * fy) is always inside the unit circle 1.271 +// SkPin32 is expensive, but so are all the SkFixedMul in this test, 1.272 +// so it shouldn't be run if count is small. 1.273 +inline bool no_need_for_radial_pin(int fx, int dx, 1.274 + int fy, int dy, int count) { 1.275 + SkASSERT(count > 0); 1.276 + if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { 1.277 + return false; 1.278 + } 1.279 + if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { 1.280 + return false; 1.281 + } 1.282 + fx += (count - 1) * dx; 1.283 + fy += (count - 1) * dy; 1.284 + if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { 1.285 + return false; 1.286 + } 1.287 + return fx*fx + fy*fy <= 0x7FFF*0x7FFF; 1.288 +} 1.289 + 1.290 +#define UNPINNED_RADIAL_STEP \ 1.291 + fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \ 1.292 + *dstC++ = cache[toggle + \ 1.293 + (sqrt_table[fi] >> SkGradientShaderBase::kSqrt32Shift)]; \ 1.294 + toggle = next_dither_toggle(toggle); \ 1.295 + fx += dx; \ 1.296 + fy += dy; 1.297 + 1.298 +typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx, 1.299 + SkScalar sfy, SkScalar sdy, 1.300 + SkPMColor* dstC, const SkPMColor* cache, 1.301 + int count, int toggle); 1.302 + 1.303 +// On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT 1.304 +void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx, 1.305 + SkScalar sfy, SkScalar sdy, 1.306 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.307 + int count, int toggle) { 1.308 + // Floating point seems to be slower than fixed point, 1.309 + // even when we have float hardware. 1.310 + const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; 1.311 + SkFixed fx = SkScalarToFixed(sfx) >> 1; 1.312 + SkFixed dx = SkScalarToFixed(sdx) >> 1; 1.313 + SkFixed fy = SkScalarToFixed(sfy) >> 1; 1.314 + SkFixed dy = SkScalarToFixed(sdy) >> 1; 1.315 + if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) { 1.316 + unsigned fi = SkGradientShaderBase::kCache32Count - 1; 1.317 + sk_memset32_dither(dstC, 1.318 + cache[toggle + fi], 1.319 + cache[next_dither_toggle(toggle) + fi], 1.320 + count); 1.321 + } else if ((count > 4) && 1.322 + no_need_for_radial_pin(fx, dx, fy, dy, count)) { 1.323 + unsigned fi; 1.324 + // 4x unroll appears to be no faster than 2x unroll on Linux 1.325 + while (count > 1) { 1.326 + UNPINNED_RADIAL_STEP; 1.327 + UNPINNED_RADIAL_STEP; 1.328 + count -= 2; 1.329 + } 1.330 + if (count) { 1.331 + UNPINNED_RADIAL_STEP; 1.332 + } 1.333 + } else { 1.334 + // Specializing for dy == 0 gains us 25% on Skia benchmarks 1.335 + if (dy == 0) { 1.336 + unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 1.337 + yy *= yy; 1.338 + do { 1.339 + unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 1.340 + unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS); 1.341 + fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 1.342 + *dstC++ = cache[toggle + (sqrt_table[fi] >> 1.343 + SkGradientShaderBase::kSqrt32Shift)]; 1.344 + toggle = next_dither_toggle(toggle); 1.345 + fx += dx; 1.346 + } while (--count != 0); 1.347 + } else { 1.348 + do { 1.349 + unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 1.350 + unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 1.351 + fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); 1.352 + fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 1.353 + *dstC++ = cache[toggle + (sqrt_table[fi] >> 1.354 + SkGradientShaderBase::kSqrt32Shift)]; 1.355 + toggle = next_dither_toggle(toggle); 1.356 + fx += dx; 1.357 + fy += dy; 1.358 + } while (--count != 0); 1.359 + } 1.360 + } 1.361 +} 1.362 + 1.363 +// Unrolling this loop doesn't seem to help (when float); we're stalling to 1.364 +// get the results of the sqrt (?), and don't have enough extra registers to 1.365 +// have many in flight. 1.366 +template <SkFixed (*TileProc)(SkFixed)> 1.367 +void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 1.368 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.369 + int count, int toggle) { 1.370 + do { 1.371 + const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); 1.372 + const unsigned fi = TileProc(dist); 1.373 + SkASSERT(fi <= 0xFFFF); 1.374 + *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)]; 1.375 + toggle = next_dither_toggle(toggle); 1.376 + fx += dx; 1.377 + fy += dy; 1.378 + } while (--count != 0); 1.379 +} 1.380 + 1.381 +void shadeSpan_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 1.382 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.383 + int count, int toggle) { 1.384 + shadeSpan_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle); 1.385 +} 1.386 + 1.387 +void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 1.388 + SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 1.389 + int count, int toggle) { 1.390 + shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle); 1.391 +} 1.392 + 1.393 +} // namespace 1.394 + 1.395 +void SkRadialGradient::shadeSpan(int x, int y, 1.396 + SkPMColor* SK_RESTRICT dstC, int count) { 1.397 + SkASSERT(count > 0); 1.398 + 1.399 + SkPoint srcPt; 1.400 + SkMatrix::MapXYProc dstProc = fDstToIndexProc; 1.401 + TileProc proc = fTileProc; 1.402 + const SkPMColor* SK_RESTRICT cache = this->getCache32(); 1.403 + int toggle = init_dither_toggle(x, y); 1.404 + 1.405 + if (fDstToIndexClass != kPerspective_MatrixClass) { 1.406 + dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 1.407 + SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 1.408 + SkScalar sdx = fDstToIndex.getScaleX(); 1.409 + SkScalar sdy = fDstToIndex.getSkewY(); 1.410 + 1.411 + if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 1.412 + SkFixed storage[2]; 1.413 + (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), 1.414 + &storage[0], &storage[1]); 1.415 + sdx = SkFixedToScalar(storage[0]); 1.416 + sdy = SkFixedToScalar(storage[1]); 1.417 + } else { 1.418 + SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 1.419 + } 1.420 + 1.421 + RadialShadeProc shadeProc = shadeSpan_radial_repeat; 1.422 + if (SkShader::kClamp_TileMode == fTileMode) { 1.423 + shadeProc = shadeSpan_radial_clamp; 1.424 + } else if (SkShader::kMirror_TileMode == fTileMode) { 1.425 + shadeProc = shadeSpan_radial_mirror; 1.426 + } else { 1.427 + SkASSERT(SkShader::kRepeat_TileMode == fTileMode); 1.428 + } 1.429 + (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); 1.430 + } else { // perspective case 1.431 + SkScalar dstX = SkIntToScalar(x); 1.432 + SkScalar dstY = SkIntToScalar(y); 1.433 + do { 1.434 + dstProc(fDstToIndex, dstX, dstY, &srcPt); 1.435 + unsigned fi = proc(SkScalarToFixed(srcPt.length())); 1.436 + SkASSERT(fi <= 0xFFFF); 1.437 + *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift]; 1.438 + dstX += SK_Scalar1; 1.439 + } while (--count != 0); 1.440 + } 1.441 +} 1.442 + 1.443 +///////////////////////////////////////////////////////////////////// 1.444 + 1.445 +#if SK_SUPPORT_GPU 1.446 + 1.447 +#include "GrTBackendEffectFactory.h" 1.448 + 1.449 +class GrGLRadialGradient : public GrGLGradientEffect { 1.450 +public: 1.451 + 1.452 + GrGLRadialGradient(const GrBackendEffectFactory& factory, 1.453 + const GrDrawEffect&) : INHERITED (factory) { } 1.454 + virtual ~GrGLRadialGradient() { } 1.455 + 1.456 + virtual void emitCode(GrGLShaderBuilder*, 1.457 + const GrDrawEffect&, 1.458 + EffectKey, 1.459 + const char* outputColor, 1.460 + const char* inputColor, 1.461 + const TransformedCoordsArray&, 1.462 + const TextureSamplerArray&) SK_OVERRIDE; 1.463 + 1.464 + static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 1.465 + return GenBaseGradientKey(drawEffect); 1.466 + } 1.467 + 1.468 +private: 1.469 + 1.470 + typedef GrGLGradientEffect INHERITED; 1.471 + 1.472 +}; 1.473 + 1.474 +///////////////////////////////////////////////////////////////////// 1.475 + 1.476 +class GrRadialGradient : public GrGradientEffect { 1.477 +public: 1.478 + static GrEffectRef* Create(GrContext* ctx, 1.479 + const SkRadialGradient& shader, 1.480 + const SkMatrix& matrix, 1.481 + SkShader::TileMode tm) { 1.482 + AutoEffectUnref effect(SkNEW_ARGS(GrRadialGradient, (ctx, shader, matrix, tm))); 1.483 + return CreateEffectRef(effect); 1.484 + } 1.485 + 1.486 + virtual ~GrRadialGradient() { } 1.487 + 1.488 + static const char* Name() { return "Radial Gradient"; } 1.489 + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 1.490 + return GrTBackendEffectFactory<GrRadialGradient>::getInstance(); 1.491 + } 1.492 + 1.493 + typedef GrGLRadialGradient GLEffect; 1.494 + 1.495 +private: 1.496 + GrRadialGradient(GrContext* ctx, 1.497 + const SkRadialGradient& shader, 1.498 + const SkMatrix& matrix, 1.499 + SkShader::TileMode tm) 1.500 + : INHERITED(ctx, shader, matrix, tm) { 1.501 + } 1.502 + 1.503 + GR_DECLARE_EFFECT_TEST; 1.504 + 1.505 + typedef GrGradientEffect INHERITED; 1.506 +}; 1.507 + 1.508 +///////////////////////////////////////////////////////////////////// 1.509 + 1.510 +GR_DEFINE_EFFECT_TEST(GrRadialGradient); 1.511 + 1.512 +GrEffectRef* GrRadialGradient::TestCreate(SkRandom* random, 1.513 + GrContext* context, 1.514 + const GrDrawTargetCaps&, 1.515 + GrTexture**) { 1.516 + SkPoint center = {random->nextUScalar1(), random->nextUScalar1()}; 1.517 + SkScalar radius = random->nextUScalar1(); 1.518 + 1.519 + SkColor colors[kMaxRandomGradientColors]; 1.520 + SkScalar stopsArray[kMaxRandomGradientColors]; 1.521 + SkScalar* stops = stopsArray; 1.522 + SkShader::TileMode tm; 1.523 + int colorCount = RandomGradientParams(random, colors, &stops, &tm); 1.524 + SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center, radius, 1.525 + colors, stops, colorCount, 1.526 + tm)); 1.527 + SkPaint paint; 1.528 + return shader->asNewEffect(context, paint); 1.529 +} 1.530 + 1.531 +///////////////////////////////////////////////////////////////////// 1.532 + 1.533 +void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder, 1.534 + const GrDrawEffect&, 1.535 + EffectKey key, 1.536 + const char* outputColor, 1.537 + const char* inputColor, 1.538 + const TransformedCoordsArray& coords, 1.539 + const TextureSamplerArray& samplers) { 1.540 + this->emitUniforms(builder, key); 1.541 + SkString t("length("); 1.542 + t.append(builder->ensureFSCoords2D(coords, 0)); 1.543 + t.append(")"); 1.544 + this->emitColor(builder, t.c_str(), key, outputColor, inputColor, samplers); 1.545 +} 1.546 + 1.547 +///////////////////////////////////////////////////////////////////// 1.548 + 1.549 +GrEffectRef* SkRadialGradient::asNewEffect(GrContext* context, const SkPaint&) const { 1.550 + SkASSERT(NULL != context); 1.551 + 1.552 + SkMatrix matrix; 1.553 + if (!this->getLocalMatrix().invert(&matrix)) { 1.554 + return NULL; 1.555 + } 1.556 + matrix.postConcat(fPtsToUnit); 1.557 + return GrRadialGradient::Create(context, *this, matrix, fTileMode); 1.558 +} 1.559 + 1.560 +#else 1.561 + 1.562 +GrEffectRef* SkRadialGradient::asNewEffect(GrContext*, const SkPaint&) const { 1.563 + SkDEBUGFAIL("Should not call in GPU-less build"); 1.564 + return NULL; 1.565 +} 1.566 + 1.567 +#endif 1.568 + 1.569 +#ifndef SK_IGNORE_TO_STRING 1.570 +void SkRadialGradient::toString(SkString* str) const { 1.571 + str->append("SkRadialGradient: ("); 1.572 + 1.573 + str->append("center: ("); 1.574 + str->appendScalar(fCenter.fX); 1.575 + str->append(", "); 1.576 + str->appendScalar(fCenter.fY); 1.577 + str->append(") radius: "); 1.578 + str->appendScalar(fRadius); 1.579 + str->append(" "); 1.580 + 1.581 + this->INHERITED::toString(str); 1.582 + 1.583 + str->append(")"); 1.584 +} 1.585 +#endif