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 "GrAllocator.h" 12#include "glsl/GrGLSLShaderVar.h" 13#include "SkTDArray.h" 14 15#include <stdarg.h> 16 17class GrGLSLProgramBuilder; 18class GrGLSLTextureSampler; 19 20/** 21 base class for all shaders builders 22*/ 23class GrGLSLShaderBuilder { 24public: 25 GrGLSLShaderBuilder(GrGLSLProgramBuilder* program); 26 virtual ~GrGLSLShaderBuilder() {} 27 28 /* 29 * We put texture lookups in the base class because it is TECHNICALLY possible to do texture 30 * lookups in any kind of shader. However, for the time being using these calls on non-fragment 31 * shaders will result in a shader compilation error as texture sampler uniforms are only 32 * visible to the fragment shader. It would not be hard to change this behavior, if someone 33 * actually wants to do texture lookups in a non-fragment shader 34 * 35 * TODO if append texture lookup is used on a non-fragment shader, sampler uniforms should be 36 * made visible to that shaders 37 */ 38 /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or 39 Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle 40 order of the result depends on the GrTextureAccess associated with the GrGLSLTextureSampler. 41 */ 42 void appendTextureLookup(SkString* out, 43 const GrGLSLTextureSampler&, 44 const char* coordName, 45 GrSLType coordType = kVec2f_GrSLType) const; 46 47 /** Version of above that appends the result to the fragment shader code instead.*/ 48 void appendTextureLookup(const GrGLSLTextureSampler&, 49 const char* coordName, 50 GrSLType coordType = kVec2f_GrSLType); 51 52 53 /** Does the work of appendTextureLookup and modulates the result by modulation. The result is 54 always a vec4. modulation and the swizzle specified by GrGLSLTextureSampler must both be 55 vec4 or float. If modulation is "" or nullptr it this function acts as though 56 appendTextureLookup were called. */ 57 void appendTextureLookupAndModulate(const char* modulation, 58 const GrGLSLTextureSampler&, 59 const char* coordName, 60 GrSLType coordType = kVec2f_GrSLType); 61 62 /** 63 * Adds a #define directive to the top of the shader. 64 */ 65 void define(const char* macro, const char* replacement) { 66 this->definitions().appendf("#define %s %s\n", macro, replacement); 67 } 68 69 void define(const char* macro, int replacement) { 70 this->definitions().appendf("#define %s %i\n", macro, replacement); 71 } 72 73 void definef(const char* macro, const char* replacement, ...) { 74 this->definitions().appendf("#define %s ", macro); 75 va_list args; 76 va_start(args, replacement); 77 this->definitions().appendVAList(replacement, args); 78 va_end(args); 79 this->definitions().append("\n"); 80 } 81 82 /** 83 * Called by GrGLSLProcessors to add code to one of the shaders. 84 */ 85 void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 86 va_list args; 87 va_start(args, format); 88 this->code().appendVAList(format, args); 89 va_end(args); 90 } 91 92 void codeAppend(const char* str) { this->code().append(str); } 93 94 void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { 95 va_list args; 96 va_start(args, format); 97 this->code().prependVAList(format, args); 98 va_end(args); 99 } 100 101 /** 102 * Appends a variable declaration to one of the shaders 103 */ 104 void declAppend(const GrGLSLShaderVar& var); 105 106 /** Emits a helper function outside of main() in the fragment shader. */ 107 void emitFunction(GrSLType returnType, 108 const char* name, 109 int argCnt, 110 const GrGLSLShaderVar* args, 111 const char* body, 112 SkString* outName); 113 114 /* 115 * Combines the various parts of the shader to create a single finalized shader string. 116 */ 117 void finalize(uint32_t visibility); 118 119 /* 120 * Get parent builder for adding uniforms 121 */ 122 GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; } 123 124 /** 125 * Helper for begining and ending a block in the shader code. 126 */ 127 class ShaderBlock { 128 public: 129 ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) { 130 SkASSERT(builder); 131 fBuilder->codeAppend("{"); 132 } 133 134 ~ShaderBlock() { 135 fBuilder->codeAppend("}"); 136 } 137 private: 138 GrGLSLShaderBuilder* fBuilder; 139 }; 140 141protected: 142 typedef GrTAllocator<GrGLSLShaderVar> VarArray; 143 void appendDecls(const VarArray& vars, SkString* out) const; 144 145 /** 146 * Features that should only be enabled internally by the builders. 147 */ 148 enum GLSLPrivateFeature { 149 kFragCoordConventions_GLSLPrivateFeature, 150 kBlendEquationAdvanced_GLSLPrivateFeature, 151 kBlendFuncExtended_GLSLPrivateFeature, 152 kExternalTexture_GLSLPrivateFeature, 153 kFramebufferFetch_GLSLPrivateFeature, 154 kNoPerspectiveInterpolation_GLSLPrivateFeature, 155 kSampleVariables_GLSLPrivateFeature, 156 kSampleMaskOverrideCoverage_GLSLPrivateFeature, 157 kLastGLSLPrivateFeature = kSampleMaskOverrideCoverage_GLSLPrivateFeature 158 }; 159 160 /* 161 * A general function which enables an extension in a shader if the feature bit is not present 162 * 163 * @return true if the feature bit was not yet present, false otherwise. 164 */ 165 bool addFeature(uint32_t featureBit, const char* extensionName); 166 167 enum InterfaceQualifier { 168 kOut_InterfaceQualifier, 169 kLastInterfaceQualifier = kOut_InterfaceQualifier 170 }; 171 172 /* 173 * A low level function to build default layout qualifiers. 174 * 175 * e.g. layout(param1, param2, ...) out; 176 * 177 * GLSL allows default layout qualifiers for in, out, and uniform. 178 */ 179 void addLayoutQualifier(const char* param, InterfaceQualifier); 180 181 void compileAndAppendLayoutQualifiers(); 182 183 void nextStage() { 184 fShaderStrings.push_back(); 185 fCompilerStrings.push_back(this->code().c_str()); 186 fCompilerStringLengths.push_back((int)this->code().size()); 187 fCodeIndex++; 188 } 189 190 SkString& versionDecl() { return fShaderStrings[kVersionDecl]; } 191 SkString& extensions() { return fShaderStrings[kExtensions]; } 192 SkString& definitions() { return fShaderStrings[kDefinitions]; } 193 SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; } 194 SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; } 195 SkString& uniforms() { return fShaderStrings[kUniforms]; } 196 SkString& inputs() { return fShaderStrings[kInputs]; } 197 SkString& outputs() { return fShaderStrings[kOutputs]; } 198 SkString& functions() { return fShaderStrings[kFunctions]; } 199 SkString& main() { return fShaderStrings[kMain]; } 200 SkString& code() { return fShaderStrings[fCodeIndex]; } 201 202 virtual void onFinalize() = 0; 203 204 enum { 205 kVersionDecl, 206 kExtensions, 207 kDefinitions, 208 kPrecisionQualifier, 209 kLayoutQualifiers, 210 kUniforms, 211 kInputs, 212 kOutputs, 213 kFunctions, 214 kMain, 215 kCode, 216 }; 217 218 GrGLSLProgramBuilder* fProgramBuilder; 219 SkSTArray<kCode, const char*, true> fCompilerStrings; 220 SkSTArray<kCode, int, true> fCompilerStringLengths; 221 SkSTArray<kCode, SkString> fShaderStrings; 222 SkString fCode; 223 SkString fFunctions; 224 SkString fExtensions; 225 226 VarArray fInputs; 227 VarArray fOutputs; 228 uint32_t fFeaturesAddedMask; 229 SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1]; 230 int fCodeIndex; 231 bool fFinalized; 232 233 friend class GrGLSLProgramBuilder; 234 friend class GrGLProgramBuilder; 235 friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature. 236 friend class GrGLPathProgramBuilder; // to access fInputs. 237 friend class GrVkProgramBuilder; 238}; 239#endif 240