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/GrTAllocator.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 | /** |
88 | * Called by GrGLSLProcessors to add code to one of the shaders. |
89 | */ |
90 | void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { |
91 | va_list args; |
92 | va_start(args, format); |
93 | this->code().appendVAList(format, args); |
94 | va_end(args); |
95 | } |
96 | |
97 | void codeAppend(const char* str) { this->code().append(str); } |
98 | |
99 | void codeAppend(const char* str, size_t length) { this->code().append(str, length); } |
100 | |
101 | void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { |
102 | va_list args; |
103 | va_start(args, format); |
104 | this->code().prependVAList(format, args); |
105 | va_end(args); |
106 | } |
107 | |
108 | /** |
109 | * Appends a variable declaration to one of the shaders |
110 | */ |
111 | void declAppend(const GrShaderVar& var); |
112 | |
113 | /** Emits a helper function outside of main() in the fragment shader. */ |
114 | void emitFunction(GrSLType returnType, |
115 | const char* name, |
116 | int argCnt, |
117 | const GrShaderVar* args, |
118 | const char* body, |
119 | SkString* outName); |
120 | |
121 | /* |
122 | * Combines the various parts of the shader to create a single finalized shader string. |
123 | */ |
124 | void finalize(uint32_t visibility); |
125 | |
126 | /* |
127 | * Get parent builder for adding uniforms |
128 | */ |
129 | GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; } |
130 | |
131 | /** |
132 | * Helper for begining and ending a block in the shader code. |
133 | */ |
134 | class ShaderBlock { |
135 | public: |
136 | ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) { |
137 | SkASSERT(builder); |
138 | fBuilder->codeAppend("{" ); |
139 | } |
140 | |
141 | ~ShaderBlock() { |
142 | fBuilder->codeAppend("}" ); |
143 | } |
144 | private: |
145 | GrGLSLShaderBuilder* fBuilder; |
146 | }; |
147 | |
148 | protected: |
149 | typedef GrTAllocator<GrShaderVar> VarArray; |
150 | void appendDecls(const VarArray& vars, SkString* out) const; |
151 | |
152 | /** |
153 | * Features that should only be enabled internally by the builders. |
154 | */ |
155 | enum GLSLPrivateFeature { |
156 | kFragCoordConventions_GLSLPrivateFeature, |
157 | kBlendEquationAdvanced_GLSLPrivateFeature, |
158 | kBlendFuncExtended_GLSLPrivateFeature, |
159 | kFramebufferFetch_GLSLPrivateFeature, |
160 | kNoPerspectiveInterpolation_GLSLPrivateFeature, |
161 | kSampleVariables_GLSLPrivateFeature, |
162 | kLastGLSLPrivateFeature = kSampleVariables_GLSLPrivateFeature |
163 | }; |
164 | |
165 | /* |
166 | * A general function which enables an extension in a shader if the feature bit is not present |
167 | * |
168 | * @return true if the feature bit was not yet present, false otherwise. |
169 | */ |
170 | bool addFeature(uint32_t featureBit, const char* extensionName); |
171 | |
172 | enum InterfaceQualifier { |
173 | kIn_InterfaceQualifier, |
174 | kOut_InterfaceQualifier, |
175 | kLastInterfaceQualifier = kOut_InterfaceQualifier |
176 | }; |
177 | |
178 | /* |
179 | * A low level function to build default layout qualifiers. |
180 | * |
181 | * e.g. layout(param1, param2, ...) out; |
182 | * |
183 | * GLSL allows default layout qualifiers for in, out, and uniform. |
184 | */ |
185 | void addLayoutQualifier(const char* param, InterfaceQualifier); |
186 | |
187 | void compileAndAppendLayoutQualifiers(); |
188 | |
189 | void nextStage() { |
190 | fShaderStrings.push_back(); |
191 | fCodeIndex++; |
192 | } |
193 | |
194 | void deleteStage() { |
195 | fShaderStrings.pop_back(); |
196 | fCodeIndex--; |
197 | } |
198 | |
199 | SkString& extensions() { return fShaderStrings[kExtensions]; } |
200 | SkString& definitions() { return fShaderStrings[kDefinitions]; } |
201 | SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; } |
202 | SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; } |
203 | SkString& uniforms() { return fShaderStrings[kUniforms]; } |
204 | SkString& inputs() { return fShaderStrings[kInputs]; } |
205 | SkString& outputs() { return fShaderStrings[kOutputs]; } |
206 | SkString& functions() { return fShaderStrings[kFunctions]; } |
207 | SkString& main() { return fShaderStrings[kMain]; } |
208 | SkString& code() { return fShaderStrings[fCodeIndex]; } |
209 | |
210 | virtual void onFinalize() = 0; |
211 | |
212 | enum { |
213 | kExtensions, |
214 | kDefinitions, |
215 | kPrecisionQualifier, |
216 | kLayoutQualifiers, |
217 | kUniforms, |
218 | kInputs, |
219 | kOutputs, |
220 | kFunctions, |
221 | kMain, |
222 | kCode, |
223 | |
224 | kPrealloc = kCode + 6, // 6 == Reasonable upper bound on number of processor stages |
225 | }; |
226 | |
227 | GrGLSLProgramBuilder* fProgramBuilder; |
228 | SkSL::String fCompilerString; |
229 | SkSTArray<kPrealloc, SkString> fShaderStrings; |
230 | SkString fCode; |
231 | SkString fFunctions; |
232 | SkString fExtensions; |
233 | |
234 | VarArray fInputs; |
235 | VarArray fOutputs; |
236 | uint32_t fFeaturesAddedMask; |
237 | SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1]; |
238 | int fCodeIndex; |
239 | bool fFinalized; |
240 | |
241 | friend class GrCCCoverageProcessor; // to access code(). |
242 | friend class GrGLSLProgramBuilder; |
243 | friend class GrGLProgramBuilder; |
244 | friend class GrDawnProgramBuilder; |
245 | friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature. |
246 | friend class GrGLPathProgramBuilder; // to access fInputs. |
247 | friend class GrVkPipelineStateBuilder; |
248 | friend class GrMtlPipelineStateBuilder; |
249 | }; |
250 | #endif |
251 | |