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 "glsl/GrGLSLProgramBuilder.h"
9 
10 #include "GrCaps.h"
11 #include "GrPipeline.h"
12 #include "GrShaderCaps.h"
13 #include "GrTexturePriv.h"
14 #include "glsl/GrGLSLFragmentProcessor.h"
15 #include "glsl/GrGLSLGeometryProcessor.h"
16 #include "glsl/GrGLSLVarying.h"
17 #include "glsl/GrGLSLXferProcessor.h"
18 #include "SkSLCompiler.h"
19 
20 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
21 
GrGLSLProgramBuilder(const GrPipeline & pipeline,const GrPrimitiveProcessor & primProc,GrProgramDesc * desc)22 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline,
23                                            const GrPrimitiveProcessor& primProc,
24                                            GrProgramDesc* desc)
25     : fVS(this)
26     , fGS(this)
27     , fFS(this)
28     , fStageIndex(-1)
29     , fPipeline(pipeline)
30     , fPrimProc(primProc)
31     , fDesc(desc)
32     , fGeometryProcessor(nullptr)
33     , fXferProcessor(nullptr)
34     , fNumVertexSamplers(0)
35     , fNumGeometrySamplers(0)
36     , fNumFragmentSamplers(0) {
37 }
38 
addFeature(GrShaderFlags shaders,uint32_t featureBit,const char * extensionName)39 void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
40                                       uint32_t featureBit,
41                                       const char* extensionName) {
42     if (shaders & kVertex_GrShaderFlag) {
43         fVS.addFeature(featureBit, extensionName);
44     }
45     if (shaders & kGeometry_GrShaderFlag) {
46         SkASSERT(this->primitiveProcessor().willUseGeoShader());
47         fGS.addFeature(featureBit, extensionName);
48     }
49     if (shaders & kFragment_GrShaderFlag) {
50         fFS.addFeature(featureBit, extensionName);
51     }
52 }
53 
emitAndInstallProcs()54 bool GrGLSLProgramBuilder::emitAndInstallProcs() {
55     // First we loop over all of the installed processors and collect coord transforms.  These will
56     // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
57     const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
58 
59     SkString inputColor;
60     SkString inputCoverage;
61     this->emitAndInstallPrimProc(primProc, &inputColor, &inputCoverage);
62     this->emitAndInstallFragProcs(&inputColor, &inputCoverage);
63     this->emitAndInstallXferProc(inputColor, inputCoverage);
64     this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
65 
66     return this->checkSamplerCounts();
67 }
68 
emitAndInstallPrimProc(const GrPrimitiveProcessor & proc,SkString * outputColor,SkString * outputCoverage)69 void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
70                                                   SkString* outputColor,
71                                                   SkString* outputCoverage) {
72     // Program builders have a bit of state we need to clear with each effect
73     AutoStageAdvance adv(this);
74     this->nameExpression(outputColor, "outputColor");
75     this->nameExpression(outputCoverage, "outputCoverage");
76 
77     SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
78     GrShaderFlags rtAdjustVisibility;
79     if (proc.willUseGeoShader()) {
80         rtAdjustVisibility = kGeometry_GrShaderFlag;
81     } else {
82         rtAdjustVisibility = kVertex_GrShaderFlag;
83     }
84     fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(
85                                                                      rtAdjustVisibility,
86                                                                      kFloat4_GrSLType,
87                                                                      SkSL::Compiler::RTADJUST_NAME);
88     const char* rtAdjustName =
89         this->uniformHandler()->getUniformCStr(fUniformHandles.fRTAdjustmentUni);
90 
91     // Enclose custom code in a block to avoid namespace conflicts
92     SkString openBrace;
93     openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
94     fFS.codeAppend(openBrace.c_str());
95     fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
96 
97     SkASSERT(!fGeometryProcessor);
98     fGeometryProcessor.reset(proc.createGLSLInstance(*this->shaderCaps()));
99 
100     SkSTArray<4, SamplerHandle>      texSamplers(proc.numTextureSamplers());
101     SkSTArray<2, TexelBufferHandle>  texelBuffers(proc.numBuffers());
102     this->emitSamplers(proc, &texSamplers, &texelBuffers);
103 
104     GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(fPipeline,
105                                                                        &fTransformedCoordVars);
106     GrGLSLGeometryProcessor::EmitArgs args(&fVS,
107                                            proc.willUseGeoShader() ? &fGS : nullptr,
108                                            &fFS,
109                                            this->varyingHandler(),
110                                            this->uniformHandler(),
111                                            this->shaderCaps(),
112                                            proc,
113                                            outputColor->c_str(),
114                                            outputCoverage->c_str(),
115                                            rtAdjustName,
116                                            texSamplers.begin(),
117                                            texelBuffers.begin(),
118                                            &transformHandler);
119     fGeometryProcessor->emitCode(args);
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(proc);)
124 
125     fFS.codeAppend("}");
126 }
127 
emitAndInstallFragProcs(SkString * color,SkString * coverage)128 void GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) {
129     int transformedCoordVarsIdx = 0;
130     SkString** inOut = &color;
131     for (int i = 0; i < this->pipeline().numFragmentProcessors(); ++i) {
132         if (i == this->pipeline().numColorFragmentProcessors()) {
133             inOut = &coverage;
134         }
135         SkString output;
136         const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
137         output = this->emitAndInstallFragProc(fp, i, transformedCoordVarsIdx, **inOut, output);
138         GrFragmentProcessor::Iter iter(&fp);
139         while (const GrFragmentProcessor* fp = iter.next()) {
140             transformedCoordVarsIdx += fp->numCoordTransforms();
141         }
142         **inOut = output;
143     }
144 }
145 
146 // TODO Processors cannot output zeros because an empty string is all 1s
147 // the fix is to allow effects to take the SkString directly
emitAndInstallFragProc(const GrFragmentProcessor & fp,int index,int transformedCoordVarsIdx,const SkString & input,SkString output)148 SkString GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
149                                                       int index,
150                                                       int transformedCoordVarsIdx,
151                                                       const SkString& input,
152                                                       SkString output) {
153     SkASSERT(input.size());
154     // Program builders have a bit of state we need to clear with each effect
155     AutoStageAdvance adv(this);
156     this->nameExpression(&output, "output");
157 
158     // Enclose custom code in a block to avoid namespace conflicts
159     SkString openBrace;
160     openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
161     fFS.codeAppend(openBrace.c_str());
162 
163     GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
164 
165     SkSTArray<4, SamplerHandle> textureSamplerArray(fp.numTextureSamplers());
166     SkSTArray<2, TexelBufferHandle> texelBufferArray(fp.numBuffers());
167     GrFragmentProcessor::Iter iter(&fp);
168     while (const GrFragmentProcessor* subFP = iter.next()) {
169         this->emitSamplers(*subFP, &textureSamplerArray, &texelBufferArray);
170     }
171 
172     const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
173     GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
174     GrGLSLFragmentProcessor::TextureSamplers textureSamplers(&fp, textureSamplerArray.begin());
175     GrGLSLFragmentProcessor::TexelBuffers texelBuffers(&fp, texelBufferArray.begin());
176     GrGLSLFragmentProcessor::EmitArgs args(&fFS,
177                                            this->uniformHandler(),
178                                            this->shaderCaps(),
179                                            fp,
180                                            output.c_str(),
181                                            input.c_str(),
182                                            coords,
183                                            textureSamplers,
184                                            texelBuffers);
185 
186     fragProc->emitCode(args);
187 
188     // We have to check that effects and the code they emit are consistent, ie if an effect
189     // asks for dst color, then the emit code needs to follow suit
190     SkDEBUGCODE(verify(fp);)
191     fFragmentProcessors.push_back(fragProc);
192 
193     fFS.codeAppend("}");
194     return output;
195 }
196 
emitAndInstallXferProc(const SkString & colorIn,const SkString & coverageIn)197 void GrGLSLProgramBuilder::emitAndInstallXferProc(const SkString& colorIn,
198                                                   const SkString& coverageIn) {
199     // Program builders have a bit of state we need to clear with each effect
200     AutoStageAdvance adv(this);
201 
202     SkASSERT(!fXferProcessor);
203     const GrXferProcessor& xp = fPipeline.getXferProcessor();
204     fXferProcessor.reset(xp.createGLSLInstance());
205 
206     // Enable dual source secondary output if we have one
207     if (xp.hasSecondaryOutput()) {
208         fFS.enableSecondaryOutput();
209     }
210 
211     if (this->shaderCaps()->mustDeclareFragmentShaderOutput()) {
212         fFS.enableCustomOutput();
213     }
214 
215     SkString openBrace;
216     openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
217     fFS.codeAppend(openBrace.c_str());
218 
219     SamplerHandle dstTextureSamplerHandle;
220     GrSurfaceOrigin dstTextureOrigin = kTopLeft_GrSurfaceOrigin;
221 
222     if (GrTexture* dstTexture = fPipeline.peekDstTexture()) {
223         // GrProcessor::TextureSampler sampler(dstTexture);
224         SkString name("DstTextureSampler");
225         dstTextureSamplerHandle =
226                 this->emitSampler(dstTexture->texturePriv().samplerType(), dstTexture->config(),
227                                   "DstTextureSampler", kFragment_GrShaderFlag);
228         dstTextureOrigin = fPipeline.dstTextureProxy()->origin();
229         SkASSERT(kTextureExternalSampler_GrSLType != dstTexture->texturePriv().samplerType());
230     }
231 
232     GrGLSLXferProcessor::EmitArgs args(&fFS,
233                                        this->uniformHandler(),
234                                        this->shaderCaps(),
235                                        xp,
236                                        colorIn.size() ? colorIn.c_str() : "float4(1)",
237                                        coverageIn.size() ? coverageIn.c_str() : "float4(1)",
238                                        fFS.getPrimaryColorOutputName(),
239                                        fFS.getSecondaryColorOutputName(),
240                                        dstTextureSamplerHandle,
241                                        dstTextureOrigin);
242     fXferProcessor->emitCode(args);
243 
244     // We have to check that effects and the code they emit are consistent, ie if an effect
245     // asks for dst color, then the emit code needs to follow suit
246     SkDEBUGCODE(verify(xp);)
247     fFS.codeAppend("}");
248 }
249 
emitSamplers(const GrResourceIOProcessor & processor,SkTArray<SamplerHandle> * outTexSamplerHandles,SkTArray<TexelBufferHandle> * outTexelBufferHandles)250 void GrGLSLProgramBuilder::emitSamplers(
251         const GrResourceIOProcessor& processor,
252         SkTArray<SamplerHandle>* outTexSamplerHandles,
253         SkTArray<TexelBufferHandle>* outTexelBufferHandles) {
254     SkString name;
255     int numTextureSamplers = processor.numTextureSamplers();
256     for (int t = 0; t < numTextureSamplers; ++t) {
257         const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(t);
258         name.printf("TextureSampler_%d", outTexSamplerHandles->count());
259         GrSLType samplerType = sampler.peekTexture()->texturePriv().samplerType();
260         if (kTextureExternalSampler_GrSLType == samplerType) {
261             const char* externalFeatureString =
262                     this->shaderCaps()->externalTextureExtensionString();
263             // We shouldn't ever create a GrGLTexture that requires external sampler type
264             SkASSERT(externalFeatureString);
265             this->addFeature(sampler.visibility(),
266                              1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
267                              externalFeatureString);
268         }
269         outTexSamplerHandles->emplace_back(this->emitSampler(
270                 samplerType, sampler.peekTexture()->config(), name.c_str(), sampler.visibility()));
271     }
272     if (int numBuffers = processor.numBuffers()) {
273         SkASSERT(this->shaderCaps()->texelBufferSupport());
274         GrShaderFlags texelBufferVisibility = kNone_GrShaderFlags;
275 
276         for (int b = 0; b < numBuffers; ++b) {
277             const GrResourceIOProcessor::BufferAccess& access = processor.bufferAccess(b);
278             name.printf("TexelBuffer_%d", outTexelBufferHandles->count());
279             outTexelBufferHandles->emplace_back(
280                     this->emitTexelBuffer(access.texelConfig(), name.c_str(), access.visibility()));
281             texelBufferVisibility |= access.visibility();
282         }
283 
284         if (const char* extension = this->shaderCaps()->texelBufferExtensionString()) {
285             this->addFeature(texelBufferVisibility,
286                              1 << GrGLSLShaderBuilder::kTexelBuffer_GLSLPrivateFeature,
287                              extension);
288         }
289     }
290 }
291 
updateSamplerCounts(GrShaderFlags visibility)292 void GrGLSLProgramBuilder::updateSamplerCounts(GrShaderFlags visibility) {
293     if (visibility & kVertex_GrShaderFlag) {
294         ++fNumVertexSamplers;
295     }
296     if (visibility & kGeometry_GrShaderFlag) {
297         SkASSERT(this->primitiveProcessor().willUseGeoShader());
298         ++fNumGeometrySamplers;
299     }
300     if (visibility & kFragment_GrShaderFlag) {
301         ++fNumFragmentSamplers;
302     }
303 }
304 
emitSampler(GrSLType samplerType,GrPixelConfig config,const char * name,GrShaderFlags visibility)305 GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(GrSLType samplerType,
306                                                                       GrPixelConfig config,
307                                                                       const char* name,
308                                                                       GrShaderFlags visibility) {
309     this->updateSamplerCounts(visibility);
310     GrSLPrecision precision = GrSLSamplerPrecision(config);
311     GrSwizzle swizzle = this->shaderCaps()->configTextureSwizzle(config);
312     return this->uniformHandler()->addSampler(visibility, swizzle, samplerType, precision, name);
313 }
314 
emitTexelBuffer(GrPixelConfig config,const char * name,GrShaderFlags visibility)315 GrGLSLProgramBuilder::TexelBufferHandle GrGLSLProgramBuilder::emitTexelBuffer(
316         GrPixelConfig config, const char* name, GrShaderFlags visibility) {
317     this->updateSamplerCounts(visibility);
318     GrSLPrecision precision = GrSLSamplerPrecision(config);
319     return this->uniformHandler()->addTexelBuffer(visibility, precision, name);
320 }
321 
emitFSOutputSwizzle(bool hasSecondaryOutput)322 void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
323     // Swizzle the fragment shader outputs if necessary.
324     GrSwizzle swizzle;
325     swizzle.setFromKey(this->desc()->header().fOutputSwizzle);
326     if (swizzle != GrSwizzle::RGBA()) {
327         fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
328                         fFS.getPrimaryColorOutputName(),
329                         swizzle.c_str());
330         if (hasSecondaryOutput) {
331             fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
332                             fFS.getSecondaryColorOutputName(),
333                             swizzle.c_str());
334         }
335     }
336 }
337 
checkSamplerCounts()338 bool GrGLSLProgramBuilder::checkSamplerCounts() {
339     const GrShaderCaps& shaderCaps = *this->shaderCaps();
340     if (fNumVertexSamplers > shaderCaps.maxVertexSamplers()) {
341         GrCapsDebugf(this->caps(), "Program would use too many vertex samplers\n");
342         return false;
343     }
344     if (fNumGeometrySamplers > shaderCaps.maxGeometrySamplers()) {
345         GrCapsDebugf(this->caps(), "Program would use too many geometry samplers\n");
346         return false;
347     }
348     if (fNumFragmentSamplers > shaderCaps.maxFragmentSamplers()) {
349         GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
350         return false;
351     }
352     // If the same sampler is used in two different shaders, it counts as two combined samplers.
353     int numCombinedSamplers = fNumVertexSamplers + fNumGeometrySamplers + fNumFragmentSamplers;
354     if (numCombinedSamplers > shaderCaps.maxCombinedSamplers()) {
355         GrCapsDebugf(this->caps(), "Program would use too many combined samplers\n");
356         return false;
357     }
358     return true;
359 }
360 
361 #ifdef SK_DEBUG
verify(const GrPrimitiveProcessor & gp)362 void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
363 }
364 
verify(const GrXferProcessor & xp)365 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
366     SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
367 }
368 
verify(const GrFragmentProcessor & fp)369 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
370 }
371 #endif
372 
nameVariable(SkString * out,char prefix,const char * name,bool mangle)373 void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
374     if ('\0' == prefix) {
375         *out = name;
376     } else {
377         out->printf("%c%s", prefix, name);
378     }
379     if (mangle) {
380         if (out->endsWith('_')) {
381             // Names containing "__" are reserved.
382             out->append("x");
383         }
384         out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str());
385     }
386 }
387 
nameExpression(SkString * output,const char * baseName)388 void GrGLSLProgramBuilder::nameExpression(SkString* output, const char* baseName) {
389     // create var to hold stage result.  If we already have a valid output name, just use that
390     // otherwise create a new mangled one.  This name is only valid if we are reordering stages
391     // and have to tell stage exactly where to put its output.
392     SkString outName;
393     if (output->size()) {
394         outName = output->c_str();
395     } else {
396         this->nameVariable(&outName, '\0', baseName);
397     }
398     fFS.codeAppendf("half4 %s;", outName.c_str());
399     *output = outName;
400 }
401 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const402 void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
403     this->uniformHandler()->appendUniformDecls(visibility, out);
404 }
405 
addRTHeightUniform(const char * name)406 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
407         SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
408         GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
409         fUniformHandles.fRTHeightUni =
410             uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
411                                                     kHalf_GrSLType, kDefault_GrSLPrecision,
412                                                     name, false, 0, nullptr);
413 }
414 
cleanupFragmentProcessors()415 void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
416     for (int i = 0; i < fFragmentProcessors.count(); ++i) {
417         delete fFragmentProcessors[i];
418     }
419 }
420 
finalizeShaders()421 void GrGLSLProgramBuilder::finalizeShaders() {
422     this->varyingHandler()->finalize();
423     fVS.finalize(kVertex_GrShaderFlag);
424     if (this->primitiveProcessor().willUseGeoShader()) {
425         SkASSERT(this->shaderCaps()->geometryShaderSupport());
426         fGS.finalize(kGeometry_GrShaderFlag);
427     }
428     fFS.finalize(kFragment_GrShaderFlag);
429 }
430