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 "SkGradientShader.h" 12 #include "SkClampRange.h" 13 #include "SkColorPriv.h" 14 #include "SkReadBuffer.h" 15 #include "SkWriteBuffer.h" 16 #include "SkMallocPixelRef.h" 17 #include "SkUtils.h" 18 #include "SkTemplates.h" 19 #include "SkBitmapCache.h" 20 #include "SkShader.h" 21 #include "SkOnce.h" 22 23 static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1, 24 int count) { 25 if (count > 0) { 26 if (v0 == v1) { 27 sk_memset32(dst, v0, count); 28 } else { 29 int pairs = count >> 1; 30 for (int i = 0; i < pairs; i++) { 31 *dst++ = v0; 32 *dst++ = v1; 33 } 34 if (count & 1) { 35 *dst = v0; 36 } 37 } 38 } 39 } 40 41 // Clamp 42 43 static inline SkFixed clamp_tileproc(SkFixed x) { 44 return SkClampMax(x, 0xFFFF); 45 } 46 47 // Repeat 48 49 static inline SkFixed repeat_tileproc(SkFixed x) { 50 return x & 0xFFFF; 51 } 52 53 // Mirror 54 55 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. 56 // See http://code.google.com/p/skia/issues/detail?id=472 57 #if defined(_MSC_VER) && (_MSC_VER >= 1600) 58 #pragma optimize("", off) 59 #endif 60 61 static inline SkFixed mirror_tileproc(SkFixed x) { 62 int s = x << 15 >> 31; 63 return (x ^ s) & 0xFFFF; 64 } 65 66 #if defined(_MSC_VER) && (_MSC_VER >= 1600) 67 #pragma optimize("", on) 68 #endif 69 70 /////////////////////////////////////////////////////////////////////////////// 71 72 typedef SkFixed (*TileProc)(SkFixed); 73 74 /////////////////////////////////////////////////////////////////////////////// 75 76 static const TileProc gTileProcs[] = { 77 clamp_tileproc, 78 repeat_tileproc, 79 mirror_tileproc 80 }; 81 82 /////////////////////////////////////////////////////////////////////////////// 83 84 class SkGradientShaderBase : public SkShader { 85 public: 86 struct Descriptor { 87 Descriptor() { 88 sk_bzero(this, sizeof(*this)); 89 fTileMode = SkShader::kClamp_TileMode; 90 } 91 92 const SkColor* fColors; 93 const SkScalar* fPos; 94 int fCount; 95 SkShader::TileMode fTileMode; 96 uint32_t fGradFlags; 97 }; 98 99 public: 100 SkGradientShaderBase(const Descriptor& desc, const SkMatrix* localMatrix); 101 virtual ~SkGradientShaderBase(); 102 103 // The cache is initialized on-demand when getCache16/32 is called. 104 class GradientShaderCache : public SkRefCnt { 105 public: 106 GradientShaderCache(U8CPU alpha, const SkGradientShaderBase& shader); 107 ~GradientShaderCache(); 108 109 const uint16_t* getCache16(); 110 const SkPMColor* getCache32(); 111 112 SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; } 113 114 unsigned getAlpha() const { return fCacheAlpha; } 115 116 private: 117 // Working pointers. If either is NULL, we need to recompute the corresponding cache values. 118 uint16_t* fCache16; 119 SkPMColor* fCache32; 120 121 uint16_t* fCache16Storage; // Storage for fCache16, allocated on demand. 122 SkMallocPixelRef* fCache32PixelRef; 123 const unsigned fCacheAlpha; // The alpha value we used when we computed the cache. 124 // Larger than 8bits so we can store uninitialized 125 // value. 126 127 const SkGradientShaderBase& fShader; 128 129 // Make sure we only initialize the caches once. 130 bool fCache16Inited, fCache32Inited; 131 SkMutex fCache16Mutex, fCache32Mutex; 132 133 static void initCache16(GradientShaderCache* cache); 134 static void initCache32(GradientShaderCache* cache); 135 136 static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count); 137 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count, 138 U8CPU alpha, uint32_t gradFlags); 139 }; 140 141 class GradientShaderBaseContext : public SkShader::Context { 142 public: 143 GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&); 144 145 virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; } 146 147 protected: 148 SkMatrix fDstToIndex; 149 SkMatrix::MapXYProc fDstToIndexProc; 150 uint8_t fDstToIndexClass; 151 uint8_t fFlags; 152 153 SkAutoTUnref<GradientShaderCache> fCache; 154 155 private: 156 typedef SkShader::Context INHERITED; 157 }; 158 159 virtual bool isOpaque() const SK_OVERRIDE; 160 161 void getGradientTableBitmap(SkBitmap*) const; 162 163 enum { 164 /// Seems like enough for visual accuracy. TODO: if pos[] deserves 165 /// it, use a larger cache. 166 kCache16Bits = 8, 167 kCache16Count = (1 << kCache16Bits), 168 kCache16Shift = 16 - kCache16Bits, 169 kSqrt16Shift = 8 - kCache16Bits, 170 171 /// Seems like enough for visual accuracy. TODO: if pos[] deserves 172 /// it, use a larger cache. 173 kCache32Bits = 8, 174 kCache32Count = (1 << kCache32Bits), 175 kCache32Shift = 16 - kCache32Bits, 176 kSqrt32Shift = 8 - kCache32Bits, 177 178 /// This value is used to *read* the dither cache; it may be 0 179 /// if dithering is disabled. 180 kDitherStride32 = kCache32Count, 181 kDitherStride16 = kCache16Count, 182 }; 183 184 enum GpuColorType { 185 kTwo_GpuColorType, 186 kThree_GpuColorType, // Symmetric three color 187 kTexture_GpuColorType 188 }; 189 190 // Determines and returns the gradient is a two color gradient, symmetric three color gradient 191 // or other (texture gradient). If it is two or symmetric three color, the colors array will 192 // also be filled with the gradient colors 193 GpuColorType getGpuColorType(SkColor colors[3]) const; 194 195 uint32_t getGradFlags() const { return fGradFlags; } 196 197 protected: 198 SkGradientShaderBase(SkReadBuffer& ); 199 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; 200 SK_TO_STRING_OVERRIDE() 201 202 SkMatrix fPtsToUnit; // set by subclass 203 TileMode fTileMode; 204 TileProc fTileProc; 205 int fColorCount; 206 uint8_t fGradFlags; 207 208 struct Rec { 209 SkFixed fPos; // 0...1 210 uint32_t fScale; // (1 << 24) / range 211 }; 212 Rec* fRecs; 213 214 void commonAsAGradient(GradientInfo*, bool flipGrad = false) const; 215 216 /* 217 * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively. 218 * Count is the number of colors in the gradient 219 * It will then flip all the color and rec information and return in their respective Dst 220 * pointers. It is assumed that space has already been allocated for the Dst pointers. 221 * The rec src and dst are only assumed to be valid if count > 2 222 */ 223 static void FlipGradientColors(SkColor* colorDst, Rec* recDst, 224 SkColor* colorSrc, Rec* recSrc, 225 int count); 226 227 // V23_COMPATIBILITY_CODE 228 // Used for 2-pt conical gradients since we sort start/end cirlces by radius 229 // Assumes space has already been allocated for fOrigColors 230 void flipGradientColors(); 231 232 private: 233 enum { 234 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space 235 236 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec)) 237 }; 238 SkColor fStorage[(kStorageSize + 3) >> 2]; 239 SkColor* fOrigColors; // original colors, before modulation by paint in context. 240 bool fColorsAreOpaque; 241 242 GradientShaderCache* refCache(U8CPU alpha) const; 243 mutable SkMutex fCacheMutex; 244 mutable SkAutoTUnref<GradientShaderCache> fCache; 245 246 void initCommon(); 247 248 typedef SkShader INHERITED; 249 }; 250 251 static inline int init_dither_toggle(int x, int y) { 252 x &= 1; 253 y = (y & 1) << 1; 254 return (x | y) * SkGradientShaderBase::kDitherStride32; 255 } 256 257 static inline int next_dither_toggle(int toggle) { 258 return toggle ^ SkGradientShaderBase::kDitherStride32; 259 } 260 261 static inline int init_dither_toggle16(int x, int y) { 262 return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16; 263 } 264 265 static inline int next_dither_toggle16(int toggle) { 266 return toggle ^ SkGradientShaderBase::kDitherStride16; 267 } 268 269 /////////////////////////////////////////////////////////////////////////////// 270 271 #if SK_SUPPORT_GPU 272 273 #include "GrCoordTransform.h" 274 #include "gl/GrGLEffect.h" 275 276 class GrEffectStage; 277 class GrBackendEffectFactory; 278 279 /* 280 * The interpretation of the texture matrix depends on the sample mode. The 281 * texture matrix is applied both when the texture coordinates are explicit 282 * and when vertex positions are used as texture coordinates. In the latter 283 * case the texture matrix is applied to the pre-view-matrix position 284 * values. 285 * 286 * Normal SampleMode 287 * The post-matrix texture coordinates are in normalize space with (0,0) at 288 * the top-left and (1,1) at the bottom right. 289 * RadialGradient 290 * The matrix specifies the radial gradient parameters. 291 * (0,0) in the post-matrix space is center of the radial gradient. 292 * Radial2Gradient 293 * Matrix transforms to space where first circle is centered at the 294 * origin. The second circle will be centered (x, 0) where x may be 295 * 0 and is provided by setRadial2Params. The post-matrix space is 296 * normalized such that 1 is the second radius - first radius. 297 * SweepGradient 298 * The angle from the origin of texture coordinates in post-matrix space 299 * determines the gradient value. 300 */ 301 302 class GrTextureStripAtlas; 303 304 // Base class for Gr gradient effects 305 class GrGradientEffect : public GrEffect { 306 public: 307 308 GrGradientEffect(GrContext* ctx, 309 const SkGradientShaderBase& shader, 310 const SkMatrix& matrix, 311 SkShader::TileMode tileMode); 312 313 virtual ~GrGradientEffect(); 314 315 bool useAtlas() const { return SkToBool(-1 != fRow); } 316 SkScalar getYCoord() const { return fYCoord; }; 317 318 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 319 320 SkGradientShaderBase::GpuColorType getColorType() const { return fColorType; } 321 322 enum PremulType { 323 kBeforeInterp_PremulType, 324 kAfterInterp_PremulType, 325 }; 326 327 PremulType getPremulType() const { return fPremulType; } 328 329 const SkColor* getColors(int pos) const { 330 SkASSERT(fColorType != SkGradientShaderBase::kTexture_GpuColorType); 331 SkASSERT((pos-1) <= fColorType); 332 return &fColors[pos]; 333 } 334 335 protected: 336 337 /** Populates a pair of arrays with colors and stop info to construct a random gradient. 338 The function decides whether stop values should be used or not. The return value indicates 339 the number of colors, which will be capped by kMaxRandomGradientColors. colors should be 340 sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least 341 size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be 342 passed to the gradient factory rather than the array. 343 */ 344 static const int kMaxRandomGradientColors = 4; 345 static int RandomGradientParams(SkRandom* r, 346 SkColor colors[kMaxRandomGradientColors], 347 SkScalar** stops, 348 SkShader::TileMode* tm); 349 350 virtual bool onIsEqual(const GrEffect& effect) const SK_OVERRIDE; 351 352 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; } 353 354 private: 355 static const GrCoordSet kCoordSet = kLocal_GrCoordSet; 356 357 GrCoordTransform fCoordTransform; 358 GrTextureAccess fTextureAccess; 359 SkScalar fYCoord; 360 GrTextureStripAtlas* fAtlas; 361 int fRow; 362 bool fIsOpaque; 363 SkGradientShaderBase::GpuColorType fColorType; 364 SkColor fColors[3]; // More than 3 colors we use texture 365 PremulType fPremulType; // This only changes behavior for two and three color special cases. 366 // It is already baked into to the table for texture gradients. 367 typedef GrEffect INHERITED; 368 369 }; 370 371 /////////////////////////////////////////////////////////////////////////////// 372 373 // Base class for GL gradient effects 374 class GrGLGradientEffect : public GrGLEffect { 375 public: 376 GrGLGradientEffect(const GrBackendEffectFactory& factory); 377 virtual ~GrGLGradientEffect(); 378 379 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; 380 381 protected: 382 enum { 383 kPremulTypeKeyBitCnt = 1, 384 kPremulTypeMask = 1, 385 kPremulBeforeInterpKey = kPremulTypeMask, 386 387 kTwoColorKey = 2 << kPremulTypeKeyBitCnt, 388 kThreeColorKey = 3 << kPremulTypeKeyBitCnt, 389 kColorKeyMask = kTwoColorKey | kThreeColorKey, 390 kColorKeyBitCnt = 2, 391 392 // Subclasses must shift any key bits they produce up by this amount 393 // and combine with the result of GenBaseGradientKey. 394 kBaseKeyBitCnt = (kPremulTypeKeyBitCnt + kColorKeyBitCnt) 395 }; 396 397 static SkGradientShaderBase::GpuColorType ColorTypeFromKey(EffectKey key){ 398 if (kTwoColorKey == (key & kColorKeyMask)) { 399 return SkGradientShaderBase::kTwo_GpuColorType; 400 } else if (kThreeColorKey == (key & kColorKeyMask)) { 401 return SkGradientShaderBase::kThree_GpuColorType; 402 } else {return SkGradientShaderBase::kTexture_GpuColorType;} 403 } 404 405 static GrGradientEffect::PremulType PremulTypeFromKey(EffectKey key){ 406 if (kPremulBeforeInterpKey == (key & kPremulTypeMask)) { 407 return GrGradientEffect::kBeforeInterp_PremulType; 408 } else { 409 return GrGradientEffect::kAfterInterp_PremulType; 410 } 411 } 412 413 /** 414 * Subclasses must call this. It will return a value restricted to the lower kBaseKeyBitCnt 415 * bits. 416 */ 417 static EffectKey GenBaseGradientKey(const GrDrawEffect&); 418 419 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses 420 // should call this method from their emitCode(). 421 void emitUniforms(GrGLShaderBuilder* builder, EffectKey key); 422 423 424 // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate 425 // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using 426 // native GLSL mix), and 4+ color gradients that use the traditional texture lookup. 427 void emitColor(GrGLShaderBuilder* builder, 428 const char* gradientTValue, 429 EffectKey key, 430 const char* outputColor, 431 const char* inputColor, 432 const TextureSamplerArray& samplers); 433 434 private: 435 SkScalar fCachedYCoord; 436 GrGLUniformManager::UniformHandle fFSYUni; 437 GrGLUniformManager::UniformHandle fColorStartUni; 438 GrGLUniformManager::UniformHandle fColorMidUni; 439 GrGLUniformManager::UniformHandle fColorEndUni; 440 441 typedef GrGLEffect INHERITED; 442 }; 443 444 #endif 445 446 #endif 447