1 /*
2 * Copyright 2014 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 "GrGLProgramBuilder.h"
9
10 #include "gl/GrGLGeometryProcessor.h"
11 #include "gl/GrGLGpu.h"
12 #include "gl/GrGLPathProcessor.h"
13 #include "gl/GrGLProgram.h"
14 #include "gl/GrGLSLPrettyPrint.h"
15 #include "gl/GrGLUniformHandle.h"
16 #include "gl/GrGLXferProcessor.h"
17 #include "GrAutoLocaleSetter.h"
18 #include "GrCoordTransform.h"
19 #include "GrGLProgramBuilder.h"
20 #include "GrTexture.h"
21 #include "SkRTConf.h"
22 #include "SkTraceEvent.h"
23
24 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
25 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
26
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
28
29 class GrGLNvprProgramBuilder : public GrGLProgramBuilder {
30 public:
GrGLNvprProgramBuilder(GrGLGpu * gpu,const DrawArgs & args)31 GrGLNvprProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
32 : INHERITED(gpu, args) {}
33
createProgram(GrGLuint programID)34 GrGLProgram* createProgram(GrGLuint programID) override {
35 // this is just for nvpr es, which has separable varyings that are plugged in after
36 // building
37 GrGLPathProcessor* pathProc =
38 static_cast<GrGLPathProcessor*>(fGeometryProcessor->fGLProc.get());
39 pathProc->resolveSeparableVaryings(fGpu, programID);
40 return SkNEW_ARGS(GrGLNvprProgram, (fGpu, this->desc(), fUniformHandles, programID,
41 fUniforms,
42 fGeometryProcessor,
43 fXferProcessor, fFragmentProcessors.get()));
44 }
45
46 private:
47 typedef GrGLProgramBuilder INHERITED;
48 };
49
50
51
52 //////////////////////////////////////////////////////////////////////////////
53
54 const int GrGLProgramBuilder::kVarsPerBlock = 8;
55
CreateProgram(const DrawArgs & args,GrGLGpu * gpu)56 GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gpu) {
57 GrAutoLocaleSetter als("C");
58
59 // create a builder. This will be handed off to effects so they can use it to add
60 // uniforms, varyings, textures, etc
61 SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(args, gpu));
62
63 GrGLProgramBuilder* pb = builder.get();
64
65 // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can
66 // seed correctly here
67 GrGLSLExpr4 inputColor;
68 GrGLSLExpr4 inputCoverage;
69
70 if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) {
71 return NULL;
72 }
73
74 return pb->finalize();
75 }
76
CreateProgramBuilder(const DrawArgs & args,GrGLGpu * gpu)77 GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const DrawArgs& args,
78 GrGLGpu* gpu) {
79 if (args.fPrimitiveProcessor->isPathRendering()) {
80 SkASSERT(gpu->glCaps().shaderCaps()->pathRenderingSupport() &&
81 !args.fPrimitiveProcessor->willUseGeoShader() &&
82 args.fPrimitiveProcessor->numAttribs() == 0);
83 return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, args));
84 } else {
85 return SkNEW_ARGS(GrGLProgramBuilder, (gpu, args));
86 }
87 }
88
89 /////////////////////////////////////////////////////////////////////////////
90
GrGLProgramBuilder(GrGLGpu * gpu,const DrawArgs & args)91 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
92 : fVS(this)
93 , fGS(this)
94 , fFS(this, args.fDesc->header().fFragPosKey)
95 , fOutOfStage(true)
96 , fStageIndex(-1)
97 , fGeometryProcessor(NULL)
98 , fXferProcessor(NULL)
99 , fArgs(args)
100 , fGpu(gpu)
101 , fUniforms(kVarsPerBlock) {
102 }
103
addVarying(const char * name,GrGLVarying * varying,GrSLPrecision fsPrecision)104 void GrGLProgramBuilder::addVarying(const char* name,
105 GrGLVarying* varying,
106 GrSLPrecision fsPrecision) {
107 SkASSERT(varying);
108 if (varying->vsVarying()) {
109 fVS.addVarying(name, varying);
110 }
111 if (this->primitiveProcessor().willUseGeoShader()) {
112 fGS.addVarying(name, varying);
113 }
114 if (varying->fsVarying()) {
115 fFS.addVarying(varying, fsPrecision);
116 }
117 }
118
addPassThroughAttribute(const GrPrimitiveProcessor::Attribute * input,const char * output)119 void GrGLProgramBuilder::addPassThroughAttribute(const GrPrimitiveProcessor::Attribute* input,
120 const char* output) {
121 GrSLType type = GrVertexAttribTypeToSLType(input->fType);
122 GrGLVertToFrag v(type);
123 this->addVarying(input->fName, &v);
124 fVS.codeAppendf("%s = %s;", v.vsOut(), input->fName);
125 fFS.codeAppendf("%s = %s;", output, v.fsIn());
126 }
127
nameVariable(SkString * out,char prefix,const char * name)128 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
129 if ('\0' == prefix) {
130 *out = name;
131 } else {
132 out->printf("%c%s", prefix, name);
133 }
134 if (!fOutOfStage) {
135 if (out->endsWith('_')) {
136 // Names containing "__" are reserved.
137 out->append("x");
138 }
139 out->appendf("_Stage%d", fStageIndex);
140 }
141 }
142
addUniformArray(uint32_t visibility,GrSLType type,GrSLPrecision precision,const char * name,int count,const char ** outName)143 GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(
144 uint32_t visibility,
145 GrSLType type,
146 GrSLPrecision precision,
147 const char* name,
148 int count,
149 const char** outName) {
150 SkASSERT(name && strlen(name));
151 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
152 SkASSERT(0 == (~kVisibilityMask & visibility));
153 SkASSERT(0 != visibility);
154 SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
155
156 UniformInfo& uni = fUniforms.push_back();
157 uni.fVariable.setType(type);
158 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
159 // TODO this is a bit hacky, lets think of a better way. Basically we need to be able to use
160 // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB
161 // exactly what name it wants to use for the uniform view matrix. If we prefix anythings, then
162 // the names will mismatch. I think the correct solution is to have all GPs which need the
163 // uniform view matrix, they should upload the view matrix in their setData along with regular
164 // uniforms.
165 char prefix = 'u';
166 if ('u' == name[0]) {
167 prefix = '\0';
168 }
169 this->nameVariable(uni.fVariable.accessName(), prefix, name);
170 uni.fVariable.setArrayCount(count);
171 uni.fVisibility = visibility;
172 uni.fVariable.setPrecision(precision);
173
174 if (outName) {
175 *outName = uni.fVariable.c_str();
176 }
177 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
178 }
179
appendUniformDecls(ShaderVisibility visibility,SkString * out) const180 void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
181 SkString* out) const {
182 for (int i = 0; i < fUniforms.count(); ++i) {
183 if (fUniforms[i].fVisibility & visibility) {
184 fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out);
185 out->append(";\n");
186 }
187 }
188 }
189
ctxInfo() const190 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
191 return fGpu->ctxInfo();
192 }
193
emitAndInstallProcs(GrGLSLExpr4 * inputColor,GrGLSLExpr4 * inputCoverage)194 bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) {
195 // First we loop over all of the installed processors and collect coord transforms. These will
196 // be sent to the GrGLPrimitiveProcessor in its emitCode function
197 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
198 int totalTextures = primProc.numTextures();
199 const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits();
200 SkSTArray<8, GrGLProcessor::TransformedCoordsArray> outCoords;
201 for (int i = 0; i < this->pipeline().numFragmentStages(); i++) {
202 const GrFragmentProcessor* processor = this->pipeline().getFragmentStage(i).processor();
203 SkSTArray<2, const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
204 for (int t = 0; t < processor->numTransforms(); t++) {
205 procCoords.push_back(&processor->coordTransform(t));
206 }
207
208 totalTextures += processor->numTextures();
209 if (totalTextures >= maxTextureUnits) {
210 GrContextDebugf(fGpu->getContext(), "Program would use too many texture units\n");
211 return false;
212 }
213 }
214
215 this->emitAndInstallProc(primProc, inputColor, inputCoverage);
216
217 fFragmentProcessors.reset(SkNEW(GrGLInstalledFragProcs));
218 int numProcs = this->pipeline().numFragmentStages();
219 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentStages(), inputColor);
220 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentStages(), numProcs,
221 inputCoverage);
222 this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage);
223 return true;
224 }
225
emitAndInstallFragProcs(int procOffset,int numProcs,GrGLSLExpr4 * inOut)226 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
227 int numProcs,
228 GrGLSLExpr4* inOut) {
229 for (int e = procOffset; e < numProcs; ++e) {
230 GrGLSLExpr4 output;
231 const GrPendingFragmentStage& stage = this->pipeline().getFragmentStage(e);
232 this->emitAndInstallProc(stage, e, *inOut, &output);
233 *inOut = output;
234 }
235 }
236
nameExpression(GrGLSLExpr4 * output,const char * baseName)237 void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
238 // create var to hold stage result. If we already have a valid output name, just use that
239 // otherwise create a new mangled one. This name is only valid if we are reordering stages
240 // and have to tell stage exactly where to put its output.
241 SkString outName;
242 if (output->isValid()) {
243 outName = output->c_str();
244 } else {
245 this->nameVariable(&outName, '\0', baseName);
246 }
247 fFS.codeAppendf("vec4 %s;", outName.c_str());
248 *output = outName;
249 }
250
251 // TODO Processors cannot output zeros because an empty string is all 1s
252 // the fix is to allow effects to take the GrGLSLExpr4 directly
emitAndInstallProc(const GrPendingFragmentStage & proc,int index,const GrGLSLExpr4 & input,GrGLSLExpr4 * output)253 void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& proc,
254 int index,
255 const GrGLSLExpr4& input,
256 GrGLSLExpr4* output) {
257 // Program builders have a bit of state we need to clear with each effect
258 AutoStageAdvance adv(this);
259 this->nameExpression(output, "output");
260
261 // Enclose custom code in a block to avoid namespace conflicts
262 SkString openBrace;
263 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
264 fFS.codeAppend(openBrace.c_str());
265
266 this->emitAndInstallProc(proc, index, output->c_str(), input.isOnes() ? NULL : input.c_str());
267
268 fFS.codeAppend("}");
269 }
270
emitAndInstallProc(const GrPrimitiveProcessor & proc,GrGLSLExpr4 * outputColor,GrGLSLExpr4 * outputCoverage)271 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc,
272 GrGLSLExpr4* outputColor,
273 GrGLSLExpr4* outputCoverage) {
274 // Program builders have a bit of state we need to clear with each effect
275 AutoStageAdvance adv(this);
276 this->nameExpression(outputColor, "outputColor");
277 this->nameExpression(outputCoverage, "outputCoverage");
278
279 // Enclose custom code in a block to avoid namespace conflicts
280 SkString openBrace;
281 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
282 fFS.codeAppend(openBrace.c_str());
283
284 this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str());
285
286 fFS.codeAppend("}");
287 }
288
emitAndInstallProc(const GrPendingFragmentStage & fs,int index,const char * outColor,const char * inColor)289 void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& fs,
290 int index,
291 const char* outColor,
292 const char* inColor) {
293 GrGLInstalledFragProc* ifp = SkNEW(GrGLInstalledFragProc);
294
295 const GrFragmentProcessor& fp = *fs.processor();
296 ifp->fGLProc.reset(fp.createGLInstance());
297
298 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(fp.numTextures());
299 this->emitSamplers(fp, &samplers, ifp);
300
301 ifp->fGLProc->emitCode(this, fp, outColor, inColor, fOutCoords[index], samplers);
302
303 // We have to check that effects and the code they emit are consistent, ie if an effect
304 // asks for dst color, then the emit code needs to follow suit
305 verify(fp);
306 fFragmentProcessors->fProcs.push_back(ifp);
307 }
308
emitAndInstallProc(const GrPrimitiveProcessor & gp,const char * outColor,const char * outCoverage)309 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp,
310 const char* outColor,
311 const char* outCoverage) {
312 SkASSERT(!fGeometryProcessor);
313 fGeometryProcessor = SkNEW(GrGLInstalledGeoProc);
314
315 const GrBatchTracker& bt = this->batchTracker();
316 fGeometryProcessor->fGLProc.reset(gp.createGLInstance(bt, *fGpu->glCaps().glslCaps()));
317
318 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(gp.numTextures());
319 this->emitSamplers(gp, &samplers, fGeometryProcessor);
320
321 GrGLGeometryProcessor::EmitArgs args(this, gp, bt, outColor, outCoverage, samplers,
322 fCoordTransforms, &fOutCoords);
323 fGeometryProcessor->fGLProc->emitCode(args);
324
325 // We have to check that effects and the code they emit are consistent, ie if an effect
326 // asks for dst color, then the emit code needs to follow suit
327 verify(gp);
328 }
329
emitAndInstallXferProc(const GrXferProcessor & xp,const GrGLSLExpr4 & colorIn,const GrGLSLExpr4 & coverageIn)330 void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
331 const GrGLSLExpr4& colorIn,
332 const GrGLSLExpr4& coverageIn) {
333 // Program builders have a bit of state we need to clear with each effect
334 AutoStageAdvance adv(this);
335
336 SkASSERT(!fXferProcessor);
337 fXferProcessor = SkNEW(GrGLInstalledXferProc);
338
339 fXferProcessor->fGLProc.reset(xp.createGLInstance());
340
341 // Enable dual source secondary output if we have one
342 if (xp.hasSecondaryOutput()) {
343 fFS.enableSecondaryOutput();
344 }
345
346 // On any post 1.10 GLSL supporting GPU, we declare custom output
347 if (k110_GrGLSLGeneration != fFS.fProgramBuilder->gpu()->glslGeneration()) {
348 fFS.enableCustomOutput();
349 }
350
351 SkString openBrace;
352 openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
353 fFS.codeAppend(openBrace.c_str());
354
355 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(xp.numTextures());
356 this->emitSamplers(xp, &samplers, fXferProcessor);
357
358 GrGLXferProcessor::EmitArgs args(this, xp, colorIn.c_str(), coverageIn.c_str(),
359 fFS.getPrimaryColorOutputName(),
360 fFS.getSecondaryColorOutputName(), samplers);
361 fXferProcessor->fGLProc->emitCode(args);
362
363 // We have to check that effects and the code they emit are consistent, ie if an effect
364 // asks for dst color, then the emit code needs to follow suit
365 verify(xp);
366 fFS.codeAppend("}");
367 }
368
verify(const GrPrimitiveProcessor & gp)369 void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
370 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
371 }
372
verify(const GrXferProcessor & xp)373 void GrGLProgramBuilder::verify(const GrXferProcessor& xp) {
374 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
375 }
376
verify(const GrFragmentProcessor & fp)377 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
378 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
379 }
380
381 template <class Proc>
emitSamplers(const GrProcessor & processor,GrGLProcessor::TextureSamplerArray * outSamplers,GrGLInstalledProc<Proc> * ip)382 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
383 GrGLProcessor::TextureSamplerArray* outSamplers,
384 GrGLInstalledProc<Proc>* ip) {
385 int numTextures = processor.numTextures();
386 ip->fSamplers.push_back_n(numTextures);
387 SkString name;
388 for (int t = 0; t < numTextures; ++t) {
389 name.printf("Sampler%d", t);
390 ip->fSamplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
391 kSampler2D_GrSLType, kDefault_GrSLPrecision,
392 name.c_str());
393 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
394 (ip->fSamplers[t].fUniform, processor.textureAccess(t)));
395 }
396 }
397
finalize()398 GrGLProgram* GrGLProgramBuilder::finalize() {
399 // verify we can get a program id
400 GrGLuint programID;
401 GL_CALL_RET(programID, CreateProgram());
402 if (0 == programID) {
403 return NULL;
404 }
405
406 // compile shaders and bind attributes / uniforms
407 SkTDArray<GrGLuint> shadersToDelete;
408
409 if (!fVS.compileAndAttachShaders(programID, &shadersToDelete)) {
410 this->cleanupProgram(programID, shadersToDelete);
411 return NULL;
412 }
413
414 // NVPR actually requires a vertex shader to compile
415 bool useNvpr = primitiveProcessor().isPathRendering();
416 if (!useNvpr) {
417 fVS.bindVertexAttributes(programID);
418 }
419
420 if (!fFS.compileAndAttachShaders(programID, &shadersToDelete)) {
421 this->cleanupProgram(programID, shadersToDelete);
422 return NULL;
423 }
424
425 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
426 if (usingBindUniform) {
427 this->bindUniformLocations(programID);
428 }
429 fFS.bindFragmentShaderLocations(programID);
430 GL_CALL(LinkProgram(programID));
431
432 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
433 bool checkLinked = !fGpu->ctxInfo().isChromium();
434 #ifdef SK_DEBUG
435 checkLinked = true;
436 #endif
437 if (checkLinked) {
438 checkLinkStatus(programID);
439 }
440 if (!usingBindUniform) {
441 this->resolveUniformLocations(programID);
442 }
443
444 this->cleanupShaders(shadersToDelete);
445
446 return this->createProgram(programID);
447 }
448
bindUniformLocations(GrGLuint programID)449 void GrGLProgramBuilder::bindUniformLocations(GrGLuint programID) {
450 int count = fUniforms.count();
451 for (int i = 0; i < count; ++i) {
452 GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str()));
453 fUniforms[i].fLocation = i;
454 }
455 }
456
checkLinkStatus(GrGLuint programID)457 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
458 GrGLint linked = GR_GL_INIT_ZERO;
459 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
460 if (!linked) {
461 GrGLint infoLen = GR_GL_INIT_ZERO;
462 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
463 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
464 if (infoLen > 0) {
465 // retrieve length even though we don't need it to workaround
466 // bug in chrome cmd buffer param validation.
467 GrGLsizei length = GR_GL_INIT_ZERO;
468 GL_CALL(GetProgramInfoLog(programID,
469 infoLen+1,
470 &length,
471 (char*)log.get()));
472 SkDebugf("%s", (char*)log.get());
473 }
474 SkDEBUGFAIL("Error linking program");
475 GL_CALL(DeleteProgram(programID));
476 programID = 0;
477 }
478 return SkToBool(linked);
479 }
480
resolveUniformLocations(GrGLuint programID)481 void GrGLProgramBuilder::resolveUniformLocations(GrGLuint programID) {
482 int count = fUniforms.count();
483 for (int i = 0; i < count; ++i) {
484 GrGLint location;
485 GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariable.c_str()));
486 fUniforms[i].fLocation = location;
487 }
488 }
489
cleanupProgram(GrGLuint programID,const SkTDArray<GrGLuint> & shaderIDs)490 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
491 GL_CALL(DeleteProgram(programID));
492 cleanupShaders(shaderIDs);
493 }
cleanupShaders(const SkTDArray<GrGLuint> & shaderIDs)494 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
495 for (int i = 0; i < shaderIDs.count(); ++i) {
496 GL_CALL(DeleteShader(shaderIDs[i]));
497 }
498 }
499
createProgram(GrGLuint programID)500 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
501 return SkNEW_ARGS(GrGLProgram, (fGpu, this->desc(), fUniformHandles, programID, fUniforms,
502 fGeometryProcessor, fXferProcessor, fFragmentProcessors.get()));
503 }
504
505 ///////////////////////////////////////////////////////////////////////////////////////////////////
506
~GrGLInstalledFragProcs()507 GrGLInstalledFragProcs::~GrGLInstalledFragProcs() {
508 int numProcs = fProcs.count();
509 for (int e = 0; e < numProcs; ++e) {
510 SkDELETE(fProcs[e]);
511 }
512 }
513