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 "SkColorSpace_XYZ.h" 10 #include "SkGradientShaderPriv.h" 11 #include "SkHalf.h" 12 #include "SkLinearGradient.h" 13 #include "SkRadialGradient.h" 14 #include "SkTwoPointConicalGradient.h" 15 #include "SkSweepGradient.h" 16 17 enum GradientSerializationFlags { 18 // Bits 29:31 used for various boolean flags 19 kHasPosition_GSF = 0x80000000, 20 kHasLocalMatrix_GSF = 0x40000000, 21 kHasColorSpace_GSF = 0x20000000, 22 23 // Bits 12:28 unused 24 25 // Bits 8:11 for fTileMode 26 kTileModeShift_GSF = 8, 27 kTileModeMask_GSF = 0xF, 28 29 // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80) 30 kGradFlagsShift_GSF = 0, 31 kGradFlagsMask_GSF = 0xFF, 32 }; 33 34 void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const { 35 uint32_t flags = 0; 36 if (fPos) { 37 flags |= kHasPosition_GSF; 38 } 39 if (fLocalMatrix) { 40 flags |= kHasLocalMatrix_GSF; 41 } 42 sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr; 43 if (colorSpaceData) { 44 flags |= kHasColorSpace_GSF; 45 } 46 SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF); 47 flags |= (fTileMode << kTileModeShift_GSF); 48 SkASSERT(fGradFlags <= kGradFlagsMask_GSF); 49 flags |= (fGradFlags << kGradFlagsShift_GSF); 50 51 buffer.writeUInt(flags); 52 53 buffer.writeColor4fArray(fColors, fCount); 54 if (colorSpaceData) { 55 buffer.writeDataAsByteArray(colorSpaceData.get()); 56 } 57 if (fPos) { 58 buffer.writeScalarArray(fPos, fCount); 59 } 60 if (fLocalMatrix) { 61 buffer.writeMatrix(*fLocalMatrix); 62 } 63 } 64 65 bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) { 66 if (buffer.isVersionLT(SkReadBuffer::kGradientShaderFloatColor_Version)) { 67 fCount = buffer.getArrayCount(); 68 if (fCount > kStorageCount) { 69 size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount; 70 fDynamicStorage.reset(allocSize); 71 fColors = (SkColor4f*)fDynamicStorage.get(); 72 fPos = (SkScalar*)(fColors + fCount); 73 } else { 74 fColors = fColorStorage; 75 fPos = fPosStorage; 76 } 77 78 // Old gradients serialized SkColor. Read that to a temporary location, then convert. 79 SkSTArray<2, SkColor, true> colors; 80 colors.resize_back(fCount); 81 if (!buffer.readColorArray(colors.begin(), fCount)) { 82 return false; 83 } 84 for (int i = 0; i < fCount; ++i) { 85 mutableColors()[i] = SkColor4f::FromColor(colors[i]); 86 } 87 88 if (buffer.readBool()) { 89 if (!buffer.readScalarArray(const_cast<SkScalar*>(fPos), fCount)) { 90 return false; 91 } 92 } else { 93 fPos = nullptr; 94 } 95 96 fColorSpace = nullptr; 97 fTileMode = (SkShader::TileMode)buffer.read32(); 98 fGradFlags = buffer.read32(); 99 100 if (buffer.readBool()) { 101 fLocalMatrix = &fLocalMatrixStorage; 102 buffer.readMatrix(&fLocalMatrixStorage); 103 } else { 104 fLocalMatrix = nullptr; 105 } 106 } else { 107 // New gradient format. Includes floating point color, color space, densely packed flags 108 uint32_t flags = buffer.readUInt(); 109 110 fTileMode = (SkShader::TileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF); 111 fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF; 112 113 fCount = buffer.getArrayCount(); 114 if (fCount > kStorageCount) { 115 size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount; 116 fDynamicStorage.reset(allocSize); 117 fColors = (SkColor4f*)fDynamicStorage.get(); 118 fPos = (SkScalar*)(fColors + fCount); 119 } else { 120 fColors = fColorStorage; 121 fPos = fPosStorage; 122 } 123 if (!buffer.readColor4fArray(mutableColors(), fCount)) { 124 return false; 125 } 126 if (SkToBool(flags & kHasColorSpace_GSF)) { 127 sk_sp<SkData> data = buffer.readByteArrayAsData(); 128 fColorSpace = SkColorSpace::Deserialize(data->data(), data->size()); 129 } else { 130 fColorSpace = nullptr; 131 } 132 if (SkToBool(flags & kHasPosition_GSF)) { 133 if (!buffer.readScalarArray(mutablePos(), fCount)) { 134 return false; 135 } 136 } else { 137 fPos = nullptr; 138 } 139 if (SkToBool(flags & kHasLocalMatrix_GSF)) { 140 fLocalMatrix = &fLocalMatrixStorage; 141 buffer.readMatrix(&fLocalMatrixStorage); 142 } else { 143 fLocalMatrix = nullptr; 144 } 145 } 146 return buffer.isValid(); 147 } 148 149 //////////////////////////////////////////////////////////////////////////////////////////// 150 151 SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit) 152 : INHERITED(desc.fLocalMatrix) 153 , fPtsToUnit(ptsToUnit) 154 { 155 fPtsToUnit.getType(); // Precache so reads are threadsafe. 156 SkASSERT(desc.fCount > 1); 157 158 fGradFlags = static_cast<uint8_t>(desc.fGradFlags); 159 160 SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount); 161 SkASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gTileProcs)); 162 fTileMode = desc.fTileMode; 163 fTileProc = gTileProcs[desc.fTileMode]; 164 165 /* Note: we let the caller skip the first and/or last position. 166 i.e. pos[0] = 0.3, pos[1] = 0.7 167 In these cases, we insert dummy entries to ensure that the final data 168 will be bracketed by [0, 1]. 169 i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1 170 171 Thus colorCount (the caller's value, and fColorCount (our value) may 172 differ by up to 2. In the above example: 173 colorCount = 2 174 fColorCount = 4 175 */ 176 fColorCount = desc.fCount; 177 // check if we need to add in dummy start and/or end position/colors 178 bool dummyFirst = false; 179 bool dummyLast = false; 180 if (desc.fPos) { 181 dummyFirst = desc.fPos[0] != 0; 182 dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1; 183 fColorCount += dummyFirst + dummyLast; 184 } 185 186 if (fColorCount > kColorStorageCount) { 187 size_t size = sizeof(SkColor) + sizeof(SkColor4f) + sizeof(Rec); 188 if (desc.fPos) { 189 size += sizeof(SkScalar); 190 } 191 fOrigColors = reinterpret_cast<SkColor*>(sk_malloc_throw(size * fColorCount)); 192 } 193 else { 194 fOrigColors = fStorage; 195 } 196 197 fOrigColors4f = (SkColor4f*)(fOrigColors + fColorCount); 198 199 // Now copy over the colors, adding the dummies as needed 200 SkColor4f* origColors = fOrigColors4f; 201 if (dummyFirst) { 202 *origColors++ = desc.fColors[0]; 203 } 204 memcpy(origColors, desc.fColors, desc.fCount * sizeof(SkColor4f)); 205 if (dummyLast) { 206 origColors += desc.fCount; 207 *origColors = desc.fColors[desc.fCount - 1]; 208 } 209 210 // Convert our SkColor4f colors to SkColor as well. Note that this is incorrect if the 211 // source colors are not in sRGB gamut. We would need to do a gamut transformation, but 212 // SkColorSpaceXform can't do that (yet). GrColorSpaceXform can, but we may not have GPU 213 // support compiled in here. For the common case (sRGB colors), this does the right thing. 214 for (int i = 0; i < fColorCount; ++i) { 215 fOrigColors[i] = fOrigColors4f[i].toSkColor(); 216 } 217 218 if (!desc.fColorSpace) { 219 // This happens if we were constructed from SkColors, so our colors are really sRGB 220 fColorSpace = SkColorSpace::MakeSRGBLinear(); 221 } else { 222 // The color space refers to the float colors, so it must be linear gamma 223 SkASSERT(desc.fColorSpace->gammaIsLinear()); 224 fColorSpace = desc.fColorSpace; 225 } 226 227 if (desc.fPos && fColorCount) { 228 fOrigPos = (SkScalar*)(fOrigColors4f + fColorCount); 229 fRecs = (Rec*)(fOrigPos + fColorCount); 230 } else { 231 fOrigPos = nullptr; 232 fRecs = (Rec*)(fOrigColors4f + fColorCount); 233 } 234 235 if (fColorCount > 2) { 236 Rec* recs = fRecs; 237 recs->fPos = 0; 238 // recs->fScale = 0; // unused; 239 recs += 1; 240 if (desc.fPos) { 241 SkScalar* origPosPtr = fOrigPos; 242 *origPosPtr++ = 0; 243 244 /* We need to convert the user's array of relative positions into 245 fixed-point positions and scale factors. We need these results 246 to be strictly monotonic (no two values equal or out of order). 247 Hence this complex loop that just jams a zero for the scale 248 value if it sees a segment out of order, and it assures that 249 we start at 0 and end at 1.0 250 */ 251 SkScalar prev = 0; 252 int startIndex = dummyFirst ? 0 : 1; 253 int count = desc.fCount + dummyLast; 254 for (int i = startIndex; i < count; i++) { 255 // force the last value to be 1.0 256 SkScalar curr; 257 if (i == desc.fCount) { // we're really at the dummyLast 258 curr = 1; 259 } else { 260 curr = SkScalarPin(desc.fPos[i], 0, 1); 261 } 262 *origPosPtr++ = curr; 263 264 recs->fPos = SkScalarToFixed(curr); 265 SkFixed diff = SkScalarToFixed(curr - prev); 266 if (diff > 0) { 267 recs->fScale = (1 << 24) / diff; 268 } else { 269 recs->fScale = 0; // ignore this segment 270 } 271 // get ready for the next value 272 prev = curr; 273 recs += 1; 274 } 275 } else { // assume even distribution 276 fOrigPos = nullptr; 277 278 SkFixed dp = SK_Fixed1 / (desc.fCount - 1); 279 SkFixed p = dp; 280 SkFixed scale = (desc.fCount - 1) << 8; // (1 << 24) / dp 281 for (int i = 1; i < desc.fCount - 1; i++) { 282 recs->fPos = p; 283 recs->fScale = scale; 284 recs += 1; 285 p += dp; 286 } 287 recs->fPos = SK_Fixed1; 288 recs->fScale = scale; 289 } 290 } else if (desc.fPos) { 291 SkASSERT(2 == fColorCount); 292 fOrigPos[0] = SkScalarPin(desc.fPos[0], 0, 1); 293 fOrigPos[1] = SkScalarPin(desc.fPos[1], fOrigPos[0], 1); 294 if (0 == fOrigPos[0] && 1 == fOrigPos[1]) { 295 fOrigPos = nullptr; 296 } 297 } 298 this->initCommon(); 299 } 300 301 SkGradientShaderBase::~SkGradientShaderBase() { 302 if (fOrigColors != fStorage) { 303 sk_free(fOrigColors); 304 } 305 } 306 307 void SkGradientShaderBase::initCommon() { 308 unsigned colorAlpha = 0xFF; 309 for (int i = 0; i < fColorCount; i++) { 310 colorAlpha &= SkColorGetA(fOrigColors[i]); 311 } 312 fColorsAreOpaque = colorAlpha == 0xFF; 313 } 314 315 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const { 316 Descriptor desc; 317 desc.fColors = fOrigColors4f; 318 desc.fColorSpace = fColorSpace; 319 desc.fPos = fOrigPos; 320 desc.fCount = fColorCount; 321 desc.fTileMode = fTileMode; 322 desc.fGradFlags = fGradFlags; 323 324 const SkMatrix& m = this->getLocalMatrix(); 325 desc.fLocalMatrix = m.isIdentity() ? nullptr : &m; 326 desc.flatten(buffer); 327 } 328 329 void SkGradientShaderBase::FlipGradientColors(SkColor* colorDst, Rec* recDst, 330 SkColor* colorSrc, Rec* recSrc, 331 int count) { 332 SkAutoSTArray<8, SkColor> colorsTemp(count); 333 for (int i = 0; i < count; ++i) { 334 int offset = count - i - 1; 335 colorsTemp[i] = colorSrc[offset]; 336 } 337 if (count > 2) { 338 SkAutoSTArray<8, Rec> recsTemp(count); 339 for (int i = 0; i < count; ++i) { 340 int offset = count - i - 1; 341 recsTemp[i].fPos = SK_Fixed1 - recSrc[offset].fPos; 342 recsTemp[i].fScale = recSrc[offset].fScale; 343 } 344 memcpy(recDst, recsTemp.get(), count * sizeof(Rec)); 345 } 346 memcpy(colorDst, colorsTemp.get(), count * sizeof(SkColor)); 347 } 348 349 bool SkGradientShaderBase::isOpaque() const { 350 return fColorsAreOpaque; 351 } 352 353 static unsigned rounded_divide(unsigned numer, unsigned denom) { 354 return (numer + (denom >> 1)) / denom; 355 } 356 357 bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const { 358 // we just compute an average color. 359 // possibly we could weight this based on the proportional width for each color 360 // assuming they are not evenly distributed in the fPos array. 361 int r = 0; 362 int g = 0; 363 int b = 0; 364 const int n = fColorCount; 365 for (int i = 0; i < n; ++i) { 366 SkColor c = fOrigColors[i]; 367 r += SkColorGetR(c); 368 g += SkColorGetG(c); 369 b += SkColorGetB(c); 370 } 371 *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n)); 372 return true; 373 } 374 375 SkGradientShaderBase::GradientShaderBaseContext::GradientShaderBaseContext( 376 const SkGradientShaderBase& shader, const ContextRec& rec) 377 : INHERITED(shader, rec) 378 #ifdef SK_SUPPORT_LEGACY_GRADIENT_DITHERING 379 , fDither(true) 380 #else 381 , fDither(rec.fPaint->isDither()) 382 #endif 383 , fCache(shader.refCache(getPaintAlpha(), fDither)) 384 { 385 const SkMatrix& inverse = this->getTotalInverse(); 386 387 fDstToIndex.setConcat(shader.fPtsToUnit, inverse); 388 389 fDstToIndexProc = fDstToIndex.getMapXYProc(); 390 fDstToIndexClass = (uint8_t)SkShader::Context::ComputeMatrixClass(fDstToIndex); 391 392 // now convert our colors in to PMColors 393 unsigned paintAlpha = this->getPaintAlpha(); 394 395 fFlags = this->INHERITED::getFlags(); 396 if (shader.fColorsAreOpaque && paintAlpha == 0xFF) { 397 fFlags |= kOpaqueAlpha_Flag; 398 } 399 } 400 401 bool SkGradientShaderBase::GradientShaderBaseContext::isValid() const { 402 return fDstToIndex.isFinite(); 403 } 404 405 SkGradientShaderBase::GradientShaderCache::GradientShaderCache( 406 U8CPU alpha, bool dither, const SkGradientShaderBase& shader) 407 : fCacheAlpha(alpha) 408 , fCacheDither(dither) 409 , fShader(shader) 410 { 411 // Only initialize the cache in getCache32. 412 fCache32 = nullptr; 413 fCache32PixelRef = nullptr; 414 } 415 416 SkGradientShaderBase::GradientShaderCache::~GradientShaderCache() { 417 SkSafeUnref(fCache32PixelRef); 418 } 419 420 /* 421 * r,g,b used to be SkFixed, but on gcc (4.2.1 mac and 4.6.3 goobuntu) in 422 * release builds, we saw a compiler error where the 0xFF parameter in 423 * SkPackARGB32() was being totally ignored whenever it was called with 424 * a non-zero add (e.g. 0x8000). 425 * 426 * We found two work-arounds: 427 * 1. change r,g,b to unsigned (or just one of them) 428 * 2. change SkPackARGB32 to + its (a << SK_A32_SHIFT) value instead 429 * of using | 430 * 431 * We chose #1 just because it was more localized. 432 * See http://code.google.com/p/skia/issues/detail?id=1113 433 * 434 * The type SkUFixed encapsulate this need for unsigned, but logically Fixed. 435 */ 436 typedef uint32_t SkUFixed; 437 438 void SkGradientShaderBase::GradientShaderCache::Build32bitCache( 439 SkPMColor cache[], SkColor c0, SkColor c1, 440 int count, U8CPU paintAlpha, uint32_t gradFlags, bool dither) { 441 SkASSERT(count > 1); 442 443 // need to apply paintAlpha to our two endpoints 444 uint32_t a0 = SkMulDiv255Round(SkColorGetA(c0), paintAlpha); 445 uint32_t a1 = SkMulDiv255Round(SkColorGetA(c1), paintAlpha); 446 447 448 const bool interpInPremul = SkToBool(gradFlags & 449 SkGradientShader::kInterpolateColorsInPremul_Flag); 450 451 uint32_t r0 = SkColorGetR(c0); 452 uint32_t g0 = SkColorGetG(c0); 453 uint32_t b0 = SkColorGetB(c0); 454 455 uint32_t r1 = SkColorGetR(c1); 456 uint32_t g1 = SkColorGetG(c1); 457 uint32_t b1 = SkColorGetB(c1); 458 459 if (interpInPremul) { 460 r0 = SkMulDiv255Round(r0, a0); 461 g0 = SkMulDiv255Round(g0, a0); 462 b0 = SkMulDiv255Round(b0, a0); 463 464 r1 = SkMulDiv255Round(r1, a1); 465 g1 = SkMulDiv255Round(g1, a1); 466 b1 = SkMulDiv255Round(b1, a1); 467 } 468 469 SkFixed da = SkIntToFixed(a1 - a0) / (count - 1); 470 SkFixed dr = SkIntToFixed(r1 - r0) / (count - 1); 471 SkFixed dg = SkIntToFixed(g1 - g0) / (count - 1); 472 SkFixed db = SkIntToFixed(b1 - b0) / (count - 1); 473 474 /* We pre-add 1/8 to avoid having to add this to our [0] value each time 475 in the loop. Without this, the bias for each would be 476 0x2000 0xA000 0xE000 0x6000 477 With this trick, we can add 0 for the first (no-op) and just adjust the 478 others. 479 */ 480 const SkUFixed bias0 = dither ? 0x2000 : 0x8000; 481 const SkUFixed bias1 = dither ? 0x8000 : 0; 482 const SkUFixed bias2 = dither ? 0xC000 : 0; 483 const SkUFixed bias3 = dither ? 0x4000 : 0; 484 485 SkUFixed a = SkIntToFixed(a0) + bias0; 486 SkUFixed r = SkIntToFixed(r0) + bias0; 487 SkUFixed g = SkIntToFixed(g0) + bias0; 488 SkUFixed b = SkIntToFixed(b0) + bias0; 489 490 /* 491 * Our dither-cell (spatially) is 492 * 0 2 493 * 3 1 494 * Where 495 * [0] -> [-1/8 ... 1/8 ) values near 0 496 * [1] -> [ 1/8 ... 3/8 ) values near 1/4 497 * [2] -> [ 3/8 ... 5/8 ) values near 1/2 498 * [3] -> [ 5/8 ... 7/8 ) values near 3/4 499 */ 500 501 if (0xFF == a0 && 0 == da) { 502 do { 503 cache[kCache32Count*0] = SkPackARGB32(0xFF, (r + 0 ) >> 16, 504 (g + 0 ) >> 16, 505 (b + 0 ) >> 16); 506 cache[kCache32Count*1] = SkPackARGB32(0xFF, (r + bias1) >> 16, 507 (g + bias1) >> 16, 508 (b + bias1) >> 16); 509 cache[kCache32Count*2] = SkPackARGB32(0xFF, (r + bias2) >> 16, 510 (g + bias2) >> 16, 511 (b + bias2) >> 16); 512 cache[kCache32Count*3] = SkPackARGB32(0xFF, (r + bias3) >> 16, 513 (g + bias3) >> 16, 514 (b + bias3) >> 16); 515 cache += 1; 516 r += dr; 517 g += dg; 518 b += db; 519 } while (--count != 0); 520 } else if (interpInPremul) { 521 do { 522 cache[kCache32Count*0] = SkPackARGB32((a + 0 ) >> 16, 523 (r + 0 ) >> 16, 524 (g + 0 ) >> 16, 525 (b + 0 ) >> 16); 526 cache[kCache32Count*1] = SkPackARGB32((a + bias1) >> 16, 527 (r + bias1) >> 16, 528 (g + bias1) >> 16, 529 (b + bias1) >> 16); 530 cache[kCache32Count*2] = SkPackARGB32((a + bias2) >> 16, 531 (r + bias2) >> 16, 532 (g + bias2) >> 16, 533 (b + bias2) >> 16); 534 cache[kCache32Count*3] = SkPackARGB32((a + bias3) >> 16, 535 (r + bias3) >> 16, 536 (g + bias3) >> 16, 537 (b + bias3) >> 16); 538 cache += 1; 539 a += da; 540 r += dr; 541 g += dg; 542 b += db; 543 } while (--count != 0); 544 } else { // interpolate in unpreml space 545 do { 546 cache[kCache32Count*0] = SkPremultiplyARGBInline((a + 0 ) >> 16, 547 (r + 0 ) >> 16, 548 (g + 0 ) >> 16, 549 (b + 0 ) >> 16); 550 cache[kCache32Count*1] = SkPremultiplyARGBInline((a + bias1) >> 16, 551 (r + bias1) >> 16, 552 (g + bias1) >> 16, 553 (b + bias1) >> 16); 554 cache[kCache32Count*2] = SkPremultiplyARGBInline((a + bias2) >> 16, 555 (r + bias2) >> 16, 556 (g + bias2) >> 16, 557 (b + bias2) >> 16); 558 cache[kCache32Count*3] = SkPremultiplyARGBInline((a + bias3) >> 16, 559 (r + bias3) >> 16, 560 (g + bias3) >> 16, 561 (b + bias3) >> 16); 562 cache += 1; 563 a += da; 564 r += dr; 565 g += dg; 566 b += db; 567 } while (--count != 0); 568 } 569 } 570 571 static inline int SkFixedToFFFF(SkFixed x) { 572 SkASSERT((unsigned)x <= SK_Fixed1); 573 return x - (x >> 16); 574 } 575 576 const SkPMColor* SkGradientShaderBase::GradientShaderCache::getCache32() { 577 fCache32InitOnce(SkGradientShaderBase::GradientShaderCache::initCache32, this); 578 SkASSERT(fCache32); 579 return fCache32; 580 } 581 582 void SkGradientShaderBase::GradientShaderCache::initCache32(GradientShaderCache* cache) { 583 const int kNumberOfDitherRows = 4; 584 const SkImageInfo info = SkImageInfo::MakeN32Premul(kCache32Count, kNumberOfDitherRows); 585 586 SkASSERT(nullptr == cache->fCache32PixelRef); 587 cache->fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, nullptr); 588 cache->fCache32 = (SkPMColor*)cache->fCache32PixelRef->getAddr(); 589 if (cache->fShader.fColorCount == 2) { 590 Build32bitCache(cache->fCache32, cache->fShader.fOrigColors[0], 591 cache->fShader.fOrigColors[1], kCache32Count, cache->fCacheAlpha, 592 cache->fShader.fGradFlags, cache->fCacheDither); 593 } else { 594 Rec* rec = cache->fShader.fRecs; 595 int prevIndex = 0; 596 for (int i = 1; i < cache->fShader.fColorCount; i++) { 597 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift; 598 SkASSERT(nextIndex < kCache32Count); 599 600 if (nextIndex > prevIndex) 601 Build32bitCache(cache->fCache32 + prevIndex, cache->fShader.fOrigColors[i-1], 602 cache->fShader.fOrigColors[i], nextIndex - prevIndex + 1, 603 cache->fCacheAlpha, cache->fShader.fGradFlags, cache->fCacheDither); 604 prevIndex = nextIndex; 605 } 606 } 607 } 608 609 void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap) const { 610 const bool interpInPremul = SkToBool(fGradFlags & 611 SkGradientShader::kInterpolateColorsInPremul_Flag); 612 bitmap->lockPixels(); 613 SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels()); 614 uint32_t* pixelsS32 = reinterpret_cast<uint32_t*>(bitmap->getPixels()); 615 616 typedef std::function<void(const Sk4f&, int)> pixelWriteFn_t; 617 618 pixelWriteFn_t writeF16Pixel = [&](const Sk4f& x, int index) { 619 Sk4h c = SkFloatToHalf_finite_ftz(x); 620 pixelsF16[4*index+0] = c[0]; 621 pixelsF16[4*index+1] = c[1]; 622 pixelsF16[4*index+2] = c[2]; 623 pixelsF16[4*index+3] = c[3]; 624 }; 625 pixelWriteFn_t writeS32Pixel = [&](const Sk4f& c, int index) { 626 pixelsS32[index] = Sk4f_toS32(c); 627 }; 628 629 pixelWriteFn_t writeSizedPixel = 630 (kRGBA_F16_SkColorType == bitmap->colorType()) ? writeF16Pixel : writeS32Pixel; 631 pixelWriteFn_t writeUnpremulPixel = [&](const Sk4f& c, int index) { 632 writeSizedPixel(c * Sk4f(c[3], c[3], c[3], 1.0f), index); 633 }; 634 635 pixelWriteFn_t writePixel = interpInPremul ? writeSizedPixel : writeUnpremulPixel; 636 637 int prevIndex = 0; 638 for (int i = 1; i < fColorCount; i++) { 639 int nextIndex = (fColorCount == 2) ? (kCache32Count - 1) 640 : SkFixedToFFFF(fRecs[i].fPos) >> kCache32Shift; 641 SkASSERT(nextIndex < kCache32Count); 642 643 if (nextIndex > prevIndex) { 644 Sk4f c0 = Sk4f::Load(fOrigColors4f[i - 1].vec()); 645 Sk4f c1 = Sk4f::Load(fOrigColors4f[i].vec()); 646 if (interpInPremul) { 647 c0 = c0 * Sk4f(c0[3], c0[3], c0[3], 1.0f); 648 c1 = c1 * Sk4f(c1[3], c1[3], c1[3], 1.0f); 649 } 650 651 Sk4f step = Sk4f(1.0f / static_cast<float>(nextIndex - prevIndex)); 652 Sk4f delta = (c1 - c0) * step; 653 654 for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) { 655 writePixel(c0, curIndex); 656 c0 += delta; 657 } 658 } 659 prevIndex = nextIndex; 660 } 661 SkASSERT(prevIndex == kCache32Count - 1); 662 bitmap->unlockPixels(); 663 } 664 665 /* 666 * The gradient holds a cache for the most recent value of alpha. Successive 667 * callers with the same alpha value will share the same cache. 668 */ 669 sk_sp<SkGradientShaderBase::GradientShaderCache> SkGradientShaderBase::refCache(U8CPU alpha, 670 bool dither) const { 671 SkAutoMutexAcquire ama(fCacheMutex); 672 if (!fCache || fCache->getAlpha() != alpha || fCache->getDither() != dither) { 673 fCache.reset(new GradientShaderCache(alpha, dither, *this)); 674 } 675 // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. 676 // Otherwise, the pointer may have been overwritten on a different thread before the object's 677 // ref count was incremented. 678 return fCache; 679 } 680 681 SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex); 682 /* 683 * Because our caller might rebuild the same (logically the same) gradient 684 * over and over, we'd like to return exactly the same "bitmap" if possible, 685 * allowing the client to utilize a cache of our bitmap (e.g. with a GPU). 686 * To do that, we maintain a private cache of built-bitmaps, based on our 687 * colors and positions. Note: we don't try to flatten the fMapper, so if one 688 * is present, we skip the cache for now. 689 */ 690 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, 691 GradientBitmapType bitmapType) const { 692 // our caller assumes no external alpha, so we ensure that our cache is built with 0xFF 693 sk_sp<GradientShaderCache> cache(this->refCache(0xFF, true)); 694 695 // build our key: [numColors + colors[] + {positions[]} + flags + colorType ] 696 int count = 1 + fColorCount + 1 + 1; 697 if (fColorCount > 2) { 698 count += fColorCount - 1; // fRecs[].fPos 699 } 700 701 SkAutoSTMalloc<16, int32_t> storage(count); 702 int32_t* buffer = storage.get(); 703 704 *buffer++ = fColorCount; 705 memcpy(buffer, fOrigColors, fColorCount * sizeof(SkColor)); 706 buffer += fColorCount; 707 if (fColorCount > 2) { 708 for (int i = 1; i < fColorCount; i++) { 709 *buffer++ = fRecs[i].fPos; 710 } 711 } 712 *buffer++ = fGradFlags; 713 *buffer++ = static_cast<int32_t>(bitmapType); 714 SkASSERT(buffer - storage.get() == count); 715 716 /////////////////////////////////// 717 718 static SkGradientBitmapCache* gCache; 719 // each cache cost 1K or 2K of RAM, since each bitmap will be 1x256 at either 32bpp or 64bpp 720 static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32; 721 SkAutoMutexAcquire ama(gGradientCacheMutex); 722 723 if (nullptr == gCache) { 724 gCache = new SkGradientBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS); 725 } 726 size_t size = count * sizeof(int32_t); 727 728 if (!gCache->find(storage.get(), size, bitmap)) { 729 if (GradientBitmapType::kLegacy == bitmapType) { 730 // force our cache32pixelref to be built 731 (void)cache->getCache32(); 732 bitmap->setInfo(SkImageInfo::MakeN32Premul(kCache32Count, 1)); 733 bitmap->setPixelRef(sk_ref_sp(cache->getCache32PixelRef()), 0, 0); 734 } else { 735 // For these cases we use the bitmap cache, but not the GradientShaderCache. So just 736 // allocate and populate the bitmap's data directly. 737 738 SkImageInfo info; 739 switch (bitmapType) { 740 case GradientBitmapType::kSRGB: 741 info = SkImageInfo::Make(kCache32Count, 1, kRGBA_8888_SkColorType, 742 kPremul_SkAlphaType, 743 SkColorSpace::MakeSRGB()); 744 break; 745 case GradientBitmapType::kHalfFloat: 746 info = SkImageInfo::Make( 747 kCache32Count, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType, 748 SkColorSpace::MakeSRGBLinear()); 749 break; 750 default: 751 SkFAIL("Unexpected bitmap type"); 752 return; 753 } 754 bitmap->allocPixels(info); 755 this->initLinearBitmap(bitmap); 756 } 757 gCache->add(storage.get(), size, *bitmap); 758 } 759 } 760 761 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info, bool flipGrad) const { 762 if (info) { 763 if (info->fColorCount >= fColorCount) { 764 SkColor* colorLoc; 765 Rec* recLoc; 766 SkAutoSTArray<8, SkColor> colorStorage; 767 SkAutoSTArray<8, Rec> recStorage; 768 if (flipGrad && (info->fColors || info->fColorOffsets)) { 769 colorStorage.reset(fColorCount); 770 recStorage.reset(fColorCount); 771 colorLoc = colorStorage.get(); 772 recLoc = recStorage.get(); 773 FlipGradientColors(colorLoc, recLoc, fOrigColors, fRecs, fColorCount); 774 } else { 775 colorLoc = fOrigColors; 776 recLoc = fRecs; 777 } 778 if (info->fColors) { 779 memcpy(info->fColors, colorLoc, fColorCount * sizeof(SkColor)); 780 } 781 if (info->fColorOffsets) { 782 if (fColorCount == 2) { 783 info->fColorOffsets[0] = 0; 784 info->fColorOffsets[1] = SK_Scalar1; 785 } else if (fColorCount > 2) { 786 for (int i = 0; i < fColorCount; ++i) { 787 info->fColorOffsets[i] = SkFixedToScalar(recLoc[i].fPos); 788 } 789 } 790 } 791 } 792 info->fColorCount = fColorCount; 793 info->fTileMode = fTileMode; 794 info->fGradientFlags = fGradFlags; 795 } 796 } 797 798 #ifndef SK_IGNORE_TO_STRING 799 void SkGradientShaderBase::toString(SkString* str) const { 800 801 str->appendf("%d colors: ", fColorCount); 802 803 for (int i = 0; i < fColorCount; ++i) { 804 str->appendHex(fOrigColors[i], 8); 805 if (i < fColorCount-1) { 806 str->append(", "); 807 } 808 } 809 810 if (fColorCount > 2) { 811 str->append(" points: ("); 812 for (int i = 0; i < fColorCount; ++i) { 813 str->appendScalar(SkFixedToScalar(fRecs[i].fPos)); 814 if (i < fColorCount-1) { 815 str->append(", "); 816 } 817 } 818 str->append(")"); 819 } 820 821 static const char* gTileModeName[SkShader::kTileModeCount] = { 822 "clamp", "repeat", "mirror" 823 }; 824 825 str->append(" "); 826 str->append(gTileModeName[fTileMode]); 827 828 this->INHERITED::toString(str); 829 } 830 #endif 831 832 /////////////////////////////////////////////////////////////////////////////// 833 /////////////////////////////////////////////////////////////////////////////// 834 835 // Return true if these parameters are valid/legal/safe to construct a gradient 836 // 837 static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count, 838 unsigned tileMode) { 839 return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount; 840 } 841 842 static void desc_init(SkGradientShaderBase::Descriptor* desc, 843 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 844 const SkScalar pos[], int colorCount, 845 SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) { 846 SkASSERT(colorCount > 1); 847 848 desc->fColors = colors; 849 desc->fColorSpace = std::move(colorSpace); 850 desc->fPos = pos; 851 desc->fCount = colorCount; 852 desc->fTileMode = mode; 853 desc->fGradFlags = flags; 854 desc->fLocalMatrix = localMatrix; 855 } 856 857 // assumes colors is SkColor4f* and pos is SkScalar* 858 #define EXPAND_1_COLOR(count) \ 859 SkColor4f tmp[2]; \ 860 do { \ 861 if (1 == count) { \ 862 tmp[0] = tmp[1] = colors[0]; \ 863 colors = tmp; \ 864 pos = nullptr; \ 865 count = 2; \ 866 } \ 867 } while (0) 868 869 struct ColorStopOptimizer { 870 ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos, 871 int count, SkShader::TileMode mode) 872 : fColors(colors) 873 , fPos(pos) 874 , fCount(count) { 875 876 if (!pos || count != 3) { 877 return; 878 } 879 880 if (SkScalarNearlyEqual(pos[0], 0.0f) && 881 SkScalarNearlyEqual(pos[1], 0.0f) && 882 SkScalarNearlyEqual(pos[2], 1.0f)) { 883 884 if (SkShader::kRepeat_TileMode == mode || 885 SkShader::kMirror_TileMode == mode || 886 colors[0] == colors[1]) { 887 888 // Ignore the leftmost color/pos. 889 fColors += 1; 890 fPos += 1; 891 fCount = 2; 892 } 893 } else if (SkScalarNearlyEqual(pos[0], 0.0f) && 894 SkScalarNearlyEqual(pos[1], 1.0f) && 895 SkScalarNearlyEqual(pos[2], 1.0f)) { 896 897 if (SkShader::kRepeat_TileMode == mode || 898 SkShader::kMirror_TileMode == mode || 899 colors[1] == colors[2]) { 900 901 // Ignore the rightmost color/pos. 902 fCount = 2; 903 } 904 } 905 } 906 907 const SkColor4f* fColors; 908 const SkScalar* fPos; 909 int fCount; 910 }; 911 912 struct ColorConverter { 913 ColorConverter(const SkColor* colors, int count) { 914 for (int i = 0; i < count; ++i) { 915 fColors4f.push_back(SkColor4f::FromColor(colors[i])); 916 } 917 } 918 919 SkSTArray<2, SkColor4f, true> fColors4f; 920 }; 921 922 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2], 923 const SkColor colors[], 924 const SkScalar pos[], int colorCount, 925 SkShader::TileMode mode, 926 uint32_t flags, 927 const SkMatrix* localMatrix) { 928 ColorConverter converter(colors, colorCount); 929 return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags, 930 localMatrix); 931 } 932 933 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2], 934 const SkColor4f colors[], 935 sk_sp<SkColorSpace> colorSpace, 936 const SkScalar pos[], int colorCount, 937 SkShader::TileMode mode, 938 uint32_t flags, 939 const SkMatrix* localMatrix) { 940 if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) { 941 return nullptr; 942 } 943 if (!valid_grad(colors, pos, colorCount, mode)) { 944 return nullptr; 945 } 946 if (1 == colorCount) { 947 return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); 948 } 949 if (localMatrix && !localMatrix->invert(nullptr)) { 950 return nullptr; 951 } 952 953 ColorStopOptimizer opt(colors, pos, colorCount, mode); 954 955 SkGradientShaderBase::Descriptor desc; 956 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 957 localMatrix); 958 return sk_make_sp<SkLinearGradient>(pts, desc); 959 } 960 961 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius, 962 const SkColor colors[], 963 const SkScalar pos[], int colorCount, 964 SkShader::TileMode mode, 965 uint32_t flags, 966 const SkMatrix* localMatrix) { 967 ColorConverter converter(colors, colorCount); 968 return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, 969 flags, localMatrix); 970 } 971 972 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius, 973 const SkColor4f colors[], 974 sk_sp<SkColorSpace> colorSpace, 975 const SkScalar pos[], int colorCount, 976 SkShader::TileMode mode, 977 uint32_t flags, 978 const SkMatrix* localMatrix) { 979 if (radius <= 0) { 980 return nullptr; 981 } 982 if (!valid_grad(colors, pos, colorCount, mode)) { 983 return nullptr; 984 } 985 if (1 == colorCount) { 986 return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); 987 } 988 if (localMatrix && !localMatrix->invert(nullptr)) { 989 return nullptr; 990 } 991 992 ColorStopOptimizer opt(colors, pos, colorCount, mode); 993 994 SkGradientShaderBase::Descriptor desc; 995 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 996 localMatrix); 997 return sk_make_sp<SkRadialGradient>(center, radius, desc); 998 } 999 1000 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start, 1001 SkScalar startRadius, 1002 const SkPoint& end, 1003 SkScalar endRadius, 1004 const SkColor colors[], 1005 const SkScalar pos[], 1006 int colorCount, 1007 SkShader::TileMode mode, 1008 uint32_t flags, 1009 const SkMatrix* localMatrix) { 1010 ColorConverter converter(colors, colorCount); 1011 return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(), 1012 nullptr, pos, colorCount, mode, flags, localMatrix); 1013 } 1014 1015 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start, 1016 SkScalar startRadius, 1017 const SkPoint& end, 1018 SkScalar endRadius, 1019 const SkColor4f colors[], 1020 sk_sp<SkColorSpace> colorSpace, 1021 const SkScalar pos[], 1022 int colorCount, 1023 SkShader::TileMode mode, 1024 uint32_t flags, 1025 const SkMatrix* localMatrix) { 1026 if (startRadius < 0 || endRadius < 0) { 1027 return nullptr; 1028 } 1029 if (!valid_grad(colors, pos, colorCount, mode)) { 1030 return nullptr; 1031 } 1032 if (startRadius == endRadius) { 1033 if (start == end || startRadius == 0) { 1034 return SkShader::MakeEmptyShader(); 1035 } 1036 } 1037 if (localMatrix && !localMatrix->invert(nullptr)) { 1038 return nullptr; 1039 } 1040 EXPAND_1_COLOR(colorCount); 1041 1042 ColorStopOptimizer opt(colors, pos, colorCount, mode); 1043 1044 bool flipGradient = startRadius > endRadius; 1045 1046 SkGradientShaderBase::Descriptor desc; 1047 1048 if (!flipGradient) { 1049 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 1050 localMatrix); 1051 return sk_make_sp<SkTwoPointConicalGradient>(start, startRadius, end, endRadius, 1052 flipGradient, desc); 1053 } else { 1054 SkAutoSTArray<8, SkColor4f> colorsNew(opt.fCount); 1055 SkAutoSTArray<8, SkScalar> posNew(opt.fCount); 1056 for (int i = 0; i < opt.fCount; ++i) { 1057 colorsNew[i] = opt.fColors[opt.fCount - i - 1]; 1058 } 1059 1060 if (pos) { 1061 for (int i = 0; i < opt.fCount; ++i) { 1062 posNew[i] = 1 - opt.fPos[opt.fCount - i - 1]; 1063 } 1064 desc_init(&desc, colorsNew.get(), std::move(colorSpace), posNew.get(), opt.fCount, mode, 1065 flags, localMatrix); 1066 } else { 1067 desc_init(&desc, colorsNew.get(), std::move(colorSpace), nullptr, opt.fCount, mode, 1068 flags, localMatrix); 1069 } 1070 1071 return sk_make_sp<SkTwoPointConicalGradient>(end, endRadius, start, startRadius, 1072 flipGradient, desc); 1073 } 1074 } 1075 1076 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy, 1077 const SkColor colors[], 1078 const SkScalar pos[], 1079 int colorCount, 1080 uint32_t flags, 1081 const SkMatrix* localMatrix) { 1082 ColorConverter converter(colors, colorCount); 1083 return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount, flags, 1084 localMatrix); 1085 } 1086 1087 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy, 1088 const SkColor4f colors[], 1089 sk_sp<SkColorSpace> colorSpace, 1090 const SkScalar pos[], 1091 int colorCount, 1092 uint32_t flags, 1093 const SkMatrix* localMatrix) { 1094 if (!valid_grad(colors, pos, colorCount, SkShader::kClamp_TileMode)) { 1095 return nullptr; 1096 } 1097 if (1 == colorCount) { 1098 return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); 1099 } 1100 if (localMatrix && !localMatrix->invert(nullptr)) { 1101 return nullptr; 1102 } 1103 1104 auto mode = SkShader::kClamp_TileMode; 1105 1106 ColorStopOptimizer opt(colors, pos, colorCount, mode); 1107 1108 SkGradientShaderBase::Descriptor desc; 1109 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 1110 localMatrix); 1111 return sk_make_sp<SkSweepGradient>(cx, cy, desc); 1112 } 1113 1114 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader) 1115 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient) 1116 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient) 1117 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient) 1118 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient) 1119 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 1120 1121 /////////////////////////////////////////////////////////////////////////////// 1122 1123 #if SK_SUPPORT_GPU 1124 1125 #include "GrContext.h" 1126 #include "GrShaderCaps.h" 1127 #include "GrTextureStripAtlas.h" 1128 #include "gl/GrGLContext.h" 1129 #include "glsl/GrGLSLColorSpaceXformHelper.h" 1130 #include "glsl/GrGLSLFragmentShaderBuilder.h" 1131 #include "glsl/GrGLSLProgramDataManager.h" 1132 #include "glsl/GrGLSLUniformHandler.h" 1133 #include "SkGr.h" 1134 1135 static inline bool close_to_one_half(const SkFixed& val) { 1136 return SkScalarNearlyEqual(SkFixedToScalar(val), SK_ScalarHalf); 1137 } 1138 1139 static inline int color_type_to_color_count(GrGradientEffect::ColorType colorType) { 1140 switch (colorType) { 1141 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1142 case GrGradientEffect::kSingleHardStop_ColorType: 1143 return 4; 1144 case GrGradientEffect::kHardStopLeftEdged_ColorType: 1145 case GrGradientEffect::kHardStopRightEdged_ColorType: 1146 return 3; 1147 #endif 1148 case GrGradientEffect::kTwo_ColorType: 1149 return 2; 1150 case GrGradientEffect::kThree_ColorType: 1151 return 3; 1152 case GrGradientEffect::kTexture_ColorType: 1153 return 0; 1154 } 1155 1156 SkDEBUGFAIL("Unhandled ColorType in color_type_to_color_count()"); 1157 return -1; 1158 } 1159 1160 GrGradientEffect::ColorType GrGradientEffect::determineColorType( 1161 const SkGradientShaderBase& shader) { 1162 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1163 if (shader.fOrigPos) { 1164 if (4 == shader.fColorCount) { 1165 if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) && 1166 SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2]) && 1167 SkScalarNearlyEqual(shader.fOrigPos[3], 1.0f)) { 1168 1169 return kSingleHardStop_ColorType; 1170 } 1171 } else if (3 == shader.fColorCount) { 1172 if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) && 1173 SkScalarNearlyEqual(shader.fOrigPos[1], 0.0f) && 1174 SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) { 1175 1176 return kHardStopLeftEdged_ColorType; 1177 } else if (SkScalarNearlyEqual(shader.fOrigPos[0], 0.0f) && 1178 SkScalarNearlyEqual(shader.fOrigPos[1], 1.0f) && 1179 SkScalarNearlyEqual(shader.fOrigPos[2], 1.0f)) { 1180 1181 return kHardStopRightEdged_ColorType; 1182 } 1183 } 1184 } 1185 #endif 1186 1187 if (SkShader::kClamp_TileMode == shader.getTileMode()) { 1188 if (2 == shader.fColorCount) { 1189 return kTwo_ColorType; 1190 } else if (3 == shader.fColorCount && 1191 close_to_one_half(shader.getRecs()[1].fPos)) { 1192 return kThree_ColorType; 1193 } 1194 } 1195 1196 return kTexture_ColorType; 1197 } 1198 1199 void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler, 1200 const GrGradientEffect& ge) { 1201 if (int colorCount = color_type_to_color_count(ge.getColorType())) { 1202 fColorsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, 1203 kVec4f_GrSLType, 1204 kDefault_GrSLPrecision, 1205 "Colors", 1206 colorCount); 1207 if (ge.fColorType == kSingleHardStop_ColorType) { 1208 fHardStopT = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, 1209 kDefault_GrSLPrecision, "HardStopT"); 1210 } 1211 } else { 1212 fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 1213 kFloat_GrSLType, kDefault_GrSLPrecision, 1214 "GradientYCoordFS"); 1215 } 1216 } 1217 1218 static inline void set_after_interp_color_uni_array( 1219 const GrGLSLProgramDataManager& pdman, 1220 const GrGLSLProgramDataManager::UniformHandle uni, 1221 const SkTDArray<SkColor4f>& colors, 1222 const GrColorSpaceXform* colorSpaceXform) { 1223 int count = colors.count(); 1224 if (colorSpaceXform) { 1225 constexpr int kSmallCount = 10; 1226 SkAutoSTArray<4 * kSmallCount, float> vals(4 * count); 1227 1228 for (int i = 0; i < count; i++) { 1229 colorSpaceXform->srcToDst().mapScalars(colors[i].vec(), &vals[4 * i]); 1230 } 1231 1232 pdman.set4fv(uni, count, vals.get()); 1233 } else { 1234 pdman.set4fv(uni, count, (float*)&colors[0]); 1235 } 1236 } 1237 1238 static inline void set_before_interp_color_uni_array( 1239 const GrGLSLProgramDataManager& pdman, 1240 const GrGLSLProgramDataManager::UniformHandle uni, 1241 const SkTDArray<SkColor4f>& colors, 1242 const GrColorSpaceXform* colorSpaceXform) { 1243 int count = colors.count(); 1244 constexpr int kSmallCount = 10; 1245 SkAutoSTArray<4 * kSmallCount, float> vals(4 * count); 1246 1247 for (int i = 0; i < count; i++) { 1248 float a = colors[i].fA; 1249 vals[4 * i + 0] = colors[i].fR * a; 1250 vals[4 * i + 1] = colors[i].fG * a; 1251 vals[4 * i + 2] = colors[i].fB * a; 1252 vals[4 * i + 3] = a; 1253 } 1254 1255 if (colorSpaceXform) { 1256 for (int i = 0; i < count; i++) { 1257 colorSpaceXform->srcToDst().mapScalars(&vals[4 * i]); 1258 } 1259 } 1260 1261 pdman.set4fv(uni, count, vals.get()); 1262 } 1263 1264 static inline void set_after_interp_color_uni_array(const GrGLSLProgramDataManager& pdman, 1265 const GrGLSLProgramDataManager::UniformHandle uni, 1266 const SkTDArray<SkColor>& colors) { 1267 int count = colors.count(); 1268 constexpr int kSmallCount = 10; 1269 1270 SkAutoSTArray<4*kSmallCount, float> vals(4*count); 1271 1272 for (int i = 0; i < colors.count(); i++) { 1273 // RGBA 1274 vals[4*i + 0] = SkColorGetR(colors[i]) / 255.f; 1275 vals[4*i + 1] = SkColorGetG(colors[i]) / 255.f; 1276 vals[4*i + 2] = SkColorGetB(colors[i]) / 255.f; 1277 vals[4*i + 3] = SkColorGetA(colors[i]) / 255.f; 1278 } 1279 1280 pdman.set4fv(uni, colors.count(), vals.get()); 1281 } 1282 1283 static inline void set_before_interp_color_uni_array(const GrGLSLProgramDataManager& pdman, 1284 const GrGLSLProgramDataManager::UniformHandle uni, 1285 const SkTDArray<SkColor>& colors) { 1286 int count = colors.count(); 1287 constexpr int kSmallCount = 10; 1288 1289 SkAutoSTArray<4*kSmallCount, float> vals(4*count); 1290 1291 for (int i = 0; i < count; i++) { 1292 float a = SkColorGetA(colors[i]) / 255.f; 1293 float aDiv255 = a / 255.f; 1294 1295 // RGBA 1296 vals[4*i + 0] = SkColorGetR(colors[i]) * aDiv255; 1297 vals[4*i + 1] = SkColorGetG(colors[i]) * aDiv255; 1298 vals[4*i + 2] = SkColorGetB(colors[i]) * aDiv255; 1299 vals[4*i + 3] = a; 1300 } 1301 1302 pdman.set4fv(uni, count, vals.get()); 1303 } 1304 1305 void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman, 1306 const GrProcessor& processor) { 1307 const GrGradientEffect& e = processor.cast<GrGradientEffect>(); 1308 1309 switch (e.getColorType()) { 1310 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1311 case GrGradientEffect::kSingleHardStop_ColorType: 1312 pdman.set1f(fHardStopT, e.fPositions[1]); 1313 // fall through 1314 case GrGradientEffect::kHardStopLeftEdged_ColorType: 1315 case GrGradientEffect::kHardStopRightEdged_ColorType: 1316 #endif 1317 case GrGradientEffect::kTwo_ColorType: 1318 case GrGradientEffect::kThree_ColorType: { 1319 if (e.fColors4f.count() > 0) { 1320 // Gamma-correct / color-space aware 1321 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { 1322 set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors4f, 1323 e.fColorSpaceXform.get()); 1324 } else { 1325 set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors4f, 1326 e.fColorSpaceXform.get()); 1327 } 1328 } else { 1329 // Legacy mode. Would be nice if we had converted the 8-bit colors to float earlier 1330 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { 1331 set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors); 1332 } else { 1333 set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors); 1334 } 1335 } 1336 1337 break; 1338 } 1339 1340 case GrGradientEffect::kTexture_ColorType: { 1341 SkScalar yCoord = e.getYCoord(); 1342 if (yCoord != fCachedYCoord) { 1343 pdman.set1f(fFSYUni, yCoord); 1344 fCachedYCoord = yCoord; 1345 } 1346 if (SkToBool(e.fColorSpaceXform)) { 1347 fColorSpaceHelper.setData(pdman, e.fColorSpaceXform.get()); 1348 } 1349 break; 1350 } 1351 } 1352 } 1353 1354 uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) { 1355 const GrGradientEffect& e = processor.cast<GrGradientEffect>(); 1356 1357 uint32_t key = 0; 1358 1359 if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) { 1360 key |= kPremulBeforeInterpKey; 1361 } 1362 1363 if (GrGradientEffect::kTwo_ColorType == e.getColorType()) { 1364 key |= kTwoColorKey; 1365 } else if (GrGradientEffect::kThree_ColorType == e.getColorType()) { 1366 key |= kThreeColorKey; 1367 } 1368 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1369 else if (GrGradientEffect::kSingleHardStop_ColorType == e.getColorType()) { 1370 key |= kHardStopCenteredKey; 1371 } else if (GrGradientEffect::kHardStopLeftEdged_ColorType == e.getColorType()) { 1372 key |= kHardStopZeroZeroOneKey; 1373 } else if (GrGradientEffect::kHardStopRightEdged_ColorType == e.getColorType()) { 1374 key |= kHardStopZeroOneOneKey; 1375 } 1376 1377 if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) { 1378 key |= kClampTileMode; 1379 } else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) { 1380 key |= kRepeatTileMode; 1381 } else { 1382 key |= kMirrorTileMode; 1383 } 1384 #endif 1385 1386 key |= GrColorSpaceXform::XformKey(e.fColorSpaceXform.get()) << kReservedBits; 1387 1388 return key; 1389 } 1390 1391 void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBuilder, 1392 GrGLSLUniformHandler* uniformHandler, 1393 const GrShaderCaps* shaderCaps, 1394 const GrGradientEffect& ge, 1395 const char* gradientTValue, 1396 const char* outputColor, 1397 const char* inputColor, 1398 const TextureSamplers& texSamplers) { 1399 switch (ge.getColorType()) { 1400 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1401 case kSingleHardStop_ColorType: { 1402 const char* t = gradientTValue; 1403 const char* colors = uniformHandler->getUniformCStr(fColorsUni); 1404 const char* stopT = uniformHandler->getUniformCStr(fHardStopT); 1405 1406 fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t); 1407 1408 // Account for tile mode 1409 if (SkShader::kRepeat_TileMode == ge.fTileMode) { 1410 fragBuilder->codeAppendf("clamp_t = fract(%s);", t); 1411 } else if (SkShader::kMirror_TileMode == ge.fTileMode) { 1412 fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t); 1413 fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t); 1414 fragBuilder->codeAppendf(" clamp_t = fract(%s);", t); 1415 fragBuilder->codeAppendf(" } else {"); 1416 fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t); 1417 fragBuilder->codeAppendf(" }"); 1418 fragBuilder->codeAppendf("}"); 1419 } 1420 1421 // Calculate color 1422 fragBuilder->codeAppend ("vec4 start, end;"); 1423 fragBuilder->codeAppend ("float relative_t;"); 1424 fragBuilder->codeAppendf("if (clamp_t < %s) {", stopT); 1425 fragBuilder->codeAppendf(" start = %s[0];", colors); 1426 fragBuilder->codeAppendf(" end = %s[1];", colors); 1427 fragBuilder->codeAppendf(" relative_t = clamp_t / %s;", stopT); 1428 fragBuilder->codeAppend ("} else {"); 1429 fragBuilder->codeAppendf(" start = %s[2];", colors); 1430 fragBuilder->codeAppendf(" end = %s[3];", colors); 1431 fragBuilder->codeAppendf(" relative_t = (clamp_t - %s) / (1 - %s);", stopT, stopT); 1432 fragBuilder->codeAppend ("}"); 1433 fragBuilder->codeAppend ("vec4 colorTemp = mix(start, end, relative_t);"); 1434 1435 if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { 1436 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); 1437 } 1438 if (ge.fColorSpaceXform) { 1439 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); 1440 } 1441 fragBuilder->codeAppendf("%s = %s;", outputColor, 1442 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); 1443 1444 break; 1445 } 1446 1447 case kHardStopLeftEdged_ColorType: { 1448 const char* t = gradientTValue; 1449 const char* colors = uniformHandler->getUniformCStr(fColorsUni); 1450 1451 fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t); 1452 1453 // Account for tile mode 1454 if (SkShader::kRepeat_TileMode == ge.fTileMode) { 1455 fragBuilder->codeAppendf("clamp_t = fract(%s);", t); 1456 } else if (SkShader::kMirror_TileMode == ge.fTileMode) { 1457 fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t); 1458 fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t); 1459 fragBuilder->codeAppendf(" clamp_t = fract(%s);", t); 1460 fragBuilder->codeAppendf(" } else {"); 1461 fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t); 1462 fragBuilder->codeAppendf(" }"); 1463 fragBuilder->codeAppendf("}"); 1464 } 1465 1466 fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[1], %s[2], clamp_t);", colors, 1467 colors); 1468 if (SkShader::kClamp_TileMode == ge.fTileMode) { 1469 fragBuilder->codeAppendf("if (%s < 0.0) {", t); 1470 fragBuilder->codeAppendf(" colorTemp = %s[0];", colors); 1471 fragBuilder->codeAppendf("}"); 1472 } 1473 1474 if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { 1475 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); 1476 } 1477 if (ge.fColorSpaceXform) { 1478 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); 1479 } 1480 fragBuilder->codeAppendf("%s = %s;", outputColor, 1481 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); 1482 1483 break; 1484 } 1485 1486 case kHardStopRightEdged_ColorType: { 1487 const char* t = gradientTValue; 1488 const char* colors = uniformHandler->getUniformCStr(fColorsUni); 1489 1490 fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t); 1491 1492 // Account for tile mode 1493 if (SkShader::kRepeat_TileMode == ge.fTileMode) { 1494 fragBuilder->codeAppendf("clamp_t = fract(%s);", t); 1495 } else if (SkShader::kMirror_TileMode == ge.fTileMode) { 1496 fragBuilder->codeAppendf("if (%s < 0.0 || %s > 1.0) {", t, t); 1497 fragBuilder->codeAppendf(" if (mod(floor(%s), 2.0) == 0.0) {", t); 1498 fragBuilder->codeAppendf(" clamp_t = fract(%s);", t); 1499 fragBuilder->codeAppendf(" } else {"); 1500 fragBuilder->codeAppendf(" clamp_t = 1.0 - fract(%s);", t); 1501 fragBuilder->codeAppendf(" }"); 1502 fragBuilder->codeAppendf("}"); 1503 } 1504 1505 fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp_t);", colors, 1506 colors); 1507 if (SkShader::kClamp_TileMode == ge.fTileMode) { 1508 fragBuilder->codeAppendf("if (%s > 1.0) {", t); 1509 fragBuilder->codeAppendf(" colorTemp = %s[2];", colors); 1510 fragBuilder->codeAppendf("}"); 1511 } 1512 1513 if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { 1514 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); 1515 } 1516 if (ge.fColorSpaceXform) { 1517 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); 1518 } 1519 fragBuilder->codeAppendf("%s = %s;", outputColor, 1520 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); 1521 1522 break; 1523 } 1524 #endif 1525 1526 case kTwo_ColorType: { 1527 const char* t = gradientTValue; 1528 const char* colors = uniformHandler->getUniformCStr(fColorsUni); 1529 1530 fragBuilder->codeAppendf("vec4 colorTemp = mix(%s[0], %s[1], clamp(%s, 0.0, 1.0));", 1531 colors, colors, t); 1532 1533 // We could skip this step if both colors are known to be opaque. Two 1534 // considerations: 1535 // The gradient SkShader reporting opaque is more restrictive than necessary in the two 1536 // pt case. Make sure the key reflects this optimization (and note that it can use the 1537 // same shader as thekBeforeIterp case). This same optimization applies to the 3 color 1538 // case below. 1539 if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { 1540 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); 1541 } 1542 if (ge.fColorSpaceXform) { 1543 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); 1544 } 1545 1546 fragBuilder->codeAppendf("%s = %s;", outputColor, 1547 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); 1548 1549 break; 1550 } 1551 1552 case kThree_ColorType: { 1553 const char* t = gradientTValue; 1554 const char* colors = uniformHandler->getUniformCStr(fColorsUni); 1555 1556 fragBuilder->codeAppendf("float oneMinus2t = 1.0 - (2.0 * %s);", t); 1557 fragBuilder->codeAppendf("vec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s[0];", 1558 colors); 1559 if (!shaderCaps->canUseMinAndAbsTogether()) { 1560 // The Tegra3 compiler will sometimes never return if we have 1561 // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression. 1562 fragBuilder->codeAppendf("float minAbs = abs(oneMinus2t);"); 1563 fragBuilder->codeAppendf("minAbs = minAbs > 1.0 ? 1.0 : minAbs;"); 1564 fragBuilder->codeAppendf("colorTemp += (1.0 - minAbs) * %s[1];", colors); 1565 } else { 1566 fragBuilder->codeAppendf("colorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s[1];", 1567 colors); 1568 } 1569 fragBuilder->codeAppendf("colorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s[2];", colors); 1570 1571 if (GrGradientEffect::kAfterInterp_PremulType == ge.getPremulType()) { 1572 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); 1573 } 1574 if (ge.fColorSpaceXform) { 1575 fragBuilder->codeAppend("colorTemp.rgb = clamp(colorTemp.rgb, 0, colorTemp.a);"); 1576 } 1577 1578 fragBuilder->codeAppendf("%s = %s;", outputColor, 1579 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str()); 1580 1581 break; 1582 } 1583 1584 case kTexture_ColorType: { 1585 fColorSpaceHelper.emitCode(uniformHandler, ge.fColorSpaceXform.get()); 1586 1587 const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni); 1588 1589 fragBuilder->codeAppendf("vec2 coord = vec2(%s, %s);", gradientTValue, fsyuni); 1590 fragBuilder->codeAppendf("%s = ", outputColor); 1591 fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord", 1592 kVec2f_GrSLType, &fColorSpaceHelper); 1593 fragBuilder->codeAppend(";"); 1594 1595 break; 1596 } 1597 } 1598 } 1599 1600 ///////////////////////////////////////////////////////////////////// 1601 1602 inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool isOpaque) { 1603 return isOpaque 1604 ? kPreservesOpaqueInput_OptimizationFlag | 1605 kCompatibleWithCoverageAsAlpha_OptimizationFlag 1606 : kCompatibleWithCoverageAsAlpha_OptimizationFlag; 1607 } 1608 1609 GrGradientEffect::GrGradientEffect(const CreateArgs& args, bool isOpaque) 1610 : INHERITED(OptFlags(isOpaque)) { 1611 const SkGradientShaderBase& shader(*args.fShader); 1612 1613 fIsOpaque = shader.isOpaque(); 1614 1615 fColorType = this->determineColorType(shader); 1616 fColorSpaceXform = std::move(args.fColorSpaceXform); 1617 1618 if (kTexture_ColorType != fColorType) { 1619 SkASSERT(shader.fOrigColors && shader.fOrigColors4f); 1620 if (args.fGammaCorrect) { 1621 fColors4f = SkTDArray<SkColor4f>(shader.fOrigColors4f, shader.fColorCount); 1622 } else { 1623 fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount); 1624 } 1625 1626 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1627 if (shader.fOrigPos) { 1628 fPositions = SkTDArray<SkScalar>(shader.fOrigPos, shader.fColorCount); 1629 } 1630 #endif 1631 } 1632 1633 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1634 fTileMode = args.fTileMode; 1635 #endif 1636 1637 switch (fColorType) { 1638 // The two and three color specializations do not currently support tiling. 1639 case kTwo_ColorType: 1640 case kThree_ColorType: 1641 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1642 case kHardStopLeftEdged_ColorType: 1643 case kHardStopRightEdged_ColorType: 1644 case kSingleHardStop_ColorType: 1645 #endif 1646 fRow = -1; 1647 1648 if (SkGradientShader::kInterpolateColorsInPremul_Flag & shader.getGradFlags()) { 1649 fPremulType = kBeforeInterp_PremulType; 1650 } else { 1651 fPremulType = kAfterInterp_PremulType; 1652 } 1653 1654 fCoordTransform.reset(*args.fMatrix); 1655 1656 break; 1657 case kTexture_ColorType: 1658 // doesn't matter how this is set, just be consistent because it is part of the 1659 // effect key. 1660 fPremulType = kBeforeInterp_PremulType; 1661 1662 SkGradientShaderBase::GradientBitmapType bitmapType = 1663 SkGradientShaderBase::GradientBitmapType::kLegacy; 1664 if (args.fGammaCorrect) { 1665 // Try to use F16 if we can 1666 if (args.fContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) { 1667 bitmapType = SkGradientShaderBase::GradientBitmapType::kHalfFloat; 1668 } else if (args.fContext->caps()->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) { 1669 bitmapType = SkGradientShaderBase::GradientBitmapType::kSRGB; 1670 } else { 1671 // This can happen, but only if someone explicitly creates an unsupported 1672 // (eg sRGB) surface. Just fall back to legacy behavior. 1673 } 1674 } 1675 1676 SkBitmap bitmap; 1677 shader.getGradientTableBitmap(&bitmap, bitmapType); 1678 SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width())); 1679 1680 1681 GrTextureStripAtlas::Desc desc; 1682 desc.fWidth = bitmap.width(); 1683 desc.fHeight = 32; 1684 desc.fRowHeight = bitmap.height(); 1685 desc.fContext = args.fContext; 1686 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *args.fContext->caps()); 1687 fAtlas = GrTextureStripAtlas::GetAtlas(desc); 1688 SkASSERT(fAtlas); 1689 1690 // We always filter the gradient table. Each table is one row of a texture, always 1691 // y-clamp. 1692 GrSamplerParams params; 1693 params.setFilterMode(GrSamplerParams::kBilerp_FilterMode); 1694 params.setTileModeX(args.fTileMode); 1695 1696 fRow = fAtlas->lockRow(bitmap); 1697 if (-1 != fRow) { 1698 fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight(); 1699 // This is 1/2 places where auto-normalization is disabled 1700 fCoordTransform.reset(args.fContext->resourceProvider(), *args.fMatrix, 1701 fAtlas->asTextureProxyRef().get(), 1702 params.filterMode(), false); 1703 fTextureSampler.reset(args.fContext->resourceProvider(), 1704 fAtlas->asTextureProxyRef(), params); 1705 } else { 1706 // In this instance we know the params are: 1707 // clampY, bilerp 1708 // and the proxy is: 1709 // exact fit, power of two in both dimensions 1710 // Only the x-tileMode is unknown. However, given all the other knowns we know 1711 // that GrMakeCachedBitmapProxy is sufficient (i.e., it won't need to be 1712 // extracted to a subset or mipmapped). 1713 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy( 1714 args.fContext->resourceProvider(), 1715 bitmap); 1716 if (!proxy) { 1717 return; 1718 } 1719 // This is 2/2 places where auto-normalization is disabled 1720 fCoordTransform.reset(args.fContext->resourceProvider(), *args.fMatrix, 1721 proxy.get(), params.filterMode(), false); 1722 fTextureSampler.reset(args.fContext->resourceProvider(), 1723 std::move(proxy), params); 1724 fYCoord = SK_ScalarHalf; 1725 } 1726 1727 this->addTextureSampler(&fTextureSampler); 1728 1729 break; 1730 } 1731 1732 this->addCoordTransform(&fCoordTransform); 1733 } 1734 1735 GrGradientEffect::~GrGradientEffect() { 1736 if (this->useAtlas()) { 1737 fAtlas->unlockRow(fRow); 1738 } 1739 } 1740 1741 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const { 1742 const GrGradientEffect& ge = processor.cast<GrGradientEffect>(); 1743 1744 if (this->fColorType != ge.getColorType()) { 1745 return false; 1746 } 1747 SkASSERT(this->useAtlas() == ge.useAtlas()); 1748 if (kTexture_ColorType == fColorType) { 1749 if (fYCoord != ge.getYCoord()) { 1750 return false; 1751 } 1752 } else { 1753 if (kSingleHardStop_ColorType == fColorType) { 1754 if (!SkScalarNearlyEqual(ge.fPositions[1], fPositions[1])) { 1755 return false; 1756 } 1757 } 1758 if (this->getPremulType() != ge.getPremulType() || 1759 this->fColors.count() != ge.fColors.count() || 1760 this->fColors4f.count() != ge.fColors4f.count()) { 1761 return false; 1762 } 1763 1764 for (int i = 0; i < this->fColors.count(); i++) { 1765 if (*this->getColors(i) != *ge.getColors(i)) { 1766 return false; 1767 } 1768 } 1769 for (int i = 0; i < this->fColors4f.count(); i++) { 1770 if (*this->getColors4f(i) != *ge.getColors4f(i)) { 1771 return false; 1772 } 1773 } 1774 } 1775 return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get()); 1776 } 1777 1778 #if GR_TEST_UTILS 1779 GrGradientEffect::RandomGradientParams::RandomGradientParams(SkRandom* random) { 1780 // Set color count to min of 2 so that we don't trigger the const color optimization and make 1781 // a non-gradient processor. 1782 fColorCount = random->nextRangeU(2, kMaxRandomGradientColors); 1783 fUseColors4f = random->nextBool(); 1784 1785 // if one color, omit stops, otherwise randomly decide whether or not to 1786 if (fColorCount == 1 || (fColorCount >= 2 && random->nextBool())) { 1787 fStops = nullptr; 1788 } else { 1789 fStops = fStopStorage; 1790 } 1791 1792 // if using SkColor4f, attach a random (possibly null) color space (with linear gamma) 1793 if (fUseColors4f) { 1794 fColorSpace = GrTest::TestColorSpace(random); 1795 if (fColorSpace) { 1796 SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(fColorSpace)->type()); 1797 fColorSpace = static_cast<SkColorSpace_XYZ*>(fColorSpace.get())->makeLinearGamma(); 1798 } 1799 } 1800 1801 SkScalar stop = 0.f; 1802 for (int i = 0; i < fColorCount; ++i) { 1803 if (fUseColors4f) { 1804 fColors4f[i].fR = random->nextUScalar1(); 1805 fColors4f[i].fG = random->nextUScalar1(); 1806 fColors4f[i].fB = random->nextUScalar1(); 1807 fColors4f[i].fA = random->nextUScalar1(); 1808 } else { 1809 fColors[i] = random->nextU(); 1810 } 1811 if (fStops) { 1812 fStops[i] = stop; 1813 stop = i < fColorCount - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f; 1814 } 1815 } 1816 fTileMode = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount)); 1817 } 1818 #endif 1819 1820 #endif 1821