1 /*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "Sk4fLinearGradient.h"
9 #include "SkGradientShaderPriv.h"
10 #include "SkLinearGradient.h"
11 #include "SkRadialGradient.h"
12 #include "SkTwoPointConicalGradient.h"
13 #include "SkSweepGradient.h"
14
flatten(SkWriteBuffer & buffer) const15 void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
16 buffer.writeColorArray(fColors, fCount);
17 if (fPos) {
18 buffer.writeBool(true);
19 buffer.writeScalarArray(fPos, fCount);
20 } else {
21 buffer.writeBool(false);
22 }
23 buffer.write32(fTileMode);
24 buffer.write32(fGradFlags);
25 if (fLocalMatrix) {
26 buffer.writeBool(true);
27 buffer.writeMatrix(*fLocalMatrix);
28 } else {
29 buffer.writeBool(false);
30 }
31 }
32
unflatten(SkReadBuffer & buffer)33 bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
34 fCount = buffer.getArrayCount();
35 if (fCount > kStorageCount) {
36 size_t allocSize = (sizeof(SkColor) + sizeof(SkScalar)) * fCount;
37 fDynamicStorage.reset(allocSize);
38 fColors = (SkColor*)fDynamicStorage.get();
39 fPos = (SkScalar*)(fColors + fCount);
40 } else {
41 fColors = fColorStorage;
42 fPos = fPosStorage;
43 }
44
45 if (!buffer.readColorArray(const_cast<SkColor*>(fColors), fCount)) {
46 return false;
47 }
48 if (buffer.readBool()) {
49 if (!buffer.readScalarArray(const_cast<SkScalar*>(fPos), fCount)) {
50 return false;
51 }
52 } else {
53 fPos = nullptr;
54 }
55
56 fTileMode = (SkShader::TileMode)buffer.read32();
57 fGradFlags = buffer.read32();
58
59 if (buffer.readBool()) {
60 fLocalMatrix = &fLocalMatrixStorage;
61 buffer.readMatrix(&fLocalMatrixStorage);
62 } else {
63 fLocalMatrix = nullptr;
64 }
65 return buffer.isValid();
66 }
67
68 ////////////////////////////////////////////////////////////////////////////////////////////
69
SkGradientShaderBase(const Descriptor & desc,const SkMatrix & ptsToUnit)70 SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
71 : INHERITED(desc.fLocalMatrix)
72 , fPtsToUnit(ptsToUnit)
73 {
74 fPtsToUnit.getType(); // Precache so reads are threadsafe.
75 SkASSERT(desc.fCount > 1);
76
77 fGradFlags = SkToU8(desc.fGradFlags);
78
79 SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
80 SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs));
81 fTileMode = desc.fTileMode;
82 fTileProc = gTileProcs[desc.fTileMode];
83
84 /* Note: we let the caller skip the first and/or last position.
85 i.e. pos[0] = 0.3, pos[1] = 0.7
86 In these cases, we insert dummy entries to ensure that the final data
87 will be bracketed by [0, 1].
88 i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
89
90 Thus colorCount (the caller's value, and fColorCount (our value) may
91 differ by up to 2. In the above example:
92 colorCount = 2
93 fColorCount = 4
94 */
95 fColorCount = desc.fCount;
96 // check if we need to add in dummy start and/or end position/colors
97 bool dummyFirst = false;
98 bool dummyLast = false;
99 if (desc.fPos) {
100 dummyFirst = desc.fPos[0] != 0;
101 dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
102 fColorCount += dummyFirst + dummyLast;
103 }
104
105 if (fColorCount > kColorStorageCount) {
106 size_t size = sizeof(SkColor) + sizeof(Rec);
107 if (desc.fPos) {
108 size += sizeof(SkScalar);
109 }
110 fOrigColors = reinterpret_cast<SkColor*>(
111 sk_malloc_throw(size * fColorCount));
112 }
113 else {
114 fOrigColors = fStorage;
115 }
116
117 // Now copy over the colors, adding the dummies as needed
118 {
119 SkColor* origColors = fOrigColors;
120 if (dummyFirst) {
121 *origColors++ = desc.fColors[0];
122 }
123 memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor));
124 if (dummyLast) {
125 origColors += desc.fCount;
126 *origColors = desc.fColors[desc.fCount - 1];
127 }
128 }
129
130 if (desc.fPos && fColorCount) {
131 fOrigPos = (SkScalar*)(fOrigColors + fColorCount);
132 fRecs = (Rec*)(fOrigPos + fColorCount);
133 } else {
134 fOrigPos = nullptr;
135 fRecs = (Rec*)(fOrigColors + fColorCount);
136 }
137
138 if (fColorCount > 2) {
139 Rec* recs = fRecs;
140 recs->fPos = 0;
141 // recs->fScale = 0; // unused;
142 recs += 1;
143 if (desc.fPos) {
144 SkScalar* origPosPtr = fOrigPos;
145 *origPosPtr++ = 0;
146
147 /* We need to convert the user's array of relative positions into
148 fixed-point positions and scale factors. We need these results
149 to be strictly monotonic (no two values equal or out of order).
150 Hence this complex loop that just jams a zero for the scale
151 value if it sees a segment out of order, and it assures that
152 we start at 0 and end at 1.0
153 */
154 SkScalar prev = 0;
155 int startIndex = dummyFirst ? 0 : 1;
156 int count = desc.fCount + dummyLast;
157 for (int i = startIndex; i < count; i++) {
158 // force the last value to be 1.0
159 SkScalar curr;
160 if (i == desc.fCount) { // we're really at the dummyLast
161 curr = 1;
162 } else {
163 curr = SkScalarPin(desc.fPos[i], 0, 1);
164 }
165 *origPosPtr++ = curr;
166
167 recs->fPos = SkScalarToFixed(curr);
168 SkFixed diff = SkScalarToFixed(curr - prev);
169 if (diff > 0) {
170 recs->fScale = (1 << 24) / diff;
171 } else {
172 recs->fScale = 0; // ignore this segment
173 }
174 // get ready for the next value
175 prev = curr;
176 recs += 1;
177 }
178 } else { // assume even distribution
179 fOrigPos = nullptr;
180
181 SkFixed dp = SK_Fixed1 / (desc.fCount - 1);
182 SkFixed p = dp;
183 SkFixed scale = (desc.fCount - 1) << 8; // (1 << 24) / dp
184 for (int i = 1; i < desc.fCount - 1; i++) {
185 recs->fPos = p;
186 recs->fScale = scale;
187 recs += 1;
188 p += dp;
189 }
190 recs->fPos = SK_Fixed1;
191 recs->fScale = scale;
192 }
193 } else if (desc.fPos) {
194 SkASSERT(2 == fColorCount);
195 fOrigPos[0] = SkScalarPin(desc.fPos[0], 0, 1);
196 fOrigPos[1] = SkScalarPin(desc.fPos[1], fOrigPos[0], 1);
197 if (0 == fOrigPos[0] && 1 == fOrigPos[1]) {
198 fOrigPos = nullptr;
199 }
200 }
201 this->initCommon();
202 }
203
~SkGradientShaderBase()204 SkGradientShaderBase::~SkGradientShaderBase() {
205 if (fOrigColors != fStorage) {
206 sk_free(fOrigColors);
207 }
208 }
209
initCommon()210 void SkGradientShaderBase::initCommon() {
211 unsigned colorAlpha = 0xFF;
212 for (int i = 0; i < fColorCount; i++) {
213 colorAlpha &= SkColorGetA(fOrigColors[i]);
214 }
215 fColorsAreOpaque = colorAlpha == 0xFF;
216 }
217
flatten(SkWriteBuffer & buffer) const218 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
219 Descriptor desc;
220 desc.fColors = fOrigColors;
221 desc.fPos = fOrigPos;
222 desc.fCount = fColorCount;
223 desc.fTileMode = fTileMode;
224 desc.fGradFlags = fGradFlags;
225
226 const SkMatrix& m = this->getLocalMatrix();
227 desc.fLocalMatrix = m.isIdentity() ? nullptr : &m;
228 desc.flatten(buffer);
229 }
230
getGpuColorType(SkColor colors[3]) const231 SkGradientShaderBase::GpuColorType SkGradientShaderBase::getGpuColorType(SkColor colors[3]) const {
232 if (fColorCount <= 3) {
233 memcpy(colors, fOrigColors, fColorCount * sizeof(SkColor));
234 }
235
236 if (SkShader::kClamp_TileMode == fTileMode) {
237 if (2 == fColorCount) {
238 return kTwo_GpuColorType;
239 } else if (3 == fColorCount &&
240 (SkScalarAbs(
241 SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) {
242 return kThree_GpuColorType;
243 }
244 }
245 return kTexture_GpuColorType;
246 }
247
FlipGradientColors(SkColor * colorDst,Rec * recDst,SkColor * colorSrc,Rec * recSrc,int count)248 void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst,
249 SkColor* colorSrc, Rec* recSrc,
250 int count) {
251 SkAutoSTArray<8, SkColor> colorsTemp(count);
252 for (int i = 0; i < count; ++i) {
253 int offset = count - i - 1;
254 colorsTemp[i] = colorSrc[offset];
255 }
256 if (count > 2) {
257 SkAutoSTArray<8, Rec> recsTemp(count);
258 for (int i = 0; i < count; ++i) {
259 int offset = count - i - 1;
260 recsTemp[i].fPos = SK_Fixed1 - recSrc[offset].fPos;
261 recsTemp[i].fScale = recSrc[offset].fScale;
262 }
263 memcpy(recDst, recsTemp.get(), count * sizeof(Rec));
264 }
265 memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor));
266 }
267
isOpaque() const268 bool SkGradientShaderBase::isOpaque() const {
269 return fColorsAreOpaque;
270 }
271
rounded_divide(unsigned numer,unsigned denom)272 static unsigned rounded_divide(unsigned numer, unsigned denom) {
273 return (numer + (denom >> 1)) / denom;
274 }
275
onAsLuminanceColor(SkColor * lum) const276 bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
277 // we just compute an average color.
278 // possibly we could weight this based on the proportional width for each color
279 // assuming they are not evenly distributed in the fPos array.
280 int r = 0;
281 int g = 0;
282 int b = 0;
283 const int n = fColorCount;
284 for (int i = 0; i < n; ++i) {
285 SkColor c = fOrigColors[i];
286 r += SkColorGetR(c);
287 g += SkColorGetG(c);
288 b += SkColorGetB(c);
289 }
290 *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
291 return true;
292 }
293
GradientShaderBaseContext(const SkGradientShaderBase & shader,const ContextRec & rec)294 SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext(
295 const SkGradientShaderBase& shader, const ContextRec& rec)
296 : INHERITED(shader, rec)
297 #ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING
298 , fDither(true)
299 #else
300 , fDither(rec.fPaint->isDither())
301 #endif
302 , fCache(shader.refCache(getPaintAlpha(), fDither))
303 {
304 const SkMatrix& inverse = this->getTotalInverse();
305
306 fDstToIndex.setConcat(shader.fPtsToUnit, inverse);
307
308 fDstToIndexProc = fDstToIndex.getMapXYProc();
309 fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex);
310
311 // now convert our colors in to PMColors
312 unsigned paintAlpha = this->getPaintAlpha();
313
314 fFlags = this->INHERITED::getFlags();
315 if (shader.fColorsAreOpaque && paintAlpha == 0xFF) {
316 fFlags |= kOpaqueAlpha_Flag;
317 }
318 }
319
GradientShaderCache(U8CPU alpha,bool dither,const SkGradientShaderBase & shader)320 SkGradientShaderBase::GradientShaderCache::GradientShaderCache(
321 U8CPU alpha, bool dither, const SkGradientShaderBase& shader)
322 : fCacheAlpha(alpha)
323 , fCacheDither(dither)
324 , fShader(shader)
325 , fCache16Inited(false)
326 , fCache32Inited(false)
327 {
328 // Only initialize the cache in getCache16/32.
329 fCache16 = nullptr;
330 fCache32 = nullptr;
331 fCache16Storage = nullptr;
332 fCache32PixelRef = nullptr;
333 }
334
~GradientShaderCache()335 SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() {
336 sk_free(fCache16Storage);
337 SkSafeUnref(fCache32PixelRef);
338 }
339
340 #define Fixed_To_Dot8(x) (((x) + 0x80) >> 8)
341
342 /** We take the original colors, not our premultiplied PMColors, since we can
343 build a 16bit table as long as the original colors are opaque, even if the
344 paint specifies a non-opaque alpha.
345 */
Build16bitCache(uint16_t cache[],SkColor c0,SkColor c1,int count,bool dither)346 void SkGradientShaderBase::GradientShaderCache::Build16bitCache(
347 uint16_t cache[], SkColor c0, SkColor c1, int count, bool dither) {
348 SkASSERT(count > 1);
349 SkASSERT(SkColorGetA(c0) == 0xFF);
350 SkASSERT(SkColorGetA(c1) == 0xFF);
351
352 SkFixed r = SkColorGetR(c0);
353 SkFixed g = SkColorGetG(c0);
354 SkFixed b = SkColorGetB(c0);
355
356 SkFixed dr = SkIntToFixed(SkColorGetR(c1) - r) / (count - 1);
357 SkFixed dg = SkIntToFixed(SkColorGetG(c1) - g) / (count - 1);
358 SkFixed db = SkIntToFixed(SkColorGetB(c1) - b) / (count - 1);
359
360 r = SkIntToFixed(r) + 0x8000;
361 g = SkIntToFixed(g) + 0x8000;
362 b = SkIntToFixed(b) + 0x8000;
363
364 if (dither) {
365 do {
366 unsigned rr = r >> 16;
367 unsigned gg = g >> 16;
368 unsigned bb = b >> 16;
369 cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
370 cache[kCache16Count] = SkDitherPack888ToRGB16(rr, gg, bb);
371 cache += 1;
372 r += dr;
373 g += dg;
374 b += db;
375 } while (--count != 0);
376 } else {
377 do {
378 unsigned rr = r >> 16;
379 unsigned gg = g >> 16;
380 unsigned bb = b >> 16;
381 cache[0] = SkPackRGB16(SkR32ToR16(rr), SkG32ToG16(gg), SkB32ToB16(bb));
382 cache[kCache16Count] = cache[0];
383 cache += 1;
384 r += dr;
385 g += dg;
386 b += db;
387 } while (--count != 0);
388 }
389 }
390
391 /*
392 * r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in
393 * release builds, we saw a compiler error where the 0xFF parameter in
394 * SkPackARGB32() was being totally ignored whenever it was called with
395 * a non-zero add (e.g. 0x8000).
396 *
397 * We found two work-arounds:
398 * 1. change r,g,b to unsigned (or just one of them)
399 * 2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead
400 * of using |
401 *
402 * We chose #1 just because it was more localized.
403 * See http://code.google.com/p/skia/issues/detail?id=1113
404 *
405 * The type SkUFixed encapsulate this need for unsigned, but logically Fixed.
406 */
407 typedef uint32_t SkUFixed;
408
Build32bitCache(SkPMColor cache[],SkColor c0,SkColor c1,int count,U8CPU paintAlpha,uint32_t gradFlags,bool dither)409 void SkGradientShaderBase::GradientShaderCache::Build32bitCache(
410 SkPMColor cache[], SkColor c0, SkColor c1,
411 int count, U8CPU paintAlpha, uint32_t gradFlags, bool dither) {
412 SkASSERT(count > 1);
413
414 // need to apply paintAlpha to our two endpoints
415 uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha);
416 uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha);
417
418
419 const bool interpInPremul = SkToBool(gradFlags &
420 SkGradientShader::kInterpolateColorsInPremul_Flag);
421
422 uint32_t r0 = SkColorGetR(c0);
423 uint32_t g0 = SkColorGetG(c0);
424 uint32_t b0 = SkColorGetB(c0);
425
426 uint32_t r1 = SkColorGetR(c1);
427 uint32_t g1 = SkColorGetG(c1);
428 uint32_t b1 = SkColorGetB(c1);
429
430 if (interpInPremul) {
431 r0 = SkMulDiv255Round(r0, a0);
432 g0 = SkMulDiv255Round(g0, a0);
433 b0 = SkMulDiv255Round(b0, a0);
434
435 r1 = SkMulDiv255Round(r1, a1);
436 g1 = SkMulDiv255Round(g1, a1);
437 b1 = SkMulDiv255Round(b1, a1);
438 }
439
440 SkFixed da = SkIntToFixed(a1 - a0) / (count - 1);
441 SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1);
442 SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1);
443 SkFixed db = SkIntToFixed(b1 - b0) / (count - 1);
444
445 /* We pre-add 1/8 to avoid having to add this to our [0] value each time
446 in the loop. Without this, the bias for each would be
447 0x2000 0xA000 0xE000 0x6000
448 With this trick, we can add 0 for the first (no-op) and just adjust the
449 others.
450 */
451 const SkUFixed bias0 = dither ? 0x2000 : 0x8000;
452 const SkUFixed bias1 = dither ? 0x8000 : 0;
453 const SkUFixed bias2 = dither ? 0xC000 : 0;
454 const SkUFixed bias3 = dither ? 0x4000 : 0;
455
456 SkUFixed a = SkIntToFixed(a0) + bias0;
457 SkUFixed r = SkIntToFixed(r0) + bias0;
458 SkUFixed g = SkIntToFixed(g0) + bias0;
459 SkUFixed b = SkIntToFixed(b0) + bias0;
460
461 /*
462 * Our dither-cell (spatially) is
463 * 0 2
464 * 3 1
465 * Where
466 * [0] -> [-1/8 ... 1/8 ) values near 0
467 * [1] -> [ 1/8 ... 3/8 ) values near 1/4
468 * [2] -> [ 3/8 ... 5/8 ) values near 1/2
469 * [3] -> [ 5/8 ... 7/8 ) values near 3/4
470 */
471
472 if (0xFF == a0 && 0 == da) {
473 do {
474 cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0 ) >> 16,
475 (g + 0 ) >> 16,
476 (b + 0 ) >> 16);
477 cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + bias1) >> 16,
478 (g + bias1) >> 16,
479 (b + bias1) >> 16);
480 cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + bias2) >> 16,
481 (g + bias2) >> 16,
482 (b + bias2) >> 16);
483 cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + bias3) >> 16,
484 (g + bias3) >> 16,
485 (b + bias3) >> 16);
486 cache += 1;
487 r += dr;
488 g += dg;
489 b += db;
490 } while (--count != 0);
491 } else if (interpInPremul) {
492 do {
493 cache[kCache32Count*0] = SkPackARGB32((a + 0 ) >> 16,
494 (r + 0 ) >> 16,
495 (g + 0 ) >> 16,
496 (b + 0 ) >> 16);
497 cache[kCache32Count*1] = SkPackARGB32((a + bias1) >> 16,
498 (r + bias1) >> 16,
499 (g + bias1) >> 16,
500 (b + bias1) >> 16);
501 cache[kCache32Count*2] = SkPackARGB32((a + bias2) >> 16,
502 (r + bias2) >> 16,
503 (g + bias2) >> 16,
504 (b + bias2) >> 16);
505 cache[kCache32Count*3] = SkPackARGB32((a + bias3) >> 16,
506 (r + bias3) >> 16,
507 (g + bias3) >> 16,
508 (b + bias3) >> 16);
509 cache += 1;
510 a += da;
511 r += dr;
512 g += dg;
513 b += db;
514 } while (--count != 0);
515 } else { // interpolate in unpreml space
516 do {
517 cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0 ) >> 16,
518 (r + 0 ) >> 16,
519 (g + 0 ) >> 16,
520 (b + 0 ) >> 16);
521 cache[kCache32Count*1] = SkPremultiplyARGBInline((a + bias1) >> 16,
522 (r + bias1) >> 16,
523 (g + bias1) >> 16,
524 (b + bias1) >> 16);
525 cache[kCache32Count*2] = SkPremultiplyARGBInline((a + bias2) >> 16,
526 (r + bias2) >> 16,
527 (g + bias2) >> 16,
528 (b + bias2) >> 16);
529 cache[kCache32Count*3] = SkPremultiplyARGBInline((a + bias3) >> 16,
530 (r + bias3) >> 16,
531 (g + bias3) >> 16,
532 (b + bias3) >> 16);
533 cache += 1;
534 a += da;
535 r += dr;
536 g += dg;
537 b += db;
538 } while (--count != 0);
539 }
540 }
541
SkFixedToFFFF(SkFixed x)542 static inline int SkFixedToFFFF(SkFixed x) {
543 SkASSERT((unsigned)x <= SK_Fixed1);
544 return x - (x >> 16);
545 }
546
getCache16()547 const uint16_t* SkGradientShaderBase::GradientShaderCache::getCache16() {
548 SkOnce(&fCache16Inited, &fCache16Mutex, SkGradientShaderBase::GradientShaderCache::initCache16,
549 this);
550 SkASSERT(fCache16);
551 return fCache16;
552 }
553
initCache16(GradientShaderCache * cache)554 void SkGradientShaderBase::GradientShaderCache::initCache16(GradientShaderCache* cache) {
555 // double the count for dither entries
556 const int entryCount = kCache16Count * 2;
557 const size_t allocSize = sizeof(uint16_t) * entryCount;
558
559 SkASSERT(nullptr == cache->fCache16Storage);
560 cache->fCache16Storage = (uint16_t*)sk_malloc_throw(allocSize);
561 cache->fCache16 = cache->fCache16Storage;
562 if (cache->fShader.fColorCount == 2) {
563 Build16bitCache(cache->fCache16, cache->fShader.fOrigColors[0],
564 cache->fShader.fOrigColors[1], kCache16Count, cache->fCacheDither);
565 } else {
566 Rec* rec = cache->fShader.fRecs;
567 int prevIndex = 0;
568 for (int i = 1; i < cache->fShader.fColorCount; i++) {
569 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache16Shift;
570 SkASSERT(nextIndex < kCache16Count);
571
572 if (nextIndex > prevIndex)
573 Build16bitCache(cache->fCache16 + prevIndex, cache->fShader.fOrigColors[i-1],
574 cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
575 cache->fCacheDither);
576 prevIndex = nextIndex;
577 }
578 }
579 }
580
getCache32()581 const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() {
582 SkOnce(&fCache32Inited, &fCache32Mutex, SkGradientShaderBase::GradientShaderCache::initCache32,
583 this);
584 SkASSERT(fCache32);
585 return fCache32;
586 }
587
initCache32(GradientShaderCache * cache)588 void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) {
589 const int kNumberOfDitherRows = 4;
590 const SkImageInfo info = SkImageInfo::MakeN32Premul(kCache32Count, kNumberOfDitherRows);
591
592 SkASSERT(nullptr == cache->fCache32PixelRef);
593 cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, nullptr);
594 cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr();
595 if (cache->fShader.fColorCount == 2) {
596 Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0],
597 cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha,
598 cache->fShader.fGradFlags, cache->fCacheDither);
599 } else {
600 Rec* rec = cache->fShader.fRecs;
601 int prevIndex = 0;
602 for (int i = 1; i < cache->fShader.fColorCount; i++) {
603 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
604 SkASSERT(nextIndex < kCache32Count);
605
606 if (nextIndex > prevIndex)
607 Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1],
608 cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1,
609 cache->fCacheAlpha, cache->fShader.fGradFlags, cache->fCacheDither);
610 prevIndex = nextIndex;
611 }
612 }
613 }
614
615 /*
616 * The gradient holds a cache for the most recent value of alpha. Successive
617 * callers with the same alpha value will share the same cache.
618 */
refCache(U8CPU alpha,bool dither) const619 SkGradientShaderBase::GradientShaderCache* SkGradientShaderBase::refCache(U8CPU alpha,
620 bool dither) const {
621 SkAutoMutexAcquire ama(fCacheMutex);
622 if (!fCache || fCache->getAlpha() != alpha || fCache->getDither() != dither) {
623 fCache.reset(new GradientShaderCache(alpha, dither, *this));
624 }
625 // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
626 // Otherwise, the pointer may have been overwritten on a different thread before the object's
627 // ref count was incremented.
628 fCache.get()->ref();
629 return fCache;
630 }
631
632 SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
633 /*
634 * Because our caller might rebuild the same (logically the same) gradient
635 * over and over, we'd like to return exactly the same "bitmap" if possible,
636 * allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
637 * To do that, we maintain a private cache of built-bitmaps, based on our
638 * colors and positions. Note: we don't try to flatten the fMapper, so if one
639 * is present, we skip the cache for now.
640 */
getGradientTableBitmap(SkBitmap * bitmap) const641 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap) const {
642 // our caller assumes no external alpha, so we ensure that our cache is
643 // built with 0xFF
644 SkAutoTUnref<GradientShaderCache> cache(this->refCache(0xFF, true));
645
646 // build our key: [numColors + colors[] + {positions[]} + flags ]
647 int count = 1 + fColorCount + 1;
648 if (fColorCount > 2) {
649 count += fColorCount - 1; // fRecs[].fPos
650 }
651
652 SkAutoSTMalloc<16, int32_t> storage(count);
653 int32_t* buffer = storage.get();
654
655 *buffer++ = fColorCount;
656 memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor));
657 buffer += fColorCount;
658 if (fColorCount > 2) {
659 for (int i = 1; i < fColorCount; i++) {
660 *buffer++ = fRecs[i].fPos;
661 }
662 }
663 *buffer++ = fGradFlags;
664 SkASSERT(buffer - storage.get() == count);
665
666 ///////////////////////////////////
667
668 static SkGradientBitmapCache* gCache;
669 // each cache cost 1K of RAM, since each bitmap will be 1x256 at 32bpp
670 static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
671 SkAutoMutexAcquire ama(gGradientCacheMutex);
672
673 if (nullptr == gCache) {
674 gCache = new SkGradientBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
675 }
676 size_t size = count * sizeof(int32_t);
677
678 if (!gCache->find(storage.get(), size, bitmap)) {
679 // force our cahce32pixelref to be built
680 (void)cache->getCache32();
681 bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1));
682 bitmap->setPixelRef(cache->getCache32PixelRef());
683
684 gCache->add(storage.get(), size, *bitmap);
685 }
686 }
687
commonAsAGradient(GradientInfo * info,bool flipGrad) const688 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) const {
689 if (info) {
690 if (info->fColorCount >= fColorCount) {
691 SkColor* colorLoc;
692 Rec* recLoc;
693 if (flipGrad && (info->fColors || info->fColorOffsets)) {
694 SkAutoSTArray<8, SkColor> colorStorage(fColorCount);
695 SkAutoSTArray<8, Rec> recStorage(fColorCount);
696 colorLoc = colorStorage.get();
697 recLoc = recStorage.get();
698 FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount);
699 } else {
700 colorLoc = fOrigColors;
701 recLoc = fRecs;
702 }
703 if (info->fColors) {
704 memcpy(info->fColors, colorLoc, fColorCount * sizeof(SkColor));
705 }
706 if (info->fColorOffsets) {
707 if (fColorCount == 2) {
708 info->fColorOffsets[0] = 0;
709 info->fColorOffsets[1] = SK_Scalar1;
710 } else if (fColorCount > 2) {
711 for (int i = 0; i < fColorCount; ++i) {
712 info->fColorOffsets[i] = SkFixedToScalar(recLoc[i].fPos);
713 }
714 }
715 }
716 }
717 info->fColorCount = fColorCount;
718 info->fTileMode = fTileMode;
719 info->fGradientFlags = fGradFlags;
720 }
721 }
722
723 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const724 void SkGradientShaderBase::toString(SkString* str) const {
725
726 str->appendf("%d colors: ", fColorCount);
727
728 for (int i = 0; i < fColorCount; ++i) {
729 str->appendHex(fOrigColors[i], 8);
730 if (i < fColorCount-1) {
731 str->append(", ");
732 }
733 }
734
735 if (fColorCount > 2) {
736 str->append(" points: (");
737 for (int i = 0; i < fColorCount; ++i) {
738 str->appendScalar(SkFixedToScalar(fRecs[i].fPos));
739 if (i < fColorCount-1) {
740 str->append(", ");
741 }
742 }
743 str->append(")");
744 }
745
746 static const char* gTileModeName[SkShader::kTileModeCount] = {
747 "clamp", "repeat", "mirror"
748 };
749
750 str->append(" ");
751 str->append(gTileModeName[fTileMode]);
752
753 this->INHERITED::toString(str);
754 }
755 #endif
756
757 ///////////////////////////////////////////////////////////////////////////////
758 ///////////////////////////////////////////////////////////////////////////////
759
760 // Return true if these parameters are valid/legal/safe to construct a gradient
761 //
valid_grad(const SkColor colors[],const SkScalar pos[],int count,unsigned tileMode)762 static bool valid_grad(const SkColor colors[], const SkScalar pos[], int count, unsigned tileMode) {
763 return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount;
764 }
765
766 // assumes colors is SkColor* and pos is SkScalar*
767 #define EXPAND_1_COLOR(count) \
768 SkColor tmp[2]; \
769 do { \
770 if (1 == count) { \
771 tmp[0] = tmp[1] = colors[0]; \
772 colors = tmp; \
773 pos = nullptr; \
774 count = 2; \
775 } \
776 } while (0)
777
desc_init(SkGradientShaderBase::Descriptor * desc,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)778 static void desc_init(SkGradientShaderBase::Descriptor* desc,
779 const SkColor colors[], const SkScalar pos[], int colorCount,
780 SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
781 desc->fColors = colors;
782 desc->fPos = pos;
783 desc->fCount = colorCount;
784 desc->fTileMode = mode;
785 desc->fGradFlags = flags;
786 desc->fLocalMatrix = localMatrix;
787 }
788
CreateLinear(const SkPoint pts[2],const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)789 SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2],
790 const SkColor colors[],
791 const SkScalar pos[], int colorCount,
792 SkShader::TileMode mode,
793 uint32_t flags,
794 const SkMatrix* localMatrix) {
795 if (!pts) {
796 return nullptr;
797 }
798 if (!valid_grad(colors, pos, colorCount, mode)) {
799 return nullptr;
800 }
801 EXPAND_1_COLOR(colorCount);
802
803 SkGradientShaderBase::Descriptor desc;
804 desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
805 return new SkLinearGradient(pts, desc);
806 }
807
CreateRadial(const SkPoint & center,SkScalar radius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)808 SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius,
809 const SkColor colors[],
810 const SkScalar pos[], int colorCount,
811 SkShader::TileMode mode,
812 uint32_t flags,
813 const SkMatrix* localMatrix) {
814 if (radius <= 0) {
815 return nullptr;
816 }
817 if (!valid_grad(colors, pos, colorCount, mode)) {
818 return nullptr;
819 }
820 EXPAND_1_COLOR(colorCount);
821
822 SkGradientShaderBase::Descriptor desc;
823 desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
824 return new SkRadialGradient(center, radius, desc);
825 }
826
CreateTwoPointConical(const SkPoint & start,SkScalar startRadius,const SkPoint & end,SkScalar endRadius,const SkColor colors[],const SkScalar pos[],int colorCount,SkShader::TileMode mode,uint32_t flags,const SkMatrix * localMatrix)827 SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start,
828 SkScalar startRadius,
829 const SkPoint& end,
830 SkScalar endRadius,
831 const SkColor colors[],
832 const SkScalar pos[],
833 int colorCount,
834 SkShader::TileMode mode,
835 uint32_t flags,
836 const SkMatrix* localMatrix) {
837 if (startRadius < 0 || endRadius < 0) {
838 return nullptr;
839 }
840 if (!valid_grad(colors, pos, colorCount, mode)) {
841 return nullptr;
842 }
843 if (start == end && startRadius == endRadius) {
844 return SkShader::CreateEmptyShader();
845 }
846
847 EXPAND_1_COLOR(colorCount);
848
849 bool flipGradient = startRadius > endRadius;
850
851 SkGradientShaderBase::Descriptor desc;
852
853 if (!flipGradient) {
854 desc_init(&desc, colors, pos, colorCount, mode, flags, localMatrix);
855 return new SkTwoPointConicalGradient(start, startRadius, end, endRadius, flipGradient,
856 desc);
857 } else {
858 SkAutoSTArray<8, SkColor> colorsNew(colorCount);
859 SkAutoSTArray<8, SkScalar> posNew(colorCount);
860 for (int i = 0; i < colorCount; ++i) {
861 colorsNew[i] = colors[colorCount - i - 1];
862 }
863
864 if (pos) {
865 for (int i = 0; i < colorCount; ++i) {
866 posNew[i] = 1 - pos[colorCount - i - 1];
867 }
868 desc_init(&desc, colorsNew.get(), posNew.get(), colorCount, mode, flags, localMatrix);
869 } else {
870 desc_init(&desc, colorsNew.get(), nullptr, colorCount, mode, flags, localMatrix);
871 }
872
873 return new SkTwoPointConicalGradient(end, endRadius, start, startRadius, flipGradient,
874 desc);
875 }
876 }
877
CreateSweep(SkScalar cx,SkScalar cy,const SkColor colors[],const SkScalar pos[],int colorCount,uint32_t flags,const SkMatrix * localMatrix)878 SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy,
879 const SkColor colors[],
880 const SkScalar pos[],
881 int colorCount,
882 uint32_t flags,
883 const SkMatrix* localMatrix) {
884 if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) {
885 return nullptr;
886 }
887 EXPAND_1_COLOR(colorCount);
888
889 SkGradientShaderBase::Descriptor desc;
890 desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, flags, localMatrix);
891 return new SkSweepGradient(cx, cy, desc);
892 }
893
894 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)895 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
896 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
897 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
898 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
899 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
900
901 ///////////////////////////////////////////////////////////////////////////////
902
903 #if SK_SUPPORT_GPU
904
905 #include "effects/GrTextureStripAtlas.h"
906 #include "GrInvariantOutput.h"
907 #include "gl/GrGLContext.h"
908 #include "glsl/GrGLSLFragmentShaderBuilder.h"
909 #include "glsl/GrGLSLProgramDataManager.h"
910 #include "glsl/GrGLSLUniformHandler.h"
911 #include "SkGr.h"
912
913 GrGLGradientEffect::GrGLGradientEffect()
914 : fCachedYCoord(SK_ScalarMax) {
915 }
916
emitUniforms(GrGLSLUniformHandler * uniformHandler,const GrGradientEffect & ge)917 void GrGLGradientEffect::emitUniforms(GrGLSLUniformHandler* uniformHandler,
918 const GrGradientEffect& ge) {
919
920 if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()) { // 2 Color case
921 fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
922 kVec4f_GrSLType, kDefault_GrSLPrecision,
923 "GradientStartColor");
924 fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
925 kVec4f_GrSLType, kDefault_GrSLPrecision,
926 "GradientEndColor");
927
928 } else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) { // 3 Color Case
929 fColorStartUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
930 kVec4f_GrSLType, kDefault_GrSLPrecision,
931 "GradientStartColor");
932 fColorMidUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
933 kVec4f_GrSLType, kDefault_GrSLPrecision,
934 "GradientMidColor");
935 fColorEndUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
936 kVec4f_GrSLType, kDefault_GrSLPrecision,
937 "GradientEndColor");
938
939 } else { // if not a fast case
940 fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
941 kFloat_GrSLType, kDefault_GrSLPrecision,
942 "GradientYCoordFS");
943 }
944 }
945
set_color_uni(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkColor * color)946 static inline void set_color_uni(const GrGLSLProgramDataManager& pdman,
947 const GrGLSLProgramDataManager::UniformHandle uni,
948 const SkColor* color) {
949 pdman.set4f(uni,
950 SkColorGetR(*color) / 255.f,
951 SkColorGetG(*color) / 255.f,
952 SkColorGetB(*color) / 255.f,
953 SkColorGetA(*color) / 255.f);
954 }
955
set_mul_color_uni(const GrGLSLProgramDataManager & pdman,const GrGLSLProgramDataManager::UniformHandle uni,const SkColor * color)956 static inline void set_mul_color_uni(const GrGLSLProgramDataManager& pdman,
957 const GrGLSLProgramDataManager::UniformHandle uni,
958 const SkColor* color){
959 float a = SkColorGetA(*color) / 255.f;
960 float aDiv255 = a / 255.f;
961 pdman.set4f(uni,
962 SkColorGetR(*color) * aDiv255,
963 SkColorGetG(*color) * aDiv255,
964 SkColorGetB(*color) * aDiv255,
965 a);
966 }
967
onSetData(const GrGLSLProgramDataManager & pdman,const GrProcessor & processor)968 void GrGLGradientEffect::onSetData(const GrGLSLProgramDataManager& pdman,
969 const GrProcessor& processor) {
970
971 const GrGradientEffect& e = processor.cast<GrGradientEffect>();
972
973
974 if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()){
975
976 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
977 set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
978 set_mul_color_uni(pdman, fColorEndUni, e.getColors(1));
979 } else {
980 set_color_uni(pdman, fColorStartUni, e.getColors(0));
981 set_color_uni(pdman, fColorEndUni, e.getColors(1));
982 }
983
984 } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()){
985
986 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
987 set_mul_color_uni(pdman, fColorStartUni, e.getColors(0));
988 set_mul_color_uni(pdman, fColorMidUni, e.getColors(1));
989 set_mul_color_uni(pdman, fColorEndUni, e.getColors(2));
990 } else {
991 set_color_uni(pdman, fColorStartUni, e.getColors(0));
992 set_color_uni(pdman, fColorMidUni, e.getColors(1));
993 set_color_uni(pdman, fColorEndUni, e.getColors(2));
994 }
995 } else {
996
997 SkScalar yCoord = e.getYCoord();
998 if (yCoord != fCachedYCoord) {
999 pdman.set1f(fFSYUni, yCoord);
1000 fCachedYCoord = yCoord;
1001 }
1002 }
1003 }
1004
1005
GenBaseGradientKey(const GrProcessor & processor)1006 uint32_t GrGLGradientEffect::GenBaseGradientKey(const GrProcessor& processor) {
1007 const GrGradientEffect& e = processor.cast<GrGradientEffect>();
1008
1009 uint32_t key = 0;
1010
1011 if (SkGradientShaderBase::kTwo_GpuColorType == e.getColorType()) {
1012 key |= kTwoColorKey;
1013 } else if (SkGradientShaderBase::kThree_GpuColorType == e.getColorType()) {
1014 key |= kThreeColorKey;
1015 }
1016
1017 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
1018 key |= kPremulBeforeInterpKey;
1019 }
1020
1021 return key;
1022 }
1023
emitColor(GrGLSLFPFragmentBuilder * fragBuilder,GrGLSLUniformHandler * uniformHandler,const GrGLSLCaps * glslCaps,const GrGradientEffect & ge,const char * gradientTValue,const char * outputColor,const char * inputColor,const TextureSamplerArray & samplers)1024 void GrGLGradientEffect::emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
1025 GrGLSLUniformHandler* uniformHandler,
1026 const GrGLSLCaps* glslCaps,
1027 const GrGradientEffect& ge,
1028 const char* gradientTValue,
1029 const char* outputColor,
1030 const char* inputColor,
1031 const TextureSamplerArray& samplers) {
1032 if (SkGradientShaderBase::kTwo_GpuColorType == ge.getColorType()){
1033 fragBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
1034 uniformHandler->getUniformVariable(fColorStartUni).c_str(),
1035 uniformHandler->getUniformVariable(fColorEndUni).c_str(),
1036 gradientTValue);
1037 // Note that we could skip this step if both colors are known to be opaque. Two
1038 // considerations:
1039 // The gradient SkShader reporting opaque is more restrictive than necessary in the two pt
1040 // case. Make sure the key reflects this optimization (and note that it can use the same
1041 // shader as thekBeforeIterp case). This same optimization applies to the 3 color case
1042 // below.
1043 if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1044 fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
1045 }
1046
1047 fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
1048 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
1049 } else if (SkGradientShaderBase::kThree_GpuColorType == ge.getColorType()) {
1050 fragBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
1051 gradientTValue);
1052 fragBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
1053 uniformHandler->getUniformVariable(fColorStartUni).c_str());
1054 if (!glslCaps->canUseMinAndAbsTogether()) {
1055 // The Tegra3 compiler will sometimes never return if we have
1056 // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
1057 fragBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
1058 fragBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
1059 fragBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
1060 uniformHandler->getUniformVariable(fColorMidUni).c_str());
1061 } else {
1062 fragBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
1063 uniformHandler->getUniformVariable(fColorMidUni).c_str());
1064 }
1065 fragBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
1066 uniformHandler->getUniformVariable(fColorEndUni).c_str());
1067 if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) {
1068 fragBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
1069 }
1070
1071 fragBuilder->codeAppendf("\t%s = %s;\n", outputColor,
1072 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
1073 } else {
1074 fragBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n",
1075 gradientTValue,
1076 uniformHandler->getUniformVariable(fFSYUni).c_str());
1077 fragBuilder->codeAppendf("\t%s = ", outputColor);
1078 fragBuilder->appendTextureLookupAndModulate(inputColor,
1079 samplers[0],
1080 "coord");
1081 fragBuilder->codeAppend(";\n");
1082 }
1083 }
1084
1085 /////////////////////////////////////////////////////////////////////
1086
GrGradientEffect(GrContext * ctx,const SkGradientShaderBase & shader,const SkMatrix & matrix,SkShader::TileMode tileMode)1087 GrGradientEffect::GrGradientEffect(GrContext* ctx,
1088 const SkGradientShaderBase& shader,
1089 const SkMatrix& matrix,
1090 SkShader::TileMode tileMode) {
1091
1092 fIsOpaque = shader.isOpaque();
1093
1094 fColorType = shader.getGpuColorType(&fColors[0]);
1095
1096 // The two and three color specializations do not currently support tiling.
1097 if (SkGradientShaderBase::kTwo_GpuColorType == fColorType ||
1098 SkGradientShaderBase::kThree_GpuColorType == fColorType) {
1099 fRow = -1;
1100
1101 if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) {
1102 fPremulType = kBeforeInterp_PremulType;
1103 } else {
1104 fPremulType = kAfterInterp_PremulType;
1105 }
1106 fCoordTransform.reset(kCoordSet, matrix);
1107 } else {
1108 // doesn't matter how this is set, just be consistent because it is part of the effect key.
1109 fPremulType = kBeforeInterp_PremulType;
1110 SkBitmap bitmap;
1111 shader.getGradientTableBitmap(&bitmap);
1112
1113 GrTextureStripAtlas::Desc desc;
1114 desc.fWidth = bitmap.width();
1115 desc.fHeight = 32;
1116 desc.fRowHeight = bitmap.height();
1117 desc.fContext = ctx;
1118 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
1119 fAtlas = GrTextureStripAtlas::GetAtlas(desc);
1120 SkASSERT(fAtlas);
1121
1122 // We always filter the gradient table. Each table is one row of a texture, always y-clamp.
1123 GrTextureParams params;
1124 params.setFilterMode(GrTextureParams::kBilerp_FilterMode);
1125 params.setTileModeX(tileMode);
1126
1127 fRow = fAtlas->lockRow(bitmap);
1128 if (-1 != fRow) {
1129 fYCoord = fAtlas->getYOffset(fRow) + SK_ScalarHalf * fAtlas->getNormalizedTexelHeight();
1130 fCoordTransform.reset(kCoordSet, matrix, fAtlas->getTexture(), params.filterMode());
1131 fTextureAccess.reset(fAtlas->getTexture(), params);
1132 } else {
1133 SkAutoTUnref<GrTexture> texture(GrRefCachedBitmapTexture(ctx, bitmap, params));
1134 if (!texture) {
1135 return;
1136 }
1137 fCoordTransform.reset(kCoordSet, matrix, texture, params.filterMode());
1138 fTextureAccess.reset(texture, params);
1139 fYCoord = SK_ScalarHalf;
1140 }
1141 this->addTextureAccess(&fTextureAccess);
1142 }
1143 this->addCoordTransform(&fCoordTransform);
1144 }
1145
~GrGradientEffect()1146 GrGradientEffect::~GrGradientEffect() {
1147 if (this->useAtlas()) {
1148 fAtlas->unlockRow(fRow);
1149 }
1150 }
1151
onIsEqual(const GrFragmentProcessor & processor) const1152 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
1153 const GrGradientEffect& s = processor.cast<GrGradientEffect>();
1154
1155 if (this->fColorType == s.getColorType()){
1156
1157 if (SkGradientShaderBase::kTwo_GpuColorType == fColorType) {
1158 if (*this->getColors(0) != *s.getColors(0) ||
1159 *this->getColors(1) != *s.getColors(1)) {
1160 return false;
1161 }
1162 } else if (SkGradientShaderBase::kThree_GpuColorType == fColorType) {
1163 if (*this->getColors(0) != *s.getColors(0) ||
1164 *this->getColors(1) != *s.getColors(1) ||
1165 *this->getColors(2) != *s.getColors(2)) {
1166 return false;
1167 }
1168 } else {
1169 if (fYCoord != s.getYCoord()) {
1170 return false;
1171 }
1172 }
1173
1174 SkASSERT(this->useAtlas() == s.useAtlas());
1175 return true;
1176 }
1177
1178 return false;
1179 }
1180
onComputeInvariantOutput(GrInvariantOutput * inout) const1181 void GrGradientEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
1182 if (fIsOpaque) {
1183 inout->mulByUnknownOpaqueFourComponents();
1184 } else {
1185 inout->mulByUnknownFourComponents();
1186 }
1187 }
1188
RandomGradientParams(SkRandom * random,SkColor colors[],SkScalar ** stops,SkShader::TileMode * tm)1189 int GrGradientEffect::RandomGradientParams(SkRandom* random,
1190 SkColor colors[],
1191 SkScalar** stops,
1192 SkShader::TileMode* tm) {
1193 int outColors = random->nextRangeU(1, kMaxRandomGradientColors);
1194
1195 // if one color, omit stops, otherwise randomly decide whether or not to
1196 if (outColors == 1 || (outColors >= 2 && random->nextBool())) {
1197 *stops = nullptr;
1198 }
1199
1200 SkScalar stop = 0.f;
1201 for (int i = 0; i < outColors; ++i) {
1202 colors[i] = random->nextU();
1203 if (*stops) {
1204 (*stops)[i] = stop;
1205 stop = i < outColors - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
1206 }
1207 }
1208 *tm = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
1209
1210 return outColors;
1211 }
1212
1213 #endif
1214