|
1 /* |
|
2 * Copyright 2012 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 GrGLShaderBuilder_DEFINED |
|
9 #define GrGLShaderBuilder_DEFINED |
|
10 |
|
11 #include "GrAllocator.h" |
|
12 #include "GrBackendEffectFactory.h" |
|
13 #include "GrColor.h" |
|
14 #include "GrEffect.h" |
|
15 #include "SkTypes.h" |
|
16 #include "gl/GrGLProgramEffects.h" |
|
17 #include "gl/GrGLSL.h" |
|
18 #include "gl/GrGLUniformManager.h" |
|
19 |
|
20 #include <stdarg.h> |
|
21 |
|
22 class GrGLContextInfo; |
|
23 class GrEffectStage; |
|
24 class GrGLProgramDesc; |
|
25 |
|
26 /** |
|
27 Contains all the incremental state of a shader as it is being built,as well as helpers to |
|
28 manipulate that state. |
|
29 */ |
|
30 class GrGLShaderBuilder { |
|
31 public: |
|
32 typedef GrTAllocator<GrGLShaderVar> VarArray; |
|
33 typedef GrBackendEffectFactory::EffectKey EffectKey; |
|
34 typedef GrGLProgramEffects::TextureSampler TextureSampler; |
|
35 typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray; |
|
36 typedef GrGLUniformManager::BuilderUniform BuilderUniform; |
|
37 |
|
38 enum ShaderVisibility { |
|
39 kVertex_Visibility = 0x1, |
|
40 kGeometry_Visibility = 0x2, |
|
41 kFragment_Visibility = 0x4, |
|
42 }; |
|
43 |
|
44 GrGLShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); |
|
45 virtual ~GrGLShaderBuilder() {} |
|
46 |
|
47 /** |
|
48 * Use of these features may require a GLSL extension to be enabled. Shaders may not compile |
|
49 * if code is added that uses one of these features without calling enableFeature() |
|
50 */ |
|
51 enum GLSLFeature { |
|
52 kStandardDerivatives_GLSLFeature = 0, |
|
53 |
|
54 kLastGLSLFeature = kStandardDerivatives_GLSLFeature |
|
55 }; |
|
56 |
|
57 /** |
|
58 * If the feature is supported then true is returned and any necessary #extension declarations |
|
59 * are added to the shaders. If the feature is not supported then false will be returned. |
|
60 */ |
|
61 bool enableFeature(GLSLFeature); |
|
62 |
|
63 /** |
|
64 * Called by GrGLEffects to add code the fragment shader. |
|
65 */ |
|
66 void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { |
|
67 va_list args; |
|
68 va_start(args, format); |
|
69 fFSCode.appendVAList(format, args); |
|
70 va_end(args); |
|
71 } |
|
72 |
|
73 void fsCodeAppend(const char* str) { fFSCode.append(str); } |
|
74 |
|
75 /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or |
|
76 Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle |
|
77 order of the result depends on the GrTextureAccess associated with the TextureSampler. */ |
|
78 void appendTextureLookup(SkString* out, |
|
79 const TextureSampler&, |
|
80 const char* coordName, |
|
81 GrSLType coordType = kVec2f_GrSLType) const; |
|
82 |
|
83 /** Version of above that appends the result to the fragment shader code instead.*/ |
|
84 void fsAppendTextureLookup(const TextureSampler&, |
|
85 const char* coordName, |
|
86 GrSLType coordType = kVec2f_GrSLType); |
|
87 |
|
88 |
|
89 /** Does the work of appendTextureLookup and modulates the result by modulation. The result is |
|
90 always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or |
|
91 float. If modulation is "" or NULL it this function acts as though appendTextureLookup were |
|
92 called. */ |
|
93 void fsAppendTextureLookupAndModulate(const char* modulation, |
|
94 const TextureSampler&, |
|
95 const char* coordName, |
|
96 GrSLType coordType = kVec2f_GrSLType); |
|
97 |
|
98 /** Emits a helper function outside of main() in the fragment shader. */ |
|
99 void fsEmitFunction(GrSLType returnType, |
|
100 const char* name, |
|
101 int argCnt, |
|
102 const GrGLShaderVar* args, |
|
103 const char* body, |
|
104 SkString* outName); |
|
105 |
|
106 typedef uint8_t DstReadKey; |
|
107 typedef uint8_t FragPosKey; |
|
108 |
|
109 /** Returns a key for adding code to read the copy-of-dst color in service of effects that |
|
110 require reading the dst. It must not return 0 because 0 indicates that there is no dst |
|
111 copy read at all (in which case this function should not be called). */ |
|
112 static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&); |
|
113 |
|
114 /** Returns a key for reading the fragment location. This should only be called if there is an |
|
115 effect that will requires the fragment position. If the fragment position is not required, |
|
116 the key is 0. */ |
|
117 static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&); |
|
118 |
|
119 /** If texture swizzling is available using tex parameters then it is preferred over mangling |
|
120 the generated shader code. This potentially allows greater reuse of cached shaders. */ |
|
121 static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps); |
|
122 |
|
123 /** Add a uniform variable to the current program, that has visibility in one or more shaders. |
|
124 visibility is a bitfield of ShaderVisibility values indicating from which shaders the |
|
125 uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not |
|
126 supported at this time. The actual uniform name will be mangled. If outName is not NULL then |
|
127 it will refer to the final uniform name after return. Use the addUniformArray variant to add |
|
128 an array of uniforms. |
|
129 */ |
|
130 GrGLUniformManager::UniformHandle addUniform(uint32_t visibility, |
|
131 GrSLType type, |
|
132 const char* name, |
|
133 const char** outName = NULL) { |
|
134 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName); |
|
135 } |
|
136 GrGLUniformManager::UniformHandle addUniformArray(uint32_t visibility, |
|
137 GrSLType type, |
|
138 const char* name, |
|
139 int arrayCount, |
|
140 const char** outName = NULL); |
|
141 |
|
142 const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle u) const { |
|
143 return fUniformManager.getBuilderUniform(fUniforms, u).fVariable; |
|
144 } |
|
145 |
|
146 /** |
|
147 * Shortcut for getUniformVariable(u).c_str() |
|
148 */ |
|
149 const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const { |
|
150 return this->getUniformVariable(u).c_str(); |
|
151 } |
|
152 |
|
153 /** |
|
154 * This returns a variable name to access the 2D, perspective correct version of the coords in |
|
155 * the fragment shader. If the coordinates at index are 3-dimensional, it immediately emits a |
|
156 * perspective divide into the fragment shader (xy / z) to convert them to 2D. |
|
157 */ |
|
158 SkString ensureFSCoords2D(const TransformedCoordsArray&, int index); |
|
159 |
|
160 /** Returns a variable name that represents the position of the fragment in the FS. The position |
|
161 is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */ |
|
162 const char* fragmentPosition(); |
|
163 |
|
164 /** Returns the color of the destination pixel. This may be NULL if no effect advertised |
|
165 that it will read the destination. */ |
|
166 const char* dstColor(); |
|
167 |
|
168 /** |
|
169 * Interfaces used by GrGLProgram. |
|
170 */ |
|
171 const GrGLSLExpr4& getInputColor() const { |
|
172 return fInputColor; |
|
173 } |
|
174 const GrGLSLExpr4& getInputCoverage() const { |
|
175 return fInputCoverage; |
|
176 } |
|
177 |
|
178 /** |
|
179 * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for |
|
180 * deleting it when finished. effectStages contains the effects to add. effectKeys[i] is the key |
|
181 * generated from effectStages[i]. inOutFSColor specifies the input color to the first stage and |
|
182 * is updated to be the output color of the last stage. |
|
183 * The handles to texture samplers for effectStage[i] are added to |
|
184 * effectSamplerHandles[i]. |
|
185 */ |
|
186 virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], |
|
187 const EffectKey effectKeys[], |
|
188 int effectCnt, |
|
189 GrGLSLExpr4* inOutFSColor) = 0; |
|
190 |
|
191 const char* getColorOutputName() const; |
|
192 const char* enableSecondaryOutput(); |
|
193 |
|
194 GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; } |
|
195 GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const { |
|
196 return fDstCopyTopLeftUniform; |
|
197 } |
|
198 GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const { |
|
199 return fDstCopyScaleUniform; |
|
200 } |
|
201 GrGLUniformManager::UniformHandle getColorUniform() const { return fColorUniform; } |
|
202 GrGLUniformManager::UniformHandle getCoverageUniform() const { return fCoverageUniform; } |
|
203 GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const { |
|
204 return fDstCopySamplerUniform; |
|
205 } |
|
206 |
|
207 bool finish(GrGLuint* outProgramId); |
|
208 |
|
209 const GrGLContextInfo& ctxInfo() const; |
|
210 |
|
211 /** |
|
212 * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder |
|
213 * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that |
|
214 * our shaders print pretty without effect writers tracking indentation. |
|
215 */ |
|
216 class FSBlock { |
|
217 public: |
|
218 FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) { |
|
219 SkASSERT(NULL != builder); |
|
220 fBuilder->fsCodeAppend("\t{\n"); |
|
221 } |
|
222 |
|
223 ~FSBlock() { |
|
224 fBuilder->fsCodeAppend("\t}\n"); |
|
225 } |
|
226 private: |
|
227 GrGLShaderBuilder* fBuilder; |
|
228 }; |
|
229 |
|
230 protected: |
|
231 GrGpuGL* gpu() const { return fGpu; } |
|
232 |
|
233 void setInputColor(const GrGLSLExpr4& inputColor) { fInputColor = inputColor; } |
|
234 void setInputCoverage(const GrGLSLExpr4& inputCoverage) { fInputCoverage = inputCoverage; } |
|
235 |
|
236 /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */ |
|
237 GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); } |
|
238 |
|
239 // Generates a name for a variable. The generated string will be name prefixed by the prefix |
|
240 // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're |
|
241 // generating stage code. |
|
242 void nameVariable(SkString* out, char prefix, const char* name); |
|
243 |
|
244 // Helper for emitEffects(). |
|
245 void createAndEmitEffects(GrGLProgramEffectsBuilder*, |
|
246 const GrEffectStage* effectStages[], |
|
247 const EffectKey effectKeys[], |
|
248 int effectCnt, |
|
249 GrGLSLExpr4* inOutFSColor); |
|
250 |
|
251 virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const; |
|
252 virtual void bindProgramLocations(GrGLuint programId) const; |
|
253 |
|
254 void appendDecls(const VarArray&, SkString*) const; |
|
255 void appendUniformDecls(ShaderVisibility, SkString*) const; |
|
256 |
|
257 private: |
|
258 class CodeStage : public SkNoncopyable { |
|
259 public: |
|
260 CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} |
|
261 |
|
262 bool inStageCode() const { |
|
263 this->validate(); |
|
264 return NULL != fEffectStage; |
|
265 } |
|
266 |
|
267 const GrEffectStage* effectStage() const { |
|
268 this->validate(); |
|
269 return fEffectStage; |
|
270 } |
|
271 |
|
272 int stageIndex() const { |
|
273 this->validate(); |
|
274 return fCurrentIndex; |
|
275 } |
|
276 |
|
277 class AutoStageRestore : public SkNoncopyable { |
|
278 public: |
|
279 AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) { |
|
280 SkASSERT(NULL != codeStage); |
|
281 fSavedIndex = codeStage->fCurrentIndex; |
|
282 fSavedEffectStage = codeStage->fEffectStage; |
|
283 |
|
284 if (NULL == newStage) { |
|
285 codeStage->fCurrentIndex = -1; |
|
286 } else { |
|
287 codeStage->fCurrentIndex = codeStage->fNextIndex++; |
|
288 } |
|
289 codeStage->fEffectStage = newStage; |
|
290 |
|
291 fCodeStage = codeStage; |
|
292 } |
|
293 ~AutoStageRestore() { |
|
294 fCodeStage->fCurrentIndex = fSavedIndex; |
|
295 fCodeStage->fEffectStage = fSavedEffectStage; |
|
296 } |
|
297 private: |
|
298 CodeStage* fCodeStage; |
|
299 int fSavedIndex; |
|
300 const GrEffectStage* fSavedEffectStage; |
|
301 }; |
|
302 private: |
|
303 void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); } |
|
304 int fNextIndex; |
|
305 int fCurrentIndex; |
|
306 const GrEffectStage* fEffectStage; |
|
307 } fCodeStage; |
|
308 |
|
309 /** |
|
310 * Features that should only be enabled by GrGLShaderBuilder itself. |
|
311 */ |
|
312 enum GLSLPrivateFeature { |
|
313 kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1, |
|
314 kEXTShaderFramebufferFetch_GLSLPrivateFeature, |
|
315 kNVShaderFramebufferFetch_GLSLPrivateFeature, |
|
316 }; |
|
317 bool enablePrivateFeature(GLSLPrivateFeature); |
|
318 |
|
319 // If we ever have VS/GS features we can expand this to take a bitmask of ShaderVisibility and |
|
320 // track the enables separately for each shader. |
|
321 void addFSFeature(uint32_t featureBit, const char* extensionName); |
|
322 |
|
323 // Interpretation of DstReadKey when generating code |
|
324 enum { |
|
325 kNoDstRead_DstReadKey = 0, |
|
326 kYesDstRead_DstReadKeyBit = 0x1, // Set if we do a dst-copy-read. |
|
327 kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alpha only. |
|
328 kTopLeftOrigin_DstReadKeyBit = 0x4, // Set if dst-copy origin is top-left. |
|
329 }; |
|
330 |
|
331 enum { |
|
332 kNoFragPosRead_FragPosKey = 0, // The fragment positition will not be needed. |
|
333 kTopLeftFragPosRead_FragPosKey = 0x1,// Read frag pos relative to top-left. |
|
334 kBottomLeftFragPosRead_FragPosKey = 0x2,// Read frag pos relative to bottom-left. |
|
335 }; |
|
336 |
|
337 GrGpuGL* fGpu; |
|
338 GrGLUniformManager& fUniformManager; |
|
339 uint32_t fFSFeaturesAddedMask; |
|
340 SkString fFSFunctions; |
|
341 SkString fFSExtensions; |
|
342 VarArray fFSInputs; |
|
343 VarArray fFSOutputs; |
|
344 GrGLUniformManager::BuilderUniformArray fUniforms; |
|
345 |
|
346 SkString fFSCode; |
|
347 |
|
348 bool fSetupFragPosition; |
|
349 GrGLUniformManager::UniformHandle fDstCopySamplerUniform; |
|
350 |
|
351 GrGLSLExpr4 fInputColor; |
|
352 GrGLSLExpr4 fInputCoverage; |
|
353 |
|
354 bool fHasCustomColorOutput; |
|
355 bool fHasSecondaryOutput; |
|
356 |
|
357 GrGLUniformManager::UniformHandle fRTHeightUniform; |
|
358 GrGLUniformManager::UniformHandle fDstCopyTopLeftUniform; |
|
359 GrGLUniformManager::UniformHandle fDstCopyScaleUniform; |
|
360 GrGLUniformManager::UniformHandle fColorUniform; |
|
361 GrGLUniformManager::UniformHandle fCoverageUniform; |
|
362 |
|
363 bool fTopLeftFragPosRead; |
|
364 }; |
|
365 |
|
366 //////////////////////////////////////////////////////////////////////////////// |
|
367 |
|
368 class GrGLFullShaderBuilder : public GrGLShaderBuilder { |
|
369 public: |
|
370 GrGLFullShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); |
|
371 |
|
372 /** |
|
373 * Called by GrGLEffects to add code to one of the shaders. |
|
374 */ |
|
375 void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { |
|
376 va_list args; |
|
377 va_start(args, format); |
|
378 fVSCode.appendVAList(format, args); |
|
379 va_end(args); |
|
380 } |
|
381 |
|
382 void vsCodeAppend(const char* str) { fVSCode.append(str); } |
|
383 |
|
384 /** Add a vertex attribute to the current program that is passed in from the vertex data. |
|
385 Returns false if the attribute was already there, true otherwise. */ |
|
386 bool addAttribute(GrSLType type, const char* name); |
|
387 |
|
388 /** Add a varying variable to the current program to pass values between vertex and fragment |
|
389 shaders. If the last two parameters are non-NULL, they are filled in with the name |
|
390 generated. */ |
|
391 void addVarying(GrSLType type, |
|
392 const char* name, |
|
393 const char** vsOutName = NULL, |
|
394 const char** fsInName = NULL); |
|
395 |
|
396 /** Returns a vertex attribute that represents the vertex position in the VS. This is the |
|
397 pre-matrix position and is commonly used by effects to compute texture coords via a matrix. |
|
398 */ |
|
399 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; } |
|
400 |
|
401 /** Returns a vertex attribute that represents the local coords in the VS. This may be the same |
|
402 as positionAttribute() or it may not be. It depends upon whether the rendering code |
|
403 specified explicit local coords or not in the GrDrawState. */ |
|
404 const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; } |
|
405 |
|
406 /** |
|
407 * Are explicit local coordinates provided as input to the vertex shader. |
|
408 */ |
|
409 bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } |
|
410 |
|
411 bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name); |
|
412 const SkString* getEffectAttributeName(int attributeIndex) const; |
|
413 |
|
414 virtual GrGLProgramEffects* createAndEmitEffects( |
|
415 const GrEffectStage* effectStages[], |
|
416 const EffectKey effectKeys[], |
|
417 int effectCnt, |
|
418 GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; |
|
419 |
|
420 GrGLUniformManager::UniformHandle getViewMatrixUniform() const { |
|
421 return fViewMatrixUniform; |
|
422 } |
|
423 |
|
424 protected: |
|
425 virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE; |
|
426 virtual void bindProgramLocations(GrGLuint programId) const SK_OVERRIDE; |
|
427 |
|
428 private: |
|
429 const GrGLProgramDesc& fDesc; |
|
430 VarArray fVSAttrs; |
|
431 VarArray fVSOutputs; |
|
432 VarArray fGSInputs; |
|
433 VarArray fGSOutputs; |
|
434 |
|
435 SkString fVSCode; |
|
436 |
|
437 struct AttributePair { |
|
438 void set(int index, const SkString& name) { |
|
439 fIndex = index; fName = name; |
|
440 } |
|
441 int fIndex; |
|
442 SkString fName; |
|
443 }; |
|
444 SkSTArray<10, AttributePair, true> fEffectAttributes; |
|
445 |
|
446 GrGLUniformManager::UniformHandle fViewMatrixUniform; |
|
447 |
|
448 GrGLShaderVar* fPositionVar; |
|
449 GrGLShaderVar* fLocalCoordsVar; |
|
450 |
|
451 typedef GrGLShaderBuilder INHERITED; |
|
452 }; |
|
453 |
|
454 //////////////////////////////////////////////////////////////////////////////// |
|
455 |
|
456 class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder { |
|
457 public: |
|
458 GrGLFragmentOnlyShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&); |
|
459 |
|
460 int getNumTexCoordSets() const { return fNumTexCoordSets; } |
|
461 int addTexCoordSets(int count); |
|
462 |
|
463 virtual GrGLProgramEffects* createAndEmitEffects( |
|
464 const GrEffectStage* effectStages[], |
|
465 const EffectKey effectKeys[], |
|
466 int effectCnt, |
|
467 GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; |
|
468 |
|
469 private: |
|
470 int fNumTexCoordSets; |
|
471 |
|
472 typedef GrGLShaderBuilder INHERITED; |
|
473 }; |
|
474 |
|
475 #endif |