• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 GrGLSLShaderBuilder_DEFINED
9 #define GrGLSLShaderBuilder_DEFINED
10 
11 #include "include/core/SkSpan.h"
12 #include "include/private/SkSLStatement.h"
13 #include "include/private/SkSLString.h"
14 #include "include/private/SkTDArray.h"
15 #include "src/gpu/GrShaderVar.h"
16 #include "src/gpu/GrTBlockList.h"
17 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
18 
19 #include <stdarg.h>
20 
21 class GrGLSLColorSpaceXformHelper;
22 
23 namespace SkSL {
24     namespace dsl {
25         class DSLWriter;
26     }
27 }
28 
29 /**
30   base class for all shaders builders
31 */
32 class GrGLSLShaderBuilder {
33 public:
34     GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
~GrGLSLShaderBuilder()35     virtual ~GrGLSLShaderBuilder() {}
36 
37     using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
38 
39     /** Appends a 2D texture sample with projection if necessary. The vec length and swizzle
40         order of the result depends on the GrProcessor::TextureSampler associated with the
41         SamplerHandle.
42         */
43     void appendTextureLookup(SkString* out, SamplerHandle, const char* coordName) const;
44 
45     /** Version of above that appends the result to the shader code instead.*/
46     void appendTextureLookup(SamplerHandle,
47                              const char* coordName,
48                              GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
49 
50     /** Does the work of appendTextureLookup and blends the result by dst, treating the texture
51         lookup a the src input to the blend. The dst is assumed to be half4 and the result is always
52         a half4. If dst is nullptr we use half4(1) as the blend dst. */
53     void appendTextureLookupAndBlend(const char* dst,
54                                      SkBlendMode,
55                                      SamplerHandle,
56                                      const char* coordName,
57                                      GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
58 
59     /** Appends a load of an input attachment into the shader code. */
60     void appendInputLoad(SamplerHandle);
61 
62     /** Adds a helper function to facilitate color gamut transformation, and produces code that
63         returns the srcColor transformed into a new gamut (via multiplication by the xform from
64         colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
65         determines if the source is premultipled or not). */
66     void appendColorGamutXform(SkString* out, const char* srcColor,
67                                GrGLSLColorSpaceXformHelper* colorXformHelper);
68 
69     /** Version of above that appends the result to the shader code instead. */
70     void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
71 
72     /**
73     * Adds a constant declaration to the top of the shader.
74     */
defineConstant(const char * type,const char * name,const char * value)75     void defineConstant(const char* type, const char* name, const char* value) {
76         this->definitions().appendf("const %s %s = %s;\n", type, name, value);
77     }
78 
defineConstant(const char * name,int value)79     void defineConstant(const char* name, int value) {
80         this->definitions().appendf("const int %s = %i;\n", name, value);
81     }
82 
defineConstant(const char * name,float value)83     void defineConstant(const char* name, float value) {
84         this->definitions().appendf("const float %s = %f;\n", name, value);
85     }
86 
defineConstantf(const char * type,const char * name,const char * fmt,...)87     void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
88        this->definitions().appendf("const %s %s = ", type, name);
89        va_list args;
90        va_start(args, fmt);
91        this->definitions().appendVAList(fmt, args);
92        va_end(args);
93        this->definitions().append(";\n");
94     }
95 
definitionAppend(const char * str)96     void definitionAppend(const char* str) { this->definitions().append(str); }
97 
98     void declareGlobal(const GrShaderVar&);
99 
100     // Generates a unique variable name for holding the result of a temporary expression when it's
101     // not reasonable to just add a new block for scoping. Does not declare anything.
newTmpVarName(const char * suffix)102     SkString newTmpVarName(const char* suffix) {
103         int tmpIdx = fTmpVariableCounter++;
104         return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix);
105     }
106 
107     /**
108      * Called by GrGLSLProcessors to add code to one of the shaders.
109      */
codeAppendf(const char format[],...)110     void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
111        va_list args;
112        va_start(args, format);
113        this->code().appendVAList(format, args);
114        va_end(args);
115     }
116 
codeAppend(const char * str)117     void codeAppend(const char* str) { this->code().append(str); }
118 
codeAppend(const char * str,size_t length)119     void codeAppend(const char* str, size_t length) { this->code().append(str, length); }
120 
121     void codeAppend(std::unique_ptr<SkSL::Statement> stmt);
122 
codePrependf(const char format[],...)123     void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
124        va_list args;
125        va_start(args, format);
126        this->code().prependVAList(format, args);
127        va_end(args);
128     }
129 
130     /**
131      * Appends a variable declaration to one of the shaders
132      */
133     void declAppend(const GrShaderVar& var);
134 
135     /**
136      * Generates a mangled name for a helper function in the fragment shader. Will give consistent
137      * results if called more than once.
138      */
139     SkString getMangledFunctionName(const char* baseName);
140 
141     /** Emits a prototype for a helper function outside of main() in the fragment shader. */
142     void emitFunctionPrototype(GrSLType returnType,
143                                const char* mangledName,
144                                SkSpan<const GrShaderVar> args);
145 
146     /** Emits a helper function outside of main() in the fragment shader. */
147     void emitFunction(GrSLType returnType,
148                       const char* mangledName,
149                       SkSpan<const GrShaderVar> args,
150                       const char* body);
151 
152     void emitFunction(const char* declaration, const char* body);
153 
154     /**
155      * Combines the various parts of the shader to create a single finalized shader string.
156      */
157     void finalize(uint32_t visibility);
158 
159     /**
160      * Get parent builder for adding uniforms.
161      */
getProgramBuilder()162     GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
163 
164     /**
165      * Helper for begining and ending a block in the shader code.
166      */
167     class ShaderBlock {
168     public:
ShaderBlock(GrGLSLShaderBuilder * builder)169         ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
170             SkASSERT(builder);
171             fBuilder->codeAppend("{");
172         }
173 
~ShaderBlock()174         ~ShaderBlock() {
175             fBuilder->codeAppend("}");
176         }
177     private:
178         GrGLSLShaderBuilder* fBuilder;
179     };
180 
181 protected:
182     typedef GrTBlockList<GrShaderVar> VarArray;
183     void appendDecls(const VarArray& vars, SkString* out) const;
184 
185     void appendFunctionDecl(GrSLType returnType,
186                             const char* mangledName,
187                             SkSpan<const GrShaderVar> args);
188 
189     /**
190      * Features that should only be enabled internally by the builders.
191      */
192     enum GLSLPrivateFeature {
193         kFragCoordConventions_GLSLPrivateFeature,
194         kBlendEquationAdvanced_GLSLPrivateFeature,
195         kBlendFuncExtended_GLSLPrivateFeature,
196         kFramebufferFetch_GLSLPrivateFeature,
197         kNoPerspectiveInterpolation_GLSLPrivateFeature,
198         kSampleVariables_GLSLPrivateFeature,
199         kLastGLSLPrivateFeature = kSampleVariables_GLSLPrivateFeature
200     };
201 
202     /*
203      * A general function which enables an extension in a shader if the feature bit is not present
204      *
205      * @return true if the feature bit was not yet present, false otherwise.
206      */
207     bool addFeature(uint32_t featureBit, const char* extensionName);
208 
209     enum InterfaceQualifier {
210         kIn_InterfaceQualifier,
211         kOut_InterfaceQualifier,
212         kLastInterfaceQualifier = kOut_InterfaceQualifier
213     };
214 
215     /*
216      * A low level function to build default layout qualifiers.
217      *
218      *   e.g. layout(param1, param2, ...) out;
219      *
220      * GLSL allows default layout qualifiers for in, out, and uniform.
221      */
222     void addLayoutQualifier(const char* param, InterfaceQualifier);
223 
224     void compileAndAppendLayoutQualifiers();
225 
nextStage()226     void nextStage() {
227         fShaderStrings.push_back();
228         fCodeIndex++;
229     }
230 
deleteStage()231     void deleteStage() {
232         fShaderStrings.pop_back();
233         fCodeIndex--;
234     }
235 
extensions()236     SkString& extensions() { return fShaderStrings[kExtensions]; }
definitions()237     SkString& definitions() { return fShaderStrings[kDefinitions]; }
precisionQualifier()238     SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
layoutQualifiers()239     SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
uniforms()240     SkString& uniforms() { return fShaderStrings[kUniforms]; }
inputs()241     SkString& inputs() { return fShaderStrings[kInputs]; }
outputs()242     SkString& outputs() { return fShaderStrings[kOutputs]; }
functions()243     SkString& functions() { return fShaderStrings[kFunctions]; }
main()244     SkString& main() { return fShaderStrings[kMain]; }
code()245     SkString& code() { return fShaderStrings[fCodeIndex]; }
246 
247     virtual void onFinalize() = 0;
248 
249     enum {
250         kExtensions,
251         kDefinitions,
252         kPrecisionQualifier,
253         kLayoutQualifiers,
254         kUniforms,
255         kInputs,
256         kOutputs,
257         kFunctions,
258         kMain,
259         kCode,
260 
261         kPrealloc = kCode + 6,  // 6 == Reasonable upper bound on number of processor stages
262     };
263 
264     GrGLSLProgramBuilder* fProgramBuilder;
265     SkSL::String fCompilerString;
266     SkSTArray<kPrealloc, SkString> fShaderStrings;
267     SkString fCode;
268     SkString fFunctions;
269     SkString fExtensions;
270     // Hangs onto Declarations so we don't destroy them prior to the variables that refer to them.
271     SkSL::StatementArray fDeclarations;
272 
273     VarArray fInputs;
274     VarArray fOutputs;
275     uint32_t fFeaturesAddedMask;
276     SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
277     int fCodeIndex;
278     bool fFinalized;
279 
280     // Counter for generating unique scratch variable names in a shader.
281     int fTmpVariableCounter;
282 
283     friend class GrCCCoverageProcessor; // to access code().
284     friend class GrGLSLProgramBuilder;
285     friend class GrGLProgramBuilder;
286     friend class GrD3DPipelineStateBuilder;
287     friend class GrDawnProgramBuilder;
288     friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
289     friend class GrGLPathProgramBuilder; // to access fInputs.
290     friend class GrVkPipelineStateBuilder;
291     friend class GrMtlPipelineStateBuilder;
292     friend class SkSL::dsl::DSLWriter;
293 };
294 #endif
295