| 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 |  |