1/*
2 * Copyright 2013 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 GrGLProgramEffects_DEFINED
9#define GrGLProgramEffects_DEFINED
10
11#include "GrBackendEffectFactory.h"
12#include "GrTexture.h"
13#include "GrTextureAccess.h"
14#include "GrGLUniformManager.h"
15
16class GrEffectStage;
17class GrGLVertexProgramEffectsBuilder;
18class GrGLShaderBuilder;
19class GrGLFullShaderBuilder;
20class GrGLFragmentOnlyShaderBuilder;
21
22/**
23 * This class encapsulates an array of GrGLEffects and their supporting data (coord transforms
24 * and textures). It is built with GrGLProgramEffectsBuilder, then used to manage the necessary GL
25 * state and shader uniforms.
26 */
27class GrGLProgramEffects : public SkRefCnt {
28public:
29    typedef GrBackendEffectFactory::EffectKey EffectKey;
30    typedef GrGLUniformManager::UniformHandle UniformHandle;
31
32    /**
33     * These methods generate different portions of an effect's final key.
34     */
35    static EffectKey GenAttribKey(const GrDrawEffect&);
36    static EffectKey GenTransformKey(const GrDrawEffect&);
37    static EffectKey GenTextureKey(const GrDrawEffect&, const GrGLCaps&);
38
39    virtual ~GrGLProgramEffects();
40
41    /**
42     * Assigns a texture unit to each sampler. It starts on *texUnitIdx and writes the next
43     * available unit to *texUnitIdx when it returns.
44     */
45    void initSamplers(const GrGLUniformManager&, int* texUnitIdx);
46
47    /**
48     * Calls setData() on each effect, and sets their transformation matrices and texture bindings.
49     */
50    virtual void setData(GrGpuGL*,
51                         const GrGLUniformManager&,
52                         const GrEffectStage* effectStages[]) = 0;
53
54    /**
55     * Passed to GrGLEffects so they can add transformed coordinates to their shader code.
56     */
57    class TransformedCoords {
58    public:
59        TransformedCoords(const SkString& name, GrSLType type)
60            : fName(name), fType(type) {
61        }
62
63        const char* c_str() const { return fName.c_str(); }
64        GrSLType type() const { return fType; }
65        const SkString& getName() const { return fName; }
66
67    private:
68        SkString fName;
69        GrSLType fType;
70    };
71
72    typedef SkTArray<TransformedCoords> TransformedCoordsArray;
73
74    /**
75     * Passed to GrGLEffects so they can add texture reads to their shader code.
76     */
77    class TextureSampler {
78    public:
79        TextureSampler(UniformHandle uniform, const GrTextureAccess& access)
80            : fSamplerUniform(uniform)
81            , fConfigComponentMask(GrPixelConfigComponentMask(access.getTexture()->config())) {
82            SkASSERT(0 != fConfigComponentMask);
83            memcpy(fSwizzle, access.getSwizzle(), 5);
84        }
85
86        UniformHandle samplerUniform() const { return fSamplerUniform; }
87        // bitfield of GrColorComponentFlags present in the texture's config.
88        uint32_t configComponentMask() const { return fConfigComponentMask; }
89        const char* swizzle() const { return fSwizzle; }
90
91    private:
92        UniformHandle fSamplerUniform;
93        uint32_t      fConfigComponentMask;
94        char          fSwizzle[5];
95    };
96
97    typedef SkTArray<TextureSampler> TextureSamplerArray;
98
99protected:
100    GrGLProgramEffects(int reserveCount)
101        : fGLEffects(reserveCount)
102        , fSamplers(reserveCount) {
103    }
104
105    /**
106     * Helper for emitEffect() in a subclasses. Emits uniforms for an effect's texture accesses and
107     * appends the necessary data to the TextureSamplerArray* object so effects can add texture
108     * lookups to their code. This method is only meant to be called during the construction phase.
109     */
110    void emitSamplers(GrGLShaderBuilder*, const GrEffectRef&, TextureSamplerArray*);
111
112    /**
113     * Helper for setData(). Binds all the textures for an effect.
114     */
115    void bindTextures(GrGpuGL*, const GrEffectRef&, int effectIdx);
116
117    struct Sampler {
118        SkDEBUGCODE(Sampler() : fTextureUnit(-1) {})
119        UniformHandle fUniform;
120        int           fTextureUnit;
121    };
122
123    SkTArray<GrGLEffect*>                  fGLEffects;
124    SkTArray<SkSTArray<4, Sampler, true> > fSamplers;
125
126private:
127    typedef SkRefCnt INHERITED;
128};
129
130/**
131 * This is an abstract base class for constructing different types of GrGLProgramEffects objects.
132 */
133class GrGLProgramEffectsBuilder {
134public:
135    virtual ~GrGLProgramEffectsBuilder() { }
136
137    /**
138     * Emits the effect's shader code, and stores the necessary uniforms internally.
139     */
140    virtual void emitEffect(const GrEffectStage&,
141                            GrGLProgramEffects::EffectKey,
142                            const char* outColor,
143                            const char* inColor,
144                            int stageIndex) = 0;
145};
146
147////////////////////////////////////////////////////////////////////////////////
148
149/**
150 * This is a GrGLProgramEffects implementation that does coord transforms with the vertex shader.
151 */
152class GrGLVertexProgramEffects : public GrGLProgramEffects {
153public:
154    virtual void setData(GrGpuGL*,
155                         const GrGLUniformManager&,
156                         const GrEffectStage* effectStages[]) SK_OVERRIDE;
157
158private:
159    friend class GrGLVertexProgramEffectsBuilder;
160
161    GrGLVertexProgramEffects(int reserveCount, bool explicitLocalCoords)
162        : INHERITED(reserveCount)
163        , fTransforms(reserveCount)
164        , fHasExplicitLocalCoords(explicitLocalCoords) {
165    }
166
167    /**
168     * Helper for GrGLProgramEffectsBuilder::emitEfffect(). This method is meant to only be called
169     * during the construction phase.
170     */
171    void emitEffect(GrGLFullShaderBuilder*,
172                    const GrEffectStage&,
173                    GrGLProgramEffects::EffectKey,
174                    const char* outColor,
175                    const char* inColor,
176                    int stageIndex);
177
178    /**
179     * Helper for emitEffect(). Emits any attributes an effect may have.
180     */
181    void emitAttributes(GrGLFullShaderBuilder*, const GrEffectStage&);
182
183    /**
184     * Helper for emitEffect(). Emits code to implement an effect's coord transforms in the VS.
185     * Varyings are added as an outputs of the VS and inputs to the FS. The varyings may be either a
186     * vec2f or vec3f depending upon whether perspective interpolation is required or not. The names
187     * of the varyings in the VS and FS as well their types are appended to the
188     * TransformedCoordsArray* object, which is in turn passed to the effect's emitCode() function.
189     */
190    void emitTransforms(GrGLFullShaderBuilder*,
191                        const GrEffectRef&,
192                        EffectKey,
193                        TransformedCoordsArray*);
194
195    /**
196     * Helper for setData(). Sets all the transform matrices for an effect.
197     */
198    void setTransformData(const GrGLUniformManager&, const GrDrawEffect&, int effectIdx);
199
200    struct Transform {
201        Transform() { fCurrentValue = SkMatrix::InvalidMatrix(); }
202        UniformHandle fHandle;
203        GrSLType      fType;
204        SkMatrix      fCurrentValue;
205    };
206
207    SkTArray<SkSTArray<2, Transform, true> > fTransforms;
208    bool                                     fHasExplicitLocalCoords;
209
210    typedef GrGLProgramEffects INHERITED;
211};
212
213/**
214 * This class is used to construct a GrGLVertexProgramEffects* object.
215 */
216class GrGLVertexProgramEffectsBuilder : public GrGLProgramEffectsBuilder {
217public:
218    GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder*, int reserveCount);
219    virtual ~GrGLVertexProgramEffectsBuilder() { }
220
221    virtual void emitEffect(const GrEffectStage&,
222                            GrGLProgramEffects::EffectKey,
223                            const char* outColor,
224                            const char* inColor,
225                            int stageIndex) SK_OVERRIDE;
226
227    /**
228     * Finalizes the building process and returns the effect array. After this call, the builder
229     * becomes invalid.
230     */
231    GrGLProgramEffects* finish() { return fProgramEffects.detach(); }
232
233private:
234    GrGLFullShaderBuilder*                  fBuilder;
235    SkAutoTDelete<GrGLVertexProgramEffects> fProgramEffects;
236
237    typedef GrGLProgramEffectsBuilder INHERITED;
238};
239
240////////////////////////////////////////////////////////////////////////////////
241
242/**
243 * This is a GrGLProgramEffects implementation that does coord transforms with
244 * the the  NV_path_rendering PathTexGen functionality.
245 */
246class GrGLPathTexGenProgramEffects : public GrGLProgramEffects {
247public:
248    virtual void setData(GrGpuGL*,
249                         const GrGLUniformManager&,
250                         const GrEffectStage* effectStages[]) SK_OVERRIDE;
251
252private:
253    friend class GrGLPathTexGenProgramEffectsBuilder;
254
255    GrGLPathTexGenProgramEffects(int reserveCount)
256        : INHERITED(reserveCount)
257        , fTransforms(reserveCount) {
258    }
259
260    /**
261     * Helper for GrGLProgramEffectsBuilder::emitEfffect(). This method is meant to only be called
262     * during the construction phase.
263     */
264    void emitEffect(GrGLFragmentOnlyShaderBuilder*,
265                    const GrEffectStage&,
266                    GrGLProgramEffects::EffectKey,
267                    const char* outColor,
268                    const char* inColor,
269                    int stageIndex);
270
271    /**
272     * Helper for emitEffect(). Allocates texture units from the builder for each transform in an
273     * effect. The transforms all use adjacent texture units. They either use two or three of the
274     * coordinates at a given texture unit, depending on if they need perspective interpolation.
275     * The expressions to access the transformed coords (i.e. 'vec2(gl_TexCoord[0])') as well as the
276     * types are appended to the TransformedCoordsArray* object, which is in turn passed to the
277     * effect's emitCode() function.
278     */
279    void setupPathTexGen(GrGLFragmentOnlyShaderBuilder*,
280                         const GrEffectRef&,
281                         EffectKey,
282                         TransformedCoordsArray*);
283
284    /**
285     * Helper for setData(). Sets the PathTexGen state for each transform in an effect.
286     */
287    void setPathTexGenState(GrGpuGL*, const GrDrawEffect&, int effectIdx);
288
289    struct Transforms {
290        Transforms(EffectKey transformKey, int texCoordIndex)
291            : fTransformKey(transformKey), fTexCoordIndex(texCoordIndex) {}
292        EffectKey fTransformKey;
293        int fTexCoordIndex;
294    };
295
296    SkTArray<Transforms> fTransforms;
297
298    typedef GrGLProgramEffects INHERITED;
299};
300
301/**
302 * This class is used to construct a GrGLPathTexGenProgramEffects* object.
303 */
304class GrGLPathTexGenProgramEffectsBuilder : public GrGLProgramEffectsBuilder {
305public:
306    GrGLPathTexGenProgramEffectsBuilder(GrGLFragmentOnlyShaderBuilder*, int reserveCount);
307    virtual ~GrGLPathTexGenProgramEffectsBuilder() { }
308
309    virtual void emitEffect(const GrEffectStage&,
310                            GrGLProgramEffects::EffectKey,
311                            const char* outColor,
312                            const char* inColor,
313                            int stageIndex) SK_OVERRIDE;
314
315    /**
316     * Finalizes the building process and returns the effect array. After this call, the builder
317     * becomes invalid.
318     */
319    GrGLProgramEffects* finish() { return fProgramEffects.detach(); }
320
321private:
322    GrGLFragmentOnlyShaderBuilder*          fBuilder;
323    SkAutoTDelete<GrGLPathTexGenProgramEffects> fProgramEffects;
324
325    typedef GrGLProgramEffectsBuilder INHERITED;
326};
327
328#endif
329