blob: 64bc0640b9d92547aa18f1d883424a14ceb1944a [file] [log] [blame]
egdaniel8dcdedc2015-11-11 06:27:20 -08001/*
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
egdanielfa896322016-01-13 12:19:30 -080010#include "GrPipeline.h"
11#include "glsl/GrGLSLFragmentProcessor.h"
12#include "glsl/GrGLSLGeometryProcessor.h"
egdaniel9f1d4152016-02-10 09:50:38 -080013#include "glsl/GrGLSLVarying.h"
egdanielfa896322016-01-13 12:19:30 -080014#include "glsl/GrGLSLXferProcessor.h"
15
egdaniel8dcdedc2015-11-11 06:27:20 -080016const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
17
egdaniel0e1853c2016-03-17 11:35:45 -070018GrGLSLProgramBuilder::GrGLSLProgramBuilder(const GrPipeline& pipeline,
19 const GrPrimitiveProcessor& primProc,
20 const GrProgramDesc& desc)
egdaniel8dcdedc2015-11-11 06:27:20 -080021 : fVS(this)
22 , fGS(this)
cdalton28f45b92016-03-07 13:58:26 -080023 , fFS(this)
egdaniel8dcdedc2015-11-11 06:27:20 -080024 , fStageIndex(-1)
egdaniel0e1853c2016-03-17 11:35:45 -070025 , fPipeline(pipeline)
26 , fPrimProc(primProc)
27 , fDesc(desc)
egdanielfa896322016-01-13 12:19:30 -080028 , fGeometryProcessor(nullptr)
cdalton9c3f1432016-03-11 10:07:37 -080029 , fXferProcessor(nullptr)
cdalton9c3f1432016-03-11 10:07:37 -080030 , fNumVertexSamplers(0)
31 , fNumGeometrySamplers(0)
32 , fNumFragmentSamplers(0) {
33}
34
35void GrGLSLProgramBuilder::addFeature(GrShaderFlags shaders,
36 uint32_t featureBit,
37 const char* extensionName) {
38 if (shaders & kVertex_GrShaderFlag) {
39 fVS.addFeature(featureBit, extensionName);
40 }
41 if (shaders & kGeometry_GrShaderFlag) {
42 SkASSERT(this->glslCaps()->geometryShaderSupport());
43 fGS.addFeature(featureBit, extensionName);
44 }
45 if (shaders & kFragment_GrShaderFlag) {
46 fFS.addFeature(featureBit, extensionName);
47 }
egdanielfa896322016-01-13 12:19:30 -080048}
49
50bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
cdalton9c3f1432016-03-11 10:07:37 -080051 GrGLSLExpr4* inputCoverage) {
egdanielfa896322016-01-13 12:19:30 -080052 // First we loop over all of the installed processors and collect coord transforms. These will
53 // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
54 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
egdanielfa896322016-01-13 12:19:30 -080055
56 for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
57 const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
58
59 if (!primProc.hasTransformedLocalCoords()) {
60 SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
61 processor.gatherCoordTransforms(&procCoords);
62 }
egdanielfa896322016-01-13 12:19:30 -080063 }
64
65 this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage);
66
67 int numProcs = this->pipeline().numFragmentProcessors();
68 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
69 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
70 inputCoverage);
halcanary9d524f22016-03-29 09:03:52 -070071 if (primProc.getPixelLocalStorageState() !=
ethannicholas22793252016-01-30 09:59:10 -080072 GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) {
halcanary9d524f22016-03-29 09:03:52 -070073 this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor,
ethannicholas22793252016-01-30 09:59:10 -080074 *inputCoverage, this->pipeline().ignoresCoverage(),
75 primProc.getPixelLocalStorageState());
76 this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
77 }
cdalton9c3f1432016-03-11 10:07:37 -080078
79 return this->checkSamplerCounts();
egdanielfa896322016-01-13 12:19:30 -080080}
81
82void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
83 GrGLSLExpr4* outputColor,
84 GrGLSLExpr4* outputCoverage) {
85 // Program builders have a bit of state we need to clear with each effect
86 AutoStageAdvance adv(this);
87 this->nameExpression(outputColor, "outputColor");
88 this->nameExpression(outputCoverage, "outputCoverage");
89
90 // Enclose custom code in a block to avoid namespace conflicts
91 SkString openBrace;
92 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
93 fFS.codeAppend(openBrace.c_str());
94 fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
95
96 SkASSERT(!fGeometryProcessor);
97 fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps());
98
egdaniel09aa1fc2016-04-20 07:09:46 -070099 SkSTArray<4, SamplerHandle> texSamplers(proc.numTextures());
100 SkSTArray<2, SamplerHandle> bufferSamplers(proc.numBuffers());
cdalton74b8d322016-04-11 14:47:28 -0700101 this->emitSamplers(proc, &texSamplers, &bufferSamplers);
egdanielfa896322016-01-13 12:19:30 -0800102
103 GrGLSLGeometryProcessor::EmitArgs args(&fVS,
104 &fFS,
105 this->varyingHandler(),
106 this->uniformHandler(),
107 this->glslCaps(),
108 proc,
109 outputColor->c_str(),
110 outputCoverage->c_str(),
egdaniel09aa1fc2016-04-20 07:09:46 -0700111 texSamplers.begin(),
112 bufferSamplers.begin(),
egdanielfa896322016-01-13 12:19:30 -0800113 fCoordTransforms,
114 &fOutCoords);
115 fGeometryProcessor->emitCode(args);
116
117 // We have to check that effects and the code they emit are consistent, ie if an effect
118 // asks for dst color, then the emit code needs to follow suit
cdalton87332102016-02-26 12:22:02 -0800119 SkDEBUGCODE(verify(proc);)
egdanielfa896322016-01-13 12:19:30 -0800120
121 fFS.codeAppend("}");
122}
123
124void GrGLSLProgramBuilder::emitAndInstallFragProcs(int procOffset,
125 int numProcs,
126 GrGLSLExpr4* inOut) {
127 for (int i = procOffset; i < numProcs; ++i) {
128 GrGLSLExpr4 output;
129 const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
130 this->emitAndInstallFragProc(fp, i, *inOut, &output);
131 *inOut = output;
132 }
133}
134
135// TODO Processors cannot output zeros because an empty string is all 1s
136// the fix is to allow effects to take the GrGLSLExpr4 directly
137void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
138 int index,
139 const GrGLSLExpr4& input,
140 GrGLSLExpr4* output) {
141 // Program builders have a bit of state we need to clear with each effect
142 AutoStageAdvance adv(this);
143 this->nameExpression(output, "output");
144
145 // Enclose custom code in a block to avoid namespace conflicts
146 SkString openBrace;
147 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
148 fFS.codeAppend(openBrace.c_str());
149
150 GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
151
egdaniel09aa1fc2016-04-20 07:09:46 -0700152 SkSTArray<4, SamplerHandle> texSamplers(fp.numTextures());
153 SkSTArray<2, SamplerHandle> bufferSamplers(fp.numBuffers());
cdalton74b8d322016-04-11 14:47:28 -0700154 this->emitSamplers(fp, &texSamplers, &bufferSamplers);
egdanielfa896322016-01-13 12:19:30 -0800155
156 GrGLSLFragmentProcessor::EmitArgs args(&fFS,
157 this->uniformHandler(),
158 this->glslCaps(),
159 fp,
160 output->c_str(),
161 input.isOnes() ? nullptr : input.c_str(),
162 fOutCoords[index],
egdaniel09aa1fc2016-04-20 07:09:46 -0700163 texSamplers.begin(),
164 bufferSamplers.begin());
egdanielfa896322016-01-13 12:19:30 -0800165 fragProc->emitCode(args);
166
167 // We have to check that effects and the code they emit are consistent, ie if an effect
168 // asks for dst color, then the emit code needs to follow suit
cdalton87332102016-02-26 12:22:02 -0800169 SkDEBUGCODE(verify(fp);)
egdanielfa896322016-01-13 12:19:30 -0800170 fFragmentProcessors.push_back(fragProc);
171
172 fFS.codeAppend("}");
173}
174
175void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
176 const GrGLSLExpr4& colorIn,
177 const GrGLSLExpr4& coverageIn,
ethannicholas22793252016-01-30 09:59:10 -0800178 bool ignoresCoverage,
179 GrPixelLocalStorageState plsState) {
egdanielfa896322016-01-13 12:19:30 -0800180 // Program builders have a bit of state we need to clear with each effect
181 AutoStageAdvance adv(this);
182
183 SkASSERT(!fXferProcessor);
184 fXferProcessor = xp.createGLSLInstance();
185
186 // Enable dual source secondary output if we have one
187 if (xp.hasSecondaryOutput()) {
188 fFS.enableSecondaryOutput();
189 }
190
191 if (this->glslCaps()->mustDeclareFragmentShaderOutput()) {
192 fFS.enableCustomOutput();
193 }
194
195 SkString openBrace;
196 openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
197 fFS.codeAppend(openBrace.c_str());
198
egdaniel09aa1fc2016-04-20 07:09:46 -0700199 SkSTArray<4, SamplerHandle> texSamplers(xp.numTextures());
200 SkSTArray<2, SamplerHandle> bufferSamplers(xp.numBuffers());
cdalton74b8d322016-04-11 14:47:28 -0700201 this->emitSamplers(xp, &texSamplers, &bufferSamplers);
egdanielfa896322016-01-13 12:19:30 -0800202
ethannicholas22793252016-01-30 09:59:10 -0800203 bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState);
egdanielfa896322016-01-13 12:19:30 -0800204 GrGLSLXferProcessor::EmitArgs args(&fFS,
205 this->uniformHandler(),
206 this->glslCaps(),
207 xp, colorIn.c_str(),
208 ignoresCoverage ? nullptr : coverageIn.c_str(),
209 fFS.getPrimaryColorOutputName(),
210 fFS.getSecondaryColorOutputName(),
egdaniel09aa1fc2016-04-20 07:09:46 -0700211 texSamplers.begin(),
212 bufferSamplers.begin(),
ethannicholas22793252016-01-30 09:59:10 -0800213 usePLSDstRead);
egdanielfa896322016-01-13 12:19:30 -0800214 fXferProcessor->emitCode(args);
215
216 // We have to check that effects and the code they emit are consistent, ie if an effect
217 // asks for dst color, then the emit code needs to follow suit
cdalton87332102016-02-26 12:22:02 -0800218 SkDEBUGCODE(verify(xp);)
egdanielfa896322016-01-13 12:19:30 -0800219 fFS.codeAppend("}");
220}
221
cdalton9c3f1432016-03-11 10:07:37 -0800222void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor,
egdaniel09aa1fc2016-04-20 07:09:46 -0700223 SkTArray<SamplerHandle>* outTexSamplers,
224 SkTArray<SamplerHandle>* outBufferSamplers) {
cdalton9c3f1432016-03-11 10:07:37 -0800225 SkString name;
cdalton74b8d322016-04-11 14:47:28 -0700226 int numTextures = processor.numTextures();
cdalton9c3f1432016-03-11 10:07:37 -0800227 for (int t = 0; t < numTextures; ++t) {
228 const GrTextureAccess& access = processor.textureAccess(t);
cdalton9c3f1432016-03-11 10:07:37 -0800229 GrSLType samplerType = access.getTexture()->samplerType();
egdaniel990dbc82016-07-13 14:09:30 -0700230 if (kTextureExternalSampler_GrSLType == samplerType) {
cdalton9c3f1432016-03-11 10:07:37 -0800231 const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
232 // We shouldn't ever create a GrGLTexture that requires external sampler type
233 SkASSERT(externalFeatureString);
cdalton74b8d322016-04-11 14:47:28 -0700234 this->addFeature(access.getVisibility(),
cdalton9c3f1432016-03-11 10:07:37 -0800235 1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
236 externalFeatureString);
237 }
cdalton74b8d322016-04-11 14:47:28 -0700238 name.printf("TextureSampler%d", t);
239 this->emitSampler(samplerType, access.getTexture()->config(),
240 name.c_str(), access.getVisibility(), outTexSamplers);
cdalton9c3f1432016-03-11 10:07:37 -0800241 }
cdalton74b8d322016-04-11 14:47:28 -0700242
243 if (int numBuffers = processor.numBuffers()) {
244 SkASSERT(this->glslCaps()->texelBufferSupport());
245 GrShaderFlags texelBufferVisibility = kNone_GrShaderFlags;
246
247 for (int b = 0; b < numBuffers; ++b) {
248 const GrBufferAccess& access = processor.bufferAccess(b);
249 name.printf("BufferSampler%d", b);
egdaniel990dbc82016-07-13 14:09:30 -0700250 this->emitSampler(kTextureBufferSampler_GrSLType, access.texelConfig(), name.c_str(),
cdalton74b8d322016-04-11 14:47:28 -0700251 access.visibility(), outBufferSamplers);
252 texelBufferVisibility |= access.visibility();
253 }
254
255 if (const char* extension = this->glslCaps()->texelBufferExtensionString()) {
256 this->addFeature(texelBufferVisibility,
257 1 << GrGLSLShaderBuilder::kTexelBuffer_GLSLPrivateFeature,
258 extension);
259 }
260 }
261}
262
263void GrGLSLProgramBuilder::emitSampler(GrSLType samplerType,
264 GrPixelConfig config,
265 const char* name,
266 GrShaderFlags visibility,
egdaniel09aa1fc2016-04-20 07:09:46 -0700267 SkTArray<SamplerHandle>* outSamplers) {
cdalton74b8d322016-04-11 14:47:28 -0700268 if (visibility & kVertex_GrShaderFlag) {
269 ++fNumVertexSamplers;
270 }
271 if (visibility & kGeometry_GrShaderFlag) {
272 SkASSERT(this->primitiveProcessor().willUseGeoShader());
273 ++fNumGeometrySamplers;
274 }
275 if (visibility & kFragment_GrShaderFlag) {
276 ++fNumFragmentSamplers;
277 }
278 GrSLPrecision precision = this->glslCaps()->samplerPrecision(config, visibility);
egdaniel09aa1fc2016-04-20 07:09:46 -0700279 SamplerHandle handle = this->uniformHandler()->addSampler(visibility,
280 config,
281 samplerType,
282 precision,
283 name);
284 outSamplers->emplace_back(handle);
cdalton9c3f1432016-03-11 10:07:37 -0800285}
286
egdanielfa896322016-01-13 12:19:30 -0800287void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
288 // Swizzle the fragment shader outputs if necessary.
289 GrSwizzle swizzle;
290 swizzle.setFromKey(this->desc().header().fOutputSwizzle);
291 if (swizzle != GrSwizzle::RGBA()) {
292 fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
293 fFS.getPrimaryColorOutputName(),
294 swizzle.c_str());
295 if (hasSecondaryOutput) {
296 fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
297 fFS.getSecondaryColorOutputName(),
298 swizzle.c_str());
299 }
300 }
301}
302
cdalton9c3f1432016-03-11 10:07:37 -0800303bool GrGLSLProgramBuilder::checkSamplerCounts() {
304 const GrGLSLCaps& glslCaps = *this->glslCaps();
305 if (fNumVertexSamplers > glslCaps.maxVertexSamplers()) {
306 GrCapsDebugf(this->caps(), "Program would use too many vertex samplers\n");
307 return false;
308 }
309 if (fNumGeometrySamplers > glslCaps.maxGeometrySamplers()) {
310 GrCapsDebugf(this->caps(), "Program would use too many geometry samplers\n");
311 return false;
312 }
313 if (fNumFragmentSamplers > glslCaps.maxFragmentSamplers()) {
314 GrCapsDebugf(this->caps(), "Program would use too many fragment samplers\n");
315 return false;
316 }
317 // If the same sampler is used in two different shaders, it counts as two combined samplers.
318 int numCombinedSamplers = fNumVertexSamplers + fNumGeometrySamplers + fNumFragmentSamplers;
319 if (numCombinedSamplers > glslCaps.maxCombinedSamplers()) {
320 GrCapsDebugf(this->caps(), "Program would use too many combined samplers\n");
321 return false;
322 }
323 return true;
324}
325
cdalton87332102016-02-26 12:22:02 -0800326#ifdef SK_DEBUG
egdanielfa896322016-01-13 12:19:30 -0800327void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
cdalton87332102016-02-26 12:22:02 -0800328 SkASSERT(fFS.usedProcessorFeatures() == gp.requiredFeatures());
egdanielfa896322016-01-13 12:19:30 -0800329}
330
331void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
cdalton87332102016-02-26 12:22:02 -0800332 SkASSERT(fFS.usedProcessorFeatures() == xp.requiredFeatures());
egdanielfa896322016-01-13 12:19:30 -0800333 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
334}
335
336void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
cdalton87332102016-02-26 12:22:02 -0800337 SkASSERT(fFS.usedProcessorFeatures() == fp.requiredFeatures());
egdaniel8dcdedc2015-11-11 06:27:20 -0800338}
cdalton87332102016-02-26 12:22:02 -0800339#endif
egdaniel8dcdedc2015-11-11 06:27:20 -0800340
341void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
342 if ('\0' == prefix) {
343 *out = name;
344 } else {
345 out->printf("%c%s", prefix, name);
346 }
347 if (mangle) {
348 if (out->endsWith('_')) {
349 // Names containing "__" are reserved.
350 out->append("x");
351 }
352 out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str());
353 }
354}
355
egdanielfa896322016-01-13 12:19:30 -0800356void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
357 // create var to hold stage result. If we already have a valid output name, just use that
358 // otherwise create a new mangled one. This name is only valid if we are reordering stages
359 // and have to tell stage exactly where to put its output.
360 SkString outName;
361 if (output->isValid()) {
362 outName = output->c_str();
363 } else {
364 this->nameVariable(&outName, '\0', baseName);
365 }
366 fFS.codeAppendf("vec4 %s;", outName.c_str());
367 *output = outName;
368}
369
cdalton5e58cee2016-02-11 12:49:47 -0800370void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
egdaniel7ea439b2015-12-03 09:20:44 -0800371 this->uniformHandler()->appendUniformDecls(visibility, out);
372}
373
egdaniel09aa1fc2016-04-20 07:09:46 -0700374const GrGLSLSampler& GrGLSLProgramBuilder::getSampler(SamplerHandle handle) const {
375 return this->uniformHandler()->getSampler(handle);
376}
377
egdaniel7ea439b2015-12-03 09:20:44 -0800378void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision,
379 const char* name,
380 const char** outName) {
381 SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
382 fUniformHandles.fRTAdjustmentUni =
cdalton5e58cee2016-02-11 12:49:47 -0800383 this->uniformHandler()->addUniform(kVertex_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800384 kVec4f_GrSLType,
385 precision,
386 name,
387 outName);
388}
389
390void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** outName) {
391 SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
392 GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
393 fUniformHandles.fRTHeightUni =
cdalton5e58cee2016-02-11 12:49:47 -0800394 uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800395 kFloat_GrSLType, kDefault_GrSLPrecision,
396 name, false, 0, outName);
egdaniel8dcdedc2015-11-11 06:27:20 -0800397}
398
egdanielfa896322016-01-13 12:19:30 -0800399void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
400 for (int i = 0; i < fFragmentProcessors.count(); ++i) {
401 delete fFragmentProcessors[i];
402 }
403}
404
egdaniel9f1d4152016-02-10 09:50:38 -0800405void GrGLSLProgramBuilder::finalizeShaders() {
406 this->varyingHandler()->finalize();
cdalton5e58cee2016-02-11 12:49:47 -0800407 fVS.finalize(kVertex_GrShaderFlag);
408 fFS.finalize(kFragment_GrShaderFlag);
egdaniel9f1d4152016-02-10 09:50:38 -0800409
410}