1 /* 2 * Copyright 2012 Google Inc. 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 #ifndef SkGradientShaderPriv_DEFINED 9 #define SkGradientShaderPriv_DEFINED 10 11 #include "SkGradientBitmapCache.h" 12 #include "SkGradientShader.h" 13 14 #include "SkArenaAlloc.h" 15 #include "SkAutoMalloc.h" 16 #include "SkClampRange.h" 17 #include "SkColorPriv.h" 18 #include "SkColorSpace.h" 19 #include "SkMallocPixelRef.h" 20 #include "SkOnce.h" 21 #include "SkReadBuffer.h" 22 #include "SkShader.h" 23 #include "SkUtils.h" 24 #include "SkWriteBuffer.h" 25 26 #if SK_SUPPORT_GPU 27 #define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1 28 #endif 29 30 static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1, 31 int count) { 32 if (count > 0) { 33 if (v0 == v1) { 34 sk_memset32(dst, v0, count); 35 } else { 36 int pairs = count >> 1; 37 for (int i = 0; i < pairs; i++) { 38 *dst++ = v0; 39 *dst++ = v1; 40 } 41 if (count & 1) { 42 *dst = v0; 43 } 44 } 45 } 46 } 47 48 // Clamp 49 50 static inline SkFixed clamp_tileproc(SkFixed x) { 51 return SkClampMax(x, 0xFFFF); 52 } 53 54 // Repeat 55 56 static inline SkFixed repeat_tileproc(SkFixed x) { 57 return x & 0xFFFF; 58 } 59 60 // Mirror 61 62 static inline SkFixed mirror_tileproc(SkFixed x) { 63 int s = SkLeftShift(x, 15) >> 31; 64 return (x ^ s) & 0xFFFF; 65 } 66 67 /////////////////////////////////////////////////////////////////////////////// 68 69 typedef SkFixed (*TileProc)(SkFixed); 70 71 /////////////////////////////////////////////////////////////////////////////// 72 73 static const TileProc gTileProcs[] = { 74 clamp_tileproc, 75 repeat_tileproc, 76 mirror_tileproc 77 }; 78 79 /////////////////////////////////////////////////////////////////////////////// 80 81 class SkGradientShaderBase : public SkShader { 82 public: 83 struct Descriptor { 84 Descriptor() { 85 sk_bzero(this, sizeof(*this)); 86 fTileMode = SkShader::kClamp_TileMode; 87 } 88 89 const SkMatrix* fLocalMatrix; 90 const SkColor4f* fColors; 91 sk_sp<SkColorSpace> fColorSpace; 92 const SkScalar* fPos; 93 int fCount; 94 SkShader::TileMode fTileMode; 95 uint32_t fGradFlags; 96 97 void flatten(SkWriteBuffer&) const; 98 }; 99 100 class DescriptorScope : public Descriptor { 101 public: 102 DescriptorScope() {} 103 104 bool unflatten(SkReadBuffer&); 105 106 // fColors and fPos always point into local memory, so they can be safely mutated 107 // 108 SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); } 109 SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); } 110 111 private: 112 enum { 113 kStorageCount = 16 114 }; 115 SkColor4f fColorStorage[kStorageCount]; 116 SkScalar fPosStorage[kStorageCount]; 117 SkMatrix fLocalMatrixStorage; 118 SkAutoMalloc fDynamicStorage; 119 }; 120 121 SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit); 122 ~SkGradientShaderBase() override; 123 124 // The cache is initialized on-demand when getCache32 is called. 125 class GradientShaderCache : public SkRefCnt { 126 public: 127 GradientShaderCache(U8CPU alpha, bool dither, const SkGradientShaderBase& shader); 128 ~GradientShaderCache(); 129 130 const SkPMColor* getCache32(); 131 132 SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; } 133 134 unsigned getAlpha() const { return fCacheAlpha; } 135 bool getDither() const { return fCacheDither; } 136 137 private: 138 // Working pointer. If it's nullptr, we need to recompute the cache values. 139 SkPMColor* fCache32; 140 141 SkMallocPixelRef* fCache32PixelRef; 142 const unsigned fCacheAlpha; // The alpha value we used when we computed the cache. 143 // Larger than 8bits so we can store uninitialized 144 // value. 145 const bool fCacheDither; // The dither flag used when we computed the cache. 146 147 const SkGradientShaderBase& fShader; 148 149 // Make sure we only initialize the cache once. 150 SkOnce fCache32InitOnce; 151 152 static void initCache32(GradientShaderCache* cache); 153 154 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count, 155 U8CPU alpha, uint32_t gradFlags, bool dither); 156 }; 157 158 class GradientShaderBaseContext : public SkShader::Context { 159 public: 160 GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&); 161 162 uint32_t getFlags() const override { return fFlags; } 163 164 bool isValid() const; 165 166 protected: 167 SkMatrix fDstToIndex; 168 SkMatrix::MapXYProc fDstToIndexProc; 169 uint8_t fDstToIndexClass; 170 uint8_t fFlags; 171 bool fDither; 172 173 sk_sp<GradientShaderCache> fCache; 174 175 private: 176 typedef SkShader::Context INHERITED; 177 }; 178 179 bool isOpaque() const override; 180 181 enum class GradientBitmapType : uint8_t { 182 kLegacy, 183 kSRGB, 184 kHalfFloat, 185 }; 186 187 void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const; 188 189 enum { 190 /// Seems like enough for visual accuracy. TODO: if pos[] deserves 191 /// it, use a larger cache. 192 kCache32Bits = 8, 193 kCache32Count = (1 << kCache32Bits), 194 kCache32Shift = 16 - kCache32Bits, 195 kSqrt32Shift = 8 - kCache32Bits, 196 197 /// This value is used to *read* the dither cache; it may be 0 198 /// if dithering is disabled. 199 kDitherStride32 = kCache32Count, 200 }; 201 202 uint32_t getGradFlags() const { return fGradFlags; } 203 204 protected: 205 class GradientShaderBase4fContext; 206 207 SkGradientShaderBase(SkReadBuffer& ); 208 void flatten(SkWriteBuffer&) const override; 209 SK_TO_STRING_OVERRIDE() 210 211 const SkMatrix fPtsToUnit; 212 TileMode fTileMode; 213 TileProc fTileProc; 214 uint8_t fGradFlags; 215 216 struct Rec { 217 SkFixed fPos; // 0...1 218 uint32_t fScale; // (1 << 24) / range 219 }; 220 Rec* fRecs; 221 222 void commonAsAGradient(GradientInfo*, bool flipGrad = false) const; 223 224 bool onAsLuminanceColor(SkColor*) const override; 225 226 227 void initLinearBitmap(SkBitmap* bitmap) const; 228 229 /* 230 * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively. 231 * Count is the number of colors in the gradient 232 * It will then flip all the color and rec information and return in their respective Dst 233 * pointers. It is assumed that space has already been allocated for the Dst pointers. 234 * The rec src and dst are only assumed to be valid if count > 2 235 */ 236 static void FlipGradientColors(SkColor* colorDst, Rec* recDst, 237 SkColor* colorSrc, Rec* recSrc, 238 int count); 239 240 template <typename T, typename... Args> 241 static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) { 242 auto* ctx = alloc->make<T>(std::forward<Args>(args)...); 243 if (!ctx->isValid()) { 244 return nullptr; 245 } 246 return ctx; 247 } 248 249 private: 250 enum { 251 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space 252 253 kStorageSize = kColorStorageCount * 254 (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f)) 255 }; 256 SkColor fStorage[(kStorageSize + 3) >> 2]; 257 public: 258 SkColor* fOrigColors; // original colors, before modulation by paint in context. 259 SkColor4f* fOrigColors4f; // original colors, as linear floats 260 SkScalar* fOrigPos; // original positions 261 int fColorCount; 262 sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops 263 264 bool colorsAreOpaque() const { return fColorsAreOpaque; } 265 266 TileMode getTileMode() const { return fTileMode; } 267 Rec* getRecs() const { return fRecs; } 268 269 private: 270 bool fColorsAreOpaque; 271 272 sk_sp<GradientShaderCache> refCache(U8CPU alpha, bool dither) const; 273 mutable SkMutex fCacheMutex; 274 mutable sk_sp<GradientShaderCache> fCache; 275 276 void initCommon(); 277 278 typedef SkShader INHERITED; 279 }; 280 281 static inline int init_dither_toggle(int x, int y) { 282 x &= 1; 283 y = (y & 1) << 1; 284 return (x | y) * SkGradientShaderBase::kDitherStride32; 285 } 286 287 static inline int next_dither_toggle(int toggle) { 288 return toggle ^ SkGradientShaderBase::kDitherStride32; 289 } 290 291 /////////////////////////////////////////////////////////////////////////////// 292 293 #if SK_SUPPORT_GPU 294 295 #include "GrColorSpaceXform.h" 296 #include "GrCoordTransform.h" 297 #include "GrFragmentProcessor.h" 298 #include "glsl/GrGLSLColorSpaceXformHelper.h" 299 #include "glsl/GrGLSLFragmentProcessor.h" 300 #include "glsl/GrGLSLProgramDataManager.h" 301 302 class GrInvariantOutput; 303 304 /* 305 * The interpretation of the texture matrix depends on the sample mode. The 306 * texture matrix is applied both when the texture coordinates are explicit 307 * and when vertex positions are used as texture coordinates. In the latter 308 * case the texture matrix is applied to the pre-view-matrix position 309 * values. 310 * 311 * Normal SampleMode 312 * The post-matrix texture coordinates are in normalize space with (0,0) at 313 * the top-left and (1,1) at the bottom right. 314 * RadialGradient 315 * The matrix specifies the radial gradient parameters. 316 * (0,0) in the post-matrix space is center of the radial gradient. 317 * Radial2Gradient 318 * Matrix transforms to space where first circle is centered at the 319 * origin. The second circle will be centered (x, 0) where x may be 320 * 0 and is provided by setRadial2Params. The post-matrix space is 321 * normalized such that 1 is the second radius - first radius. 322 * SweepGradient 323 * The angle from the origin of texture coordinates in post-matrix space 324 * determines the gradient value. 325 */ 326 327 class GrTextureStripAtlas; 328 329 // Base class for Gr gradient effects 330 class GrGradientEffect : public GrFragmentProcessor { 331 public: 332 struct CreateArgs { 333 CreateArgs(GrContext* context, 334 const SkGradientShaderBase* shader, 335 const SkMatrix* matrix, 336 SkShader::TileMode tileMode, 337 sk_sp<GrColorSpaceXform> colorSpaceXform, 338 bool gammaCorrect) 339 : fContext(context) 340 , fShader(shader) 341 , fMatrix(matrix) 342 , fTileMode(tileMode) 343 , fColorSpaceXform(std::move(colorSpaceXform)) 344 , fGammaCorrect(gammaCorrect) {} 345 346 GrContext* fContext; 347 const SkGradientShaderBase* fShader; 348 const SkMatrix* fMatrix; 349 SkShader::TileMode fTileMode; 350 sk_sp<GrColorSpaceXform> fColorSpaceXform; 351 bool fGammaCorrect; 352 }; 353 354 class GLSLProcessor; 355 356 ~GrGradientEffect() override; 357 358 bool useAtlas() const { return SkToBool(-1 != fRow); } 359 SkScalar getYCoord() const { return fYCoord; } 360 361 enum ColorType { 362 kTwo_ColorType, 363 kThree_ColorType, // Symmetric three color 364 kTexture_ColorType, 365 366 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 367 kSingleHardStop_ColorType, // 0, t, t, 1 368 kHardStopLeftEdged_ColorType, // 0, 0, 1 369 kHardStopRightEdged_ColorType, // 0, 1, 1 370 #endif 371 }; 372 373 ColorType getColorType() const { return fColorType; } 374 375 // Determines the type of gradient, one of: 376 // - Two-color 377 // - Symmetric three-color 378 // - Texture 379 // - Centered hard stop 380 // - Left-edged hard stop 381 // - Right-edged hard stop 382 ColorType determineColorType(const SkGradientShaderBase& shader); 383 384 enum PremulType { 385 kBeforeInterp_PremulType, 386 kAfterInterp_PremulType, 387 }; 388 389 PremulType getPremulType() const { return fPremulType; } 390 391 const SkColor* getColors(int pos) const { 392 SkASSERT(fColorType != kTexture_ColorType); 393 SkASSERT(pos < fColors.count()); 394 return &fColors[pos]; 395 } 396 397 const SkColor4f* getColors4f(int pos) const { 398 SkASSERT(fColorType != kTexture_ColorType); 399 SkASSERT(pos < fColors4f.count()); 400 return &fColors4f[pos]; 401 } 402 403 protected: 404 GrGradientEffect(const CreateArgs&, bool isOpaque); 405 406 #if GR_TEST_UTILS 407 /** Helper struct that stores (and populates) parameters to construct a random gradient. 408 If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and 409 fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount 410 will be the number of color stops in either case, and fColors and fStops can be passed to 411 the gradient factory. (The constructor may decide not to use stops, in which case fStops 412 will be nullptr). */ 413 struct RandomGradientParams { 414 static const int kMaxRandomGradientColors = 5; 415 416 RandomGradientParams(SkRandom* r); 417 418 bool fUseColors4f; 419 SkColor fColors[kMaxRandomGradientColors]; 420 SkColor4f fColors4f[kMaxRandomGradientColors]; 421 sk_sp<SkColorSpace> fColorSpace; 422 SkScalar fStopStorage[kMaxRandomGradientColors]; 423 SkShader::TileMode fTileMode; 424 int fColorCount; 425 SkScalar* fStops; 426 }; 427 #endif 428 429 bool onIsEqual(const GrFragmentProcessor&) const override; 430 431 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; } 432 433 private: 434 static OptimizationFlags OptFlags(bool isOpaque); 435 436 // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then 437 // fColors4f and fColorSpaceXform will be populated. 438 SkTDArray<SkColor> fColors; 439 440 SkTDArray<SkColor4f> fColors4f; 441 sk_sp<GrColorSpaceXform> fColorSpaceXform; 442 443 SkTDArray<SkScalar> fPositions; 444 SkShader::TileMode fTileMode; 445 446 GrCoordTransform fCoordTransform; 447 TextureSampler fTextureSampler; 448 SkScalar fYCoord; 449 GrTextureStripAtlas* fAtlas; 450 int fRow; 451 bool fIsOpaque; 452 ColorType fColorType; 453 PremulType fPremulType; // This is already baked into the table for texture gradients, and 454 // only changes behavior for gradients that don't use a texture. 455 typedef GrFragmentProcessor INHERITED; 456 457 }; 458 459 /////////////////////////////////////////////////////////////////////////////// 460 461 // Base class for GL gradient effects 462 class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor { 463 public: 464 GLSLProcessor() { 465 fCachedYCoord = SK_ScalarMax; 466 } 467 468 protected: 469 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override; 470 471 protected: 472 /** 473 * Subclasses must call this. It will return a key for the part of the shader code controlled 474 * by the base class. The subclasses must stick it in their key and then pass it to the below 475 * emit* functions from their emitCode function. 476 */ 477 static uint32_t GenBaseGradientKey(const GrProcessor&); 478 479 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses 480 // should call this method from their emitCode(). 481 void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&); 482 483 // Emit code that gets a fragment's color from an expression for t; has branches for 484 // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+ 485 // color gradients that use the traditional texture lookup, as well as several varieties 486 // of hard stop gradients 487 void emitColor(GrGLSLFPFragmentBuilder* fragBuilder, 488 GrGLSLUniformHandler* uniformHandler, 489 const GrShaderCaps* shaderCaps, 490 const GrGradientEffect&, 491 const char* gradientTValue, 492 const char* outputColor, 493 const char* inputColor, 494 const TextureSamplers&); 495 496 private: 497 enum { 498 // First bit for premul before/after interp 499 kPremulBeforeInterpKey = 1, 500 501 // Next three bits for 2/3 color type or different special 502 // hard stop cases (neither means using texture atlas) 503 kTwoColorKey = 2, 504 kThreeColorKey = 4, 505 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 506 kHardStopCenteredKey = 6, 507 kHardStopZeroZeroOneKey = 8, 508 kHardStopZeroOneOneKey = 10, 509 510 // Next two bits for tile mode 511 kClampTileMode = 16, 512 kRepeatTileMode = 32, 513 kMirrorTileMode = 48, 514 515 // Lower six bits for premul, 2/3 color type, and tile mode 516 kReservedBits = 6, 517 #endif 518 }; 519 520 SkScalar fCachedYCoord; 521 GrGLSLProgramDataManager::UniformHandle fColorsUni; 522 GrGLSLProgramDataManager::UniformHandle fHardStopT; 523 GrGLSLProgramDataManager::UniformHandle fFSYUni; 524 GrGLSLColorSpaceXformHelper fColorSpaceHelper; 525 526 typedef GrGLSLFragmentProcessor INHERITED; 527 }; 528 529 #endif 530 531 #endif 532