• 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/GrPipeline.h"
14 #include "src/gpu/GrRenderTarget.h"
15 #include "src/gpu/GrShaderCaps.h"
16 #include "src/gpu/GrTexture.h"
17 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
18 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
19 #include "src/gpu/glsl/GrGLSLVarying.h"
20 #include "src/gpu/glsl/GrGLSLXferProcessor.h"
21 #include "src/sksl/SkSLCompiler.h"
22 #include "src/sksl/dsl/priv/DSLFPs.h"
23 
24 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
25 
GrGLSLProgramBuilder(const GrProgramDesc & desc,const GrProgramInfo & programInfo)26 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrProgramDesc& desc,
27                                            const GrProgramInfo& programInfo)
28         : fVS(this)
29         , fGS(this)
30         , fFS(this)
31         , fStageIndex(-1)
32         , fDesc(desc)
33         , fProgramInfo(programInfo)
34         , fGeometryProcessor(nullptr)
35         , fXferProcessor(nullptr)
36         , fNumFragmentSamplers(0) {}
37 
38 GrGLSLProgramBuilder::~GrGLSLProgramBuilder() = default;
39 
addFeature(GrShaderFlags shaders,uint32_t featureBit,const char * extensionName)40 void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
41                                       uint32_t featureBit,
42                                       const char* extensionName) {
43     if (shaders & kVertex_GrShaderFlag) {
44         fVS.addFeature(featureBit, extensionName);
45     }
46     if (shaders & kGeometry_GrShaderFlag) {
47         SkASSERT(this->geometryProcessor().willUseGeoShader());
48         fGS.addFeature(featureBit, extensionName);
49     }
50     if (shaders & kFragment_GrShaderFlag) {
51         fFS.addFeature(featureBit, extensionName);
52     }
53 }
54 
emitAndInstallProcs()55 bool GrGLSLProgramBuilder::emitAndInstallProcs() {
56     // First we loop over all of the installed processors and collect coord transforms.  These will
57     // be sent to the GrGLSLGeometryProcessor in its emitCode function
58     SkSL::dsl::Start(this->shaderCompiler());
59     SkString inputColor;
60     SkString inputCoverage;
61     if (!this->emitAndInstallPrimProc(&inputColor, &inputCoverage)) {
62         return false;
63     }
64     if (!this->emitAndInstallFragProcs(&inputColor, &inputCoverage)) {
65         return false;
66     }
67     if (!this->emitAndInstallXferProc(inputColor, inputCoverage)) {
68         return false;
69     }
70     fGeometryProcessor->emitTransformCode(&fVS, this->uniformHandler());
71     SkSL::dsl::End();
72 
73     return this->checkSamplerCounts();
74 }
75 
emitAndInstallPrimProc(SkString * outputColor,SkString * outputCoverage)76 bool GrGLSLProgramBuilder::emitAndInstallPrimProc(SkString* outputColor, SkString* outputCoverage) {
77     const GrGeometryProcessor& geomProc = this->geometryProcessor();
78 
79     // Program builders have a bit of state we need to clear with each effect
80     AutoStageAdvance adv(this);
81     this->nameExpression(outputColor, "outputColor");
82     this->nameExpression(outputCoverage, "outputCoverage");
83 
84     SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
85     GrShaderFlags rtAdjustVisibility;
86     if (geomProc.willUseGeoShader()) {
87         rtAdjustVisibility = kGeometry_GrShaderFlag;
88     } else if (geomProc.willUseTessellationShaders()) {
89         rtAdjustVisibility = kTessEvaluation_GrShaderFlag;
90     } else {
91         rtAdjustVisibility = kVertex_GrShaderFlag;
92     }
93     fUniformHandles.fRTAdjustmentUni = this->uniformHandler()->addUniform(
94             nullptr, rtAdjustVisibility, kFloat4_GrSLType, SkSL::Compiler::RTADJUST_NAME);
95 
96     fFS.codeAppendf("// Stage %d, %s\n", fStageIndex, geomProc.name());
97     fVS.codeAppendf("// Primitive Processor %s\n", geomProc.name());
98 
99     SkASSERT(!fGeometryProcessor);
100     fGeometryProcessor.reset(geomProc.createGLSLInstance(*this->shaderCaps()));
101 
102     SkAutoSTArray<4, SamplerHandle> texSamplers(geomProc.numTextureSamplers());
103     for (int i = 0; i < geomProc.numTextureSamplers(); ++i) {
104         SkString name;
105         name.printf("TextureSampler_%d", i);
106         const auto& sampler = geomProc.textureSampler(i);
107         texSamplers[i] = this->emitSampler(geomProc.textureSampler(i).backendFormat(),
108                                            sampler.samplerState(),
109                                            sampler.swizzle(),
110                                            name.c_str());
111         if (!texSamplers[i].isValid()) {
112             return false;
113         }
114     }
115 
116     GrGLSLGeometryProcessor::FPCoordTransformHandler transformHandler(this->pipeline(),
117                                                                       &fTransformedCoordVars);
118     GrGLSLGeometryProcessor::EmitArgs args(&fVS,
119                                            geomProc.willUseGeoShader() ? &fGS : nullptr,
120                                            &fFS,
121                                            this->varyingHandler(),
122                                            this->uniformHandler(),
123                                            this->shaderCaps(),
124                                            geomProc,
125                                            outputColor->c_str(),
126                                            outputCoverage->c_str(),
127                                            texSamplers.get(),
128                                            &transformHandler);
129     fGeometryProcessor->emitCode(args);
130 
131     // We have to check that effects and the code they emit are consistent, ie if an effect
132     // asks for dst color, then the emit code needs to follow suit
133     SkDEBUGCODE(verify(geomProc);)
134 
135     return true;
136 }
137 
emitAndInstallFragProcs(SkString * color,SkString * coverage)138 bool GrGLSLProgramBuilder::emitAndInstallFragProcs(SkString* color, SkString* coverage) {
139     int transformedCoordVarsIdx = 0;
140     int fpCount = this->pipeline().numFragmentProcessors();
141     SkASSERT(fFPImpls.empty());
142     fFPImpls.reserve(fpCount);
143     for (int i = 0; i < fpCount; ++i) {
144         SkString* inOut = this->pipeline().isColorFragmentProcessor(i) ? color : coverage;
145         SkString output;
146         const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
147         fFPImpls.push_back(fp.makeProgramImpl());
148         output = this->emitFragProc(fp,
149                                     *fFPImpls.back(),
150                                     transformedCoordVarsIdx,
151                                     *inOut,
152                                     output);
153         if (output.isEmpty()) {
154             return false;
155         }
156         for (const auto& subFP : GrFragmentProcessor::FPRange(fp)) {
157             transformedCoordVarsIdx += subFP.numVaryingCoordsUsed();
158         }
159         *inOut = std::move(output);
160     }
161     return true;
162 }
163 
emitFragProc(const GrFragmentProcessor & fp,GrGLSLFragmentProcessor & glslFP,int transformedCoordVarsIdx,const SkString & input,SkString output)164 SkString GrGLSLProgramBuilder::emitFragProc(const GrFragmentProcessor& fp,
165                                             GrGLSLFragmentProcessor& glslFP,
166                                             int transformedCoordVarsIdx,
167                                             const SkString& input,
168                                             SkString output) {
169     SkASSERT(input.size());
170     // Program builders have a bit of state we need to clear with each effect
171     AutoStageAdvance adv(this);
172     this->nameExpression(&output, "output");
173     fFS.codeAppendf("half4 %s;", output.c_str());
174 
175     int samplerIdx = 0;
176     for (auto [subFP, subGLSLFP] : GrGLSLFragmentProcessor::ParallelRange(fp, glslFP)) {
177         if (auto* te = subFP.asTextureEffect()) {
178             SkString name;
179             name.printf("TextureSampler_%d", samplerIdx++);
180 
181             GrSamplerState samplerState = te->samplerState();
182             const GrBackendFormat& format = te->view().proxy()->backendFormat();
183             GrSwizzle swizzle = te->view().swizzle();
184             SamplerHandle handle = this->emitSampler(format, samplerState, swizzle, name.c_str());
185             if (!handle.isValid()) {
186                 return {};
187             }
188             static_cast<GrTextureEffect::Impl&>(subGLSLFP).setSamplerHandle(handle);
189         }
190     }
191     const GrShaderVar* coordVars = fTransformedCoordVars.begin() + transformedCoordVarsIdx;
192     GrGLSLFragmentProcessor::TransformedCoordVars coords(&fp, coordVars);
193     GrGLSLFragmentProcessor::EmitArgs args(&fFS,
194                                            this->uniformHandler(),
195                                            this->shaderCaps(),
196                                            fp,
197                                            "_input",
198                                            "_coords",
199                                            coords);
200     auto name = fFS.writeProcessorFunction(&glslFP, args);
201     fFS.codeAppendf("%s = %s(%s);", output.c_str(), name.c_str(), input.c_str());
202 
203     // We have to check that effects and the code they emit are consistent, ie if an effect asks
204     // for dst color, then the emit code needs to follow suit
205     SkDEBUGCODE(verify(fp);)
206 
207     return output;
208 }
209 
emitAndInstallXferProc(const SkString & colorIn,const SkString & coverageIn)210 bool GrGLSLProgramBuilder::emitAndInstallXferProc(const SkString& colorIn,
211                                                   const SkString& coverageIn) {
212     // Program builders have a bit of state we need to clear with each effect
213     AutoStageAdvance adv(this);
214 
215     SkASSERT(!fXferProcessor);
216     const GrXferProcessor& xp = this->pipeline().getXferProcessor();
217     fXferProcessor.reset(xp.createGLSLInstance());
218 
219     // Enable dual source secondary output if we have one
220     if (xp.hasSecondaryOutput()) {
221         fFS.enableSecondaryOutput();
222     }
223 
224     if (this->shaderCaps()->mustDeclareFragmentShaderOutput()) {
225         fFS.enableCustomOutput();
226     }
227 
228     SkString openBrace;
229     openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
230     fFS.codeAppend(openBrace.c_str());
231 
232     SamplerHandle dstTextureSamplerHandle;
233     GrSurfaceOrigin dstTextureOrigin = kTopLeft_GrSurfaceOrigin;
234 
235     const GrSurfaceProxyView& dstView = this->pipeline().dstProxyView();
236     if (this->pipeline().usesDstTexture()) {
237         GrTextureProxy* dstTextureProxy = dstView.asTextureProxy();
238         SkASSERT(dstTextureProxy);
239         const GrSwizzle& swizzle = dstView.swizzle();
240         dstTextureSamplerHandle = this->emitSampler(dstTextureProxy->backendFormat(),
241                                                     GrSamplerState(), swizzle, "DstTextureSampler");
242         if (!dstTextureSamplerHandle.isValid()) {
243             return false;
244         }
245         dstTextureOrigin = dstView.origin();
246         SkASSERT(dstTextureProxy->textureType() != GrTextureType::kExternal);
247     } else if (this->pipeline().usesInputAttachment()) {
248         const GrSwizzle& swizzle = dstView.swizzle();
249         dstTextureSamplerHandle = this->emitInputSampler(swizzle, "DstTextureInput");
250         if (!dstTextureSamplerHandle.isValid()) {
251             return false;
252         }
253     }
254 
255     SkString finalInColor = colorIn.size() ? colorIn : SkString("float4(1)");
256 
257     GrGLSLXferProcessor::EmitArgs args(&fFS,
258                                        this->uniformHandler(),
259                                        this->shaderCaps(),
260                                        xp,
261                                        finalInColor.c_str(),
262                                        coverageIn.size() ? coverageIn.c_str() : "float4(1)",
263                                        fFS.getPrimaryColorOutputName(),
264                                        fFS.getSecondaryColorOutputName(),
265                                        this->pipeline().dstSampleType(),
266                                        dstTextureSamplerHandle,
267                                        dstTextureOrigin,
268                                        this->pipeline().writeSwizzle());
269     fXferProcessor->emitCode(args);
270 
271     // We have to check that effects and the code they emit are consistent, ie if an effect
272     // asks for dst color, then the emit code needs to follow suit
273     SkDEBUGCODE(verify(xp);)
274     fFS.codeAppend("}");
275     return true;
276 }
277 
emitSampler(const GrBackendFormat & backendFormat,GrSamplerState state,const GrSwizzle & swizzle,const char * name)278 GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitSampler(
279         const GrBackendFormat& backendFormat, GrSamplerState state, const GrSwizzle& swizzle,
280         const char* name) {
281     ++fNumFragmentSamplers;
282     return this->uniformHandler()->addSampler(backendFormat, state, swizzle, name,
283                                               this->shaderCaps());
284 }
285 
emitInputSampler(const GrSwizzle & swizzle,const char * name)286 GrGLSLProgramBuilder::SamplerHandle GrGLSLProgramBuilder::emitInputSampler(const GrSwizzle& swizzle,
287                                                                            const char* name) {
288     return this->uniformHandler()->addInputSampler(swizzle, name);
289 }
290 
checkSamplerCounts()291 bool GrGLSLProgramBuilder::checkSamplerCounts() {
292     const GrShaderCaps& shaderCaps = *this->shaderCaps();
293     if (fNumFragmentSamplers > shaderCaps.maxFragmentSamplers()) {
294         GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
295         return false;
296     }
297     return true;
298 }
299 
300 #ifdef SK_DEBUG
verify(const GrGeometryProcessor & geomProc)301 void GrGLSLProgramBuilder::verify(const GrGeometryProcessor& geomProc) {
302     SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
303     SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == geomProc.requestedFeatures());
304 }
305 
verify(const GrFragmentProcessor & fp)306 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
307     SkASSERT(!fFS.fHasReadDstColorThisStage_DebugOnly);
308     SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == fp.requestedFeatures());
309 }
310 
verify(const GrXferProcessor & xp)311 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
312     SkASSERT(xp.willReadDstColor() == fFS.fHasReadDstColorThisStage_DebugOnly);
313     SkASSERT(fFS.fUsedProcessorFeaturesThisStage_DebugOnly == xp.requestedFeatures());
314 }
315 #endif
316 
nameVariable(char prefix,const char * name,bool mangle)317 SkString GrGLSLProgramBuilder::nameVariable(char prefix, const char* name, bool mangle) {
318     SkString out;
319     if ('\0' == prefix) {
320         out = name;
321     } else {
322         out.printf("%c%s", prefix, name);
323     }
324     if (mangle) {
325         // Names containing "__" are reserved; add "x" if needed to avoid consecutive underscores.
326         const char *underscoreSplitter = out.endsWith('_') ? "x" : "";
327 
328         out.appendf("%s_Stage%d%s", underscoreSplitter, fStageIndex, fFS.getMangleString().c_str());
329     }
330     return out;
331 }
332 
nameExpression(SkString * output,const char * baseName)333 void GrGLSLProgramBuilder::nameExpression(SkString* output, const char* baseName) {
334     // Name a variable to hold stage result. If we already have a valid output name, use that as-is;
335     // otherwise, create a new mangled one.
336     if (output->isEmpty()) {
337         *output = this->nameVariable(/*prefix=*/'\0', baseName);
338     }
339 }
340 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const341 void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
342     this->uniformHandler()->appendUniformDecls(visibility, out);
343 }
344 
addRTHeightUniform(const char * name)345 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name) {
346     SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
347     GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
348     fUniformHandles.fRTHeightUni =
349             uniformHandler->internalAddUniformArray(nullptr, kFragment_GrShaderFlag, kHalf_GrSLType,
350                                                     name, false, 0, nullptr);
351 }
352 
finalizeShaders()353 void GrGLSLProgramBuilder::finalizeShaders() {
354     this->varyingHandler()->finalize();
355     fVS.finalize(kVertex_GrShaderFlag);
356     if (this->geometryProcessor().willUseGeoShader()) {
357         SkASSERT(this->shaderCaps()->geometryShaderSupport());
358         fGS.finalize(kGeometry_GrShaderFlag);
359     }
360     fFS.finalize(kFragment_GrShaderFlag);
361 }
362