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
19class GrGLSLColorSpaceXformHelper;
20
21/**
22 base class for all shaders builders
23*/
24class GrGLSLShaderBuilder {
25public:
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
155protected:
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