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 
sk_memset32_dither(uint32_t dst[],uint32_t v0,uint32_t v1,int count)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 
clamp_tileproc(SkFixed x)50 static inline SkFixed clamp_tileproc(SkFixed x) {
51     return SkClampMax(x, 0xFFFF);
52 }
53 
54 // Repeat
55 
repeat_tileproc(SkFixed x)56 static inline SkFixed repeat_tileproc(SkFixed x) {
57     return x & 0xFFFF;
58 }
59 
60 // Mirror
61 
mirror_tileproc(SkFixed x)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 {
DescriptorDescriptor84         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:
DescriptorScope()102         DescriptorScope() {}
103 
104         bool unflatten(SkReadBuffer&);
105 
106         // fColors and fPos always point into local memory, so they can be safely mutated
107         //
mutableColors()108         SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
mutablePos()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 
getCache32PixelRef()132         SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; }
133 
getAlpha()134         unsigned getAlpha() const { return fCacheAlpha; }
getDither()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 
getFlags()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 
getGradFlags()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>
CheckedMakeContext(SkArenaAlloc * alloc,Args &&...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 
colorsAreOpaque()264     bool colorsAreOpaque() const { return fColorsAreOpaque; }
265 
getTileMode()266     TileMode getTileMode() const { return fTileMode; }
getRecs()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 
init_dither_toggle(int x,int y)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 
next_dither_toggle(int toggle)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 {
CreateArgsCreateArgs333         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 
useAtlas()358     bool useAtlas() const { return SkToBool(-1 != fRow); }
getYCoord()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 
getColorType()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 
getPremulType()389     PremulType getPremulType() const { return fPremulType; }
390 
getColors(int pos)391     const SkColor* getColors(int pos) const {
392         SkASSERT(fColorType != kTexture_ColorType);
393         SkASSERT(pos < fColors.count());
394         return &fColors[pos];
395     }
396 
getColors4f(int pos)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 
getCoordTransform()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:
GLSLProcessor()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