SkRadialGradient.cpp revision 8ddbe8b9366c8c59c4fb55f01f253de8a0b37d6e
1 2/* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "SkRadialGradient.h" 10#include "SkRadialGradient_Table.h" 11 12#define kSQRT_TABLE_BITS 11 13#define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) 14 15#if 0 16 17#include <stdio.h> 18 19void SkRadialGradient_BuildTable() { 20 // build it 0..127 x 0..127, so we use 2^15 - 1 in the numerator for our "fixed" table 21 22 FILE* file = ::fopen("SkRadialGradient_Table.h", "w"); 23 SkASSERT(file); 24 ::fprintf(file, "static const uint8_t gSqrt8Table[] = {\n"); 25 26 for (int i = 0; i < kSQRT_TABLE_SIZE; i++) { 27 if ((i & 15) == 0) { 28 ::fprintf(file, "\t"); 29 } 30 31 uint8_t value = SkToU8(SkFixedSqrt(i * SK_Fixed1 / kSQRT_TABLE_SIZE) >> 8); 32 33 ::fprintf(file, "0x%02X", value); 34 if (i < kSQRT_TABLE_SIZE-1) { 35 ::fprintf(file, ", "); 36 } 37 if ((i & 15) == 15) { 38 ::fprintf(file, "\n"); 39 } 40 } 41 ::fprintf(file, "};\n"); 42 ::fclose(file); 43} 44 45#endif 46 47namespace { 48 49// GCC doesn't like using static functions as template arguments. So force these to be non-static. 50inline SkFixed mirror_tileproc_nonstatic(SkFixed x) { 51 return mirror_tileproc(x); 52} 53 54inline SkFixed repeat_tileproc_nonstatic(SkFixed x) { 55 return repeat_tileproc(x); 56} 57 58void rad_to_unit_matrix(const SkPoint& center, SkScalar radius, 59 SkMatrix* matrix) { 60 SkScalar inv = SkScalarInvert(radius); 61 62 matrix->setTranslate(-center.fX, -center.fY); 63 matrix->postScale(inv, inv); 64} 65 66typedef void (* RadialShade16Proc)(SkScalar sfx, SkScalar sdx, 67 SkScalar sfy, SkScalar sdy, 68 uint16_t* dstC, const uint16_t* cache, 69 int toggle, int count); 70 71void shadeSpan16_radial_clamp(SkScalar sfx, SkScalar sdx, 72 SkScalar sfy, SkScalar sdy, 73 uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 74 int toggle, int count) { 75 const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; 76 77 /* knock these down so we can pin against +- 0x7FFF, which is an 78 immediate load, rather than 0xFFFF which is slower. This is a 79 compromise, since it reduces our precision, but that appears 80 to be visually OK. If we decide this is OK for all of our cases, 81 we could (it seems) put this scale-down into fDstToIndex, 82 to avoid having to do these extra shifts each time. 83 */ 84 SkFixed fx = SkScalarToFixed(sfx) >> 1; 85 SkFixed dx = SkScalarToFixed(sdx) >> 1; 86 SkFixed fy = SkScalarToFixed(sfy) >> 1; 87 SkFixed dy = SkScalarToFixed(sdy) >> 1; 88 // might perform this check for the other modes, 89 // but the win will be a smaller % of the total 90 if (dy == 0) { 91 fy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 92 fy *= fy; 93 do { 94 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 95 unsigned fi = (xx * xx + fy) >> (14 + 16 - kSQRT_TABLE_BITS); 96 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 97 fx += dx; 98 *dstC++ = cache[toggle + 99 (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; 100 toggle = next_dither_toggle16(toggle); 101 } while (--count != 0); 102 } else { 103 do { 104 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 105 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 106 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); 107 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 108 fx += dx; 109 fy += dy; 110 *dstC++ = cache[toggle + 111 (sqrt_table[fi] >> SkGradientShaderBase::kSqrt16Shift)]; 112 toggle = next_dither_toggle16(toggle); 113 } while (--count != 0); 114 } 115} 116 117template <SkFixed (*TileProc)(SkFixed)> 118void shadeSpan16_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 119 uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 120 int toggle, int count) { 121 do { 122 const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); 123 const unsigned fi = TileProc(dist); 124 SkASSERT(fi <= 0xFFFF); 125 *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache16Shift)]; 126 toggle = next_dither_toggle16(toggle); 127 fx += dx; 128 fy += dy; 129 } while (--count != 0); 130} 131 132void shadeSpan16_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 133 uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 134 int toggle, int count) { 135 shadeSpan16_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, toggle, count); 136} 137 138void shadeSpan16_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 139 uint16_t* SK_RESTRICT dstC, const uint16_t* SK_RESTRICT cache, 140 int toggle, int count) { 141 shadeSpan16_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, toggle, count); 142} 143 144} // namespace 145 146///////////////////////////////////////////////////////////////////// 147 148SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor& desc) 149 : SkGradientShaderBase(desc) 150 , fCenter(center) 151 , fRadius(radius) 152{ 153 // make sure our table is insync with our current #define for kSQRT_TABLE_SIZE 154 SkASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE); 155 156 rad_to_unit_matrix(center, radius, &fPtsToUnit); 157} 158 159size_t SkRadialGradient::contextSize() const { 160 return sizeof(RadialGradientContext); 161} 162 163SkShader::Context* SkRadialGradient::onCreateContext(const ContextRec& rec, void* storage) const { 164 return SkNEW_PLACEMENT_ARGS(storage, RadialGradientContext, (*this, rec)); 165} 166 167SkRadialGradient::RadialGradientContext::RadialGradientContext( 168 const SkRadialGradient& shader, const ContextRec& rec) 169 : INHERITED(shader, rec) {} 170 171void SkRadialGradient::RadialGradientContext::shadeSpan16(int x, int y, uint16_t* dstCParam, 172 int count) { 173 SkASSERT(count > 0); 174 175 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader); 176 177 uint16_t* SK_RESTRICT dstC = dstCParam; 178 179 SkPoint srcPt; 180 SkMatrix::MapXYProc dstProc = fDstToIndexProc; 181 TileProc proc = radialGradient.fTileProc; 182 const uint16_t* SK_RESTRICT cache = fCache->getCache16(); 183 int toggle = init_dither_toggle16(x, y); 184 185 if (fDstToIndexClass != kPerspective_MatrixClass) { 186 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 187 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 188 189 SkScalar sdx = fDstToIndex.getScaleX(); 190 SkScalar sdy = fDstToIndex.getSkewY(); 191 192 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 193 SkFixed storage[2]; 194 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), 195 &storage[0], &storage[1]); 196 sdx = SkFixedToScalar(storage[0]); 197 sdy = SkFixedToScalar(storage[1]); 198 } else { 199 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 200 } 201 202 RadialShade16Proc shadeProc = shadeSpan16_radial_repeat; 203 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { 204 shadeProc = shadeSpan16_radial_clamp; 205 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { 206 shadeProc = shadeSpan16_radial_mirror; 207 } else { 208 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); 209 } 210 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, 211 cache, toggle, count); 212 } else { // perspective case 213 SkScalar dstX = SkIntToScalar(x); 214 SkScalar dstY = SkIntToScalar(y); 215 do { 216 dstProc(fDstToIndex, dstX, dstY, &srcPt); 217 unsigned fi = proc(SkScalarToFixed(srcPt.length())); 218 SkASSERT(fi <= 0xFFFF); 219 220 int index = fi >> (16 - kCache16Bits); 221 *dstC++ = cache[toggle + index]; 222 toggle = next_dither_toggle16(toggle); 223 224 dstX += SK_Scalar1; 225 } while (--count != 0); 226 } 227} 228 229SkShader::BitmapType SkRadialGradient::asABitmap(SkBitmap* bitmap, 230 SkMatrix* matrix, SkShader::TileMode* xy) const { 231 if (bitmap) { 232 this->getGradientTableBitmap(bitmap); 233 } 234 if (matrix) { 235 matrix->setScale(SkIntToScalar(kCache32Count), 236 SkIntToScalar(kCache32Count)); 237 matrix->preConcat(fPtsToUnit); 238 } 239 if (xy) { 240 xy[0] = fTileMode; 241 xy[1] = kClamp_TileMode; 242 } 243 return kRadial_BitmapType; 244} 245 246SkShader::GradientType SkRadialGradient::asAGradient(GradientInfo* info) const { 247 if (info) { 248 commonAsAGradient(info); 249 info->fPoint[0] = fCenter; 250 info->fRadius[0] = fRadius; 251 } 252 return kRadial_GradientType; 253} 254 255#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 256SkRadialGradient::SkRadialGradient(SkReadBuffer& buffer) 257 : INHERITED(buffer), 258 fCenter(buffer.readPoint()), 259 fRadius(buffer.readScalar()) { 260} 261#endif 262 263SkFlattenable* SkRadialGradient::CreateProc(SkReadBuffer& buffer) { 264 DescriptorScope desc; 265 if (!desc.unflatten(buffer)) { 266 return NULL; 267 } 268 const SkPoint center = buffer.readPoint(); 269 const SkScalar radius = buffer.readScalar(); 270 return SkGradientShader::CreateRadial(center, radius, desc.fColors, desc.fPos, desc.fCount, 271 desc.fTileMode, desc.fGradFlags, desc.fLocalMatrix); 272} 273 274void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { 275 this->INHERITED::flatten(buffer); 276 buffer.writePoint(fCenter); 277 buffer.writeScalar(fRadius); 278} 279 280namespace { 281 282inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) { 283 // fast, overly-conservative test: checks unit square instead 284 // of unit circle 285 bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || 286 (fx <= -SK_FixedHalf && dx <= 0); 287 bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || 288 (fy <= -SK_FixedHalf && dy <= 0); 289 290 return xClamped || yClamped; 291} 292 293// Return true if (fx * fy) is always inside the unit circle 294// SkPin32 is expensive, but so are all the SkFixedMul in this test, 295// so it shouldn't be run if count is small. 296inline bool no_need_for_radial_pin(int fx, int dx, 297 int fy, int dy, int count) { 298 SkASSERT(count > 0); 299 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { 300 return false; 301 } 302 if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { 303 return false; 304 } 305 fx += (count - 1) * dx; 306 fy += (count - 1) * dy; 307 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { 308 return false; 309 } 310 return fx*fx + fy*fy <= 0x7FFF*0x7FFF; 311} 312 313#define UNPINNED_RADIAL_STEP \ 314 fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \ 315 *dstC++ = cache[toggle + \ 316 (sqrt_table[fi] >> SkGradientShaderBase::kSqrt32Shift)]; \ 317 toggle = next_dither_toggle(toggle); \ 318 fx += dx; \ 319 fy += dy; 320 321typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx, 322 SkScalar sfy, SkScalar sdy, 323 SkPMColor* dstC, const SkPMColor* cache, 324 int count, int toggle); 325 326// On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT 327void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx, 328 SkScalar sfy, SkScalar sdy, 329 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 330 int count, int toggle) { 331 // Floating point seems to be slower than fixed point, 332 // even when we have float hardware. 333 const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; 334 SkFixed fx = SkScalarToFixed(sfx) >> 1; 335 SkFixed dx = SkScalarToFixed(sdx) >> 1; 336 SkFixed fy = SkScalarToFixed(sfy) >> 1; 337 SkFixed dy = SkScalarToFixed(sdy) >> 1; 338 if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) { 339 unsigned fi = SkGradientShaderBase::kCache32Count - 1; 340 sk_memset32_dither(dstC, 341 cache[toggle + fi], 342 cache[next_dither_toggle(toggle) + fi], 343 count); 344 } else if ((count > 4) && 345 no_need_for_radial_pin(fx, dx, fy, dy, count)) { 346 unsigned fi; 347 // 4x unroll appears to be no faster than 2x unroll on Linux 348 while (count > 1) { 349 UNPINNED_RADIAL_STEP; 350 UNPINNED_RADIAL_STEP; 351 count -= 2; 352 } 353 if (count) { 354 UNPINNED_RADIAL_STEP; 355 } 356 } else { 357 // Specializing for dy == 0 gains us 25% on Skia benchmarks 358 if (dy == 0) { 359 unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 360 yy *= yy; 361 do { 362 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 363 unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS); 364 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 365 *dstC++ = cache[toggle + (sqrt_table[fi] >> 366 SkGradientShaderBase::kSqrt32Shift)]; 367 toggle = next_dither_toggle(toggle); 368 fx += dx; 369 } while (--count != 0); 370 } else { 371 do { 372 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); 373 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); 374 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); 375 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); 376 *dstC++ = cache[toggle + (sqrt_table[fi] >> 377 SkGradientShaderBase::kSqrt32Shift)]; 378 toggle = next_dither_toggle(toggle); 379 fx += dx; 380 fy += dy; 381 } while (--count != 0); 382 } 383 } 384} 385 386// Unrolling this loop doesn't seem to help (when float); we're stalling to 387// get the results of the sqrt (?), and don't have enough extra registers to 388// have many in flight. 389template <SkFixed (*TileProc)(SkFixed)> 390void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 391 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 392 int count, int toggle) { 393 do { 394 const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); 395 const unsigned fi = TileProc(dist); 396 SkASSERT(fi <= 0xFFFF); 397 *dstC++ = cache[toggle + (fi >> SkGradientShaderBase::kCache32Shift)]; 398 toggle = next_dither_toggle(toggle); 399 fx += dx; 400 fy += dy; 401 } while (--count != 0); 402} 403 404void shadeSpan_radial_mirror(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 405 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 406 int count, int toggle) { 407 shadeSpan_radial<mirror_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle); 408} 409 410void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, 411 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, 412 int count, int toggle) { 413 shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, count, toggle); 414} 415 416} // namespace 417 418void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, 419 SkPMColor* SK_RESTRICT dstC, int count) { 420 SkASSERT(count > 0); 421 422 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&>(fShader); 423 424 SkPoint srcPt; 425 SkMatrix::MapXYProc dstProc = fDstToIndexProc; 426 TileProc proc = radialGradient.fTileProc; 427 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); 428 int toggle = init_dither_toggle(x, y); 429 430 if (fDstToIndexClass != kPerspective_MatrixClass) { 431 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, 432 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); 433 SkScalar sdx = fDstToIndex.getScaleX(); 434 SkScalar sdy = fDstToIndex.getSkewY(); 435 436 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { 437 SkFixed storage[2]; 438 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), 439 &storage[0], &storage[1]); 440 sdx = SkFixedToScalar(storage[0]); 441 sdy = SkFixedToScalar(storage[1]); 442 } else { 443 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); 444 } 445 446 RadialShadeProc shadeProc = shadeSpan_radial_repeat; 447 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { 448 shadeProc = shadeSpan_radial_clamp; 449 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { 450 shadeProc = shadeSpan_radial_mirror; 451 } else { 452 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); 453 } 454 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); 455 } else { // perspective case 456 SkScalar dstX = SkIntToScalar(x); 457 SkScalar dstY = SkIntToScalar(y); 458 do { 459 dstProc(fDstToIndex, dstX, dstY, &srcPt); 460 unsigned fi = proc(SkScalarToFixed(srcPt.length())); 461 SkASSERT(fi <= 0xFFFF); 462 *dstC++ = cache[fi >> SkGradientShaderBase::kCache32Shift]; 463 dstX += SK_Scalar1; 464 } while (--count != 0); 465 } 466} 467 468///////////////////////////////////////////////////////////////////// 469 470#if SK_SUPPORT_GPU 471 472#include "GrTBackendEffectFactory.h" 473#include "gl/builders/GrGLProgramBuilder.h" 474#include "SkGr.h" 475 476class GrGLRadialGradient : public GrGLGradientEffect { 477public: 478 479 GrGLRadialGradient(const GrBackendEffectFactory& factory, 480 const GrEffect&) : INHERITED (factory) { } 481 virtual ~GrGLRadialGradient() { } 482 483 virtual void emitCode(GrGLProgramBuilder*, 484 const GrEffect&, 485 const GrEffectKey&, 486 const char* outputColor, 487 const char* inputColor, 488 const TransformedCoordsArray&, 489 const TextureSamplerArray&) SK_OVERRIDE; 490 491 static void GenKey(const GrEffect& effect, const GrGLCaps&, GrEffectKeyBuilder* b) { 492 b->add32(GenBaseGradientKey(effect)); 493 } 494 495private: 496 497 typedef GrGLGradientEffect INHERITED; 498 499}; 500 501///////////////////////////////////////////////////////////////////// 502 503class GrRadialGradient : public GrGradientEffect { 504public: 505 static GrEffect* Create(GrContext* ctx, 506 const SkRadialGradient& shader, 507 const SkMatrix& matrix, 508 SkShader::TileMode tm) { 509 return SkNEW_ARGS(GrRadialGradient, (ctx, shader, matrix, tm)); 510 } 511 512 virtual ~GrRadialGradient() { } 513 514 static const char* Name() { return "Radial Gradient"; } 515 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { 516 return GrTBackendEffectFactory<GrRadialGradient>::getInstance(); 517 } 518 519 typedef GrGLRadialGradient GLEffect; 520 521private: 522 GrRadialGradient(GrContext* ctx, 523 const SkRadialGradient& shader, 524 const SkMatrix& matrix, 525 SkShader::TileMode tm) 526 : INHERITED(ctx, shader, matrix, tm) { 527 } 528 529 GR_DECLARE_EFFECT_TEST; 530 531 typedef GrGradientEffect INHERITED; 532}; 533 534///////////////////////////////////////////////////////////////////// 535 536GR_DEFINE_EFFECT_TEST(GrRadialGradient); 537 538GrEffect* GrRadialGradient::TestCreate(SkRandom* random, 539 GrContext* context, 540 const GrDrawTargetCaps&, 541 GrTexture**) { 542 SkPoint center = {random->nextUScalar1(), random->nextUScalar1()}; 543 SkScalar radius = random->nextUScalar1(); 544 545 SkColor colors[kMaxRandomGradientColors]; 546 SkScalar stopsArray[kMaxRandomGradientColors]; 547 SkScalar* stops = stopsArray; 548 SkShader::TileMode tm; 549 int colorCount = RandomGradientParams(random, colors, &stops, &tm); 550 SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center, radius, 551 colors, stops, colorCount, 552 tm)); 553 SkPaint paint; 554 GrColor paintColor; 555 GrEffect* effect; 556 SkAssertResult(shader->asNewEffect(context, paint, NULL, &paintColor, &effect)); 557 return effect; 558} 559 560///////////////////////////////////////////////////////////////////// 561 562void GrGLRadialGradient::emitCode(GrGLProgramBuilder* builder, 563 const GrEffect&, 564 const GrEffectKey& key, 565 const char* outputColor, 566 const char* inputColor, 567 const TransformedCoordsArray& coords, 568 const TextureSamplerArray& samplers) { 569 uint32_t baseKey = key.get32(0); 570 this->emitUniforms(builder, baseKey); 571 SkString t("length("); 572 t.append(builder->getFragmentShaderBuilder()->ensureFSCoords2D(coords, 0)); 573 t.append(")"); 574 this->emitColor(builder, t.c_str(), baseKey, outputColor, inputColor, samplers); 575} 576 577///////////////////////////////////////////////////////////////////// 578 579bool SkRadialGradient::asNewEffect(GrContext* context, const SkPaint& paint, 580 const SkMatrix* localMatrix, GrColor* paintColor, 581 GrEffect** effect) const { 582 SkASSERT(context); 583 584 SkMatrix matrix; 585 if (!this->getLocalMatrix().invert(&matrix)) { 586 return false; 587 } 588 if (localMatrix) { 589 SkMatrix inv; 590 if (!localMatrix->invert(&inv)) { 591 return false; 592 } 593 matrix.postConcat(inv); 594 } 595 matrix.postConcat(fPtsToUnit); 596 597 *paintColor = SkColor2GrColorJustAlpha(paint.getColor()); 598 *effect = GrRadialGradient::Create(context, *this, matrix, fTileMode); 599 600 return true; 601} 602 603#else 604 605bool SkRadialGradient::asNewEffect(GrContext* context, const SkPaint& paint, 606 const SkMatrix* localMatrix, GrColor* paintColor, 607 GrEffect** effect) const { 608 SkDEBUGFAIL("Should not call in GPU-less build"); 609 return false; 610} 611 612#endif 613 614#ifndef SK_IGNORE_TO_STRING 615void SkRadialGradient::toString(SkString* str) const { 616 str->append("SkRadialGradient: ("); 617 618 str->append("center: ("); 619 str->appendScalar(fCenter.fX); 620 str->append(", "); 621 str->appendScalar(fCenter.fY); 622 str->append(") radius: "); 623 str->appendScalar(fRadius); 624 str->append(" "); 625 626 this->INHERITED::toString(str); 627 628 str->append(")"); 629} 630#endif 631