• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "gl/GrGLShaderBuilder.h"
9 #include "gl/GrGLProgram.h"
10 #include "gl/GrGLUniformHandle.h"
11 #include "GrTexture.h"
12 
13 // number of each input/output type in a single allocation block
14 static const int kVarsPerBlock = 8;
15 
16 // except FS outputs where we expect 2 at most.
17 static const int kMaxFSOutputs = 2;
18 
19 // ES2 FS only guarantees mediump and lowp support
20 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
21 
22 typedef GrGLUniformManager::UniformHandle UniformHandle;
23 ///////////////////////////////////////////////////////////////////////////////
24 
25 namespace {
26 
sample_function_name(GrSLType type)27 inline const char* sample_function_name(GrSLType type) {
28     if (kVec2f_GrSLType == type) {
29         return "texture2D";
30     } else {
31         GrAssert(kVec3f_GrSLType == type);
32         return "texture2DProj";
33     }
34 }
35 
36 /**
37  * Do we need to either map r,g,b->a or a->r.
38  */
swizzle_requires_alpha_remapping(const GrGLCaps & caps,const GrTextureAccess & access)39 inline bool swizzle_requires_alpha_remapping(const GrGLCaps& caps,
40                                              const GrTextureAccess& access) {
41     if (GrPixelConfigIsAlphaOnly(access.getTexture()->config())) {
42         if (caps.textureRedSupport() && (GrTextureAccess::kA_SwizzleFlag & access.swizzleMask())) {
43             return true;
44         }
45         if (GrTextureAccess::kRGB_SwizzleMask & access.swizzleMask()) {
46             return true;
47         }
48     }
49     return false;
50 }
51 
append_swizzle(SkString * outAppend,const GrTextureAccess & access,const GrGLCaps & caps)52 void append_swizzle(SkString* outAppend,
53                     const GrTextureAccess& access,
54                     const GrGLCaps& caps) {
55     const char* swizzle = access.getSwizzle();
56     char mangledSwizzle[5];
57 
58     // The swizzling occurs using texture params instead of shader-mangling if ARB_texture_swizzle
59     // is available.
60     if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(access.getTexture()->config())) {
61         char alphaChar = caps.textureRedSupport() ? 'r' : 'a';
62         int i;
63         for (i = 0; '\0' != swizzle[i]; ++i) {
64             mangledSwizzle[i] = alphaChar;
65         }
66         mangledSwizzle[i] ='\0';
67         swizzle = mangledSwizzle;
68     }
69     // For shader prettiness we omit the swizzle rather than appending ".rgba".
70     if (memcmp(swizzle, "rgba", 4)) {
71         outAppend->appendf(".%s", swizzle);
72     }
73 }
74 
75 }
76 
77 ///////////////////////////////////////////////////////////////////////////////
78 
79 // Architectural assumption: always 2-d input coords.
80 // Likely to become non-constant and non-static, perhaps even
81 // varying by stage, if we use 1D textures for gradients!
82 //const int GrGLShaderBuilder::fCoordDims = 2;
83 
GrGLShaderBuilder(const GrGLContextInfo & ctx,GrGLUniformManager & uniformManager)84 GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx, GrGLUniformManager& uniformManager)
85     : fUniforms(kVarsPerBlock)
86     , fVSAttrs(kVarsPerBlock)
87     , fVSOutputs(kVarsPerBlock)
88     , fGSInputs(kVarsPerBlock)
89     , fGSOutputs(kVarsPerBlock)
90     , fFSInputs(kVarsPerBlock)
91     , fFSOutputs(kMaxFSOutputs)
92     , fUsesGS(false)
93     , fContext(ctx)
94     , fUniformManager(uniformManager)
95     , fCurrentStageIdx(kNonStageIdx)
96     , fSetupFragPosition(false)
97     , fRTHeightUniform(GrGLUniformManager::kInvalidUniformHandle) {
98 
99     fPositionVar = &fVSAttrs.push_back();
100     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
101 }
102 
appendTextureLookup(SkString * out,const GrGLShaderBuilder::TextureSampler & sampler,const char * coordName,GrSLType varyingType) const103 void GrGLShaderBuilder::appendTextureLookup(SkString* out,
104                                             const GrGLShaderBuilder::TextureSampler& sampler,
105                                             const char* coordName,
106                                             GrSLType varyingType) const {
107     GrAssert(NULL != sampler.textureAccess());
108     GrAssert(NULL != coordName);
109 
110     out->appendf("%s(%s, %s)",
111                  sample_function_name(varyingType),
112                  this->getUniformCStr(sampler.fSamplerUniform),
113                  coordName);
114     append_swizzle(out, *sampler.textureAccess(), fContext.caps());
115 }
116 
appendTextureLookupAndModulate(SkString * out,const char * modulation,const GrGLShaderBuilder::TextureSampler & sampler,const char * coordName,GrSLType varyingType) const117 void GrGLShaderBuilder::appendTextureLookupAndModulate(
118                                             SkString* out,
119                                             const char* modulation,
120                                             const GrGLShaderBuilder::TextureSampler& sampler,
121                                             const char* coordName,
122                                             GrSLType varyingType) const {
123     GrAssert(NULL != out);
124     SkString lookup;
125     this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
126     GrGLSLModulate4f(out, modulation, lookup.c_str());
127 }
128 
KeyForTextureAccess(const GrTextureAccess & access,const GrGLCaps & caps)129 GrBackendEffectFactory::EffectKey GrGLShaderBuilder::KeyForTextureAccess(
130                                                             const GrTextureAccess& access,
131                                                             const GrGLCaps& caps) {
132     GrBackendEffectFactory::EffectKey key = 0;
133 
134     // Assume that swizzle support implies that we never have to modify a shader to adjust
135     // for texture format/swizzle settings.
136     if (!caps.textureSwizzleSupport() && swizzle_requires_alpha_remapping(caps, access)) {
137         key = 1;
138     }
139 #if GR_DEBUG
140     // Assert that key is set iff the swizzle will be modified.
141     SkString origString(access.getSwizzle());
142     origString.prepend(".");
143     SkString modifiedString;
144     append_swizzle(&modifiedString, access, caps);
145     if (!modifiedString.size()) {
146         modifiedString = ".rgba";
147     }
148     GrAssert(SkToBool(key) == (modifiedString != origString));
149 #endif
150     return key;
151 }
152 
GetTexParamSwizzle(GrPixelConfig config,const GrGLCaps & caps)153 const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) {
154     if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) {
155         if (caps.textureRedSupport()) {
156             static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED };
157             return gRedSmear;
158         } else {
159             static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
160                                                     GR_GL_ALPHA, GR_GL_ALPHA };
161             return gAlphaSmear;
162         }
163     } else {
164         static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA };
165         return gStraight;
166     }
167 }
168 
addUniformArray(uint32_t visibility,GrSLType type,const char * name,int count,const char ** outName)169 GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility,
170                                                                      GrSLType type,
171                                                                      const char* name,
172                                                                      int count,
173                                                                      const char** outName) {
174     GrAssert(name && strlen(name));
175     SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType);
176     GrAssert(0 == (~kVisibilityMask & visibility));
177     GrAssert(0 != visibility);
178 
179     BuilderUniform& uni = fUniforms.push_back();
180     UniformHandle h = index_to_handle(fUniforms.count() - 1);
181     GR_DEBUGCODE(UniformHandle h2 =)
182     fUniformManager.appendUniform(type, count);
183     // We expect the uniform manager to initially have no uniforms and that all uniforms are added
184     // by this function. Therefore, the handles should match.
185     GrAssert(h2 == h);
186     uni.fVariable.setType(type);
187     uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
188     SkString* uniName = uni.fVariable.accessName();
189     if (kNonStageIdx == fCurrentStageIdx) {
190         uniName->printf("u%s", name);
191     } else {
192         uniName->printf("u%s%d", name, fCurrentStageIdx);
193     }
194     uni.fVariable.setArrayCount(count);
195     uni.fVisibility = visibility;
196 
197     // If it is visible in both the VS and FS, the precision must match.
198     // We declare a default FS precision, but not a default VS. So set the var
199     // to use the default FS precision.
200     if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
201         // the fragment and vertex precisions must match
202         uni.fVariable.setPrecision(kDefaultFragmentPrecision);
203     }
204 
205     if (NULL != outName) {
206         *outName = uni.fVariable.c_str();
207     }
208 
209     return h;
210 }
211 
getUniformVariable(UniformHandle u) const212 const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const {
213     return fUniforms[handle_to_index(u)].fVariable;
214 }
215 
addVarying(GrSLType type,const char * name,const char ** vsOutName,const char ** fsInName)216 void GrGLShaderBuilder::addVarying(GrSLType type,
217                                    const char* name,
218                                    const char** vsOutName,
219                                    const char** fsInName) {
220     fVSOutputs.push_back();
221     fVSOutputs.back().setType(type);
222     fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
223     if (kNonStageIdx == fCurrentStageIdx) {
224         fVSOutputs.back().accessName()->printf("v%s", name);
225     } else {
226         fVSOutputs.back().accessName()->printf("v%s%d", name, fCurrentStageIdx);
227     }
228     if (vsOutName) {
229         *vsOutName = fVSOutputs.back().getName().c_str();
230     }
231     // input to FS comes either from VS or GS
232     const SkString* fsName;
233     if (fUsesGS) {
234         // if we have a GS take each varying in as an array
235         // and output as non-array.
236         fGSInputs.push_back();
237         fGSInputs.back().setType(type);
238         fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
239         fGSInputs.back().setUnsizedArray();
240         *fGSInputs.back().accessName() = fVSOutputs.back().getName();
241         fGSOutputs.push_back();
242         fGSOutputs.back().setType(type);
243         fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
244         if (kNonStageIdx == fCurrentStageIdx) {
245             fGSOutputs.back().accessName()->printf("g%s", name);
246         } else {
247             fGSOutputs.back().accessName()->printf("g%s%d", name, fCurrentStageIdx);
248         }
249         fsName = fGSOutputs.back().accessName();
250     } else {
251         fsName = fVSOutputs.back().accessName();
252     }
253     fFSInputs.push_back();
254     fFSInputs.back().setType(type);
255     fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
256     fFSInputs.back().setName(*fsName);
257     if (fsInName) {
258         *fsInName = fsName->c_str();
259     }
260 }
261 
fragmentPosition()262 const char* GrGLShaderBuilder::fragmentPosition() {
263     if (fContext.caps().fragCoordConventionsSupport()) {
264         if (!fSetupFragPosition) {
265             fFSHeader.append("#extension GL_ARB_fragment_coord_conventions: require\n");
266             fFSInputs.push_back().set(kVec4f_GrSLType,
267                                       GrGLShaderVar::kIn_TypeModifier,
268                                       "gl_FragCoord",
269                                       GrGLShaderVar::kDefault_Precision,
270                                       GrGLShaderVar::kUpperLeft_Origin);
271             fSetupFragPosition = true;
272         }
273         return "gl_FragCoord";
274     } else {
275         static const char* kCoordName = "fragCoordYDown";
276         if (!fSetupFragPosition) {
277             GrAssert(GrGLUniformManager::kInvalidUniformHandle == fRTHeightUniform);
278             const char* rtHeightName;
279 
280             // temporarily change the stage index because we're inserting a uniform whose name
281             // shouldn't be mangled to be stage-specific.
282             int oldStageIdx = fCurrentStageIdx;
283             fCurrentStageIdx = kNonStageIdx;
284             fRTHeightUniform = this->addUniform(kFragment_ShaderType,
285                                                 kFloat_GrSLType,
286                                                 "RTHeight",
287                                                 &rtHeightName);
288             fCurrentStageIdx = oldStageIdx;
289 
290             this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, gl_FragCoord.zw);\n",
291                                    kCoordName, rtHeightName);
292             fSetupFragPosition = true;
293         }
294         GrAssert(GrGLUniformManager::kInvalidUniformHandle != fRTHeightUniform);
295         return kCoordName;
296     }
297 }
298 
299 
emitFunction(ShaderType shader,GrSLType returnType,const char * name,int argCnt,const GrGLShaderVar * args,const char * body,SkString * outName)300 void GrGLShaderBuilder::emitFunction(ShaderType shader,
301                                      GrSLType returnType,
302                                      const char* name,
303                                      int argCnt,
304                                      const GrGLShaderVar* args,
305                                      const char* body,
306                                      SkString* outName) {
307     GrAssert(kFragment_ShaderType == shader);
308     fFSFunctions.append(GrGLShaderVar::TypeString(returnType));
309     if (kNonStageIdx != fCurrentStageIdx) {
310         outName->printf(" %s_%d", name, fCurrentStageIdx);
311     } else {
312         *outName = name;
313     }
314     fFSFunctions.append(*outName);
315     fFSFunctions.append("(");
316     for (int i = 0; i < argCnt; ++i) {
317         args[i].appendDecl(fContext, &fFSFunctions);
318         if (i < argCnt - 1) {
319             fFSFunctions.append(", ");
320         }
321     }
322     fFSFunctions.append(") {\n");
323     fFSFunctions.append(body);
324     fFSFunctions.append("}\n\n");
325 }
326 
327 namespace {
328 
append_default_precision_qualifier(GrGLShaderVar::Precision p,GrGLBinding binding,SkString * str)329 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
330                                                GrGLBinding binding,
331                                                SkString* str) {
332     // Desktop GLSL has added precision qualifiers but they don't do anything.
333     if (kES2_GrGLBinding == binding) {
334         switch (p) {
335             case GrGLShaderVar::kHigh_Precision:
336                 str->append("precision highp float;\n");
337                 break;
338             case GrGLShaderVar::kMedium_Precision:
339                 str->append("precision mediump float;\n");
340                 break;
341             case GrGLShaderVar::kLow_Precision:
342                 str->append("precision lowp float;\n");
343                 break;
344             case GrGLShaderVar::kDefault_Precision:
345                 GrCrash("Default precision now allowed.");
346             default:
347                 GrCrash("Unknown precision value.");
348         }
349     }
350 }
351 }
352 
appendDecls(const VarArray & vars,SkString * out) const353 void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
354     for (int i = 0; i < vars.count(); ++i) {
355         vars[i].appendDecl(fContext, out);
356         out->append(";\n");
357     }
358 }
359 
appendUniformDecls(ShaderType stype,SkString * out) const360 void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const {
361     for (int i = 0; i < fUniforms.count(); ++i) {
362         if (fUniforms[i].fVisibility & stype) {
363             fUniforms[i].fVariable.appendDecl(fContext, out);
364             out->append(";\n");
365         }
366     }
367 }
368 
getShader(ShaderType type,SkString * shaderStr) const369 void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
370     switch (type) {
371         case kVertex_ShaderType:
372             *shaderStr = fHeader;
373             this->appendUniformDecls(kVertex_ShaderType, shaderStr);
374             this->appendDecls(fVSAttrs, shaderStr);
375             this->appendDecls(fVSOutputs, shaderStr);
376             shaderStr->append("void main() {\n");
377             shaderStr->append(fVSCode);
378             shaderStr->append("}\n");
379             break;
380         case kGeometry_ShaderType:
381             if (fUsesGS) {
382                 *shaderStr = fHeader;
383                 shaderStr->append(fGSHeader);
384                 this->appendDecls(fGSInputs, shaderStr);
385                 this->appendDecls(fGSOutputs, shaderStr);
386                 shaderStr->append("void main() {\n");
387                 shaderStr->append(fGSCode);
388                 shaderStr->append("}\n");
389             } else {
390                 shaderStr->reset();
391             }
392             break;
393         case kFragment_ShaderType:
394             *shaderStr = fHeader;
395             append_default_precision_qualifier(kDefaultFragmentPrecision,
396                                                fContext.binding(),
397                                                shaderStr);
398             shaderStr->append(fFSHeader);
399             this->appendUniformDecls(kFragment_ShaderType, shaderStr);
400             this->appendDecls(fFSInputs, shaderStr);
401             // We shouldn't have declared outputs on 1.10
402             GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
403             this->appendDecls(fFSOutputs, shaderStr);
404             shaderStr->append(fFSFunctions);
405             shaderStr->append("void main() {\n");
406             shaderStr->append(fFSCode);
407             shaderStr->append("}\n");
408             break;
409     }
410  }
411 
finished(GrGLuint programID)412 void GrGLShaderBuilder::finished(GrGLuint programID) {
413     fUniformManager.getUniformLocations(programID, fUniforms);
414 }
415 
createAndEmitGLEffect(const GrEffectStage & stage,GrGLEffect::EffectKey key,const char * fsInColor,const char * fsOutColor,const char * vsInCoord,SkTArray<GrGLUniformManager::UniformHandle,true> * samplerHandles)416 GrGLEffect* GrGLShaderBuilder::createAndEmitGLEffect(
417                                 const GrEffectStage& stage,
418                                 GrGLEffect::EffectKey key,
419                                 const char* fsInColor,
420                                 const char* fsOutColor,
421                                 const char* vsInCoord,
422                                 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles) {
423     GrAssert(NULL != stage.getEffect());
424 
425     const GrEffectRef& effect = *stage.getEffect();
426     int numTextures = effect->numTextures();
427     SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
428     textureSamplers.push_back_n(numTextures);
429     for (int i = 0; i < numTextures; ++i) {
430         textureSamplers[i].init(this, &effect->textureAccess(i), i);
431         samplerHandles->push_back(textureSamplers[i].fSamplerUniform);
432     }
433 
434     GrGLEffect* glEffect = effect->getFactory().createGLInstance(effect);
435 
436     // Enclose custom code in a block to avoid namespace conflicts
437     this->fVSCode.appendf("\t{ // %s\n", glEffect->name());
438     this->fFSCode.appendf("\t{ // %s \n", glEffect->name());
439     glEffect->emitCode(this,
440                        stage,
441                        key,
442                        vsInCoord,
443                        fsOutColor,
444                        fsInColor,
445                        textureSamplers);
446     this->fVSCode.appendf("\t}\n");
447     this->fFSCode.appendf("\t}\n");
448 
449     return glEffect;
450 }
451