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