gfx/skia/trunk/src/effects/gradients/SkGradientShaderPriv.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial