gfx/skia/trunk/src/effects/gradients/SkRadialGradient.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial