• 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