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