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 <algorithm> 9 #include "Sk4fLinearGradient.h" 10 #include "SkColorSpace_XYZ.h" 11 #include "SkColorSpaceXformer.h" 12 #include "SkFloatBits.h" 13 #include "SkGradientBitmapCache.h" 14 #include "SkGradientShaderPriv.h" 15 #include "SkHalf.h" 16 #include "SkLinearGradient.h" 17 #include "SkMallocPixelRef.h" 18 #include "SkRadialGradient.h" 19 #include "SkReadBuffer.h" 20 #include "SkSweepGradient.h" 21 #include "SkTwoPointConicalGradient.h" 22 #include "SkWriteBuffer.h" 23 #include "../../jumper/SkJumper.h" 24 25 26 enum GradientSerializationFlags { 27 // Bits 29:31 used for various boolean flags 28 kHasPosition_GSF = 0x80000000, 29 kHasLocalMatrix_GSF = 0x40000000, 30 kHasColorSpace_GSF = 0x20000000, 31 32 // Bits 12:28 unused 33 34 // Bits 8:11 for fTileMode 35 kTileModeShift_GSF = 8, 36 kTileModeMask_GSF = 0xF, 37 38 // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80) 39 kGradFlagsShift_GSF = 0, 40 kGradFlagsMask_GSF = 0xFF, 41 }; 42 43 void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const { 44 uint32_t flags = 0; 45 if (fPos) { 46 flags |= kHasPosition_GSF; 47 } 48 if (fLocalMatrix) { 49 flags |= kHasLocalMatrix_GSF; 50 } 51 sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr; 52 if (colorSpaceData) { 53 flags |= kHasColorSpace_GSF; 54 } 55 SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF); 56 flags |= (fTileMode << kTileModeShift_GSF); 57 SkASSERT(fGradFlags <= kGradFlagsMask_GSF); 58 flags |= (fGradFlags << kGradFlagsShift_GSF); 59 60 buffer.writeUInt(flags); 61 62 buffer.writeColor4fArray(fColors, fCount); 63 if (colorSpaceData) { 64 buffer.writeDataAsByteArray(colorSpaceData.get()); 65 } 66 if (fPos) { 67 buffer.writeScalarArray(fPos, fCount); 68 } 69 if (fLocalMatrix) { 70 buffer.writeMatrix(*fLocalMatrix); 71 } 72 } 73 74 bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) { 75 // New gradient format. Includes floating point color, color space, densely packed flags 76 uint32_t flags = buffer.readUInt(); 77 78 fTileMode = (SkShader::TileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF); 79 fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF; 80 81 fCount = buffer.getArrayCount(); 82 if (fCount > kStorageCount) { 83 size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount; 84 fDynamicStorage.reset(allocSize); 85 fColors = (SkColor4f*)fDynamicStorage.get(); 86 fPos = (SkScalar*)(fColors + fCount); 87 } else { 88 fColors = fColorStorage; 89 fPos = fPosStorage; 90 } 91 if (!buffer.readColor4fArray(mutableColors(), fCount)) { 92 return false; 93 } 94 if (SkToBool(flags & kHasColorSpace_GSF)) { 95 sk_sp<SkData> data = buffer.readByteArrayAsData(); 96 fColorSpace = SkColorSpace::Deserialize(data->data(), data->size()); 97 } else { 98 fColorSpace = nullptr; 99 } 100 if (SkToBool(flags & kHasPosition_GSF)) { 101 if (!buffer.readScalarArray(mutablePos(), fCount)) { 102 return false; 103 } 104 } else { 105 fPos = nullptr; 106 } 107 if (SkToBool(flags & kHasLocalMatrix_GSF)) { 108 fLocalMatrix = &fLocalMatrixStorage; 109 buffer.readMatrix(&fLocalMatrixStorage); 110 } else { 111 fLocalMatrix = nullptr; 112 } 113 return buffer.isValid(); 114 } 115 116 //////////////////////////////////////////////////////////////////////////////////////////// 117 118 SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit) 119 : INHERITED(desc.fLocalMatrix) 120 , fPtsToUnit(ptsToUnit) 121 , fColorsAreOpaque(true) 122 { 123 fPtsToUnit.getType(); // Precache so reads are threadsafe. 124 SkASSERT(desc.fCount > 1); 125 126 fGradFlags = static_cast<uint8_t>(desc.fGradFlags); 127 128 SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount); 129 fTileMode = desc.fTileMode; 130 131 /* Note: we let the caller skip the first and/or last position. 132 i.e. pos[0] = 0.3, pos[1] = 0.7 133 In these cases, we insert dummy entries to ensure that the final data 134 will be bracketed by [0, 1]. 135 i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1 136 137 Thus colorCount (the caller's value, and fColorCount (our value) may 138 differ by up to 2. In the above example: 139 colorCount = 2 140 fColorCount = 4 141 */ 142 fColorCount = desc.fCount; 143 // check if we need to add in dummy start and/or end position/colors 144 bool dummyFirst = false; 145 bool dummyLast = false; 146 if (desc.fPos) { 147 dummyFirst = desc.fPos[0] != 0; 148 dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1; 149 fColorCount += dummyFirst + dummyLast; 150 } 151 152 size_t storageSize = fColorCount * (sizeof(SkColor4f) + (desc.fPos ? sizeof(SkScalar) : 0)); 153 fOrigColors4f = reinterpret_cast<SkColor4f*>(fStorage.reset(storageSize)); 154 fOrigPos = desc.fPos ? reinterpret_cast<SkScalar*>(fOrigColors4f + fColorCount) 155 : nullptr; 156 157 // Now copy over the colors, adding the dummies as needed 158 SkColor4f* origColors = fOrigColors4f; 159 if (dummyFirst) { 160 *origColors++ = desc.fColors[0]; 161 } 162 for (int i = 0; i < desc.fCount; ++i) { 163 origColors[i] = desc.fColors[i]; 164 fColorsAreOpaque = fColorsAreOpaque && (desc.fColors[i].fA == 1); 165 } 166 if (dummyLast) { 167 origColors += desc.fCount; 168 *origColors = desc.fColors[desc.fCount - 1]; 169 } 170 171 if (!desc.fColorSpace) { 172 // This happens if we were constructed from SkColors, so our colors are really sRGB 173 fColorSpace = SkColorSpace::MakeSRGBLinear(); 174 } else { 175 // The color space refers to the float colors, so it must be linear gamma 176 // TODO: GPU code no longer requires this (see GrGradientEffect). Remove this restriction? 177 SkASSERT(desc.fColorSpace->gammaIsLinear()); 178 fColorSpace = desc.fColorSpace; 179 } 180 181 if (desc.fPos) { 182 SkScalar prev = 0; 183 SkScalar* origPosPtr = fOrigPos; 184 *origPosPtr++ = prev; // force the first pos to 0 185 186 int startIndex = dummyFirst ? 0 : 1; 187 int count = desc.fCount + dummyLast; 188 189 bool uniformStops = true; 190 const SkScalar uniformStep = desc.fPos[startIndex] - prev; 191 for (int i = startIndex; i < count; i++) { 192 // Pin the last value to 1.0, and make sure pos is monotonic. 193 auto curr = (i == desc.fCount) ? 1 : SkScalarPin(desc.fPos[i], prev, 1); 194 uniformStops &= SkScalarNearlyEqual(uniformStep, curr - prev); 195 196 *origPosPtr++ = prev = curr; 197 } 198 199 // If the stops are uniform, treat them as implicit. 200 if (uniformStops) { 201 fOrigPos = nullptr; 202 } 203 } 204 } 205 206 SkGradientShaderBase::~SkGradientShaderBase() {} 207 208 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const { 209 Descriptor desc; 210 desc.fColors = fOrigColors4f; 211 desc.fColorSpace = fColorSpace; 212 desc.fPos = fOrigPos; 213 desc.fCount = fColorCount; 214 desc.fTileMode = fTileMode; 215 desc.fGradFlags = fGradFlags; 216 217 const SkMatrix& m = this->getLocalMatrix(); 218 desc.fLocalMatrix = m.isIdentity() ? nullptr : &m; 219 desc.flatten(buffer); 220 } 221 222 static void add_stop_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f Fs, SkPM4f Bs) { 223 (ctx->fs[0])[stop] = Fs.r(); 224 (ctx->fs[1])[stop] = Fs.g(); 225 (ctx->fs[2])[stop] = Fs.b(); 226 (ctx->fs[3])[stop] = Fs.a(); 227 (ctx->bs[0])[stop] = Bs.r(); 228 (ctx->bs[1])[stop] = Bs.g(); 229 (ctx->bs[2])[stop] = Bs.b(); 230 (ctx->bs[3])[stop] = Bs.a(); 231 } 232 233 static void add_const_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f color) { 234 add_stop_color(ctx, stop, SkPM4f::FromPremulRGBA(0,0,0,0), color); 235 } 236 237 // Calculate a factor F and a bias B so that color = F*t + B when t is in range of 238 // the stop. Assume that the distance between stops is 1/gapCount. 239 static void init_stop_evenly( 240 SkJumper_GradientCtx* ctx, float gapCount, size_t stop, SkPM4f c_l, SkPM4f c_r) { 241 // Clankium's GCC 4.9 targeting ARMv7 is barfing when we use Sk4f math here, so go scalar... 242 SkPM4f Fs = {{ 243 (c_r.r() - c_l.r()) * gapCount, 244 (c_r.g() - c_l.g()) * gapCount, 245 (c_r.b() - c_l.b()) * gapCount, 246 (c_r.a() - c_l.a()) * gapCount, 247 }}; 248 SkPM4f Bs = {{ 249 c_l.r() - Fs.r()*(stop/gapCount), 250 c_l.g() - Fs.g()*(stop/gapCount), 251 c_l.b() - Fs.b()*(stop/gapCount), 252 c_l.a() - Fs.a()*(stop/gapCount), 253 }}; 254 add_stop_color(ctx, stop, Fs, Bs); 255 } 256 257 // For each stop we calculate a bias B and a scale factor F, such that 258 // for any t between stops n and n+1, the color we want is B[n] + F[n]*t. 259 static void init_stop_pos( 260 SkJumper_GradientCtx* ctx, size_t stop, float t_l, float t_r, SkPM4f c_l, SkPM4f c_r) { 261 // See note about Clankium's old compiler in init_stop_evenly(). 262 SkPM4f Fs = {{ 263 (c_r.r() - c_l.r()) / (t_r - t_l), 264 (c_r.g() - c_l.g()) / (t_r - t_l), 265 (c_r.b() - c_l.b()) / (t_r - t_l), 266 (c_r.a() - c_l.a()) / (t_r - t_l), 267 }}; 268 SkPM4f Bs = {{ 269 c_l.r() - Fs.r()*t_l, 270 c_l.g() - Fs.g()*t_l, 271 c_l.b() - Fs.b()*t_l, 272 c_l.a() - Fs.a()*t_l, 273 }}; 274 ctx->ts[stop] = t_l; 275 add_stop_color(ctx, stop, Fs, Bs); 276 } 277 278 bool SkGradientShaderBase::onAppendStages(const StageRec& rec) const { 279 SkRasterPipeline* p = rec.fPipeline; 280 SkArenaAlloc* alloc = rec.fAlloc; 281 SkColorSpace* dstCS = rec.fDstCS; 282 283 SkMatrix matrix; 284 if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &matrix)) { 285 return false; 286 } 287 matrix.postConcat(fPtsToUnit); 288 289 SkRasterPipeline_<256> postPipeline; 290 291 p->append_seed_shader(); 292 p->append_matrix(alloc, matrix); 293 this->appendGradientStages(alloc, p, &postPipeline); 294 295 switch(fTileMode) { 296 case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x_1); break; 297 case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x_1); break; 298 case kClamp_TileMode: 299 if (!fOrigPos) { 300 // We clamp only when the stops are evenly spaced. 301 // If not, there may be hard stops, and clamping ruins hard stops at 0 and/or 1. 302 // In that case, we must make sure we're using the general "gradient" stage, 303 // which is the only stage that will correctly handle unclamped t. 304 p->append(SkRasterPipeline::clamp_x_1); 305 } 306 } 307 308 const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag; 309 auto prepareColor = [premulGrad, dstCS, this](int i) { 310 SkColor4f c = this->getXformedColor(i, dstCS); 311 return premulGrad ? c.premul() 312 : SkPM4f::From4f(Sk4f::Load(&c)); 313 }; 314 315 // The two-stop case with stops at 0 and 1. 316 if (fColorCount == 2 && fOrigPos == nullptr) { 317 const SkPM4f c_l = prepareColor(0), 318 c_r = prepareColor(1); 319 320 // See F and B below. 321 auto* f_and_b = alloc->makeArrayDefault<SkPM4f>(2); 322 f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f()); 323 f_and_b[1] = c_l; 324 325 p->append(SkRasterPipeline::evenly_spaced_2_stop_gradient, f_and_b); 326 } else { 327 auto* ctx = alloc->make<SkJumper_GradientCtx>(); 328 329 // Note: In order to handle clamps in search, the search assumes a stop conceptully placed 330 // at -inf. Therefore, the max number of stops is fColorCount+1. 331 for (int i = 0; i < 4; i++) { 332 // Allocate at least at for the AVX2 gather from a YMM register. 333 ctx->fs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8)); 334 ctx->bs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8)); 335 } 336 337 if (fOrigPos == nullptr) { 338 // Handle evenly distributed stops. 339 340 size_t stopCount = fColorCount; 341 float gapCount = stopCount - 1; 342 343 SkPM4f c_l = prepareColor(0); 344 for (size_t i = 0; i < stopCount - 1; i++) { 345 SkPM4f c_r = prepareColor(i + 1); 346 init_stop_evenly(ctx, gapCount, i, c_l, c_r); 347 c_l = c_r; 348 } 349 add_const_color(ctx, stopCount - 1, c_l); 350 351 ctx->stopCount = stopCount; 352 p->append(SkRasterPipeline::evenly_spaced_gradient, ctx); 353 } else { 354 // Handle arbitrary stops. 355 356 ctx->ts = alloc->makeArray<float>(fColorCount+1); 357 358 // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase 359 // because they are naturally handled by the search method. 360 int firstStop; 361 int lastStop; 362 if (fColorCount > 2) { 363 firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1; 364 lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1] 365 ? fColorCount - 1 : fColorCount - 2; 366 } else { 367 firstStop = 0; 368 lastStop = 1; 369 } 370 371 size_t stopCount = 0; 372 float t_l = fOrigPos[firstStop]; 373 SkPM4f c_l = prepareColor(firstStop); 374 add_const_color(ctx, stopCount++, c_l); 375 // N.B. lastStop is the index of the last stop, not one after. 376 for (int i = firstStop; i < lastStop; i++) { 377 float t_r = fOrigPos[i + 1]; 378 SkPM4f c_r = prepareColor(i + 1); 379 SkASSERT(t_l <= t_r); 380 if (t_l < t_r) { 381 init_stop_pos(ctx, stopCount, t_l, t_r, c_l, c_r); 382 stopCount += 1; 383 } 384 t_l = t_r; 385 c_l = c_r; 386 } 387 388 ctx->ts[stopCount] = t_l; 389 add_const_color(ctx, stopCount++, c_l); 390 391 ctx->stopCount = stopCount; 392 p->append(SkRasterPipeline::gradient, ctx); 393 } 394 } 395 396 if (!premulGrad && !this->colorsAreOpaque()) { 397 p->append(SkRasterPipeline::premul); 398 } 399 400 p->extend(postPipeline); 401 402 return true; 403 } 404 405 406 bool SkGradientShaderBase::isOpaque() const { 407 return fColorsAreOpaque; 408 } 409 410 static unsigned rounded_divide(unsigned numer, unsigned denom) { 411 return (numer + (denom >> 1)) / denom; 412 } 413 414 bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const { 415 // we just compute an average color. 416 // possibly we could weight this based on the proportional width for each color 417 // assuming they are not evenly distributed in the fPos array. 418 int r = 0; 419 int g = 0; 420 int b = 0; 421 const int n = fColorCount; 422 // TODO: use linear colors? 423 for (int i = 0; i < n; ++i) { 424 SkColor c = this->getLegacyColor(i); 425 r += SkColorGetR(c); 426 g += SkColorGetG(c); 427 b += SkColorGetB(c); 428 } 429 *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n)); 430 return true; 431 } 432 433 SkGradientShaderBase::AutoXformColors::AutoXformColors(const SkGradientShaderBase& grad, 434 SkColorSpaceXformer* xformer) 435 : fColors(grad.fColorCount) { 436 // TODO: stay in 4f to preserve precision? 437 438 SkAutoSTMalloc<8, SkColor> origColors(grad.fColorCount); 439 for (int i = 0; i < grad.fColorCount; ++i) { 440 origColors[i] = grad.getLegacyColor(i); 441 } 442 443 xformer->apply(fColors.get(), origColors.get(), grad.fColorCount); 444 } 445 446 static constexpr int kGradientTextureSize = 256; 447 448 void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap, GradientBitmapType bitmapType) const { 449 const bool interpInPremul = SkToBool(fGradFlags & 450 SkGradientShader::kInterpolateColorsInPremul_Flag); 451 SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels()); 452 uint32_t* pixels32 = reinterpret_cast<uint32_t*>(bitmap->getPixels()); 453 454 typedef std::function<void(const Sk4f&, int)> pixelWriteFn_t; 455 456 pixelWriteFn_t writeF16Pixel = [&](const Sk4f& x, int index) { 457 Sk4h c = SkFloatToHalf_finite_ftz(x); 458 pixelsF16[4*index+0] = c[0]; 459 pixelsF16[4*index+1] = c[1]; 460 pixelsF16[4*index+2] = c[2]; 461 pixelsF16[4*index+3] = c[3]; 462 }; 463 pixelWriteFn_t writeS32Pixel = [&](const Sk4f& c, int index) { 464 pixels32[index] = Sk4f_toS32(c); 465 }; 466 pixelWriteFn_t writeL32Pixel = [&](const Sk4f& c, int index) { 467 pixels32[index] = Sk4f_toL32(c); 468 }; 469 470 pixelWriteFn_t writeSizedPixel = 471 (bitmapType == GradientBitmapType::kHalfFloat) ? writeF16Pixel : 472 (bitmapType == GradientBitmapType::kSRGB ) ? writeS32Pixel : writeL32Pixel; 473 pixelWriteFn_t writeUnpremulPixel = [&](const Sk4f& c, int index) { 474 writeSizedPixel(c * Sk4f(c[3], c[3], c[3], 1.0f), index); 475 }; 476 477 pixelWriteFn_t writePixel = interpInPremul ? writeSizedPixel : writeUnpremulPixel; 478 479 // When not in legacy mode, we just want the original 4f colors - so we pass in 480 // our own CS for identity/no transform. 481 auto* cs = bitmapType != GradientBitmapType::kLegacy ? fColorSpace.get() : nullptr; 482 483 int prevIndex = 0; 484 for (int i = 1; i < fColorCount; i++) { 485 // Historically, stops have been mapped to [0, 256], with 256 then nudged to the 486 // next smaller value, then truncate for the texture index. This seems to produce 487 // the best results for some common distributions, so we preserve the behavior. 488 int nextIndex = SkTMin(this->getPos(i) * kGradientTextureSize, 489 SkIntToScalar(kGradientTextureSize - 1)); 490 491 if (nextIndex > prevIndex) { 492 SkColor4f color0 = this->getXformedColor(i - 1, cs), 493 color1 = this->getXformedColor(i , cs); 494 Sk4f c0 = Sk4f::Load(color0.vec()), 495 c1 = Sk4f::Load(color1.vec()); 496 497 if (interpInPremul) { 498 c0 = c0 * Sk4f(c0[3], c0[3], c0[3], 1.0f); 499 c1 = c1 * Sk4f(c1[3], c1[3], c1[3], 1.0f); 500 } 501 502 Sk4f step = Sk4f(1.0f / static_cast<float>(nextIndex - prevIndex)); 503 Sk4f delta = (c1 - c0) * step; 504 505 for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) { 506 writePixel(c0, curIndex); 507 c0 += delta; 508 } 509 } 510 prevIndex = nextIndex; 511 } 512 SkASSERT(prevIndex == kGradientTextureSize - 1); 513 } 514 515 SkColor4f SkGradientShaderBase::getXformedColor(size_t i, SkColorSpace* dstCS) const { 516 if (dstCS) { 517 return to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS); 518 } 519 520 // Legacy/srgb color. 521 // We quantize upfront to ensure stable SkColor round-trips. 522 auto rgb255 = sk_linear_to_srgb(Sk4f::Load(fOrigColors4f[i].vec())); 523 auto rgb = SkNx_cast<float>(rgb255) * (1/255.0f); 524 return { rgb[0], rgb[1], rgb[2], fOrigColors4f[i].fA }; 525 } 526 527 SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex); 528 /* 529 * Because our caller might rebuild the same (logically the same) gradient 530 * over and over, we'd like to return exactly the same "bitmap" if possible, 531 * allowing the client to utilize a cache of our bitmap (e.g. with a GPU). 532 * To do that, we maintain a private cache of built-bitmaps, based on our 533 * colors and positions. 534 */ 535 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, 536 GradientBitmapType bitmapType) const { 537 // build our key: [numColors + colors[] + {positions[]} + flags + colorType ] 538 static_assert(sizeof(SkColor4f) % sizeof(int32_t) == 0, ""); 539 const int colorsAsIntCount = fColorCount * sizeof(SkColor4f) / sizeof(int32_t); 540 int count = 1 + colorsAsIntCount + 1 + 1; 541 if (fColorCount > 2) { 542 count += fColorCount - 1; 543 } 544 545 SkAutoSTMalloc<64, int32_t> storage(count); 546 int32_t* buffer = storage.get(); 547 548 *buffer++ = fColorCount; 549 memcpy(buffer, fOrigColors4f, fColorCount * sizeof(SkColor4f)); 550 buffer += colorsAsIntCount; 551 if (fColorCount > 2) { 552 for (int i = 1; i < fColorCount; i++) { 553 *buffer++ = SkFloat2Bits(this->getPos(i)); 554 } 555 } 556 *buffer++ = fGradFlags; 557 *buffer++ = static_cast<int32_t>(bitmapType); 558 SkASSERT(buffer - storage.get() == count); 559 560 /////////////////////////////////// 561 562 static SkGradientBitmapCache* gCache; 563 // each cache cost 1K or 2K of RAM, since each bitmap will be 1x256 at either 32bpp or 64bpp 564 static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32; 565 SkAutoMutexAcquire ama(gGradientCacheMutex); 566 567 if (nullptr == gCache) { 568 gCache = new SkGradientBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS); 569 } 570 size_t size = count * sizeof(int32_t); 571 572 if (!gCache->find(storage.get(), size, bitmap)) { 573 // For these cases we use the bitmap cache, but not the GradientShaderCache. So just 574 // allocate and populate the bitmap's data directly. 575 576 SkImageInfo info; 577 switch (bitmapType) { 578 case GradientBitmapType::kLegacy: 579 info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_8888_SkColorType, 580 kPremul_SkAlphaType); 581 break; 582 case GradientBitmapType::kSRGB: 583 info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_8888_SkColorType, 584 kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); 585 break; 586 case GradientBitmapType::kHalfFloat: 587 info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_F16_SkColorType, 588 kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear()); 589 break; 590 } 591 592 bitmap->allocPixels(info); 593 this->initLinearBitmap(bitmap, bitmapType); 594 gCache->add(storage.get(), size, *bitmap); 595 } 596 } 597 598 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const { 599 if (info) { 600 if (info->fColorCount >= fColorCount) { 601 if (info->fColors) { 602 for (int i = 0; i < fColorCount; ++i) { 603 info->fColors[i] = this->getLegacyColor(i); 604 } 605 } 606 if (info->fColorOffsets) { 607 for (int i = 0; i < fColorCount; ++i) { 608 info->fColorOffsets[i] = this->getPos(i); 609 } 610 } 611 } 612 info->fColorCount = fColorCount; 613 info->fTileMode = fTileMode; 614 info->fGradientFlags = fGradFlags; 615 } 616 } 617 618 #ifndef SK_IGNORE_TO_STRING 619 void SkGradientShaderBase::toString(SkString* str) const { 620 621 str->appendf("%d colors: ", fColorCount); 622 623 for (int i = 0; i < fColorCount; ++i) { 624 str->appendHex(this->getLegacyColor(i), 8); 625 if (i < fColorCount-1) { 626 str->append(", "); 627 } 628 } 629 630 if (fColorCount > 2) { 631 str->append(" points: ("); 632 for (int i = 0; i < fColorCount; ++i) { 633 str->appendScalar(this->getPos(i)); 634 if (i < fColorCount-1) { 635 str->append(", "); 636 } 637 } 638 str->append(")"); 639 } 640 641 static const char* gTileModeName[SkShader::kTileModeCount] = { 642 "clamp", "repeat", "mirror" 643 }; 644 645 str->append(" "); 646 str->append(gTileModeName[fTileMode]); 647 648 this->INHERITED::toString(str); 649 } 650 #endif 651 652 /////////////////////////////////////////////////////////////////////////////// 653 /////////////////////////////////////////////////////////////////////////////// 654 655 // Return true if these parameters are valid/legal/safe to construct a gradient 656 // 657 static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count, 658 unsigned tileMode) { 659 return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount; 660 } 661 662 static void desc_init(SkGradientShaderBase::Descriptor* desc, 663 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 664 const SkScalar pos[], int colorCount, 665 SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) { 666 SkASSERT(colorCount > 1); 667 668 desc->fColors = colors; 669 desc->fColorSpace = std::move(colorSpace); 670 desc->fPos = pos; 671 desc->fCount = colorCount; 672 desc->fTileMode = mode; 673 desc->fGradFlags = flags; 674 desc->fLocalMatrix = localMatrix; 675 } 676 677 // assumes colors is SkColor4f* and pos is SkScalar* 678 #define EXPAND_1_COLOR(count) \ 679 SkColor4f tmp[2]; \ 680 do { \ 681 if (1 == count) { \ 682 tmp[0] = tmp[1] = colors[0]; \ 683 colors = tmp; \ 684 pos = nullptr; \ 685 count = 2; \ 686 } \ 687 } while (0) 688 689 struct ColorStopOptimizer { 690 ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos, 691 int count, SkShader::TileMode mode) 692 : fColors(colors) 693 , fPos(pos) 694 , fCount(count) { 695 696 if (!pos || count != 3) { 697 return; 698 } 699 700 if (SkScalarNearlyEqual(pos[0], 0.0f) && 701 SkScalarNearlyEqual(pos[1], 0.0f) && 702 SkScalarNearlyEqual(pos[2], 1.0f)) { 703 704 if (SkShader::kRepeat_TileMode == mode || 705 SkShader::kMirror_TileMode == mode || 706 colors[0] == colors[1]) { 707 708 // Ignore the leftmost color/pos. 709 fColors += 1; 710 fPos += 1; 711 fCount = 2; 712 } 713 } else if (SkScalarNearlyEqual(pos[0], 0.0f) && 714 SkScalarNearlyEqual(pos[1], 1.0f) && 715 SkScalarNearlyEqual(pos[2], 1.0f)) { 716 717 if (SkShader::kRepeat_TileMode == mode || 718 SkShader::kMirror_TileMode == mode || 719 colors[1] == colors[2]) { 720 721 // Ignore the rightmost color/pos. 722 fCount = 2; 723 } 724 } 725 } 726 727 const SkColor4f* fColors; 728 const SkScalar* fPos; 729 int fCount; 730 }; 731 732 struct ColorConverter { 733 ColorConverter(const SkColor* colors, int count) { 734 for (int i = 0; i < count; ++i) { 735 fColors4f.push_back(SkColor4f::FromColor(colors[i])); 736 } 737 } 738 739 SkSTArray<2, SkColor4f, true> fColors4f; 740 }; 741 742 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2], 743 const SkColor colors[], 744 const SkScalar pos[], int colorCount, 745 SkShader::TileMode mode, 746 uint32_t flags, 747 const SkMatrix* localMatrix) { 748 ColorConverter converter(colors, colorCount); 749 return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags, 750 localMatrix); 751 } 752 753 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2], 754 const SkColor4f colors[], 755 sk_sp<SkColorSpace> colorSpace, 756 const SkScalar pos[], int colorCount, 757 SkShader::TileMode mode, 758 uint32_t flags, 759 const SkMatrix* localMatrix) { 760 if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) { 761 return nullptr; 762 } 763 if (!valid_grad(colors, pos, colorCount, mode)) { 764 return nullptr; 765 } 766 if (1 == colorCount) { 767 return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); 768 } 769 if (localMatrix && !localMatrix->invert(nullptr)) { 770 return nullptr; 771 } 772 773 ColorStopOptimizer opt(colors, pos, colorCount, mode); 774 775 SkGradientShaderBase::Descriptor desc; 776 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 777 localMatrix); 778 return sk_make_sp<SkLinearGradient>(pts, desc); 779 } 780 781 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius, 782 const SkColor colors[], 783 const SkScalar pos[], int colorCount, 784 SkShader::TileMode mode, 785 uint32_t flags, 786 const SkMatrix* localMatrix) { 787 ColorConverter converter(colors, colorCount); 788 return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, 789 flags, localMatrix); 790 } 791 792 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius, 793 const SkColor4f colors[], 794 sk_sp<SkColorSpace> colorSpace, 795 const SkScalar pos[], int colorCount, 796 SkShader::TileMode mode, 797 uint32_t flags, 798 const SkMatrix* localMatrix) { 799 if (radius <= 0) { 800 return nullptr; 801 } 802 if (!valid_grad(colors, pos, colorCount, mode)) { 803 return nullptr; 804 } 805 if (1 == colorCount) { 806 return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); 807 } 808 if (localMatrix && !localMatrix->invert(nullptr)) { 809 return nullptr; 810 } 811 812 ColorStopOptimizer opt(colors, pos, colorCount, mode); 813 814 SkGradientShaderBase::Descriptor desc; 815 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 816 localMatrix); 817 return sk_make_sp<SkRadialGradient>(center, radius, desc); 818 } 819 820 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start, 821 SkScalar startRadius, 822 const SkPoint& end, 823 SkScalar endRadius, 824 const SkColor colors[], 825 const SkScalar pos[], 826 int colorCount, 827 SkShader::TileMode mode, 828 uint32_t flags, 829 const SkMatrix* localMatrix) { 830 ColorConverter converter(colors, colorCount); 831 return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(), 832 nullptr, pos, colorCount, mode, flags, localMatrix); 833 } 834 835 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start, 836 SkScalar startRadius, 837 const SkPoint& end, 838 SkScalar endRadius, 839 const SkColor4f colors[], 840 sk_sp<SkColorSpace> colorSpace, 841 const SkScalar pos[], 842 int colorCount, 843 SkShader::TileMode mode, 844 uint32_t flags, 845 const SkMatrix* localMatrix) { 846 if (startRadius < 0 || endRadius < 0) { 847 return nullptr; 848 } 849 if (SkScalarNearlyZero((start - end).length()) && SkScalarNearlyZero(startRadius)) { 850 // We can treat this gradient as radial, which is faster. 851 return MakeRadial(start, endRadius, colors, std::move(colorSpace), pos, colorCount, 852 mode, flags, localMatrix); 853 } 854 if (!valid_grad(colors, pos, colorCount, mode)) { 855 return nullptr; 856 } 857 if (startRadius == endRadius) { 858 if (start == end || startRadius == 0) { 859 return SkShader::MakeEmptyShader(); 860 } 861 } 862 if (localMatrix && !localMatrix->invert(nullptr)) { 863 return nullptr; 864 } 865 EXPAND_1_COLOR(colorCount); 866 867 ColorStopOptimizer opt(colors, pos, colorCount, mode); 868 869 SkGradientShaderBase::Descriptor desc; 870 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 871 localMatrix); 872 return SkTwoPointConicalGradient::Create(start, startRadius, end, endRadius, desc); 873 } 874 875 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy, 876 const SkColor colors[], 877 const SkScalar pos[], 878 int colorCount, 879 SkShader::TileMode mode, 880 SkScalar startAngle, 881 SkScalar endAngle, 882 uint32_t flags, 883 const SkMatrix* localMatrix) { 884 ColorConverter converter(colors, colorCount); 885 return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount, 886 mode, startAngle, endAngle, flags, localMatrix); 887 } 888 889 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy, 890 const SkColor4f colors[], 891 sk_sp<SkColorSpace> colorSpace, 892 const SkScalar pos[], 893 int colorCount, 894 SkShader::TileMode mode, 895 SkScalar startAngle, 896 SkScalar endAngle, 897 uint32_t flags, 898 const SkMatrix* localMatrix) { 899 if (!valid_grad(colors, pos, colorCount, mode)) { 900 return nullptr; 901 } 902 if (1 == colorCount) { 903 return SkShader::MakeColorShader(colors[0], std::move(colorSpace)); 904 } 905 if (startAngle >= endAngle) { 906 return nullptr; 907 } 908 if (localMatrix && !localMatrix->invert(nullptr)) { 909 return nullptr; 910 } 911 912 if (startAngle <= 0 && endAngle >= 360) { 913 // If the t-range includes [0,1], then we can always use clamping (presumably faster). 914 mode = SkShader::kClamp_TileMode; 915 } 916 917 ColorStopOptimizer opt(colors, pos, colorCount, mode); 918 919 SkGradientShaderBase::Descriptor desc; 920 desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags, 921 localMatrix); 922 923 const SkScalar t0 = startAngle / 360, 924 t1 = endAngle / 360; 925 926 return sk_make_sp<SkSweepGradient>(SkPoint::Make(cx, cy), t0, t1, desc); 927 } 928 929 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader) 930 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient) 931 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient) 932 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient) 933 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient) 934 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 935 936 /////////////////////////////////////////////////////////////////////////////// 937 938 #if SK_SUPPORT_GPU 939 940 #include "GrColorSpaceXform.h" 941 #include "GrContext.h" 942 #include "GrContextPriv.h" 943 #include "GrShaderCaps.h" 944 #include "GrTextureStripAtlas.h" 945 #include "gl/GrGLContext.h" 946 #include "glsl/GrGLSLFragmentShaderBuilder.h" 947 #include "glsl/GrGLSLProgramDataManager.h" 948 #include "glsl/GrGLSLUniformHandler.h" 949 #include "SkGr.h" 950 951 void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler, 952 const GrGradientEffect& ge) { 953 switch (ge.fStrategy) { 954 case GrGradientEffect::InterpolationStrategy::kThreshold: 955 case GrGradientEffect::InterpolationStrategy::kThresholdClamp0: 956 case GrGradientEffect::InterpolationStrategy::kThresholdClamp1: 957 fThresholdUni = uniformHandler->addUniform(kFragment_GrShaderFlag, 958 kFloat_GrSLType, 959 kHigh_GrSLPrecision, 960 "Threshold"); 961 // fall through 962 case GrGradientEffect::InterpolationStrategy::kSingle: 963 fIntervalsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag, 964 kHalf4_GrSLType, 965 "Intervals", 966 ge.fIntervals.count()); 967 break; 968 case GrGradientEffect::InterpolationStrategy::kTexture: 969 fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, 970 "GradientYCoordFS"); 971 break; 972 } 973 } 974 975 void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman, 976 const GrFragmentProcessor& processor) { 977 const GrGradientEffect& e = processor.cast<GrGradientEffect>(); 978 979 switch (e.fStrategy) { 980 case GrGradientEffect::InterpolationStrategy::kThreshold: 981 case GrGradientEffect::InterpolationStrategy::kThresholdClamp0: 982 case GrGradientEffect::InterpolationStrategy::kThresholdClamp1: 983 pdman.set1f(fThresholdUni, e.fThreshold); 984 // fall through 985 case GrGradientEffect::InterpolationStrategy::kSingle: 986 pdman.set4fv(fIntervalsUni, e.fIntervals.count(), 987 reinterpret_cast<const float*>(e.fIntervals.begin())); 988 break; 989 case GrGradientEffect::InterpolationStrategy::kTexture: 990 if (e.fYCoord != fCachedYCoord) { 991 pdman.set1f(fFSYUni, e.fYCoord); 992 fCachedYCoord = e.fYCoord; 993 } 994 break; 995 } 996 } 997 998 void GrGradientEffect::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { 999 b->add32(GLSLProcessor::GenBaseGradientKey(*this)); 1000 } 1001 1002 uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) { 1003 const GrGradientEffect& e = processor.cast<GrGradientEffect>(); 1004 1005 // Build a key using the following bit allocation: 1006 static constexpr uint32_t kStrategyBits = 3; 1007 static constexpr uint32_t kPremulBits = 1; 1008 SkDEBUGCODE(static constexpr uint32_t kWrapModeBits = 2;) 1009 1010 uint32_t key = static_cast<uint32_t>(e.fStrategy); 1011 SkASSERT(key < (1 << kStrategyBits)); 1012 1013 // This is already baked into the table for texture gradients, 1014 // and only changes behavior for analytical gradients. 1015 if (e.fStrategy != InterpolationStrategy::kTexture && 1016 e.fPremulType == GrGradientEffect::kBeforeInterp_PremulType) { 1017 key |= 1 << kStrategyBits; 1018 SkASSERT(key < (1 << (kStrategyBits + kPremulBits))); 1019 } 1020 1021 key |= static_cast<uint32_t>(e.fWrapMode) << (kStrategyBits + kPremulBits); 1022 SkASSERT(key < (1 << (kStrategyBits + kPremulBits + kWrapModeBits))); 1023 1024 return key; 1025 } 1026 1027 void GrGradientEffect::GLSLProcessor::emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder, 1028 GrGLSLUniformHandler* uniformHandler, 1029 const GrShaderCaps* shaderCaps, 1030 const GrGradientEffect& ge, 1031 const char* t, 1032 const char* outputColor, 1033 const char* inputColor) { 1034 // First, apply tiling rules. 1035 switch (ge.fWrapMode) { 1036 case GrSamplerState::WrapMode::kClamp: 1037 switch (ge.fStrategy) { 1038 case GrGradientEffect::InterpolationStrategy::kThresholdClamp0: 1039 // allow t > 1, in order to hit the clamp interval (1, inf) 1040 fragBuilder->codeAppendf("half tiled_t = max(%s, 0.0);", t); 1041 break; 1042 case GrGradientEffect::InterpolationStrategy::kThresholdClamp1: 1043 // allow t < 0, in order to hit the clamp interval (-inf, 0) 1044 fragBuilder->codeAppendf("half tiled_t = min(%s, 1.0);", t); 1045 break; 1046 default: 1047 // regular [0, 1] clamping 1048 fragBuilder->codeAppendf("half tiled_t = clamp(%s, 0.0, 1.0);", t); 1049 } 1050 break; 1051 case GrSamplerState::WrapMode::kRepeat: 1052 fragBuilder->codeAppendf("half tiled_t = fract(%s);", t); 1053 break; 1054 case GrSamplerState::WrapMode::kMirrorRepeat: 1055 fragBuilder->codeAppendf("half t_1 = %s - 1.0;", t); 1056 fragBuilder->codeAppendf("half tiled_t = t_1 - 2.0 * floor(t_1 * 0.5) - 1.0;"); 1057 if (shaderCaps->mustDoOpBetweenFloorAndAbs()) { 1058 // At this point the expected value of tiled_t should between -1 and 1, so this 1059 // clamp has no effect other than to break up the floor and abs calls and make sure 1060 // the compiler doesn't merge them back together. 1061 fragBuilder->codeAppendf("tiled_t = clamp(tiled_t, -1.0, 1.0);"); 1062 } 1063 fragBuilder->codeAppendf("tiled_t = abs(tiled_t);"); 1064 break; 1065 } 1066 1067 // Calculate the color. 1068 const char* intervals = uniformHandler->getUniformCStr(fIntervalsUni); 1069 1070 switch (ge.fStrategy) { 1071 case GrGradientEffect::InterpolationStrategy::kSingle: 1072 SkASSERT(ge.fIntervals.count() == 2); 1073 fragBuilder->codeAppendf( 1074 "half4 color_scale = %s[0]," 1075 " color_bias = %s[1];" 1076 , intervals, intervals 1077 ); 1078 break; 1079 case GrGradientEffect::InterpolationStrategy::kThreshold: 1080 case GrGradientEffect::InterpolationStrategy::kThresholdClamp0: 1081 case GrGradientEffect::InterpolationStrategy::kThresholdClamp1: 1082 { 1083 SkASSERT(ge.fIntervals.count() == 4); 1084 const char* threshold = uniformHandler->getUniformCStr(fThresholdUni); 1085 fragBuilder->codeAppendf( 1086 "half4 color_scale, color_bias;" 1087 "if (tiled_t < %s) {" 1088 " color_scale = %s[0];" 1089 " color_bias = %s[1];" 1090 "} else {" 1091 " color_scale = %s[2];" 1092 " color_bias = %s[3];" 1093 "}" 1094 , threshold, intervals, intervals, intervals, intervals 1095 ); 1096 } break; 1097 default: 1098 SkASSERT(false); 1099 break; 1100 } 1101 1102 fragBuilder->codeAppend("half4 colorTemp = tiled_t * color_scale + color_bias;"); 1103 1104 // We could skip this step if all colors are known to be opaque. Two considerations: 1105 // The gradient SkShader reporting opaque is more restrictive than necessary in the two 1106 // pt case. Make sure the key reflects this optimization (and note that it can use the 1107 // same shader as the kBeforeInterp case). 1108 if (ge.fPremulType == GrGradientEffect::kAfterInterp_PremulType) { 1109 fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;"); 1110 } 1111 1112 // If the input colors were floats, or there was a color space xform, we may end up out of 1113 // range. The simplest solution is to always clamp our (premul) value here. We only need to 1114 // clamp RGB, but that causes hangs on the Tegra3 Nexus7. Clamping RGBA avoids the problem. 1115 fragBuilder->codeAppend("colorTemp = clamp(colorTemp, 0, colorTemp.a);"); 1116 1117 fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor); 1118 } 1119 1120 void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBuilder, 1121 GrGLSLUniformHandler* uniformHandler, 1122 const GrShaderCaps* shaderCaps, 1123 const GrGradientEffect& ge, 1124 const char* gradientTValue, 1125 const char* outputColor, 1126 const char* inputColor, 1127 const TextureSamplers& texSamplers) { 1128 if (ge.fStrategy != InterpolationStrategy::kTexture) { 1129 this->emitAnalyticalColor(fragBuilder, uniformHandler, shaderCaps, ge, gradientTValue, 1130 outputColor, inputColor); 1131 return; 1132 } 1133 1134 const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni); 1135 1136 fragBuilder->codeAppendf("half2 coord = half2(%s, %s);", gradientTValue, fsyuni); 1137 fragBuilder->codeAppendf("%s = ", outputColor); 1138 fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord", 1139 kFloat2_GrSLType); 1140 fragBuilder->codeAppend(";"); 1141 } 1142 1143 ///////////////////////////////////////////////////////////////////// 1144 1145 inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool isOpaque) { 1146 return isOpaque 1147 ? kPreservesOpaqueInput_OptimizationFlag | 1148 kCompatibleWithCoverageAsAlpha_OptimizationFlag 1149 : kCompatibleWithCoverageAsAlpha_OptimizationFlag; 1150 } 1151 1152 void GrGradientEffect::addInterval(const SkGradientShaderBase& shader, size_t idx0, size_t idx1, 1153 SkColorSpace* dstCS) { 1154 SkASSERT(idx0 <= idx1); 1155 const auto c4f0 = shader.getXformedColor(idx0, dstCS), 1156 c4f1 = shader.getXformedColor(idx1, dstCS); 1157 const auto c0 = (fPremulType == kBeforeInterp_PremulType) 1158 ? c4f0.premul().to4f() : Sk4f::Load(c4f0.vec()), 1159 c1 = (fPremulType == kBeforeInterp_PremulType) 1160 ? c4f1.premul().to4f() : Sk4f::Load(c4f1.vec()); 1161 const auto t0 = shader.getPos(idx0), 1162 t1 = shader.getPos(idx1), 1163 dt = t1 - t0; 1164 SkASSERT(dt >= 0); 1165 // dt can be 0 for clamp intervals => in this case we want a scale == 0 1166 const auto scale = SkScalarNearlyZero(dt) ? 0 : (c1 - c0) / dt, 1167 bias = c0 - t0 * scale; 1168 1169 // Intervals are stored as (scale, bias) tuples. 1170 SkASSERT(!(fIntervals.count() & 1)); 1171 fIntervals.emplace_back(scale[0], scale[1], scale[2], scale[3]); 1172 fIntervals.emplace_back( bias[0], bias[1], bias[2], bias[3]); 1173 } 1174 1175 GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool isOpaque) 1176 : INHERITED(classID, OptFlags(isOpaque)) 1177 , fWrapMode(args.fWrapMode) 1178 , fRow(-1) 1179 , fIsOpaque(args.fShader->isOpaque()) 1180 , fStrategy(InterpolationStrategy::kTexture) 1181 , fThreshold(0) { 1182 1183 const SkGradientShaderBase& shader(*args.fShader); 1184 1185 fPremulType = (args.fShader->getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag) 1186 ? kBeforeInterp_PremulType : kAfterInterp_PremulType; 1187 1188 // First, determine the interpolation strategy and params. 1189 switch (shader.fColorCount) { 1190 case 2: 1191 SkASSERT(!shader.fOrigPos); 1192 fStrategy = InterpolationStrategy::kSingle; 1193 this->addInterval(shader, 0, 1, args.fDstColorSpace); 1194 break; 1195 case 3: 1196 fThreshold = shader.getPos(1); 1197 1198 if (shader.fOrigPos) { 1199 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[0], 0)); 1200 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[2], 1)); 1201 if (SkScalarNearlyEqual(shader.fOrigPos[1], 0)) { 1202 // hard stop on the left edge. 1203 if (fWrapMode == GrSamplerState::WrapMode::kClamp) { 1204 fStrategy = InterpolationStrategy::kThresholdClamp1; 1205 // Clamp interval (scale == 0, bias == colors[0]). 1206 this->addInterval(shader, 0, 0, args.fDstColorSpace); 1207 } else { 1208 // We can ignore the hard stop when not clamping. 1209 fStrategy = InterpolationStrategy::kSingle; 1210 } 1211 this->addInterval(shader, 1, 2, args.fDstColorSpace); 1212 break; 1213 } 1214 1215 if (SkScalarNearlyEqual(shader.fOrigPos[1], 1)) { 1216 // hard stop on the right edge. 1217 this->addInterval(shader, 0, 1, args.fDstColorSpace); 1218 if (fWrapMode == GrSamplerState::WrapMode::kClamp) { 1219 fStrategy = InterpolationStrategy::kThresholdClamp0; 1220 // Clamp interval (scale == 0, bias == colors[2]). 1221 this->addInterval(shader, 2, 2, args.fDstColorSpace); 1222 } else { 1223 // We can ignore the hard stop when not clamping. 1224 fStrategy = InterpolationStrategy::kSingle; 1225 } 1226 break; 1227 } 1228 } 1229 1230 // Two arbitrary interpolation intervals. 1231 fStrategy = InterpolationStrategy::kThreshold; 1232 this->addInterval(shader, 0, 1, args.fDstColorSpace); 1233 this->addInterval(shader, 1, 2, args.fDstColorSpace); 1234 break; 1235 case 4: 1236 if (shader.fOrigPos && SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2])) { 1237 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[0], 0)); 1238 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[3], 1)); 1239 1240 // Single hard stop => two arbitrary interpolation intervals. 1241 fStrategy = InterpolationStrategy::kThreshold; 1242 fThreshold = shader.getPos(1); 1243 this->addInterval(shader, 0, 1, args.fDstColorSpace); 1244 this->addInterval(shader, 2, 3, args.fDstColorSpace); 1245 } 1246 break; 1247 default: 1248 break; 1249 } 1250 1251 // Now that we've locked down a strategy, adjust any dependent params. 1252 if (fStrategy != InterpolationStrategy::kTexture) { 1253 // Analytical cases. 1254 fCoordTransform.reset(*args.fMatrix); 1255 } else { 1256 SkGradientShaderBase::GradientBitmapType bitmapType = 1257 SkGradientShaderBase::GradientBitmapType::kLegacy; 1258 if (args.fDstColorSpace) { 1259 // Try to use F16 if we can 1260 if (args.fContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) { 1261 bitmapType = SkGradientShaderBase::GradientBitmapType::kHalfFloat; 1262 } else if (args.fContext->caps()->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) { 1263 bitmapType = SkGradientShaderBase::GradientBitmapType::kSRGB; 1264 } else { 1265 // This can happen, but only if someone explicitly creates an unsupported 1266 // (eg sRGB) surface. Just fall back to legacy behavior. 1267 } 1268 } 1269 1270 SkBitmap bitmap; 1271 shader.getGradientTableBitmap(&bitmap, bitmapType); 1272 SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width())); 1273 1274 1275 GrTextureStripAtlas::Desc desc; 1276 desc.fWidth = bitmap.width(); 1277 desc.fHeight = 32; 1278 desc.fRowHeight = bitmap.height(); 1279 desc.fContext = args.fContext; 1280 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *args.fContext->caps()); 1281 fAtlas = GrTextureStripAtlas::GetAtlas(desc); 1282 SkASSERT(fAtlas); 1283 1284 // We always filter the gradient table. Each table is one row of a texture, always 1285 // y-clamp. 1286 GrSamplerState samplerState(args.fWrapMode, GrSamplerState::Filter::kBilerp); 1287 1288 fRow = fAtlas->lockRow(bitmap); 1289 if (-1 != fRow) { 1290 fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight(); 1291 // This is 1/2 places where auto-normalization is disabled 1292 fCoordTransform.reset(*args.fMatrix, fAtlas->asTextureProxyRef().get(), false); 1293 fTextureSampler.reset(fAtlas->asTextureProxyRef(), samplerState); 1294 } else { 1295 // In this instance we know the samplerState state is: 1296 // clampY, bilerp 1297 // and the proxy is: 1298 // exact fit, power of two in both dimensions 1299 // Only the x-tileMode is unknown. However, given all the other knowns we know 1300 // that GrMakeCachedBitmapProxy is sufficient (i.e., it won't need to be 1301 // extracted to a subset or mipmapped). 1302 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy( 1303 args.fContext->contextPriv().proxyProvider(), 1304 bitmap); 1305 if (!proxy) { 1306 SkDebugf("Gradient won't draw. Could not create texture."); 1307 return; 1308 } 1309 // This is 2/2 places where auto-normalization is disabled 1310 fCoordTransform.reset(*args.fMatrix, proxy.get(), false); 1311 fTextureSampler.reset(std::move(proxy), samplerState); 1312 fYCoord = SK_ScalarHalf; 1313 } 1314 1315 this->addTextureSampler(&fTextureSampler); 1316 } 1317 1318 this->addCoordTransform(&fCoordTransform); 1319 } 1320 1321 GrGradientEffect::GrGradientEffect(const GrGradientEffect& that) 1322 : INHERITED(that.classID(), OptFlags(that.fIsOpaque)) 1323 , fIntervals(that.fIntervals) 1324 , fWrapMode(that.fWrapMode) 1325 , fCoordTransform(that.fCoordTransform) 1326 , fTextureSampler(that.fTextureSampler) 1327 , fYCoord(that.fYCoord) 1328 , fAtlas(that.fAtlas) 1329 , fRow(that.fRow) 1330 , fIsOpaque(that.fIsOpaque) 1331 , fStrategy(that.fStrategy) 1332 , fThreshold(that.fThreshold) 1333 , fPremulType(that.fPremulType) { 1334 this->addCoordTransform(&fCoordTransform); 1335 if (fStrategy == InterpolationStrategy::kTexture) { 1336 this->addTextureSampler(&fTextureSampler); 1337 } 1338 if (this->useAtlas()) { 1339 fAtlas->lockRow(fRow); 1340 } 1341 } 1342 1343 GrGradientEffect::~GrGradientEffect() { 1344 if (this->useAtlas()) { 1345 fAtlas->unlockRow(fRow); 1346 } 1347 } 1348 1349 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const { 1350 const GrGradientEffect& ge = processor.cast<GrGradientEffect>(); 1351 1352 if (fWrapMode != ge.fWrapMode || fStrategy != ge.fStrategy) { 1353 return false; 1354 } 1355 1356 SkASSERT(this->useAtlas() == ge.useAtlas()); 1357 if (fStrategy == InterpolationStrategy::kTexture) { 1358 if (fYCoord != ge.fYCoord) { 1359 return false; 1360 } 1361 } else { 1362 if (fThreshold != ge.fThreshold || 1363 fIntervals != ge.fIntervals || 1364 fPremulType != ge.fPremulType) { 1365 return false; 1366 } 1367 } 1368 return true; 1369 } 1370 1371 #if GR_TEST_UTILS 1372 GrGradientEffect::RandomGradientParams::RandomGradientParams(SkRandom* random) { 1373 // Set color count to min of 2 so that we don't trigger the const color optimization and make 1374 // a non-gradient processor. 1375 fColorCount = random->nextRangeU(2, kMaxRandomGradientColors); 1376 fUseColors4f = random->nextBool(); 1377 1378 // if one color, omit stops, otherwise randomly decide whether or not to 1379 if (fColorCount == 1 || (fColorCount >= 2 && random->nextBool())) { 1380 fStops = nullptr; 1381 } else { 1382 fStops = fStopStorage; 1383 } 1384 1385 // if using SkColor4f, attach a random (possibly null) color space (with linear gamma) 1386 if (fUseColors4f) { 1387 fColorSpace = GrTest::TestColorSpace(random); 1388 if (fColorSpace) { 1389 fColorSpace = fColorSpace->makeLinearGamma(); 1390 } 1391 } 1392 1393 SkScalar stop = 0.f; 1394 for (int i = 0; i < fColorCount; ++i) { 1395 if (fUseColors4f) { 1396 fColors4f[i].fR = random->nextUScalar1(); 1397 fColors4f[i].fG = random->nextUScalar1(); 1398 fColors4f[i].fB = random->nextUScalar1(); 1399 fColors4f[i].fA = random->nextUScalar1(); 1400 } else { 1401 fColors[i] = random->nextU(); 1402 } 1403 if (fStops) { 1404 fStops[i] = stop; 1405 stop = i < fColorCount - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f; 1406 } 1407 } 1408 fTileMode = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount)); 1409 } 1410 #endif 1411 1412 #endif 1413