• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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