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