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
20class SkColorSpace;
21class SkColorSpaceXformer;
22class SkRasterPipeline;
23class SkReadBuffer;
24class SkWriteBuffer;
25
26class SkGradientShaderBase : public SkShaderBase {
27public:
28    struct Descriptor {
29        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:
47        DescriptorScope() {}
48
49        bool unflatten(SkReadBuffer&);
50
51        // fColors and fPos always point into local memory, so they can be safely mutated
52        //
53        SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
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
79    uint32_t getGradFlags() const { return fGradFlags; }
80
81    SkColor4f getXformedColor(size_t index, SkColorSpace*) const;
82
83protected:
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>
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
121public:
122    SkScalar getPos(int i) const {
123        SkASSERT(i < fColorCount);
124        return fOrigPos ? fOrigPos[i] : SkIntToScalar(i) / (fColorCount - 1);
125    }
126
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
137    bool colorsAreOpaque() const { return fColorsAreOpaque; }
138
139    TileMode getTileMode() const { return fTileMode; }
140
141private:
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
163class 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
191class GrGradientEffect : public GrFragmentProcessor {
192public:
193    struct CreateArgs {
194        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
220        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
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
259protected:
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.
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
316    const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
317
318    /** Checks whether the constructor failed to fully initialize the processor. */
319    bool isValid() const {
320        return fStrategy != InterpolationStrategy::kTexture || fTextureSampler.isInitialized();
321    }
322
323private:
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
354class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
355public:
356    GLSLProcessor() {
357        fCachedYCoord = SK_ScalarMax;
358    }
359
360    static uint32_t GenBaseGradientKey(const GrProcessor&);
361
362protected:
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
382private:
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