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 
13 #include "SkArenaAlloc.h"
14 #include "SkAutoMalloc.h"
15 #include "SkMatrix.h"
16 #include "SkShaderBase.h"
17 #include "SkTArray.h"
18 #include "SkTemplates.h"
19 
20 class SkColorSpace;
21 class SkColorSpaceXformer;
22 class SkRasterPipeline;
23 class SkReadBuffer;
24 class SkWriteBuffer;
25 
26 class SkGradientShaderBase : public SkShaderBase {
27 public:
28     struct Descriptor {
DescriptorDescriptor29         Descriptor() {
30             sk_bzero(this, sizeof(*this));
31             fTileMode = SkShader::kClamp_TileMode;
32         }
33 
34         const SkMatrix*     fLocalMatrix;
35         const SkColor4f*    fColors;
36         sk_sp<SkColorSpace> fColorSpace;
37         const SkScalar*     fPos;
38         int                 fCount;
39         SkShader::TileMode  fTileMode;
40         uint32_t            fGradFlags;
41 
42         void flatten(SkWriteBuffer&) const;
43     };
44 
45     class DescriptorScope : public Descriptor {
46     public:
DescriptorScope()47         DescriptorScope() {}
48 
49         bool unflatten(SkReadBuffer&);
50 
51         // fColors and fPos always point into local memory, so they can be safely mutated
52         //
mutableColors()53         SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
mutablePos()54         SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
55 
56     private:
57         enum {
58             kStorageCount = 16
59         };
60         SkColor4f fColorStorage[kStorageCount];
61         SkScalar fPosStorage[kStorageCount];
62         SkMatrix fLocalMatrixStorage;
63         SkAutoMalloc fDynamicStorage;
64     };
65 
66     SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
67     ~SkGradientShaderBase() override;
68 
69     bool isOpaque() const override;
70 
71     enum class GradientBitmapType : uint8_t {
72         kLegacy,
73         kSRGB,
74         kHalfFloat,
75     };
76 
77     void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
78 
getGradFlags()79     uint32_t getGradFlags() const { return fGradFlags; }
80 
81     SkColor4f getXformedColor(size_t index, SkColorSpace*) const;
82 
83 protected:
84     class GradientShaderBase4fContext;
85 
86     SkGradientShaderBase(SkReadBuffer& );
87     void flatten(SkWriteBuffer&) const override;
88     SK_TO_STRING_OVERRIDE()
89 
90     void commonAsAGradient(GradientInfo*) const;
91 
92     bool onAsLuminanceColor(SkColor*) const override;
93 
94     void initLinearBitmap(SkBitmap* bitmap, GradientBitmapType) const;
95 
96     bool onAppendStages(const StageRec&) const override;
97     bool onIsRasterPipelineOnly(const SkMatrix& ctm) const override;
98 
99     virtual void appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* tPipeline,
100                                       SkRasterPipeline* postPipeline) const = 0;
101 
102     template <typename T, typename... Args>
CheckedMakeContext(SkArenaAlloc * alloc,Args &&...args)103     static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
104         auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
105         if (!ctx->isValid()) {
106             return nullptr;
107         }
108         return ctx;
109     }
110 
111     struct AutoXformColors {
112         AutoXformColors(const SkGradientShaderBase&, SkColorSpaceXformer*);
113 
114         SkAutoSTMalloc<8, SkColor> fColors;
115     };
116 
117     const SkMatrix fPtsToUnit;
118     TileMode       fTileMode;
119     uint8_t        fGradFlags;
120 
121 public:
getPos(int i)122     SkScalar getPos(int i) const {
123         SkASSERT(i < fColorCount);
124         return fOrigPos ? fOrigPos[i] : SkIntToScalar(i) / (fColorCount - 1);
125     }
126 
getLegacyColor(int i)127     SkColor getLegacyColor(int i) const {
128         SkASSERT(i < fColorCount);
129         return fOrigColors4f[i].toSkColor();
130     }
131 
132     SkColor4f*          fOrigColors4f; // original colors, as linear floats
133     SkScalar*           fOrigPos;      // original positions
134     int                 fColorCount;
135     sk_sp<SkColorSpace> fColorSpace;   // color space of gradient stops
136 
colorsAreOpaque()137     bool colorsAreOpaque() const { return fColorsAreOpaque; }
138 
getTileMode()139     TileMode getTileMode() const { return fTileMode; }
140 
141 private:
142     // Reserve inline space for up to 4 stops.
143     static constexpr size_t kInlineStopCount   = 4;
144     static constexpr size_t kInlineStorageSize = (sizeof(SkColor4f) + sizeof(SkScalar))
145                                                * kInlineStopCount;
146     SkAutoSTMalloc<kInlineStorageSize, uint8_t> fStorage;
147 
148     bool                                        fColorsAreOpaque;
149 
150     typedef SkShaderBase INHERITED;
151 };
152 
153 ///////////////////////////////////////////////////////////////////////////////
154 
155 #if SK_SUPPORT_GPU
156 
157 #include "GrColorSpaceInfo.h"
158 #include "GrCoordTransform.h"
159 #include "GrFragmentProcessor.h"
160 #include "glsl/GrGLSLFragmentProcessor.h"
161 #include "glsl/GrGLSLProgramDataManager.h"
162 
163 class GrInvariantOutput;
164 
165 /*
166  * The interpretation of the texture matrix depends on the sample mode. The
167  * texture matrix is applied both when the texture coordinates are explicit
168  * and  when vertex positions are used as texture  coordinates. In the latter
169  * case the texture matrix is applied to the pre-view-matrix position
170  * values.
171  *
172  * Normal SampleMode
173  *  The post-matrix texture coordinates are in normalize space with (0,0) at
174  *  the top-left and (1,1) at the bottom right.
175  * RadialGradient
176  *  The matrix specifies the radial gradient parameters.
177  *  (0,0) in the post-matrix space is center of the radial gradient.
178  * Radial2Gradient
179  *   Matrix transforms to space where first circle is centered at the
180  *   origin. The second circle will be centered (x, 0) where x may be
181  *   0 and is provided by setRadial2Params. The post-matrix space is
182  *   normalized such that 1 is the second radius - first radius.
183  * SweepGradient
184  *  The angle from the origin of texture coordinates in post-matrix space
185  *  determines the gradient value.
186  */
187 
188  class GrTextureStripAtlas;
189 
190 // Base class for Gr gradient effects
191 class GrGradientEffect : public GrFragmentProcessor {
192 public:
193     struct CreateArgs {
CreateArgsCreateArgs194         CreateArgs(GrContext* context,
195                    const SkGradientShaderBase* shader,
196                    const SkMatrix* matrix,
197                    SkShader::TileMode tileMode,
198                    SkColorSpace* dstColorSpace)
199                 : fContext(context)
200                 , fShader(shader)
201                 , fMatrix(matrix)
202                 , fDstColorSpace(dstColorSpace) {
203             switch (tileMode) {
204                 case SkShader::kClamp_TileMode:
205                     fWrapMode = GrSamplerState::WrapMode::kClamp;
206                     break;
207                 case SkShader::kRepeat_TileMode:
208                     fWrapMode = GrSamplerState::WrapMode::kRepeat;
209                     break;
210                 case SkShader::kMirror_TileMode:
211                     fWrapMode = GrSamplerState::WrapMode::kMirrorRepeat;
212                     break;
213                 case SkShader::kDecal_TileMode:
214                     // TODO: actually support decal
215                     fWrapMode = GrSamplerState::WrapMode::kClamp;
216                     break;
217             }
218         }
219 
CreateArgsCreateArgs220         CreateArgs(GrContext* context,
221                    const SkGradientShaderBase* shader,
222                    const SkMatrix* matrix,
223                    GrSamplerState::WrapMode wrapMode,
224                    SkColorSpace* dstColorSpace)
225                 : fContext(context)
226                 , fShader(shader)
227                 , fMatrix(matrix)
228                 , fWrapMode(wrapMode)
229                 , fDstColorSpace(dstColorSpace) {}
230 
231         GrContext*                  fContext;
232         const SkGradientShaderBase* fShader;
233         const SkMatrix*             fMatrix;
234         GrSamplerState::WrapMode    fWrapMode;
235         SkColorSpace*               fDstColorSpace;
236     };
237 
238     class GLSLProcessor;
239 
240     ~GrGradientEffect() override;
241 
useAtlas()242     bool useAtlas() const { return SkToBool(-1 != fRow); }
243 
244     // Controls the implementation strategy for this effect.
245     // NB: all entries need to be reflected in the key.
246     enum class InterpolationStrategy : uint8_t {
247         kSingle,          // interpolation in a single domain [0,1]
248         kThreshold,       // interpolation in two domains [0,T) [T,1], with normal clamping
249         kThresholdClamp0, // same as kThreshold, but clamped only on the left edge
250         kThresholdClamp1, // same as kThreshold, but clamped only on the right edge
251         kTexture,         // texture-based fallback
252     };
253 
254     enum PremulType {
255         kBeforeInterp_PremulType,
256         kAfterInterp_PremulType,
257     };
258 
259 protected:
260     GrGradientEffect(ClassID classID, const CreateArgs&, bool isOpaque);
261     explicit GrGradientEffect(const GrGradientEffect&);  // facilitates clone() implementations
262 
263     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
264 
265     // Helper function used by derived class factories to handle color space transformation and
266     // modulation by input alpha.
AdjustFP(std::unique_ptr<GrGradientEffect> gradientFP,const CreateArgs & args)267     static std::unique_ptr<GrFragmentProcessor> AdjustFP(
268             std::unique_ptr<GrGradientEffect> gradientFP, const CreateArgs& args) {
269         if (!gradientFP->isValid()) {
270             return nullptr;
271         }
272         std::unique_ptr<GrFragmentProcessor> fp;
273         // With analytic gradients, we pre-convert the stops to the destination color space, so no
274         // xform is needed. With texture-based gradients, we leave the data in the source color
275         // space (to avoid clamping if we can't use F16)... Add an extra FP to do the xform.
276         if (gradientFP->fStrategy == InterpolationStrategy::kTexture) {
277             // Our texture is always either F16 or sRGB, so the data is "linear" in the shader.
278             // Create our xform assuming float inputs, which will suppress any extra sRGB work.
279             // We do support having a transfer function on the color space of the stops, so
280             // this FP may include that transformation.
281             fp = GrColorSpaceXformEffect::Make(std::move(gradientFP),
282                                                args.fShader->fColorSpace.get(),
283                                                kRGBA_float_GrPixelConfig,
284                                                args.fDstColorSpace);
285         } else {
286             fp = std::move(gradientFP);
287         }
288         return GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
289     }
290 
291 #if GR_TEST_UTILS
292     /** Helper struct that stores (and populates) parameters to construct a random gradient.
293         If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
294         fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
295         will be the number of color stops in either case, and fColors and fStops can be passed to
296         the gradient factory. (The constructor may decide not to use stops, in which case fStops
297         will be nullptr). */
298     struct RandomGradientParams {
299         static constexpr int kMaxRandomGradientColors = 5;
300 
301         RandomGradientParams(SkRandom* r);
302 
303         bool fUseColors4f;
304         SkColor fColors[kMaxRandomGradientColors];
305         SkColor4f fColors4f[kMaxRandomGradientColors];
306         sk_sp<SkColorSpace> fColorSpace;
307         SkScalar fStopStorage[kMaxRandomGradientColors];
308         SkShader::TileMode fTileMode;
309         int fColorCount;
310         SkScalar* fStops;
311     };
312     #endif
313 
314     bool onIsEqual(const GrFragmentProcessor&) const override;
315 
getCoordTransform()316     const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
317 
318     /** Checks whether the constructor failed to fully initialize the processor. */
isValid()319     bool isValid() const {
320         return fStrategy != InterpolationStrategy::kTexture || fTextureSampler.isInitialized();
321     }
322 
323 private:
324     void addInterval(const SkGradientShaderBase&, size_t idx0, size_t idx1, SkColorSpace*);
325 
326     static OptimizationFlags OptFlags(bool isOpaque);
327 
328     // Interpolation intervals, encoded as 4f tuples of (scale, bias)
329     // such that color(t) = t * scale + bias.
330     SkSTArray<4, GrColor4f, true> fIntervals;
331 
332     GrSamplerState::WrapMode fWrapMode;
333 
334     GrCoordTransform fCoordTransform;
335     TextureSampler fTextureSampler;
336     SkScalar fYCoord;
337     GrTextureStripAtlas* fAtlas;
338     int fRow;
339     bool fIsOpaque;
340 
341     InterpolationStrategy fStrategy;
342     SkScalar              fThreshold;  // used for InterpolationStrategy::kThreshold
343     PremulType            fPremulType; // This is already baked into the table for texture
344                                        // gradients, and only changes behavior for gradients
345                                        // that don't use a texture.
346 
347     typedef GrFragmentProcessor INHERITED;
348 
349 };
350 
351 ///////////////////////////////////////////////////////////////////////////////
352 
353 // Base class for GL gradient effects
354 class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
355 public:
GLSLProcessor()356     GLSLProcessor() {
357         fCachedYCoord = SK_ScalarMax;
358     }
359 
360     static uint32_t GenBaseGradientKey(const GrProcessor&);
361 
362 protected:
363     void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
364 
365     // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
366     // should call this method from their emitCode().
367     void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
368 
369     // Emit code that gets a fragment's color from an expression for t; has branches for
370     // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
371     // color gradients that use the traditional texture lookup, as well as several varieties
372     // of hard stop gradients
373     void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
374                    GrGLSLUniformHandler* uniformHandler,
375                    const GrShaderCaps* shaderCaps,
376                    const GrGradientEffect&,
377                    const char* gradientTValue,
378                    const char* outputColor,
379                    const char* inputColor,
380                    const TextureSamplers&);
381 
382 private:
383     void emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder,
384                              GrGLSLUniformHandler* uniformHandler,
385                              const GrShaderCaps* shaderCaps,
386                              const GrGradientEffect&,
387                              const char* gradientTValue,
388                              const char* outputColor,
389                              const char* inputColor);
390 
391     SkScalar fCachedYCoord;
392     GrGLSLProgramDataManager::UniformHandle fIntervalsUni;
393     GrGLSLProgramDataManager::UniformHandle fThresholdUni;
394     GrGLSLProgramDataManager::UniformHandle fFSYUni;
395 
396     typedef GrGLSLFragmentProcessor INHERITED;
397 };
398 
399 #endif
400 
401 #endif
402