• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright 2015 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 "src/gpu/glsl/GrGLSLProgramBuilder.h"
9  
10  #include <memory>
11  
12  #include "src/gpu/GrCaps.h"
13  #include "src/gpu/GrFragmentProcessor.h"
14  #include "src/gpu/GrGeometryProcessor.h"
15  #include "src/gpu/GrPipeline.h"
16  #include "src/gpu/GrRenderTarget.h"
17  #include "src/gpu/GrShaderCaps.h"
18  #include "src/gpu/GrTexture.h"
19  #include "src/gpu/GrXferProcessor.h"
20  #include "src/gpu/effects/GrTextureEffect.h"
21  #include "src/gpu/glsl/GrGLSLVarying.h"
22  #include "src/sksl/SkSLCompiler.h"
23  #include "src/sksl/dsl/priv/DSLFPs.h"
24  
25  const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
26  
GrGLSLProgramBuilder(const GrProgramDesc & desc,const GrProgramInfo & programInfo)27  GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrProgramDesc& desc,
28                                             const GrProgramInfo& programInfo)
29          : fVS(this)
30          , fFS(this)
31          , fDesc(desc)
32          , fProgramInfo(programInfo)
33          , fNumFragmentSamplers(0) {}
34  
35  GrGLSLProgramBuilder::~GrGLSLProgramBuilder() = default;
36  
addFeature(GrShaderFlags shaders,uint32_t featureBit,const char * extensionName)37  void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
38                                        uint32_t featureBit,
39                                        const char* extensionName) {
40      if (shaders & kVertex_GrShaderFlag) {
41          fVS.addFeature(featureBit, extensionName);
42      }
43      if (shaders & kFragment_GrShaderFlag) {
44          fFS.addFeature(featureBit, extensionName);
45      }
46  }
47  
emitAndInstallProcs()48  bool GrGLSLProgramBuilder::emitAndInstallProcs() {
49      // First we loop over all of the installed processors and collect coord transforms.  These will
50      // be sent to the ProgramImpl in its emitCode function
51      SkSL::dsl::Start(this->shaderCompiler());
52      SkString inputColor;
53      SkString inputCoverage;
54      if (!this->emitAndInstallPrimProc(&inputColor, &inputCoverage)) {
55          return false;
56      }
57      if (!this->emitAndInstallDstTexture()) {
58          return false;
59      }
60      if (!this->emitAndInstallFragProcs(&inputColor, &inputCoverage)) {
61          return false;
62      }
63      if (!this->emitAndInstallXferProc(inputColor, inputCoverage)) {
64          return false;
65      }
66      fGPImpl->emitTransformCode(&fVS, this->uniformHandler());
67      SkSL::dsl::End();
68  
69      return this->checkSamplerCounts();
70  }
71  
emitAndInstallPrimProc(SkString * outputColor,SkString * outputCoverage)72  bool GrGLSLProgramBuilder::emitAndInstallPrimProc(SkString* outputColor, SkString* outputCoverage) {
73      const GrGeometryProcessor& geomProc = this->geometryProcessor();
74  
75      // Program builders have a bit of state we need to clear with each effect
76      this->advanceStage();
77      this->nameExpression(outputColor, "outputColor");
78      this->nameExpression(outputCoverage, "outputCoverage");
79  
80      SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
81      GrShaderFlags rtAdjustVisibility;
82      if (geomProc.willUseTessellationShaders()) {
83          rtAdjustVisibility = kTessEvaluation_GrShaderFlag;
84      } else {
85          rtAdjustVisibility = kVertex_GrShaderFlag;
86      }
87      fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(
88              nullptr, rtAdjustVisibility, kFloat4_GrSLType, SkSL::Compiler::RTADJUST_NAME);
89  
90      fFS.codeAppendf("// Stage %d, %s\n", fStageIndex, geomProc.name());
91      fVS.codeAppendf("// Primitive Processor %s\n", geomProc.name());
92  
93      SkASSERT(!fGPImpl);
94      fGPImpl = geomProc.makeProgramImpl(*this->shaderCaps());
95  
96      SkAutoSTArray<4, SamplerHandle> texSamplers(geomProc.numTextureSamplers());
97      for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
98          SkString name;
99          name.printf("TextureSampler_%d", i);
100          const auto& sampler = geomProc.textureSampler(i);
101          texSamplers[i] = this->emitSampler(geomProc.textureSampler(i).backendFormat(),
102                                             sampler.samplerState(),
103                                             sampler.swizzle(),
104                                             name.c_str());
105          if (!texSamplers[i].isValid()) {
106              return false;
107          }
108      }
109  
110      GrGeometryProcessor::ProgramImpl::EmitArgs args(&fVS,
111                                                      &fFS,
112                                                      this->varyingHandler(),
113                                                      this->uniformHandler(),
114                                                      this->shaderCaps(),
115                                                      geomProc,
116                                                      outputColor->c_str(),
117                                                      outputCoverage->c_str(),
118                                                      texSamplers.get());
119      fFPCoordsMap = fGPImpl->emitCode(args, this->pipeline());
120  
121      // We have to check that effects and the code they emit are consistent, ie if an effect
122      // asks for dst color, then the emit code needs to follow suit
123      SkDEBUGCODE(verify(geomProc);)
124  
125      return true;
126  }
127  
emitAndInstallFragProcs(SkString * color,SkString * coverage)128  bool GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) {
129      int fpCount = this->pipeline().numFragmentProcessors();
130      SkASSERT(fFPImpls.empty());
131      fFPImpls.reserve(fpCount);
132      for (int i = 0; i < fpCount; ++i) {
133          SkString* inOut = this->pipeline().isColorFragmentProcessor(i) ? color : coverage;
134          SkString output;
135          const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
136          fFPImpls.push_back(fp.makeProgramImpl());
137          output = this->emitFragProc(fp, *fFPImpls.back(), *inOut, output);
138          if (output.isEmpty()) {
139              return false;
140          }
141          *inOut = std::move(output);
142      }
143      return true;
144  }
145  
emitFragProc(const GrFragmentProcessor & fp,GrFragmentProcessor::ProgramImpl & impl,const SkString & input,SkString output)146  SkString GrGLSLProgramBuilder::emitFragProc(const GrFragmentProcessor& fp,
147                                              GrFragmentProcessor::ProgramImpl& impl,
148                                              const SkString& input,
149                                              SkString output) {
150      SkASSERT(input.size());
151  
152      // Program builders have a bit of state we need to clear with each effect
153      this->advanceStage();
154      this->nameExpression(&output, "output");
155      fFS.codeAppendf("half4 %s;", output.c_str());
156      bool ok = true;
157      fp.visitWithImpls([&, samplerIdx = 0](const GrFragmentProcessor& fp,
158                                            GrFragmentProcessor::ProgramImpl& impl) mutable {
159          if (auto* te = fp.asTextureEffect()) {
160              SkString name;
161              name.printf("TextureSampler_%d", samplerIdx++);
162  
163              GrSamplerState samplerState = te->samplerState();
164              const GrBackendFormat& format = te->view().proxy()->backendFormat();
165              GrSwizzle swizzle = te->view().swizzle();
166              SamplerHandle handle = this->emitSampler(format, samplerState, swizzle, name.c_str());
167              if (!handle.isValid()) {
168                  ok = false;
169                  return;
170              }
171              static_cast<GrTextureEffect::Impl&>(impl).setSamplerHandle(handle);
172          }
173      }, impl);
174      if (!ok) {
175          return {};
176      }
177  
178      this->writeFPFunction(fp, impl);
179  
180      if (fp.isBlendFunction()) {
181          fFS.codeAppendf(
182                  "%s = %s(%s, half4(1));", output.c_str(), impl.functionName(), input.c_str());
183      } else {
184          fFS.codeAppendf("%s = %s(%s);", output.c_str(), impl.functionName(), input.c_str());
185      }
186  
187      // We have to check that effects and the code they emit are consistent, ie if an effect asks
188      // for dst color, then the emit code needs to follow suit
189      SkDEBUGCODE(verify(fp);)
190  
191      return output;
192  }
193  
writeChildFPFunctions(const GrFragmentProcessor & fp,GrFragmentProcessor::ProgramImpl & impl)194  void GrGLSLProgramBuilder::writeChildFPFunctions(const GrFragmentProcessor& fp,
195                                                   GrFragmentProcessor::ProgramImpl& impl) {
196      fSubstageIndices.push_back(0);
197      for (int i = 0; i < impl.numChildProcessors(); ++i) {
198          GrFragmentProcessor::ProgramImpl* childImpl = impl.childProcessor(i);
199          if (!childImpl) {
200              continue;
201          }
202  
203          const GrFragmentProcessor* childFP = fp.childProcessor(i);
204          SkASSERT(childFP);
205  
206          this->writeFPFunction(*childFP, *childImpl);
207          ++fSubstageIndices.back();
208      }
209      fSubstageIndices.pop_back();
210  }
211  
writeFPFunction(const GrFragmentProcessor & fp,GrFragmentProcessor::ProgramImpl & impl)212  void GrGLSLProgramBuilder::writeFPFunction(const GrFragmentProcessor& fp,
213                                             GrFragmentProcessor::ProgramImpl& impl) {
214      constexpr const char*       kDstColor    = "_dst";
215                const char* const inputColor   = fp.isBlendFunction() ? "_src" : "_input";
216                const char*       sampleCoords = "_coords";
217      fFS.nextStage();
218      // Conceptually, an FP is always sampled at a particular coordinate. However, if it is only
219      // sampled by a chain of uniform matrix expressions (or legacy coord transforms), the value that
220      // would have been passed to _coords is lifted to the vertex shader and
221      // varying. In that case it uses that variable and we do not pass a second argument for _coords.
222      GrShaderVar params[3];
223      int numParams = 0;
224  
225      params[numParams++] = GrShaderVar(inputColor, kHalf4_GrSLType);
226  
227      if (fp.isBlendFunction()) {
228          // Blend functions take a dest color as input.
229          params[numParams++] = GrShaderVar(kDstColor, kHalf4_GrSLType);
230      }
231  
232      if (this->fragmentProcessorHasCoordsParam(&fp)) {
233          params[numParams++] = GrShaderVar(sampleCoords, kFloat2_GrSLType);
234      } else {
235          // Either doesn't use coords at all or sampled through a chain of passthrough/matrix
236          // samples usages. In the latter case the coords are emitted in the vertex shader as a
237          // varying, so this only has to access it. Add a float2 _coords variable that maps to the
238          // associated varying and replaces the absent 2nd argument to the fp's function.
239          GrShaderVar varying = fFPCoordsMap[&fp].coordsVarying;
240  
241          switch (varying.getType()) {
242              case kVoid_GrSLType:
243                  SkASSERT(!fp.usesSampleCoordsDirectly());
244                  break;
245              case kFloat2_GrSLType:
246                  // Just point the local coords to the varying
247                  sampleCoords = varying.getName().c_str();
248                  break;
249              case kFloat3_GrSLType:
250                  // Must perform the perspective divide in the frag shader based on the
251                  // varying, and since we won't actually have a function parameter for local
252                  // coords, add it as a local variable.
253                  fFS.codeAppendf("float2 %s = %s.xy / %s.z;\n",
254                                  sampleCoords,
255                                  varying.getName().c_str(),
256                                  varying.getName().c_str());
257                  break;
258              default:
259                  SkDEBUGFAILF("Unexpected varying type for coord: %s %d\n",
260                               varying.getName().c_str(),
261                               (int)varying.getType());
262                  break;
263          }
264      }
265  
266      SkASSERT(numParams <= (int)SK_ARRAY_COUNT(params));
267  
268      // First, emit every child's function. This needs to happen (even for children that aren't
269      // sampled), so that all of the expected uniforms are registered.
270      this->writeChildFPFunctions(fp, impl);
271      GrFragmentProcessor::ProgramImpl::EmitArgs args(&fFS,
272                                                      this->uniformHandler(),
273                                                      this->shaderCaps(),
274                                                      fp,
275                                                      inputColor,
276                                                      kDstColor,
277                                                      sampleCoords);
278  
279      impl.emitCode(args);
280      impl.setFunctionName(fFS.getMangledFunctionName(args.fFp.name()));
281  
282      fFS.emitFunction(kHalf4_GrSLType,
283                       impl.functionName(),
284                       SkMakeSpan(params, numParams),
285                       fFS.code().c_str());
286      fFS.deleteStage();
287  }
288  
emitAndInstallDstTexture()289  bool GrGLSLProgramBuilder::emitAndInstallDstTexture() {
290      fDstTextureOrigin = kTopLeft_GrSurfaceOrigin;
291  
292      const GrSurfaceProxyView& dstView = this->pipeline().dstProxyView();
293      if (this->pipeline().usesDstTexture()) {
294          // Set up a sampler handle for the destination texture.
295          GrTextureProxy* dstTextureProxy = dstView.asTextureProxy();
296          SkASSERT(dstTextureProxy);
297          const GrSwizzle& swizzle = dstView.swizzle();
298          fDstTextureSamplerHandle = this->emitSampler(dstTextureProxy->backendFormat(),
299                                                      GrSamplerState(), swizzle, "DstTextureSampler");
300          if (!fDstTextureSamplerHandle.isValid()) {
301              return false;
302          }
303          fDstTextureOrigin = dstView.origin();
304          SkASSERT(dstTextureProxy->textureType() != GrTextureType::kExternal);
305  
306          // Declare a _dstColor global variable which samples from the dest-texture sampler at the
307          // top of the fragment shader.
308          const char* dstTextureCoordsName;
309          fUniformHandles.fDstTextureCoordsUni = this->uniformHandler()->addUniform(
310                  /*owner=*/nullptr,
311                  kFragment_GrShaderFlag,
312                  kHalf4_GrSLType,
313                  "DstTextureCoords",
314                  &dstTextureCoordsName);
315          fFS.codeAppend("// Read color from copy of the destination\n");
316          fFS.codeAppendf("half2 _dstTexCoord = (half2(sk_FragCoord.xy) - %s.xy) * %s.zw;\n",
317                          dstTextureCoordsName, dstTextureCoordsName);
318          if (fDstTextureOrigin == kBottomLeft_GrSurfaceOrigin) {
319              fFS.codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n");
320          }
321          const char* dstColor = fFS.dstColor();
322          SkString dstColorDecl = SkStringPrintf("half4 %s;", dstColor);
323          fFS.definitionAppend(dstColorDecl.c_str());
324          fFS.codeAppendf("%s = ", dstColor);
325          fFS.appendTextureLookup(fDstTextureSamplerHandle, "_dstTexCoord");
326          fFS.codeAppend(";\n");
327      } else if (this->pipeline().usesDstInputAttachment()) {
328          // Set up an input attachment for the destination texture.
329          const GrSwizzle& swizzle = dstView.swizzle();
330          fDstTextureSamplerHandle = this->emitInputSampler(swizzle, "DstTextureInput");
331          if (!fDstTextureSamplerHandle.isValid()) {
332              return false;
333          }
334  
335          // Populate the _dstColor variable by loading from the input attachment at the top of the
336          // fragment shader.
337          fFS.codeAppend("// Read color from input attachment\n");
338          const char* dstColor = fFS.dstColor();
339          SkString dstColorDecl = SkStringPrintf("half4 %s;", dstColor);
340          fFS.definitionAppend(dstColorDecl.c_str());
341          fFS.codeAppendf("%s = ", dstColor);
342          fFS.appendInputLoad(fDstTextureSamplerHandle);
343          fFS.codeAppend(";\n");
344      }
345  
346      return true;
347  }
348  
emitAndInstallXferProc(const SkString & colorIn,const SkString & coverageIn)349  bool GrGLSLProgramBuilder::emitAndInstallXferProc(const SkString& colorIn,
350                                                    const SkString& coverageIn) {
351      // Program builders have a bit of state we need to clear with each effect
352      this->advanceStage();
353  
354      SkASSERT(!fXPImpl);
355      const GrXferProcessor& xp = this->pipeline().getXferProcessor();
356      fXPImpl = xp.makeProgramImpl();
357  
358      // Enable dual source secondary output if we have one
359      if (xp.hasSecondaryOutput()) {
360          fFS.enableSecondaryOutput();
361      }
362  
363      if (this->shaderCaps()->mustDeclareFragmentShaderOutput()) {
364          fFS.enableCustomOutput();
365      }
366  
367      SkString openBrace;
368      openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
369      fFS.codeAppend(openBrace.c_str());
370  
371      SkString finalInColor = colorIn.size() ? colorIn : SkString("float4(1)");
372  
373      GrXferProcessor::ProgramImpl::EmitArgs args(
374              &fFS,
375              this->uniformHandler(),
376              this->shaderCaps(),
377              xp,
378              finalInColor.c_str(),
379              coverageIn.size() ? coverageIn.c_str() : "float4(1)",
380              fFS.getPrimaryColorOutputName(),
381              fFS.getSecondaryColorOutputName(),
382              fDstTextureSamplerHandle,
383              fDstTextureOrigin,
384              this->pipeline().writeSwizzle());
385      fXPImpl->emitCode(args);
386  
387      // We have to check that effects and the code they emit are consistent, ie if an effect
388      // asks for dst color, then the emit code needs to follow suit
389      SkDEBUGCODE(verify(xp);)
390      fFS.codeAppend("}");
391      return true;
392  }
393  
emitSampler(const GrBackendFormat & backendFormat,GrSamplerState state,const GrSwizzle & swizzle,const char * name)394  GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(
395          const GrBackendFormat& backendFormat, GrSamplerState state, const GrSwizzle& swizzle,
396          const char* name) {
397      ++fNumFragmentSamplers;
398      return this->uniformHandler()->addSampler(backendFormat, state, swizzle, name,
399                                                this->shaderCaps());
400  }
401  
emitInputSampler(const GrSwizzle & swizzle,const char * name)402  GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitInputSampler(const GrSwizzle& swizzle,
403                                                                             const char* name) {
404      return this->uniformHandler()->addInputSampler(swizzle, name);
405  }
406  
checkSamplerCounts()407  bool GrGLSLProgramBuilder::checkSamplerCounts() {
408      const GrShaderCaps& shaderCaps = *this->shaderCaps();
409      if (fNumFragmentSamplers > shaderCaps.maxFragmentSamplers()) {
410          GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
411          return false;
412      }
413      return true;
414  }
415  
416  #ifdef SK_DEBUG
verify(const GrGeometryProcessor & geomProc)417  void GrGLSLProgramBuilder::verify(const GrGeometryProcessor& geomProc) {
418      SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
419  }
420  
verify(const GrFragmentProcessor & fp)421  void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
422      SkASSERT(fp.willReadDstColor() == fFS.fHasReadDstColorThisStage_DebugOnly);
423  }
424  
verify(const GrXferProcessor & xp)425  void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
426      SkASSERT(xp.willReadDstColor() == fFS.fHasReadDstColorThisStage_DebugOnly);
427  }
428  #endif
429  
getMangleSuffix() const430  SkString GrGLSLProgramBuilder::getMangleSuffix() const {
431      SkASSERT(fStageIndex >= 0);
432      SkString suffix;
433      suffix.printf("_S%d", fStageIndex);
434      for (auto c : fSubstageIndices) {
435          suffix.appendf("_c%d", c);
436      }
437      return suffix;
438  }
439  
nameVariable(char prefix,const char * name,bool mangle)440  SkString GrGLSLProgramBuilder::nameVariable(char prefix, const char* name, bool mangle) {
441      SkString out;
442      if ('\0' == prefix) {
443          out = name;
444      } else {
445          out.printf("%c%s", prefix, name);
446      }
447      if (mangle) {
448          SkString suffix = this->getMangleSuffix();
449          // Names containing "__" are reserved; add "x" if needed to avoid consecutive underscores.
450          const char *underscoreSplitter = out.endsWith('_') ? "x" : "";
451          out.appendf("%s%s", underscoreSplitter, suffix.c_str());
452      }
453      return out;
454  }
455  
nameExpression(SkString * output,const char * baseName)456  void GrGLSLProgramBuilder::nameExpression(SkString* output, const char* baseName) {
457      // Name a variable to hold stage result. If we already have a valid output name, use that as-is;
458      // otherwise, create a new mangled one.
459      if (output->isEmpty()) {
460          *output = this->nameVariable(/*prefix=*/'\0', baseName);
461      }
462  }
463  
appendUniformDecls(GrShaderFlags visibility,SkString * out) const464  void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
465      this->uniformHandler()->appendUniformDecls(visibility, out);
466  }
467  
addRTFlipUniform(const char * name)468  void GrGLSLProgramBuilder::addRTFlipUniform(const char* name) {
469      SkASSERT(!fUniformHandles.fRTFlipUni.isValid());
470      GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
471      fUniformHandles.fRTFlipUni =
472              uniformHandler->internalAddUniformArray(nullptr,
473                                                      kFragment_GrShaderFlag,
474                                                      kFloat2_GrSLType,
475                                                      name,
476                                                      false,
477                                                      0,
478                                                      nullptr);
479  }
480  
fragmentProcessorHasCoordsParam(const GrFragmentProcessor * fp)481  bool GrGLSLProgramBuilder::fragmentProcessorHasCoordsParam(const GrFragmentProcessor* fp) {
482      return fFPCoordsMap[fp].hasCoordsParam;
483  }
484  
finalizeShaders()485  void GrGLSLProgramBuilder::finalizeShaders() {
486      this->varyingHandler()->finalize();
487      fVS.finalize(kVertex_GrShaderFlag);
488      fFS.finalize(kFragment_GrShaderFlag);
489  }
490