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/core/SkTBlockList.h"
16#include "src/gpu/GrShaderVar.h"
17#include "src/gpu/glsl/GrGLSLUniformHandler.h"
18
19#include <stdarg.h>
20
21class GrGLSLColorSpaceXformHelper;
22
23namespace SkSL {
24    class ThreadContext;
25}
26
27/**
28  base class for all shaders builders
29*/
30class GrGLSLShaderBuilder {
31public:
32    GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
33    virtual ~GrGLSLShaderBuilder() {}
34
35    using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
36
37    /** Appends a 2D texture sample with projection if necessary. The vec length and swizzle
38        order of the result depends on the GrProcessor::TextureSampler associated with the
39        SamplerHandle.
40        */
41    void appendTextureLookup(SkString* out, SamplerHandle, const char* coordName) const;
42
43    /** Version of above that appends the result to the shader code instead.*/
44    void appendTextureLookup(SamplerHandle,
45                             const char* coordName,
46                             GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
47
48    /** Does the work of appendTextureLookup and blends the result by dst, treating the texture
49        lookup as the src input to the blend. The dst is assumed to be half4 and the result is
50        always a half4. If dst is nullptr we use half4(1) as the blend dst. */
51    void appendTextureLookupAndBlend(const char* dst,
52                                     SkBlendMode,
53                                     SamplerHandle,
54                                     const char* coordName,
55                                     GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
56
57    /** Appends a load of an input attachment into the shader code. */
58    void appendInputLoad(SamplerHandle);
59
60    /** Adds a helper function to facilitate color gamut transformation, and produces code that
61        returns the srcColor transformed into a new gamut (via multiplication by the xform from
62        colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
63        determines if the source is premultipled or not). */
64    void appendColorGamutXform(SkString* out, const char* srcColor,
65                               GrGLSLColorSpaceXformHelper* colorXformHelper);
66
67    /** Version of above that appends the result to the shader code instead. */
68    void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
69
70    /**
71    * Adds a constant declaration to the top of the shader.
72    */
73    void defineConstant(const char* type, const char* name, const char* value) {
74        this->definitions().appendf("const %s %s = %s;\n", type, name, value);
75    }
76
77    void defineConstant(const char* name, int value) {
78        this->definitions().appendf("const int %s = %i;\n", name, value);
79    }
80
81    void defineConstant(const char* name, float value) {
82        this->definitions().appendf("const float %s = %f;\n", name, value);
83    }
84
85    void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
86       this->definitions().appendf("const %s %s = ", type, name);
87       va_list args;
88       va_start(args, fmt);
89       this->definitions().appendVAList(fmt, args);
90       va_end(args);
91       this->definitions().append(";\n");
92    }
93
94    void definitionAppend(const char* str) { this->definitions().append(str); }
95
96    void declareGlobal(const GrShaderVar&);
97
98    // Generates a unique variable name for holding the result of a temporary expression when it's
99    // not reasonable to just add a new block for scoping. Does not declare anything.
100    SkString newTmpVarName(const char* suffix) {
101        int tmpIdx = fTmpVariableCounter++;
102        return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix);
103    }
104
105    /**
106     * Called by GrGLSLProcessors to add code to one of the shaders.
107     */
108    void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
109       va_list args;
110       va_start(args, format);
111       this->code().appendVAList(format, args);
112       va_end(args);
113    }
114
115    void codeAppend(const char* str) { this->code().append(str); }
116
117    void codeAppend(const char* str, size_t length) { this->code().append(str, length); }
118
119    void codeAppend(std::unique_ptr<SkSL::Statement> stmt);
120
121    void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
122       va_list args;
123       va_start(args, format);
124       this->code().prependVAList(format, args);
125       va_end(args);
126    }
127
128    /**
129     * Appends a variable declaration to one of the shaders
130     */
131    void declAppend(const GrShaderVar& var);
132
133    /**
134     * Generates a mangled name for a helper function in the fragment shader. Will give consistent
135     * results if called more than once.
136     */
137    SkString getMangledFunctionName(const char* baseName);
138
139    /** Emits a prototype for a helper function outside of main() in the fragment shader. */
140    void emitFunctionPrototype(GrSLType returnType,
141                               const char* mangledName,
142                               SkSpan<const GrShaderVar> args);
143
144    void emitFunctionPrototype(const char* declaration);
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     */
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:
169        ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
170            SkASSERT(builder);
171            fBuilder->codeAppend("{");
172        }
173
174        ~ShaderBlock() {
175            fBuilder->codeAppend("}");
176        }
177    private:
178        GrGLSLShaderBuilder* fBuilder;
179    };
180
181protected:
182    typedef SkTBlockList<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
226    void nextStage() {
227        fShaderStrings.push_back();
228        fCodeIndex++;
229    }
230
231    void deleteStage() {
232        fShaderStrings.pop_back();
233        fCodeIndex--;
234    }
235
236    SkString& extensions() { return fShaderStrings[kExtensions]; }
237    SkString& definitions() { return fShaderStrings[kDefinitions]; }
238    SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
239    SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
240    SkString& uniforms() { return fShaderStrings[kUniforms]; }
241    SkString& inputs() { return fShaderStrings[kInputs]; }
242    SkString& outputs() { return fShaderStrings[kOutputs]; }
243    SkString& functions() { return fShaderStrings[kFunctions]; }
244    SkString& main() { return fShaderStrings[kMain]; }
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 GrGLSLProgramBuilder;
284    friend class GrGLProgramBuilder;
285    friend class GrD3DPipelineStateBuilder;
286    friend class GrDawnProgramBuilder;
287    friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
288    friend class GrGLPathProgramBuilder; // to access fInputs.
289    friend class GrVkPipelineStateBuilder;
290    friend class GrMtlPipelineStateBuilder;
291    friend class SkSL::ThreadContext;
292};
293#endif
294