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 "GrPipeline.h"
11 #include "glsl/GrGLSLFragmentProcessor.h"
12 #include "glsl/GrGLSLGeometryProcessor.h"
13 #include "glsl/GrGLSLVarying.h"
14 #include "glsl/GrGLSLXferProcessor.h"
15 
16 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
17 
GrGLSLProgramBuilder(const DrawArgs & args)18 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
19     : fVS(this)
20     , fGS(this)
21     , fFS(this, args.fDesc->header().fFragPosKey)
22     , fStageIndex(-1)
23     , fArgs(args)
24     , fGeometryProcessor(nullptr)
25     , fXferProcessor(nullptr) {
26 }
27 
emitAndInstallProcs(GrGLSLExpr4 * inputColor,GrGLSLExpr4 * inputCoverage,int maxTextures)28 bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
29                                                GrGLSLExpr4* inputCoverage,
30                                                int maxTextures) {
31     // First we loop over all of the installed processors and collect coord transforms.  These will
32     // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
33     const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
34     int totalTextures = primProc.numTextures();
35 
36     for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
37         const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
38 
39         if (!primProc.hasTransformedLocalCoords()) {
40             SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
41             processor.gatherCoordTransforms(&procCoords);
42         }
43 
44         totalTextures += processor.numTextures();
45         if (totalTextures >= maxTextures) {
46             GrCapsDebugf(this->caps(), "Program would use too many texture units\n");
47             return false;
48         }
49     }
50 
51     this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage);
52 
53     int numProcs = this->pipeline().numFragmentProcessors();
54     this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
55     this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
56                                   inputCoverage);
57     if (primProc.getPixelLocalStorageState() !=
58         GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) {
59         this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor,
60                                      *inputCoverage, this->pipeline().ignoresCoverage(),
61                                      primProc.getPixelLocalStorageState());
62         this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
63     }
64     return true;
65 }
66 
emitAndInstallPrimProc(const GrPrimitiveProcessor & proc,GrGLSLExpr4 * outputColor,GrGLSLExpr4 * outputCoverage)67 void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
68                                                   GrGLSLExpr4* outputColor,
69                                                   GrGLSLExpr4* outputCoverage) {
70     // Program builders have a bit of state we need to clear with each effect
71     AutoStageAdvance adv(this);
72     this->nameExpression(outputColor, "outputColor");
73     this->nameExpression(outputCoverage, "outputCoverage");
74 
75     // Enclose custom code in a block to avoid namespace conflicts
76     SkString openBrace;
77     openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
78     fFS.codeAppend(openBrace.c_str());
79     fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
80 
81     SkASSERT(!fGeometryProcessor);
82     fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps());
83 
84     SkSTArray<4, GrGLSLTextureSampler> samplers(proc.numTextures());
85     this->emitSamplers(proc, &samplers);
86 
87     GrGLSLGeometryProcessor::EmitArgs args(&fVS,
88                                            &fFS,
89                                            this->varyingHandler(),
90                                            this->uniformHandler(),
91                                            this->glslCaps(),
92                                            proc,
93                                            outputColor->c_str(),
94                                            outputCoverage->c_str(),
95                                            samplers,
96                                            fCoordTransforms,
97                                            &fOutCoords);
98     fGeometryProcessor->emitCode(args);
99 
100     // We have to check that effects and the code they emit are consistent, ie if an effect
101     // asks for dst color, then the emit code needs to follow suit
102     verify(proc);
103 
104     fFS.codeAppend("}");
105 }
106 
emitAndInstallFragProcs(int procOffset,int numProcs,GrGLSLExpr4 * inOut)107 void GrGLSLProgramBuilder::emitAndInstallFragProcs(int procOffset,
108                                                    int numProcs,
109                                                    GrGLSLExpr4* inOut) {
110     for (int i = procOffset; i < numProcs; ++i) {
111         GrGLSLExpr4 output;
112         const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
113         this->emitAndInstallFragProc(fp, i, *inOut, &output);
114         *inOut = output;
115     }
116 }
117 
118 // TODO Processors cannot output zeros because an empty string is all 1s
119 // the fix is to allow effects to take the GrGLSLExpr4 directly
emitAndInstallFragProc(const GrFragmentProcessor & fp,int index,const GrGLSLExpr4 & input,GrGLSLExpr4 * output)120 void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
121                                                   int index,
122                                                   const GrGLSLExpr4& input,
123                                                   GrGLSLExpr4* output) {
124     // Program builders have a bit of state we need to clear with each effect
125     AutoStageAdvance adv(this);
126     this->nameExpression(output, "output");
127 
128     // Enclose custom code in a block to avoid namespace conflicts
129     SkString openBrace;
130     openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
131     fFS.codeAppend(openBrace.c_str());
132 
133     GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
134 
135     SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures());
136     this->emitSamplers(fp, &samplers);
137 
138     GrGLSLFragmentProcessor::EmitArgs args(&fFS,
139                                            this->uniformHandler(),
140                                            this->glslCaps(),
141                                            fp,
142                                            output->c_str(),
143                                            input.isOnes() ? nullptr : input.c_str(),
144                                            fOutCoords[index],
145                                            samplers);
146     fragProc->emitCode(args);
147 
148     // We have to check that effects and the code they emit are consistent, ie if an effect
149     // asks for dst color, then the emit code needs to follow suit
150     verify(fp);
151     fFragmentProcessors.push_back(fragProc);
152 
153     fFS.codeAppend("}");
154 }
155 
emitAndInstallXferProc(const GrXferProcessor & xp,const GrGLSLExpr4 & colorIn,const GrGLSLExpr4 & coverageIn,bool ignoresCoverage,GrPixelLocalStorageState plsState)156 void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
157                                                   const GrGLSLExpr4& colorIn,
158                                                   const GrGLSLExpr4& coverageIn,
159                                                   bool ignoresCoverage,
160                                                   GrPixelLocalStorageState plsState) {
161     // Program builders have a bit of state we need to clear with each effect
162     AutoStageAdvance adv(this);
163 
164     SkASSERT(!fXferProcessor);
165     fXferProcessor = xp.createGLSLInstance();
166 
167     // Enable dual source secondary output if we have one
168     if (xp.hasSecondaryOutput()) {
169         fFS.enableSecondaryOutput();
170     }
171 
172     if (this->glslCaps()->mustDeclareFragmentShaderOutput()) {
173         fFS.enableCustomOutput();
174     }
175 
176     SkString openBrace;
177     openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
178     fFS.codeAppend(openBrace.c_str());
179 
180     SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures());
181     this->emitSamplers(xp, &samplers);
182 
183     bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState);
184     GrGLSLXferProcessor::EmitArgs args(&fFS,
185                                        this->uniformHandler(),
186                                        this->glslCaps(),
187                                        xp, colorIn.c_str(),
188                                        ignoresCoverage ? nullptr : coverageIn.c_str(),
189                                        fFS.getPrimaryColorOutputName(),
190                                        fFS.getSecondaryColorOutputName(),
191                                        samplers,
192                                        usePLSDstRead);
193     fXferProcessor->emitCode(args);
194 
195     // We have to check that effects and the code they emit are consistent, ie if an effect
196     // asks for dst color, then the emit code needs to follow suit
197     verify(xp);
198     fFS.codeAppend("}");
199 }
200 
emitFSOutputSwizzle(bool hasSecondaryOutput)201 void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
202     // Swizzle the fragment shader outputs if necessary.
203     GrSwizzle swizzle;
204     swizzle.setFromKey(this->desc().header().fOutputSwizzle);
205     if (swizzle != GrSwizzle::RGBA()) {
206         fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
207                         fFS.getPrimaryColorOutputName(),
208                         swizzle.c_str());
209         if (hasSecondaryOutput) {
210             fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
211                             fFS.getSecondaryColorOutputName(),
212                             swizzle.c_str());
213         }
214     }
215 }
216 
verify(const GrPrimitiveProcessor & gp)217 void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
218     SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
219 }
220 
verify(const GrXferProcessor & xp)221 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
222     SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
223 }
224 
verify(const GrFragmentProcessor & fp)225 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
226     SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
227 }
228 
nameVariable(SkString * out,char prefix,const char * name,bool mangle)229 void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
230     if ('\0' == prefix) {
231         *out = name;
232     } else {
233         out->printf("%c%s", prefix, name);
234     }
235     if (mangle) {
236         if (out->endsWith('_')) {
237             // Names containing "__" are reserved.
238             out->append("x");
239         }
240         out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str());
241     }
242 }
243 
nameExpression(GrGLSLExpr4 * output,const char * baseName)244 void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
245     // create var to hold stage result.  If we already have a valid output name, just use that
246     // otherwise create a new mangled one.  This name is only valid if we are reordering stages
247     // and have to tell stage exactly where to put its output.
248     SkString outName;
249     if (output->isValid()) {
250         outName = output->c_str();
251     } else {
252         this->nameVariable(&outName, '\0', baseName);
253     }
254     fFS.codeAppendf("vec4 %s;", outName.c_str());
255     *output = outName;
256 }
257 
appendUniformDecls(GrShaderFlags visibility,SkString * out) const258 void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
259     this->uniformHandler()->appendUniformDecls(visibility, out);
260 }
261 
addRTAdjustmentUniform(GrSLPrecision precision,const char * name,const char ** outName)262 void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision,
263                                                   const char* name,
264                                                   const char** outName) {
265         SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
266         fUniformHandles.fRTAdjustmentUni =
267             this->uniformHandler()->addUniform(kVertex_GrShaderFlag,
268                                                kVec4f_GrSLType,
269                                                precision,
270                                                name,
271                                                outName);
272 }
273 
addRTHeightUniform(const char * name,const char ** outName)274 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** outName) {
275         SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
276         GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
277         fUniformHandles.fRTHeightUni =
278             uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
279                                                     kFloat_GrSLType, kDefault_GrSLPrecision,
280                                                     name, false, 0, outName);
281 }
282 
cleanupFragmentProcessors()283 void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
284     for (int i = 0; i < fFragmentProcessors.count(); ++i) {
285         delete fFragmentProcessors[i];
286     }
287 }
288 
finalizeShaders()289 void GrGLSLProgramBuilder::finalizeShaders() {
290     this->varyingHandler()->finalize();
291     fVS.finalize(kVertex_GrShaderFlag);
292     fFS.finalize(kFragment_GrShaderFlag);
293 
294 }
295