OLD | NEW |
| (Empty) |
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/GrGLProgramDesc.h" | |
17 #include "gl/GrGLProgramEffects.h" | |
18 #include "gl/GrGLSL.h" | |
19 #include "gl/GrGLProgramDataManager.h" | |
20 | |
21 #include <stdarg.h> | |
22 | |
23 class GrGLContextInfo; | |
24 class GrEffectStage; | |
25 class GrGLProgramDesc; | |
26 | |
27 /** | |
28 Contains all the incremental state of a shader as it is being built,as well as
helpers to | |
29 manipulate that state. | |
30 */ | |
31 class GrGLShaderBuilder { | |
32 public: | |
33 typedef GrTAllocator<GrGLShaderVar> VarArray; | |
34 typedef GrGLProgramEffects::TextureSampler TextureSampler; | |
35 typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray; | |
36 | |
37 enum ShaderVisibility { | |
38 kVertex_Visibility = 0x1, | |
39 kGeometry_Visibility = 0x2, | |
40 kFragment_Visibility = 0x4, | |
41 }; | |
42 | |
43 typedef GrGLProgramDataManager::UniformHandle UniformHandle; | |
44 | |
45 // Handles for program uniforms (other than per-effect uniforms) | |
46 struct BuiltinUniformHandles { | |
47 UniformHandle fViewMatrixUni; | |
48 UniformHandle fRTAdjustmentUni; | |
49 UniformHandle fColorUni; | |
50 UniformHandle fCoverageUni; | |
51 | |
52 // We use the render target height to provide a y-down frag coord when s
pecifying | |
53 // origin_upper_left is not supported. | |
54 UniformHandle fRTHeightUni; | |
55 | |
56 // Uniforms for computing texture coords to do the dst-copy lookup | |
57 UniformHandle fDstCopyTopLeftUni; | |
58 UniformHandle fDstCopyScaleUni; | |
59 UniformHandle fDstCopySamplerUni; | |
60 }; | |
61 | |
62 struct UniformInfo { | |
63 GrGLShaderVar fVariable; | |
64 uint32_t fVisibility; | |
65 GrGLint fLocation; | |
66 }; | |
67 | |
68 // This uses an allocator rather than array so that the GrGLShaderVars don't
move in memory | |
69 // after they are inserted. Users of GrGLShaderBuilder get refs to the vars
and ptrs to their | |
70 // name strings. Otherwise, we'd have to hand out copies. | |
71 typedef GrTAllocator<UniformInfo> UniformInfoArray; | |
72 | |
73 /** Generates a shader program. | |
74 * | |
75 * The program implements what is specified in the stages given as input. | |
76 * After successful generation, the builder result objects are available | |
77 * to be used. | |
78 * @return true if generation was successful. | |
79 */ | |
80 bool genProgram(const GrEffectStage* inColorStages[], | |
81 const GrEffectStage* inCoverageStages[]); | |
82 | |
83 // Below are the results of the shader generation. | |
84 | |
85 GrGLProgramEffects* getColorEffects() const { SkASSERT(fProgramID); return f
ColorEffects.get(); } | |
86 GrGLProgramEffects* getCoverageEffects() const { SkASSERT(fProgramID); retur
n fCoverageEffects.get(); } | |
87 const BuiltinUniformHandles& getBuiltinUniformHandles() const { | |
88 SkASSERT(fProgramID); | |
89 return fUniformHandles; | |
90 } | |
91 GrGLuint getProgramID() const { SkASSERT(fProgramID); return fProgramID; } | |
92 bool hasVertexShader() const { SkASSERT(fProgramID); return fHasVertexShader
; } | |
93 int getTexCoordSetCount() const { SkASSERT(fProgramID); return fTexCoordSetC
nt; } | |
94 const UniformInfoArray& getUniformInfos() const { return fUniforms; } | |
95 | |
96 virtual ~GrGLShaderBuilder() {} | |
97 | |
98 /** | |
99 * Use of these features may require a GLSL extension to be enabled. Shaders
may not compile | |
100 * if code is added that uses one of these features without calling enableFe
ature() | |
101 */ | |
102 enum GLSLFeature { | |
103 kStandardDerivatives_GLSLFeature = 0, | |
104 | |
105 kLastGLSLFeature = kStandardDerivatives_GLSLFeature | |
106 }; | |
107 | |
108 /** | |
109 * If the feature is supported then true is returned and any necessary #exte
nsion declarations | |
110 * are added to the shaders. If the feature is not supported then false will
be returned. | |
111 */ | |
112 bool enableFeature(GLSLFeature); | |
113 | |
114 /** | |
115 * Called by GrGLEffects to add code the fragment shader. | |
116 */ | |
117 void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { | |
118 va_list args; | |
119 va_start(args, format); | |
120 fFSCode.appendVAList(format, args); | |
121 va_end(args); | |
122 } | |
123 | |
124 void fsCodeAppend(const char* str) { fFSCode.append(str); } | |
125 | |
126 /** Appends a 2D texture sample with projection if necessary. coordType must
either be Vec2f or | |
127 Vec3f. The latter is interpreted as projective texture coords. The vec l
ength and swizzle | |
128 order of the result depends on the GrTextureAccess associated with the T
extureSampler. */ | |
129 void appendTextureLookup(SkString* out, | |
130 const TextureSampler&, | |
131 const char* coordName, | |
132 GrSLType coordType = kVec2f_GrSLType) const; | |
133 | |
134 /** Version of above that appends the result to the fragment shader code ins
tead.*/ | |
135 void fsAppendTextureLookup(const TextureSampler&, | |
136 const char* coordName, | |
137 GrSLType coordType = kVec2f_GrSLType); | |
138 | |
139 | |
140 /** Does the work of appendTextureLookup and modulates the result by modulat
ion. The result is | |
141 always a vec4. modulation and the swizzle specified by TextureSampler mu
st both be vec4 or | |
142 float. If modulation is "" or NULL it this function acts as though appen
dTextureLookup were | |
143 called. */ | |
144 void fsAppendTextureLookupAndModulate(const char* modulation, | |
145 const TextureSampler&, | |
146 const char* coordName, | |
147 GrSLType coordType = kVec2f_GrSLType); | |
148 | |
149 /** Emits a helper function outside of main() in the fragment shader. */ | |
150 void fsEmitFunction(GrSLType returnType, | |
151 const char* name, | |
152 int argCnt, | |
153 const GrGLShaderVar* args, | |
154 const char* body, | |
155 SkString* outName); | |
156 | |
157 typedef uint8_t DstReadKey; | |
158 typedef uint8_t FragPosKey; | |
159 | |
160 /** Returns a key for adding code to read the copy-of-dst color in service
of effects that | |
161 require reading the dst. It must not return 0 because 0 indicates that
there is no dst | |
162 copy read at all (in which case this function should not be called). */ | |
163 static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&); | |
164 | |
165 /** Returns a key for reading the fragment location. This should only be cal
led if there is an | |
166 effect that will requires the fragment position. If the fragment positio
n is not required, | |
167 the key is 0. */ | |
168 static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const Gr
GLCaps&); | |
169 | |
170 /** If texture swizzling is available using tex parameters then it is prefer
red over mangling | |
171 the generated shader code. This potentially allows greater reuse of cach
ed shaders. */ | |
172 static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCa
ps& caps); | |
173 | |
174 /** Add a uniform variable to the current program, that has visibility in on
e or more shaders. | |
175 visibility is a bitfield of ShaderVisibility values indicating from whic
h shaders the | |
176 uniform should be accessible. At least one bit must be set. Geometry sha
der uniforms are not | |
177 supported at this time. The actual uniform name will be mangled. If outN
ame is not NULL then | |
178 it will refer to the final uniform name after return. Use the addUniform
Array variant to add | |
179 an array of uniforms. */ | |
180 GrGLProgramDataManager::UniformHandle addUniform(uint32_t visibility, | |
181 GrSLType type, | |
182 const char* name, | |
183 const char** outName = NULL
) { | |
184 return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNon
Array, outName); | |
185 } | |
186 GrGLProgramDataManager::UniformHandle addUniformArray(uint32_t visibility, | |
187 GrSLType type, | |
188 const char* name, | |
189 int arrayCount, | |
190 const char** outName =
NULL); | |
191 | |
192 const GrGLShaderVar& getUniformVariable(GrGLProgramDataManager::UniformHandl
e u) const { | |
193 return fUniforms[u.toShaderBuilderIndex()].fVariable; | |
194 } | |
195 | |
196 /** | |
197 * Shortcut for getUniformVariable(u).c_str() | |
198 */ | |
199 const char* getUniformCStr(GrGLProgramDataManager::UniformHandle u) const { | |
200 return this->getUniformVariable(u).c_str(); | |
201 } | |
202 | |
203 /** | |
204 * This returns a variable name to access the 2D, perspective correct versio
n of the coords in | |
205 * the fragment shader. If the coordinates at index are 3-dimensional, it im
mediately emits a | |
206 * perspective divide into the fragment shader (xy / z) to convert them to 2
D. | |
207 */ | |
208 SkString ensureFSCoords2D(const TransformedCoordsArray&, int index); | |
209 | |
210 /** Returns a variable name that represents the position of the fragment in
the FS. The position | |
211 is in device space (e.g. 0,0 is the top left and pixel centers are at ha
lf-integers). */ | |
212 const char* fragmentPosition(); | |
213 | |
214 /** Returns the variable name that holds the color of the destination pixel.
This may be NULL if | |
215 no effect advertised that it will read the destination. */ | |
216 const char* dstColor(); | |
217 | |
218 const GrGLContextInfo& ctxInfo() const; | |
219 | |
220 /** | |
221 * Helper for begining and ending a block in the fragment code. TODO: Make G
rGLShaderBuilder | |
222 * aware of all blocks and turn single \t's into the correct number of tabs
(or spaces) so that | |
223 * our shaders print pretty without effect writers tracking indentation. | |
224 */ | |
225 class FSBlock { | |
226 public: | |
227 FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) { | |
228 SkASSERT(NULL != builder); | |
229 fBuilder->fsCodeAppend("\t{\n"); | |
230 } | |
231 | |
232 ~FSBlock() { | |
233 fBuilder->fsCodeAppend("\t}\n"); | |
234 } | |
235 private: | |
236 GrGLShaderBuilder* fBuilder; | |
237 }; | |
238 | |
239 protected: | |
240 GrGLShaderBuilder(GrGpuGL*, const GrGLProgramDesc&); | |
241 | |
242 GrGpuGL* gpu() const { return fGpu; } | |
243 | |
244 const GrGLProgramDesc& desc() const { return fDesc; } | |
245 | |
246 /** Add input/output variable declarations (i.e. 'varying') to the fragment
shader. */ | |
247 GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); } | |
248 | |
249 // Helper for emitEffects(). | |
250 void createAndEmitEffects(GrGLProgramEffectsBuilder*, | |
251 const GrEffectStage* effectStages[], | |
252 int effectCnt, | |
253 const GrGLProgramDesc::EffectKeyProvider&, | |
254 GrGLSLExpr4* inOutFSColor); | |
255 | |
256 // Generates a name for a variable. The generated string will be name prefix
ed by the prefix | |
257 // char (unless the prefix is '\0'). It also mangles the name to be stage-sp
ecific if we're | |
258 // generating stage code. | |
259 void nameVariable(SkString* out, char prefix, const char* name); | |
260 | |
261 virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>
* shaderIds) const; | |
262 | |
263 virtual void bindProgramLocations(GrGLuint programId); | |
264 void resolveProgramLocations(GrGLuint programId); | |
265 | |
266 void appendDecls(const VarArray&, SkString*) const; | |
267 void appendUniformDecls(ShaderVisibility, SkString*) const; | |
268 | |
269 SkAutoTUnref<GrGLProgramEffects> fColorEffects; | |
270 SkAutoTUnref<GrGLProgramEffects> fCoverageEffects; | |
271 BuiltinUniformHandles fUniformHandles; | |
272 bool fHasVertexShader; | |
273 int fTexCoordSetCnt; | |
274 GrGLuint fProgramID; | |
275 private: | |
276 class CodeStage : SkNoncopyable { | |
277 public: | |
278 CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} | |
279 | |
280 bool inStageCode() const { | |
281 this->validate(); | |
282 return NULL != fEffectStage; | |
283 } | |
284 | |
285 const GrEffectStage* effectStage() const { | |
286 this->validate(); | |
287 return fEffectStage; | |
288 } | |
289 | |
290 int stageIndex() const { | |
291 this->validate(); | |
292 return fCurrentIndex; | |
293 } | |
294 | |
295 class AutoStageRestore : SkNoncopyable { | |
296 public: | |
297 AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage
) { | |
298 SkASSERT(NULL != codeStage); | |
299 fSavedIndex = codeStage->fCurrentIndex; | |
300 fSavedEffectStage = codeStage->fEffectStage; | |
301 | |
302 if (NULL == newStage) { | |
303 codeStage->fCurrentIndex = -1; | |
304 } else { | |
305 codeStage->fCurrentIndex = codeStage->fNextIndex++; | |
306 } | |
307 codeStage->fEffectStage = newStage; | |
308 | |
309 fCodeStage = codeStage; | |
310 } | |
311 ~AutoStageRestore() { | |
312 fCodeStage->fCurrentIndex = fSavedIndex; | |
313 fCodeStage->fEffectStage = fSavedEffectStage; | |
314 } | |
315 private: | |
316 CodeStage* fCodeStage; | |
317 int fSavedIndex; | |
318 const GrEffectStage* fSavedEffectStage; | |
319 }; | |
320 private: | |
321 void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurre
ntIndex)); } | |
322 int fNextIndex; | |
323 int fCurrentIndex; | |
324 const GrEffectStage* fEffectStage; | |
325 } fCodeStage; | |
326 | |
327 /** | |
328 * The base class will emit the fragment code that precedes the per-effect c
ode and then call | |
329 * this function. The subclass can use it to insert additional fragment code
that should | |
330 * execute before the effects' code and/or emit other shaders (e.g. geometry
, vertex). | |
331 * | |
332 * The subclass can modify the initial color or coverage | |
333 */ | |
334 virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage
) = 0; | |
335 | |
336 /** | |
337 * Adds code for effects and returns a GrGLProgramEffects* object. The caller
is responsible for | |
338 * deleting it when finished. effectStages contains the effects to add. The e
ffect key provider | |
339 * is used to communicate the key each effect created in its GenKey function.
inOutFSColor | |
340 * specifies the input color to the first stage and is updated to be the outp
ut color of the | |
341 * last stage. The handles to texture samplers for effectStage[i] are added t
o | |
342 * effectSamplerHandles[i]. | |
343 */ | |
344 virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effect
Stages[], | |
345 int effectCnt, | |
346 const GrGLProgramDesc::Effe
ctKeyProvider&, | |
347 GrGLSLExpr4* inOutFSColor)
= 0; | |
348 | |
349 /** | |
350 * Similar to emitCodeBeforeEffects() but called after per-effect code is em
itted. | |
351 */ | |
352 virtual void emitCodeAfterEffects() = 0; | |
353 | |
354 /** Enables using the secondary color output and returns the name of the var
in which it is | |
355 to be stored */ | |
356 const char* enableSecondaryOutput(); | |
357 /** Gets the name of the primary color output. */ | |
358 const char* getColorOutputName() const; | |
359 | |
360 /** | |
361 * Compiles all the shaders, links them into a program, and writes the progr
am id to the output | |
362 * struct. | |
363 **/ | |
364 bool finish(); | |
365 | |
366 /** | |
367 * Features that should only be enabled by GrGLShaderBuilder itself. | |
368 */ | |
369 enum GLSLPrivateFeature { | |
370 kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1, | |
371 kLastGLSLPrivateFeature = kFragCoordConventions_GLSLPrivateFeature | |
372 }; | |
373 bool enablePrivateFeature(GLSLPrivateFeature); | |
374 | |
375 // If we ever have VS/GS features we can expand this to take a bitmask of Sh
aderVisibility and | |
376 // track the enables separately for each shader. | |
377 void addFSFeature(uint32_t featureBit, const char* extensionName); | |
378 | |
379 // Interpretation of DstReadKey when generating code | |
380 enum { | |
381 kNoDstRead_DstReadKey = 0, | |
382 kYesDstRead_DstReadKeyBit = 0x1, // Set if we do a dst-copy-read. | |
383 kUseAlphaConfig_DstReadKeyBit = 0x2, // Set if dst-copy config is alph
a only. | |
384 kTopLeftOrigin_DstReadKeyBit = 0x4, // Set if dst-copy origin is top-
left. | |
385 }; | |
386 | |
387 enum { | |
388 kNoFragPosRead_FragPosKey = 0, // The fragment positition wil
l not be needed. | |
389 kTopLeftFragPosRead_FragPosKey = 0x1,// Read frag pos relative to t
op-left. | |
390 kBottomLeftFragPosRead_FragPosKey = 0x2,// Read frag pos relative to b
ottom-left. | |
391 }; | |
392 | |
393 const GrGLProgramDesc& fDesc; | |
394 GrGpuGL* fGpu; | |
395 uint32_t fFSFeaturesAddedMask; | |
396 SkString fFSFunctions; | |
397 SkString fFSExtensions; | |
398 VarArray fFSInputs; | |
399 VarArray fFSOutputs; | |
400 UniformInfoArray fUniforms; | |
401 | |
402 SkString fFSCode; | |
403 | |
404 bool fSetupFragPosition; | |
405 bool fTopLeftFragPosRead; | |
406 | |
407 bool fHasCustomColorOutput; | |
408 bool fHasSecondaryOutput; | |
409 }; | |
410 | |
411 //////////////////////////////////////////////////////////////////////////////// | |
412 | |
413 class GrGLFullShaderBuilder : public GrGLShaderBuilder { | |
414 public: | |
415 GrGLFullShaderBuilder(GrGpuGL*, const GrGLProgramDesc&); | |
416 | |
417 /** | |
418 * Called by GrGLEffects to add code to one of the shaders. | |
419 */ | |
420 void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { | |
421 va_list args; | |
422 va_start(args, format); | |
423 fVSCode.appendVAList(format, args); | |
424 va_end(args); | |
425 } | |
426 | |
427 void vsCodeAppend(const char* str) { fVSCode.append(str); } | |
428 | |
429 /** Add a vertex attribute to the current program that is passed in from the
vertex data. | |
430 Returns false if the attribute was already there, true otherwise. */ | |
431 bool addAttribute(GrSLType type, const char* name); | |
432 | |
433 /** Add a varying variable to the current program to pass values between vert
ex and fragment | |
434 shaders. If the last two parameters are non-NULL, they are filled in wit
h the name | |
435 generated. */ | |
436 void addVarying(GrSLType type, | |
437 const char* name, | |
438 const char** vsOutName = NULL, | |
439 const char** fsInName = NULL); | |
440 | |
441 /** Returns a vertex attribute that represents the vertex position in the VS
. This is the | |
442 pre-matrix position and is commonly used by effects to compute texture c
oords via a matrix. | |
443 */ | |
444 const GrGLShaderVar& positionAttribute() const { return *fPositionVar; } | |
445 | |
446 /** Returns a vertex attribute that represents the local coords in the VS. T
his may be the same | |
447 as positionAttribute() or it may not be. It depends upon whether the ren
dering code | |
448 specified explicit local coords or not in the GrDrawState. */ | |
449 const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar;
} | |
450 | |
451 /** | |
452 * Are explicit local coordinates provided as input to the vertex shader. | |
453 */ | |
454 bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVa
r); } | |
455 | |
456 bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& n
ame); | |
457 const SkString* getEffectAttributeName(int attributeIndex) const; | |
458 | |
459 private: | |
460 virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage
) SK_OVERRIDE; | |
461 | |
462 virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effect
Stages[], | |
463 int effectCnt, | |
464 const GrGLProgramDesc::Effe
ctKeyProvider&, | |
465 GrGLSLExpr4* inOutFSColor)
SK_OVERRIDE; | |
466 | |
467 virtual void emitCodeAfterEffects() SK_OVERRIDE; | |
468 | |
469 virtual bool compileAndAttachShaders(GrGLuint programId, | |
470 SkTDArray<GrGLuint>* shaderIds) const S
K_OVERRIDE; | |
471 | |
472 virtual void bindProgramLocations(GrGLuint programId) SK_OVERRIDE; | |
473 | |
474 VarArray fVSAttrs; | |
475 VarArray fVSOutputs; | |
476 VarArray fGSInputs; | |
477 VarArray fGSOutputs; | |
478 | |
479 SkString fVSCode; | |
480 | |
481 struct AttributePair { | |
482 void set(int index, const SkString& name) { | |
483 fIndex = index; fName = name; | |
484 } | |
485 int fIndex; | |
486 SkString fName; | |
487 }; | |
488 SkSTArray<10, AttributePair, true> fEffectAttributes; | |
489 | |
490 GrGLShaderVar* fPositionVar; | |
491 GrGLShaderVar* fLocalCoordsVar; | |
492 | |
493 typedef GrGLShaderBuilder INHERITED; | |
494 }; | |
495 | |
496 //////////////////////////////////////////////////////////////////////////////// | |
497 | |
498 class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder { | |
499 public: | |
500 GrGLFragmentOnlyShaderBuilder(GrGpuGL*, const GrGLProgramDesc&); | |
501 | |
502 int addTexCoordSets(int count); | |
503 | |
504 private: | |
505 virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage
) SK_OVERRIDE {} | |
506 | |
507 virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effect
Stages[], | |
508 int effectCnt, | |
509 const GrGLProgramDesc::Effe
ctKeyProvider&, | |
510 GrGLSLExpr4* inOutFSColor)
SK_OVERRIDE; | |
511 | |
512 virtual void emitCodeAfterEffects() SK_OVERRIDE {} | |
513 | |
514 typedef GrGLShaderBuilder INHERITED; | |
515 }; | |
516 | |
517 #endif | |
OLD | NEW |