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