• 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 GrGLShaderBuilder_DEFINED
9 #define GrGLShaderBuilder_DEFINED
10 
11 #include "GrAllocator.h"
12 #include "GrBackendEffectFactory.h"
13 #include "GrColor.h"
14 #include "GrEffect.h"
15 #include "SkTypes.h"
16 #include "gl/GrGLProgramEffects.h"
17 #include "gl/GrGLSL.h"
18 #include "gl/GrGLUniformManager.h"
19 
20 #include <stdarg.h>
21 
22 class GrGLContextInfo;
23 class GrEffectStage;
24 class GrGLProgramDesc;
25 
26 /**
27   Contains all the incremental state of a shader as it is being built,as well as helpers to
28   manipulate that state.
29 */
30 class GrGLShaderBuilder {
31 public:
32     typedef GrTAllocator<GrGLShaderVar> VarArray;
33     typedef GrBackendEffectFactory::EffectKey EffectKey;
34     typedef GrGLProgramEffects::TextureSampler TextureSampler;
35     typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray;
36     typedef GrGLUniformManager::BuilderUniform BuilderUniform;
37 
38     enum ShaderVisibility {
39         kVertex_Visibility   = 0x1,
40         kGeometry_Visibility = 0x2,
41         kFragment_Visibility = 0x4,
42     };
43 
44     typedef GrGLUniformManager::UniformHandle UniformHandle;
45 
46     // Handles for program uniforms (other than per-effect uniforms)
47     struct UniformHandles {
48         UniformHandle       fViewMatrixUni;
49         UniformHandle       fRTAdjustmentUni;
50         UniformHandle       fColorUni;
51         UniformHandle       fCoverageUni;
52 
53         // We use the render target height to provide a y-down frag coord when specifying
54         // origin_upper_left is not supported.
55         UniformHandle       fRTHeightUni;
56 
57         // Uniforms for computing texture coords to do the dst-copy lookup
58         UniformHandle       fDstCopyTopLeftUni;
59         UniformHandle       fDstCopyScaleUni;
60         UniformHandle       fDstCopySamplerUni;
61     };
62 
63     struct GenProgramOutput {
GenProgramOutputGenProgramOutput64         GenProgramOutput()
65             : fColorEffects(NULL)
66             , fCoverageEffects(NULL)
67             , fHasVertexShader(false)
68             , fTexCoordSetCnt(0)
69             , fProgramID(0) {}
70 
GenProgramOutputGenProgramOutput71         GenProgramOutput(const GenProgramOutput& other) {
72             *this = other;
73         }
74 
75         GenProgramOutput& operator=(const GenProgramOutput& other) {
76             fColorEffects.reset(SkRef(other.fColorEffects.get()));
77             fCoverageEffects.reset(SkRef(other.fCoverageEffects.get()));
78             fUniformHandles = other.fUniformHandles;
79             fHasVertexShader = other.fHasVertexShader;
80             fTexCoordSetCnt = other.fTexCoordSetCnt;
81             fProgramID = other.fProgramID;
82             return *this;
83         }
84 
85         SkAutoTUnref<GrGLProgramEffects> fColorEffects;
86         SkAutoTUnref<GrGLProgramEffects> fCoverageEffects;
87         UniformHandles                   fUniformHandles;
88         bool                             fHasVertexShader;
89         int                              fTexCoordSetCnt;
90         GrGLuint                         fProgramID;
91     };
92 
93     static bool GenProgram(GrGpuGL* gpu,
94                            GrGLUniformManager* uman,
95                            const GrGLProgramDesc& desc,
96                            const GrEffectStage* inColorStages[],
97                            const GrEffectStage* inCoverageStages[],
98                            GenProgramOutput* output);
99 
~GrGLShaderBuilder()100     virtual ~GrGLShaderBuilder() {}
101 
102     /**
103      * Use of these features may require a GLSL extension to be enabled. Shaders may not compile
104      * if code is added that uses one of these features without calling enableFeature()
105      */
106     enum GLSLFeature {
107         kStandardDerivatives_GLSLFeature = 0,
108 
109         kLastGLSLFeature = kStandardDerivatives_GLSLFeature
110     };
111 
112     /**
113      * If the feature is supported then true is returned and any necessary #extension declarations
114      * are added to the shaders. If the feature is not supported then false will be returned.
115      */
116     bool enableFeature(GLSLFeature);
117 
118     /**
119      * Called by GrGLEffects to add code the fragment shader.
120      */
fsCodeAppendf(const char format[],...)121     void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
122         va_list args;
123         va_start(args, format);
124         fFSCode.appendVAList(format, args);
125         va_end(args);
126     }
127 
fsCodeAppend(const char * str)128     void fsCodeAppend(const char* str) { fFSCode.append(str); }
129 
130     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
131         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
132         order of the result depends on the GrTextureAccess associated with the TextureSampler. */
133     void appendTextureLookup(SkString* out,
134                              const TextureSampler&,
135                              const char* coordName,
136                              GrSLType coordType = kVec2f_GrSLType) const;
137 
138     /** Version of above that appends the result to the fragment shader code instead.*/
139     void fsAppendTextureLookup(const TextureSampler&,
140                                const char* coordName,
141                                GrSLType coordType = kVec2f_GrSLType);
142 
143 
144     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
145         always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
146         float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
147         called. */
148     void fsAppendTextureLookupAndModulate(const char* modulation,
149                                           const TextureSampler&,
150                                           const char* coordName,
151                                           GrSLType coordType = kVec2f_GrSLType);
152 
153     /** Emits a helper function outside of main() in the fragment shader. */
154     void fsEmitFunction(GrSLType returnType,
155                         const char* name,
156                         int argCnt,
157                         const GrGLShaderVar* args,
158                         const char* body,
159                         SkString* outName);
160 
161     typedef uint8_t DstReadKey;
162     typedef uint8_t FragPosKey;
163 
164     /**  Returns a key for adding code to read the copy-of-dst color in service of effects that
165          require reading the dst. It must not return 0 because 0 indicates that there is no dst
166          copy read at all (in which case this function should not be called). */
167     static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&);
168 
169     /** Returns a key for reading the fragment location. This should only be called if there is an
170         effect that will requires the fragment position. If the fragment position is not required,
171         the key is 0. */
172     static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&);
173 
174     /** If texture swizzling is available using tex parameters then it is preferred over mangling
175         the generated shader code. This potentially allows greater reuse of cached shaders. */
176     static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
177 
178     /** Add a uniform variable to the current program, that has visibility in one or more shaders.
179         visibility is a bitfield of ShaderVisibility values indicating from which shaders the
180         uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not
181         supported at this time. The actual uniform name will be mangled. If outName is not NULL then
182         it will refer to the final uniform name after return. Use the addUniformArray variant to add
183         an array of uniforms. */
184     GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
185                                                  GrSLType type,
186                                                  const char* name,
187                                                  const char** outName = NULL) {
188         return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
189     }
190     GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility,
191                                                       GrSLType type,
192                                                       const char* name,
193                                                       int arrayCount,
194                                                       const char** outName = NULL);
195 
getUniformVariable(GrGLUniformManager::UniformHandle u)196     const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle u) const {
197         return fUniformManager->getBuilderUniform(fUniforms, u).fVariable;
198     }
199 
200     /**
201      * Shortcut for getUniformVariable(u).c_str()
202      */
getUniformCStr(GrGLUniformManager::UniformHandle u)203     const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
204         return this->getUniformVariable(u).c_str();
205     }
206 
207     /**
208      * This returns a variable name to access the 2D, perspective correct version of the coords in
209      * the fragment shader. If the coordinates at index are 3-dimensional, it immediately emits a
210      * perspective divide into the fragment shader (xy / z) to convert them to 2D.
211      */
212     SkString ensureFSCoords2D(const TransformedCoordsArray&, int index);
213 
214     /** Returns a variable name that represents the position of the fragment in the FS. The position
215         is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
216     const char* fragmentPosition();
217 
218     /** Returns the variable name that holds the color of the destination pixel. This may be NULL if
219         no effect advertised that it will read the destination. */
220     const char* dstColor();
221 
222     const GrGLContextInfo& ctxInfo() const;
223 
224     /**
225      * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder
226      * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that
227      * our shaders print pretty without effect writers tracking indentation.
228      */
229     class FSBlock {
230     public:
FSBlock(GrGLShaderBuilder * builder)231         FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) {
232             SkASSERT(NULL != builder);
233             fBuilder->fsCodeAppend("\t{\n");
234         }
235 
~FSBlock()236         ~FSBlock() {
237             fBuilder->fsCodeAppend("\t}\n");
238         }
239     private:
240         GrGLShaderBuilder* fBuilder;
241     };
242 
243 protected:
244     GrGLShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
245 
gpu()246     GrGpuGL* gpu() const { return fGpu; }
247 
desc()248     const GrGLProgramDesc& desc() const { return fDesc; }
249 
250     /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */
fsInputAppend()251     GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); }
252 
253     // Helper for emitEffects().
254     void createAndEmitEffects(GrGLProgramEffectsBuilder*,
255                               const GrEffectStage* effectStages[],
256                               const EffectKey effectKeys[],
257                               int effectCnt,
258                               GrGLSLExpr4* inOutFSColor);
259 
260     // Generates a name for a variable. The generated string will be name prefixed by the prefix
261     // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
262     // generating stage code.
263     void nameVariable(SkString* out, char prefix, const char* name);
264 
265     virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
266 
267     virtual void bindProgramLocations(GrGLuint programId) const;
268 
269     void appendDecls(const VarArray&, SkString*) const;
270     void appendUniformDecls(ShaderVisibility, SkString*) const;
271 
getOutput()272     const GenProgramOutput& getOutput() const { return fOutput; }
273 
274     GenProgramOutput fOutput;
275 
276 private:
277     class CodeStage : SkNoncopyable {
278     public:
CodeStage()279         CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
280 
inStageCode()281         bool inStageCode() const {
282             this->validate();
283             return NULL != fEffectStage;
284         }
285 
effectStage()286         const GrEffectStage* effectStage() const {
287             this->validate();
288             return fEffectStage;
289         }
290 
stageIndex()291         int stageIndex() const {
292             this->validate();
293             return fCurrentIndex;
294         }
295 
296         class AutoStageRestore : SkNoncopyable {
297         public:
AutoStageRestore(CodeStage * codeStage,const GrEffectStage * newStage)298             AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
299                 SkASSERT(NULL != codeStage);
300                 fSavedIndex = codeStage->fCurrentIndex;
301                 fSavedEffectStage = codeStage->fEffectStage;
302 
303                 if (NULL == newStage) {
304                     codeStage->fCurrentIndex = -1;
305                 } else {
306                     codeStage->fCurrentIndex = codeStage->fNextIndex++;
307                 }
308                 codeStage->fEffectStage = newStage;
309 
310                 fCodeStage = codeStage;
311             }
~AutoStageRestore()312             ~AutoStageRestore() {
313                 fCodeStage->fCurrentIndex = fSavedIndex;
314                 fCodeStage->fEffectStage = fSavedEffectStage;
315             }
316         private:
317             CodeStage*              fCodeStage;
318             int                     fSavedIndex;
319             const GrEffectStage*    fSavedEffectStage;
320         };
321     private:
validate()322         void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
323         int                     fNextIndex;
324         int                     fCurrentIndex;
325         const GrEffectStage*    fEffectStage;
326     } fCodeStage;
327 
328     bool genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]);
329 
330     /**
331      * The base class will emit the fragment code that precedes the per-effect code and then call
332      * this function. The subclass can use it to insert additional fragment code that should
333      * execute before the effects' code and/or emit other shaders (e.g. geometry, vertex).
334      *
335      * The subclass can modify the initial color or coverage
336      */
337     virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) = 0;
338 
339     /**
340     * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
341     * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key
342     * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and
343     * is updated to be the output color of the last stage.
344     * The handles to texture samplers for effectStage[i] are added to
345     * effectSamplerHandles[i].
346     */
347     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
348                                                      const EffectKey effectKeys[],
349                                                      int effectCnt,
350                                                      GrGLSLExpr4* inOutFSColor) = 0;
351 
352     /**
353      * Similar to emitCodeBeforeEffects() but called after per-effect code is emitted.
354      */
355     virtual void emitCodeAfterEffects() = 0;
356 
357     /** Enables using the secondary color output and returns the name of the var in which it is
358         to be stored */
359     const char* enableSecondaryOutput();
360     /** Gets the name of the primary color output. */
361     const char* getColorOutputName() const;
362 
363     /**
364      * Compiles all the shaders, links them into a program, and writes the program id to the output
365      * struct.
366      **/
367     bool finish();
368 
369     /**
370      * Features that should only be enabled by GrGLShaderBuilder itself.
371      */
372     enum GLSLPrivateFeature {
373         kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
374         kEXTShaderFramebufferFetch_GLSLPrivateFeature,
375         kNVShaderFramebufferFetch_GLSLPrivateFeature,
376     };
377     bool enablePrivateFeature(GLSLPrivateFeature);
378 
379     // If we ever have VS/GS features we can expand this to take a bitmask of ShaderVisibility and
380     // track the enables separately for each shader.
381     void addFSFeature(uint32_t featureBit, const char* extensionName);
382 
383     // Interpretation of DstReadKey when generating code
384     enum {
385         kNoDstRead_DstReadKey           = 0,
386         kYesDstRead_DstReadKeyBit       = 0x1, // Set if we do a dst-copy-read.
387         kUseAlphaConfig_DstReadKeyBit   = 0x2, // Set if dst-copy config is alpha only.
388         kTopLeftOrigin_DstReadKeyBit    = 0x4, // Set if dst-copy origin is top-left.
389     };
390 
391     enum {
392         kNoFragPosRead_FragPosKey           = 0,  // The fragment positition will not be needed.
393         kTopLeftFragPosRead_FragPosKey      = 0x1,// Read frag pos relative to top-left.
394         kBottomLeftFragPosRead_FragPosKey   = 0x2,// Read frag pos relative to bottom-left.
395     };
396 
397     const GrGLProgramDesc&                  fDesc;
398     GrGpuGL*                                fGpu;
399     SkAutoTUnref<GrGLUniformManager>        fUniformManager;
400     uint32_t                                fFSFeaturesAddedMask;
401     SkString                                fFSFunctions;
402     SkString                                fFSExtensions;
403     VarArray                                fFSInputs;
404     VarArray                                fFSOutputs;
405     GrGLUniformManager::BuilderUniformArray fUniforms;
406 
407     SkString                                fFSCode;
408 
409     bool                                    fSetupFragPosition;
410     bool                                    fTopLeftFragPosRead;
411 
412     bool                                    fHasCustomColorOutput;
413     bool                                    fHasSecondaryOutput;
414 };
415 
416 ////////////////////////////////////////////////////////////////////////////////
417 
418 class GrGLFullShaderBuilder : public GrGLShaderBuilder {
419 public:
420     GrGLFullShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
421 
422     /**
423      * Called by GrGLEffects to add code to one of the shaders.
424      */
vsCodeAppendf(const char format[],...)425     void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
426         va_list args;
427         va_start(args, format);
428         fVSCode.appendVAList(format, args);
429         va_end(args);
430     }
431 
vsCodeAppend(const char * str)432     void vsCodeAppend(const char* str) { fVSCode.append(str); }
433 
434    /** Add a vertex attribute to the current program that is passed in from the vertex data.
435        Returns false if the attribute was already there, true otherwise. */
436     bool addAttribute(GrSLType type, const char* name);
437 
438    /** Add a varying variable to the current program to pass values between vertex and fragment
439         shaders. If the last two parameters are non-NULL, they are filled in with the name
440         generated. */
441     void addVarying(GrSLType type,
442                     const char* name,
443                     const char** vsOutName = NULL,
444                     const char** fsInName = NULL);
445 
446     /** Returns a vertex attribute that represents the vertex position in the VS. This is the
447         pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
448       */
positionAttribute()449     const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
450 
451     /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
452         as positionAttribute() or it may not be. It depends upon whether the rendering code
453         specified explicit local coords or not in the GrDrawState. */
localCoordsAttribute()454     const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
455 
456     /**
457      * Are explicit local coordinates provided as input to the vertex shader.
458      */
hasExplicitLocalCoords()459     bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
460 
461     bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
462     const SkString* getEffectAttributeName(int attributeIndex) const;
463 
464 private:
465     virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE;
466 
467     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
468                                                      const EffectKey effectKeys[],
469                                                      int effectCnt,
470                                                      GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
471 
472     virtual void emitCodeAfterEffects() SK_OVERRIDE;
473 
474     virtual bool compileAndAttachShaders(GrGLuint programId,
475                                          SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE;
476 
477     virtual void bindProgramLocations(GrGLuint programId) const SK_OVERRIDE;
478 
479     VarArray                            fVSAttrs;
480     VarArray                            fVSOutputs;
481     VarArray                            fGSInputs;
482     VarArray                            fGSOutputs;
483 
484     SkString                            fVSCode;
485 
486     struct AttributePair {
setAttributePair487         void set(int index, const SkString& name) {
488             fIndex = index; fName = name;
489         }
490         int      fIndex;
491         SkString fName;
492     };
493     SkSTArray<10, AttributePair, true>  fEffectAttributes;
494 
495     GrGLShaderVar*                      fPositionVar;
496     GrGLShaderVar*                      fLocalCoordsVar;
497 
498     typedef GrGLShaderBuilder INHERITED;
499 };
500 
501 ////////////////////////////////////////////////////////////////////////////////
502 
503 class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder {
504 public:
505     GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager*, const GrGLProgramDesc&);
506 
507     int addTexCoordSets(int count);
508 
509 private:
emitCodeBeforeEffects(GrGLSLExpr4 * color,GrGLSLExpr4 * coverage)510     virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {}
511 
512     virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
513                                                      const EffectKey effectKeys[],
514                                                      int effectCnt,
515                                                      GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
516 
emitCodeAfterEffects()517     virtual void emitCodeAfterEffects() SK_OVERRIDE {}
518 
519     typedef GrGLShaderBuilder INHERITED;
520 };
521 
522 #endif
523