• 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 "src/gpu/GrCaps.h"
11 #include "src/gpu/GrPipeline.h"
12 #include "src/gpu/GrRenderTarget.h"
13 #include "src/gpu/GrShaderCaps.h"
14 #include "src/gpu/GrTexturePriv.h"
15 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
16 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
17 #include "src/gpu/glsl/GrGLSLVarying.h"
18 #include "src/gpu/glsl/GrGLSLXferProcessor.h"
19 #include "src/sksl/SkSLCompiler.h"
20 
21 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
22 
GrGLSLProgramBuilder(GrRenderTarget * renderTarget,const GrProgramDesc & desc,const GrProgramInfo & programInfo)23 GrGLSLProgramBuilder::GrGLSLProgramBuilder(GrRenderTarget* renderTarget,
24                                            const GrProgramDesc& desc,
25                                            const GrProgramInfo& programInfo)
26         : fVS(this)
27         , fGS(this)
28         , fFS(this)
29         , fStageIndex(-1)
30         , fRenderTarget(renderTarget)
31         , fDesc(desc)
32         , fProgramInfo(programInfo)
33         , fGeometryProcessor(nullptr)
34         , fXferProcessor(nullptr)
35         , fNumFragmentSamplers(0) {}
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 & kGeometry_GrShaderFlag) {
44         SkASSERT(this->primitiveProcessor().willUseGeoShader());
45         fGS.addFeature(featureBit, extensionName);
46     }
47     if (shaders & kFragment_GrShaderFlag) {
48         fFS.addFeature(featureBit, extensionName);
49     }
50 }
51 
emitAndInstallProcs()52 bool GrGLSLProgramBuilder::emitAndInstallProcs() {
53     // First we loop over all of the installed processors and collect coord transforms.  These will
54     // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
55     SkString inputColor;
56     SkString inputCoverage;
57     this->emitAndInstallPrimProc(&inputColor, &inputCoverage);
58     this->emitAndInstallFragProcs(&inputColor, &inputCoverage);
59     this->emitAndInstallXferProc(inputColor, inputCoverage);
60 
61     return this->checkSamplerCounts();
62 }
63 
emitAndInstallPrimProc(SkString * outputColor,SkString * outputCoverage)64 void GrGLSLProgramBuilder::emitAndInstallPrimProc(SkString* outputColor,
65                                                   SkString* outputCoverage) {
66     const GrPrimitiveProcessor& proc = this->primitiveProcessor();
67 
68     // Because all the texture properties must be consistent between all the dynamic and fixed
69     // primProc proxies, we just deal w/ the first set of dynamic proxies or the set of fixed
70     // proxies here.
71     const GrSurfaceProxy* const* primProcProxies = nullptr;
72     if (fProgramInfo.hasDynamicPrimProcTextures()) {
73         primProcProxies = fProgramInfo.dynamicPrimProcTextures(0);
74     } else if (fProgramInfo.hasFixedPrimProcTextures()) {
75         primProcProxies = fProgramInfo.fixedPrimProcTextures();
76     }
77 
78     // Program builders have a bit of state we need to clear with each effect
79     AutoStageAdvance adv(this);
80     this->nameExpression(outputColor, "outputColor");
81     this->nameExpression(outputCoverage, "outputCoverage");
82 
83     SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
84     GrShaderFlags rtAdjustVisibility;
85     if (proc.willUseGeoShader()) {
86         rtAdjustVisibility = kGeometry_GrShaderFlag;
87     } else if (proc.willUseTessellationShaders()) {
88         rtAdjustVisibility = kTessEvaluation_GrShaderFlag;
89     } else {
90         rtAdjustVisibility = kVertex_GrShaderFlag;
91     }
92     fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(
93             rtAdjustVisibility, kFloat4_GrSLType, SkSL::Compiler::RTADJUST_NAME);
94     const char* rtAdjustName =
95         this->uniformHandler()->getUniformCStr(fUniformHandles.fRTAdjustmentUni);
96 
97     // Enclose custom code in a block to avoid namespace conflicts
98     SkString openBrace;
99     openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
100     fFS.codeAppend(openBrace.c_str());
101     fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
102 
103     SkASSERT(!fGeometryProcessor);
104     fGeometryProcessor.reset(proc.createGLSLInstance(*this->shaderCaps()));
105 
106     SkAutoSTMalloc<4, SamplerHandle> texSamplers(proc.numTextureSamplers());
107     for (int i = 0; i < proc.numTextureSamplers(); ++i) {
108         SkString name;
109         name.printf("TextureSampler_%d", i);
110         const auto& sampler = proc.textureSampler(i);
111         SkASSERT(sampler.textureType() == primProcProxies[i]->backendFormat().textureType());
112         texSamplers[i] = this->emitSampler(primProcProxies[i],
113                                            sampler.samplerState(),
114                                            sampler.swizzle(),
115                                            name.c_str());
116     }
117 
118     GrGLSLPrimitiveProcessor::FPCoordTransformHandler transformHandler(this->pipeline(),
119                                                                        &fTransformedCoordVars);
120     GrGLSLGeometryProcessor::EmitArgs args(&fVS,
121                                            proc.willUseGeoShader() ? &fGS : nullptr,
122                                            &fFS,
123                                            this->varyingHandler(),
124                                            this->uniformHandler(),
125                                            this->shaderCaps(),
126                                            proc,
127                                            outputColor->c_str(),
128                                            outputCoverage->c_str(),
129                                            rtAdjustName,
130                                            texSamplers.get(),
131                                            &transformHandler);
132     fGeometryProcessor->emitCode(args);
133 
134     // We have to check that effects and the code they emit are consistent, ie if an effect
135     // asks for dst color, then the emit code needs to follow suit
136     SkDEBUGCODE(verify(proc);)
137 
138     fFS.codeAppend("}");
139 }
140 
emitAndInstallFragProcs(SkString * color,SkString * coverage)141 void GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) {
142     int transformedCoordVarsIdx = 0;
143     SkString** inOut = &color;
144     SkSTArray<8, std::unique_ptr<GrGLSLFragmentProcessor>> glslFragmentProcessors;
145     for (int i = 0; i < this->pipeline().numFragmentProcessors(); ++i) {
146         if (i == this->pipeline().numColorFragmentProcessors()) {
147             inOut = &coverage;
148         }
149         SkString output;
150         const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
151         output = this->emitAndInstallFragProc(fp, i, transformedCoordVarsIdx, **inOut, output,
152                                               &glslFragmentProcessors);
153         for (const auto& subFP : GrFragmentProcessor::FPCRange(fp)) {
154             transformedCoordVarsIdx += subFP.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     int samplerIdx = 0;
188     for (const auto& subFP : GrFragmentProcessor::FPCRange(fp)) {
189         for (int i = 0; i < subFP.numTextureSamplers(); ++i) {
190             SkString name;
191             name.printf("TextureSampler_%d", samplerIdx++);
192             const auto& sampler = subFP.textureSampler(i);
193             texSamplers.emplace_back(this->emitSampler(sampler.view().proxy(),
194                                                        sampler.samplerState(),
195                                                        sampler.view().swizzle(),
196                                                        name.c_str()));
197         }
198     }
199     const GrGLSLPrimitiveProcessor::TransformVar* coordVars = fTransformedCoordVars.begin() +
200                                                               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 = this->pipeline().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     const GrSurfaceProxyView& dstView = this->pipeline().dstProxyView();
249     if (GrTextureProxy* dstTextureProxy = dstView.asTextureProxy()) {
250         // GrProcessor::TextureSampler sampler(dstTexture);
251         const GrSwizzle& swizzle = dstView.swizzle();
252         dstTextureSamplerHandle = this->emitSampler(dstTextureProxy, GrSamplerState(),
253                                                     swizzle, "DstTextureSampler");
254         dstTextureOrigin = dstView.origin();
255         SkASSERT(dstTextureProxy->textureType() != GrTextureType::kExternal);
256     }
257 
258     SkString finalInColor = colorIn.size() ? colorIn : SkString("float4(1)");
259 
260     GrGLSLXferProcessor::EmitArgs args(&fFS,
261                                        this->uniformHandler(),
262                                        this->shaderCaps(),
263                                        xp,
264                                        finalInColor.c_str(),
265                                        coverageIn.size() ? coverageIn.c_str() : "float4(1)",
266                                        fFS.getPrimaryColorOutputName(),
267                                        fFS.getSecondaryColorOutputName(),
268                                        dstTextureSamplerHandle,
269                                        dstTextureOrigin,
270                                        this->pipeline().outputSwizzle());
271     fXferProcessor->emitCode(args);
272 
273     // We have to check that effects and the code they emit are consistent, ie if an effect
274     // asks for dst color, then the emit code needs to follow suit
275     SkDEBUGCODE(verify(xp);)
276     fFS.codeAppend("}");
277 }
278 
emitSampler(const GrSurfaceProxy * texture,GrSamplerState state,const GrSwizzle & swizzle,const char * name)279 GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(const GrSurfaceProxy* texture,
280                                                                       GrSamplerState state,
281                                                                       const GrSwizzle& swizzle,
282                                                                       const char* name) {
283     ++fNumFragmentSamplers;
284     return this->uniformHandler()->addSampler(texture, state, swizzle, name, this->shaderCaps());
285 }
286 
checkSamplerCounts()287 bool GrGLSLProgramBuilder::checkSamplerCounts() {
288     const GrShaderCaps& shaderCaps = *this->shaderCaps();
289     if (fNumFragmentSamplers > shaderCaps.maxFragmentSamplers()) {
290         GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
291         return false;
292     }
293     return true;
294 }
295 
296 #ifdef SK_DEBUG
verify(const GrPrimitiveProcessor & gp)297 void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
298     SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
299     SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == gp.requestedFeatures());
300 }
301 
verify(const GrFragmentProcessor & fp)302 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
303     SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
304     SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == fp.requestedFeatures());
305 }
306 
verify(const GrXferProcessor & xp)307 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
308     SkASSERT(xp.willReadDstColor() == fFS.fHasReadDstColorThisStage_DebugOnly);
309     SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == xp.requestedFeatures());
310 }
311 #endif
312 
nameVariable(SkString * out,char prefix,const char * name,bool mangle)313 void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
314     if ('\0' == prefix) {
315         *out = name;
316     } else {
317         out->printf("%c%s", prefix, name);
318     }
319     if (mangle) {
320         if (out->endsWith('_')) {
321             // Names containing "__" are reserved.
322             out->append("x");
323         }
324         out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str());
325     }
326 }
327 
nameExpression(SkString * output,const char * baseName)328 void GrGLSLProgramBuilder::nameExpression(SkString* output, const char* baseName) {
329     // create var to hold stage result.  If we already have a valid output name, just use that
330     // otherwise create a new mangled one.  This name is only valid if we are reordering stages
331     // and have to tell stage exactly where to put its output.
332     SkString outName;
333     if (output->size()) {
334         outName = output->c_str();
335     } else {
336         this->nameVariable(&outName, '\0', baseName);
337     }
338     fFS.codeAppendf("half4 %s;", outName.c_str());
339     *output = outName;
340 }
341 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const342 void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
343     this->uniformHandler()->appendUniformDecls(visibility, out);
344 }
345 
addRTWidthUniform(const char * name)346 void GrGLSLProgramBuilder::addRTWidthUniform(const char* name) {
347     SkASSERT(!fUniformHandles.fRTWidthUni.isValid());
348     GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
349     fUniformHandles.fRTWidthUni =
350             uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag, kHalf_GrSLType, name,
351                                                     false, 0, nullptr);
352 }
353 
addRTHeightUniform(const char * name)354 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
355     SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
356     GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
357     fUniformHandles.fRTHeightUni =
358             uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag, kHalf_GrSLType, name,
359                                                     false, 0, nullptr);
360 }
361 
finalizeShaders()362 void GrGLSLProgramBuilder::finalizeShaders() {
363     this->varyingHandler()->finalize();
364     fVS.finalize(kVertex_GrShaderFlag);
365     if (this->primitiveProcessor().willUseGeoShader()) {
366         SkASSERT(this->shaderCaps()->geometryShaderSupport());
367         fGS.finalize(kGeometry_GrShaderFlag);
368     }
369     fFS.finalize(kFragment_GrShaderFlag);
370 }
371