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 GrGLProgramBuilder_DEFINED 9 #define GrGLProgramBuilder_DEFINED 10 11 #include "GrAllocator.h" 12 #include "GrBackendProcessorFactory.h" 13 #include "GrColor.h" 14 #include "GrProcessor.h" 15 #include "GrGLFragmentShaderBuilder.h" 16 #include "GrGLGeometryShaderBuilder.h" 17 #include "GrGLVertexShaderBuilder.h" 18 #include "SkTypes.h" 19 #include "gl/GrGLProcessor.h" 20 #include "gl/GrGLProgramDesc.h" 21 #include "gl/GrGLProgramEffects.h" 22 #include "gl/GrGLSL.h" 23 #include "gl/GrGLProgramDataManager.h" 24 25 #include <stdarg.h> 26 27 class GrGLContextInfo; 28 class GrProcessorStage; 29 class GrGLProgramDesc; 30 31 /** 32 Contains all the incremental state of a shader as it is being built,as well as helpers to 33 manipulate that state. 34 */ 35 class GrGLProgramBuilder { 36 public: 37 enum ShaderVisibility { 38 kVertex_Visibility = 0x1, 39 kGeometry_Visibility = 0x2, 40 kFragment_Visibility = 0x4, 41 }; 42 43 typedef GrGLProgramDataManager::UniformHandle UniformHandle; 44 typedef GrGLProgramDataManager::VaryingHandle VaryingHandle; 45 46 // Handles for program uniforms (other than per-effect uniforms) 47 struct BuiltinUniformHandles { 48 UniformHandle fViewMatrixUni; 49 UniformHandle fRTAdjustmentUni; 50 UniformHandle fColorUni; 51 UniformHandle fCoverageUni; 52 53 // We use the render target height to provide a y-down frag coord when specifying 54 // origin_upper_left is not supported. 55 UniformHandle fRTHeightUni; 56 57 // Uniforms for computing texture coords to do the dst-copy lookup 58 UniformHandle fDstCopyTopLeftUni; 59 UniformHandle fDstCopyScaleUni; 60 UniformHandle fDstCopySamplerUni; 61 }; 62 63 struct UniformInfo { 64 GrGLShaderVar fVariable; 65 uint32_t fVisibility; 66 GrGLint fLocation; 67 }; 68 69 // This uses an allocator rather than array so that the GrGLShaderVars don't move in memory 70 // after they are inserted. Users of GrGLShaderBuilder get refs to the vars and ptrs to their 71 // name strings. Otherwise, we'd have to hand out copies. 72 typedef GrTAllocator<UniformInfo> UniformInfoArray; 73 74 struct SeparableVaryingInfo { 75 GrGLShaderVar fVariable; 76 GrGLint fLocation; 77 }; 78 79 typedef GrTAllocator<SeparableVaryingInfo> SeparableVaryingInfoArray; 80 81 /** Generates a shader program. 82 * 83 * The program implements what is specified in the stages given as input. 84 * After successful generation, the builder result objects are available 85 * to be used. 86 * @return true if generation was successful. 87 */ 88 89 bool genProgram(const GrGeometryStage* inGeometryProcessor, 90 const GrFragmentStage* inColorStages[], 91 const GrFragmentStage* inCoverageStages[]); 92 93 GrGLProgramEffects* getGeometryProcessor() const { 94 SkASSERT(fProgramID); return fGeometryProcessor.get(); 95 } 96 GrGLProgramEffects* getColorEffects() const { SkASSERT(fProgramID); return fColorEffects.get(); } 97 GrGLProgramEffects* getCoverageEffects() const { SkASSERT(fProgramID); return fCoverageEffects.get(); } 98 const BuiltinUniformHandles& getBuiltinUniformHandles() const { 99 SkASSERT(fProgramID); 100 return fUniformHandles; 101 } 102 GrGLuint getProgramID() const { SkASSERT(fProgramID); return fProgramID; } 103 bool hasVertexShader() const { SkASSERT(fProgramID); return !fFragOnly; } 104 int getTexCoordSetCount() const { SkASSERT(fProgramID); return fTexCoordSetCnt; } 105 const UniformInfoArray& getUniformInfos() const { return fUniforms; } 106 const SeparableVaryingInfoArray& getSeparableVaryingInfos() const { 107 return fSeparableVaryingInfos; 108 } 109 110 virtual ~GrGLProgramBuilder() {} 111 112 /** Add a uniform variable to the current program, that has visibility in one or more shaders. 113 visibility is a bitfield of ShaderVisibility values indicating from which shaders the 114 uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not 115 supported at this time. The actual uniform name will be mangled. If outName is not NULL then 116 it will refer to the final uniform name after return. Use the addUniformArray variant to add 117 an array of uniforms. */ 118 GrGLProgramDataManager::UniformHandle addUniform(uint32_t visibility, 119 GrSLType type, 120 const char* name, 121 const char** outName = NULL) { 122 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName); 123 } 124 GrGLProgramDataManager::UniformHandle addUniformArray(uint32_t visibility, 125 GrSLType type, 126 const char* name, 127 int arrayCount, 128 const char** outName = NULL); 129 130 const GrGLShaderVar& getUniformVariable(GrGLProgramDataManager::UniformHandle u) const { 131 return fUniforms[u.toShaderBuilderIndex()].fVariable; 132 } 133 134 /** 135 * Shortcut for getUniformVariable(u).c_str() 136 */ 137 const char* getUniformCStr(GrGLProgramDataManager::UniformHandle u) const { 138 return this->getUniformVariable(u).c_str(); 139 } 140 141 const GrGLContextInfo& ctxInfo() const; 142 143 GrGLFragmentShaderBuilder* getFragmentShaderBuilder() { return &fFS; } 144 GrGpuGL* gpu() const { return fGpu; } 145 146 protected: 147 typedef GrTAllocator<GrGLShaderVar> VarArray; 148 GrGLProgramBuilder(GrGpuGL*, const GrGLProgramDesc&); 149 150 const GrGLProgramDesc& desc() const { return fDesc; } 151 152 // Helper for emitEffects(). 153 void createAndEmitEffects(const GrFragmentStage* effectStages[], 154 int effectCnt, 155 const GrGLProgramDesc::EffectKeyProvider&, 156 GrGLSLExpr4* inOutFSColor); 157 158 /* 159 * A helper function called to emit the geometry processor as well as individual coverage 160 * and color stages. this will call into subclasses emit effect 161 */ 162 void emitEffect(const GrProcessorStage& effectStage, 163 int effectIndex, 164 const GrGLProgramDesc::EffectKeyProvider& keyProvider, 165 GrGLSLExpr4* inColor, 166 GrGLSLExpr4* outColor); 167 168 /** 169 * Helper for emitEffect() in subclasses. Emits uniforms for an effect's texture accesses and 170 * appends the necessary data to the TextureSamplerArray* object so effects can add texture 171 * lookups to their code. This method is only meant to be called during the construction phase. 172 */ 173 void emitSamplers(const GrProcessor& effect, 174 GrGLProcessor::TextureSamplerArray* outSamplers); 175 176 // Generates a name for a variable. The generated string will be name prefixed by the prefix 177 // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're 178 // generating stage code. 179 void nameVariable(SkString* out, char prefix, const char* name); 180 181 virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const; 182 183 virtual void bindProgramLocations(GrGLuint programId); 184 void resolveProgramLocations(GrGLuint programId); 185 186 void appendDecls(const VarArray&, SkString*) const; 187 void appendUniformDecls(ShaderVisibility, SkString*) const; 188 189 class CodeStage : SkNoncopyable { 190 public: 191 CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} 192 193 bool inStageCode() const { 194 this->validate(); 195 return SkToBool(fEffectStage); 196 } 197 198 const GrProcessorStage* effectStage() const { 199 this->validate(); 200 return fEffectStage; 201 } 202 203 int stageIndex() const { 204 this->validate(); 205 return fCurrentIndex; 206 } 207 208 class AutoStageRestore : SkNoncopyable { 209 public: 210 AutoStageRestore(CodeStage* codeStage, const GrProcessorStage* newStage) { 211 SkASSERT(codeStage); 212 fSavedIndex = codeStage->fCurrentIndex; 213 fSavedEffectStage = codeStage->fEffectStage; 214 215 if (NULL == newStage) { 216 codeStage->fCurrentIndex = -1; 217 } else { 218 codeStage->fCurrentIndex = codeStage->fNextIndex++; 219 } 220 codeStage->fEffectStage = newStage; 221 222 fCodeStage = codeStage; 223 } 224 ~AutoStageRestore() { 225 fCodeStage->fCurrentIndex = fSavedIndex; 226 fCodeStage->fEffectStage = fSavedEffectStage; 227 } 228 private: 229 CodeStage* fCodeStage; 230 int fSavedIndex; 231 const GrProcessorStage* fSavedEffectStage; 232 }; 233 private: 234 void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); } 235 int fNextIndex; 236 int fCurrentIndex; 237 const GrProcessorStage* fEffectStage; 238 }; 239 240 class GrGLProcessorEmitterInterface { 241 public: 242 virtual ~GrGLProcessorEmitterInterface() {} 243 virtual GrGLProcessor* createGLInstance() = 0; 244 virtual void emit(const GrProcessorKey& key, 245 const char* outColor, 246 const char* inColor, 247 const GrGLProcessor::TransformedCoordsArray& coords, 248 const GrGLProcessor::TextureSamplerArray& samplers) = 0; 249 }; 250 251 class GrGLFragmentProcessorEmitter : public GrGLProcessorEmitterInterface { 252 public: 253 GrGLFragmentProcessorEmitter(GrGLProgramBuilder* builder) 254 : fBuilder(builder) 255 , fFragmentProcessor(NULL) 256 , fGLFragmentProcessor(NULL) {} 257 virtual ~GrGLFragmentProcessorEmitter() {} 258 void set(const GrFragmentProcessor* fp) { 259 SkASSERT(NULL == fFragmentProcessor); 260 fFragmentProcessor = fp; 261 } 262 virtual GrGLProcessor* createGLInstance() { 263 SkASSERT(fFragmentProcessor); 264 SkASSERT(NULL == fGLFragmentProcessor); 265 fGLFragmentProcessor = 266 fFragmentProcessor->getFactory().createGLInstance(*fFragmentProcessor); 267 return fGLFragmentProcessor; 268 } 269 virtual void emit(const GrProcessorKey& key, 270 const char* outColor, 271 const char* inColor, 272 const GrGLProcessor::TransformedCoordsArray& coords, 273 const GrGLProcessor::TextureSamplerArray& samplers) { 274 SkASSERT(fFragmentProcessor); 275 SkASSERT(fGLFragmentProcessor); 276 fGLFragmentProcessor->emitCode(fBuilder, *fFragmentProcessor, key, outColor, inColor, 277 coords, samplers); 278 // this will not leak because it hasa already been used by createGLInstance 279 fGLFragmentProcessor = NULL; 280 fFragmentProcessor = NULL; 281 } 282 private: 283 GrGLProgramBuilder* fBuilder; 284 const GrFragmentProcessor* fFragmentProcessor; 285 GrGLFragmentProcessor* fGLFragmentProcessor; 286 }; 287 288 GrGLProcessorEmitterInterface* fEffectEmitter; 289 CodeStage fCodeStage; 290 SkAutoTUnref<GrGLProgramEffects> fGeometryProcessor; 291 SkAutoTUnref<GrGLProgramEffects> fColorEffects; 292 SkAutoTUnref<GrGLProgramEffects> fCoverageEffects; 293 BuiltinUniformHandles fUniformHandles; 294 bool fFragOnly; 295 int fTexCoordSetCnt; 296 GrGLuint fProgramID; 297 GrGLFragmentShaderBuilder fFS; 298 SeparableVaryingInfoArray fSeparableVaryingInfos; 299 300 private: 301 virtual void createAndEmitEffects(const GrGeometryStage* geometryProcessor, 302 const GrFragmentStage* colorStages[], 303 const GrFragmentStage* coverageStages[], 304 GrGLSLExpr4* inputColor, 305 GrGLSLExpr4* inputCoverage) = 0; 306 /* 307 * Subclasses override emitEffect below to emit data and code for a specific single effect 308 */ 309 virtual void emitEffect(const GrProcessorStage&, 310 const GrProcessorKey&, 311 const char* outColor, 312 const char* inColor, 313 int stageIndex) = 0; 314 315 /* 316 * Because we have fragment only builders, and those builders need to implement a subclass 317 * of program effects, we have to have base classes overload the program effects here 318 */ 319 virtual GrGLProgramEffects* getProgramEffects() = 0; 320 321 /** 322 * Compiles all the shaders, links them into a program, and writes the program id to the output 323 * struct. 324 **/ 325 bool finish(); 326 327 GrGLFragmentProcessorEmitter fGrProcessorEmitter; 328 329 const GrGLProgramDesc& fDesc; 330 GrGpuGL* fGpu; 331 UniformInfoArray fUniforms; 332 333 friend class GrGLShaderBuilder; 334 friend class GrGLVertexShaderBuilder; 335 friend class GrGLFragmentShaderBuilder; 336 friend class GrGLGeometryShaderBuilder; 337 }; 338 339 #endif 340