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