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/GrAllocator.h"
13 #include "src/gpu/GrShaderVar.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);
~GrGLSLShaderBuilder()27     virtual ~GrGLSLShaderBuilder() {}
28 
29     using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
30 
31     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
32         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
33         order of the result depends on the GrProcessor::TextureSampler associated with the
34         SamplerHandle.
35         */
36     void appendTextureLookup(SkString* out,
37                              SamplerHandle,
38                              const char* coordName,
39                              GrSLType coordType = kHalf2_GrSLType) const;
40 
41     /** Version of above that appends the result to the shader code instead.*/
42     void appendTextureLookup(SamplerHandle,
43                              const char* coordName,
44                              GrSLType coordType = kHalf2_GrSLType,
45                              GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
46 
47 
48     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
49         always a half4. modulation and the swizzle specified by SamplerHandle must both be
50         half4 or half. If modulation is "" or nullptr it this function acts as though
51         appendTextureLookup were called. */
52     void appendTextureLookupAndModulate(const char* modulation,
53                                         SamplerHandle,
54                                         const char* coordName,
55                                         GrSLType coordType = kHalf2_GrSLType,
56                                         GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
57 
58     /** Adds a helper function to facilitate color gamut transformation, and produces code that
59         returns the srcColor transformed into a new gamut (via multiplication by the xform from
60         colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
61         determines if the source is premultipled or not). */
62     void appendColorGamutXform(SkString* out, const char* srcColor,
63                                GrGLSLColorSpaceXformHelper* colorXformHelper);
64 
65     /** Version of above that appends the result to the shader code instead. */
66     void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
67 
68     /**
69     * Adds a constant declaration to the top of the shader.
70     */
defineConstant(const char * type,const char * name,const char * value)71     void defineConstant(const char* type, const char* name, const char* value) {
72         this->definitions().appendf("const %s %s = %s;\n", type, name, value);
73     }
74 
defineConstant(const char * name,int value)75     void defineConstant(const char* name, int value) {
76         this->definitions().appendf("const int %s = %i;\n", name, value);
77     }
78 
defineConstant(const char * name,float value)79     void defineConstant(const char* name, float value) {
80         this->definitions().appendf("const float %s = %f;\n", name, value);
81     }
82 
defineConstantf(const char * type,const char * name,const char * fmt,...)83     void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
84        this->definitions().appendf("const %s %s = ", type, name);
85        va_list args;
86        va_start(args, fmt);
87        this->definitions().appendVAList(fmt, args);
88        va_end(args);
89        this->definitions().append(";\n");
90     }
91 
92     void declareGlobal(const GrShaderVar&);
93 
94     /**
95     * Called by GrGLSLProcessors to add code to one of the shaders.
96     */
codeAppendf(const char format[],...)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 
codeAppend(const char * str)104     void codeAppend(const char* str) { this->code().append(str); }
105 
codeAppend(const char * str,size_t length)106     void codeAppend(const char* str, size_t length) { this->code().append(str, length); }
107 
codePrependf(const char format[],...)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      */
getProgramBuilder()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:
ShaderBlock(GrGLSLShaderBuilder * builder)143         ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
144             SkASSERT(builder);
145             fBuilder->codeAppend("{");
146         }
147 
~ShaderBlock()148         ~ShaderBlock() {
149             fBuilder->codeAppend("}");
150         }
151     private:
152         GrGLSLShaderBuilder* fBuilder;
153     };
154 
155 protected:
156     typedef GrTAllocator<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 
nextStage()196     void nextStage() {
197         fShaderStrings.push_back();
198         fCodeIndex++;
199     }
200 
deleteStage()201     void deleteStage() {
202         fShaderStrings.pop_back();
203         fCodeIndex--;
204     }
205 
extensions()206     SkString& extensions() { return fShaderStrings[kExtensions]; }
definitions()207     SkString& definitions() { return fShaderStrings[kDefinitions]; }
precisionQualifier()208     SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
layoutQualifiers()209     SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
uniforms()210     SkString& uniforms() { return fShaderStrings[kUniforms]; }
inputs()211     SkString& inputs() { return fShaderStrings[kInputs]; }
outputs()212     SkString& outputs() { return fShaderStrings[kOutputs]; }
functions()213     SkString& functions() { return fShaderStrings[kFunctions]; }
main()214     SkString& main() { return fShaderStrings[kMain]; }
code()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     friend class GrCCCoverageProcessor; // to access code().
249     friend class GrGLSLProgramBuilder;
250     friend class GrGLProgramBuilder;
251     friend class GrDawnProgramBuilder;
252     friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
253     friend class GrGLPathProgramBuilder; // to access fInputs.
254     friend class GrVkPipelineStateBuilder;
255     friend class GrMtlPipelineStateBuilder;
256 };
257 #endif
258