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