2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "GrGLProgramBuilder.h"
10 #include "GrAutoLocaleSetter.h"
11 #include "GrCoordTransform.h"
12 #include "GrGLProgramBuilder.h"
13 #include "GrTexture.h"
15 #include "SkTraceEvent.h"
16 #include "gl/GrGLGeometryProcessor.h"
17 #include "gl/GrGLGpu.h"
18 #include "gl/GrGLProgram.h"
19 #include "gl/GrGLSLPrettyPrint.h"
20 #include "gl/GrGLXferProcessor.h"
21 #include "gl/builders/GrGLShaderStringBuilder.h"
22 #include "glsl/GrGLSLCaps.h"
23 #include "glsl/GrGLSLFragmentProcessor.h"
24 #include "glsl/GrGLSLProgramDataManager.h"
25 #include "glsl/GrGLSLTextureSampler.h"
27 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
28 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
30 GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gpu) {
31 GrAutoLocaleSetter als("C");
33 // create a builder. This will be handed off to effects so they can use it to add
34 // uniforms, varyings, textures, etc
35 SkAutoTDelete<GrGLProgramBuilder> builder(new GrGLProgramBuilder(gpu, args));
37 GrGLProgramBuilder* pb = builder.get();
39 // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can
40 // seed correctly here
41 GrGLSLExpr4 inputColor;
42 GrGLSLExpr4 inputCoverage;
44 if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) {
48 return pb->finalize();
51 /////////////////////////////////////////////////////////////////////////////
53 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
55 , fGeometryProcessor(nullptr)
56 , fXferProcessor(nullptr)
58 , fUniforms(kVarsPerBlock)
60 , fSeparableVaryingInfos(kVarsPerBlock) {
63 void GrGLProgramBuilder::addVarying(const char* name,
64 GrGLSLVarying* varying,
65 GrSLPrecision precision) {
67 if (varying->vsVarying()) {
68 fVS.addVarying(name, precision, varying);
70 if (this->primitiveProcessor().willUseGeoShader()) {
71 fGS.addVarying(name, precision, varying);
73 if (varying->fsVarying()) {
74 fFS.addVarying(varying, precision);
78 void GrGLProgramBuilder::addPassThroughAttribute(const GrPrimitiveProcessor::Attribute* input,
80 GrSLType type = GrVertexAttribTypeToSLType(input->fType);
81 GrGLSLVertToFrag v(type);
82 this->addVarying(input->fName, &v);
83 fVS.codeAppendf("%s = %s;", v.vsOut(), input->fName);
84 fFS.codeAppendf("%s = %s;", output, v.fsIn());
87 GrGLProgramBuilder::SeparableVaryingHandle GrGLProgramBuilder::addSeparableVarying(
90 GrSLPrecision fsPrecision) {
91 // This call is not used for non-NVPR backends.
92 SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport() &&
93 fArgs.fPrimitiveProcessor->isPathRendering() &&
94 !fArgs.fPrimitiveProcessor->willUseGeoShader() &&
95 fArgs.fPrimitiveProcessor->numAttribs() == 0);
96 this->addVarying(name, v, fsPrecision);
97 SeparableVaryingInfo& varyingInfo = fSeparableVaryingInfos.push_back();
98 varyingInfo.fVariable = this->getFragmentShaderBuilder()->fInputs.back();
99 varyingInfo.fLocation = fSeparableVaryingInfos.count() - 1;
100 return SeparableVaryingHandle(varyingInfo.fLocation);
103 GrGLSLProgramDataManager::UniformHandle GrGLProgramBuilder::internalAddUniformArray(
106 GrSLPrecision precision,
110 const char** outName) {
111 SkASSERT(name && strlen(name));
112 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
113 SkASSERT(0 == (~kVisibilityMask & visibility));
114 SkASSERT(0 != visibility);
115 SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
117 UniformInfo& uni = fUniforms.push_back();
118 uni.fVariable.setType(type);
119 uni.fVariable.setTypeModifier(GrGLSLShaderVar::kUniform_TypeModifier);
120 // TODO this is a bit hacky, lets think of a better way. Basically we need to be able to use
121 // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB
122 // exactly what name it wants to use for the uniform view matrix. If we prefix anythings, then
123 // the names will mismatch. I think the correct solution is to have all GPs which need the
124 // uniform view matrix, they should upload the view matrix in their setData along with regular
127 if ('u' == name[0]) {
130 this->nameVariable(uni.fVariable.accessName(), prefix, name, mangleName);
131 uni.fVariable.setArrayCount(count);
132 uni.fVisibility = visibility;
133 uni.fVariable.setPrecision(precision);
136 *outName = uni.fVariable.c_str();
138 return GrGLSLProgramDataManager::UniformHandle(fUniforms.count() - 1);
141 void GrGLProgramBuilder::onAppendUniformDecls(ShaderVisibility visibility, SkString* out) const {
142 for (int i = 0; i < fUniforms.count(); ++i) {
143 if (fUniforms[i].fVisibility & visibility) {
144 fUniforms[i].fVariable.appendDecl(this->glslCaps(), out);
150 const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const {
151 return this->fGpu->ctxInfo().caps()->glslCaps();
154 bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) {
155 // First we loop over all of the installed processors and collect coord transforms. These will
156 // be sent to the GrGLPrimitiveProcessor in its emitCode function
157 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
158 int totalTextures = primProc.numTextures();
159 const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits();
161 for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
162 const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
164 if (!primProc.hasTransformedLocalCoords()) {
165 SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
166 processor.gatherCoordTransforms(&procCoords);
169 totalTextures += processor.numTextures();
170 if (totalTextures >= maxTextureUnits) {
171 GrCapsDebugf(fGpu->caps(), "Program would use too many texture units\n");
176 this->emitAndInstallProc(primProc, inputColor, inputCoverage);
178 fFragmentProcessors.reset(new GrGLInstalledFragProcs);
179 int numProcs = this->pipeline().numFragmentProcessors();
180 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
181 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
183 this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage);
187 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
189 GrGLSLExpr4* inOut) {
190 for (int i = procOffset; i < numProcs; ++i) {
192 const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
193 this->emitAndInstallProc(fp, i, *inOut, &output);
198 void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
199 // create var to hold stage result. If we already have a valid output name, just use that
200 // otherwise create a new mangled one. This name is only valid if we are reordering stages
201 // and have to tell stage exactly where to put its output.
203 if (output->isValid()) {
204 outName = output->c_str();
206 this->nameVariable(&outName, '\0', baseName);
208 fFS.codeAppendf("vec4 %s;", outName.c_str());
212 // TODO Processors cannot output zeros because an empty string is all 1s
213 // the fix is to allow effects to take the GrGLSLExpr4 directly
214 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp,
216 const GrGLSLExpr4& input,
217 GrGLSLExpr4* output) {
218 // Program builders have a bit of state we need to clear with each effect
219 AutoStageAdvance adv(this);
220 this->nameExpression(output, "output");
222 // Enclose custom code in a block to avoid namespace conflicts
224 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
225 fFS.codeAppend(openBrace.c_str());
227 this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullptr : input.c_str());
232 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc,
233 GrGLSLExpr4* outputColor,
234 GrGLSLExpr4* outputCoverage) {
235 // Program builders have a bit of state we need to clear with each effect
236 AutoStageAdvance adv(this);
237 this->nameExpression(outputColor, "outputColor");
238 this->nameExpression(outputCoverage, "outputCoverage");
240 // Enclose custom code in a block to avoid namespace conflicts
242 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
243 fFS.codeAppend(openBrace.c_str());
244 fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
246 this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str());
251 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp,
253 const char* outColor,
254 const char* inColor) {
255 GrGLInstalledFragProc* ifp = new GrGLInstalledFragProc;
257 ifp->fGLProc.reset(fp.createGLInstance());
259 SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures());
260 this->emitSamplers(fp, &samplers, ifp);
262 GrGLSLFragmentProcessor::EmitArgs args(this,
268 ifp->fGLProc->emitCode(args);
270 // We have to check that effects and the code they emit are consistent, ie if an effect
271 // asks for dst color, then the emit code needs to follow suit
273 fFragmentProcessors->fProcs.push_back(ifp);
276 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp,
277 const char* outColor,
278 const char* outCoverage) {
279 SkASSERT(!fGeometryProcessor);
280 fGeometryProcessor = new GrGLInstalledGeoProc;
282 fGeometryProcessor->fGLProc.reset(gp.createGLInstance(*fGpu->glCaps().glslCaps()));
284 SkSTArray<4, GrGLSLTextureSampler> samplers(gp.numTextures());
285 this->emitSamplers(gp, &samplers, fGeometryProcessor);
287 GrGLGeometryProcessor::EmitArgs args(this, gp, outColor, outCoverage, samplers,
288 fCoordTransforms, &fOutCoords);
289 fGeometryProcessor->fGLProc->emitCode(args);
291 // We have to check that effects and the code they emit are consistent, ie if an effect
292 // asks for dst color, then the emit code needs to follow suit
296 void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
297 const GrGLSLExpr4& colorIn,
298 const GrGLSLExpr4& coverageIn) {
299 // Program builders have a bit of state we need to clear with each effect
300 AutoStageAdvance adv(this);
302 SkASSERT(!fXferProcessor);
303 fXferProcessor = new GrGLInstalledXferProc;
305 fXferProcessor->fGLProc.reset(xp.createGLInstance());
307 // Enable dual source secondary output if we have one
308 if (xp.hasSecondaryOutput()) {
309 fFS.enableSecondaryOutput();
312 if (this->glslCaps()->mustDeclareFragmentShaderOutput()) {
313 fFS.enableCustomOutput();
317 openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
318 fFS.codeAppend(openBrace.c_str());
320 SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures());
321 this->emitSamplers(xp, &samplers, fXferProcessor);
323 GrGLXferProcessor::EmitArgs args(this, xp, colorIn.c_str(), coverageIn.c_str(),
324 fFS.getPrimaryColorOutputName(),
325 fFS.getSecondaryColorOutputName(), samplers);
326 fXferProcessor->fGLProc->emitCode(args);
328 // We have to check that effects and the code they emit are consistent, ie if an effect
329 // asks for dst color, then the emit code needs to follow suit
334 void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
335 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
338 void GrGLProgramBuilder::verify(const GrXferProcessor& xp) {
339 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
342 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
343 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
346 template <class Proc>
347 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
348 GrGLSLTextureSampler::TextureSamplerArray* outSamplers,
349 GrGLInstalledProc<Proc>* ip) {
350 SkDEBUGCODE(ip->fSamplersIdx = fSamplerUniforms.count();)
351 int numTextures = processor.numTextures();
352 UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
354 for (int t = 0; t < numTextures; ++t) {
355 name.printf("Sampler%d", t);
356 localSamplerUniforms[t] = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
357 kSampler2D_GrSLType, kDefault_GrSLPrecision,
359 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLSLTextureSampler,
360 (localSamplerUniforms[t], processor.textureAccess(t)));
364 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
367 SkTDArray<GrGLuint>* shaderIds) {
368 GrGLGpu* gpu = this->gpu();
369 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
372 shader.fCompilerStrings.begin(),
373 shader.fCompilerStringLengths.begin(),
374 shader.fCompilerStrings.count(),
381 *shaderIds->append() = shaderId;
386 GrGLProgram* GrGLProgramBuilder::finalize() {
387 // verify we can get a program id
389 GL_CALL_RET(programID, CreateProgram());
390 if (0 == programID) {
394 // compile shaders and bind attributes / uniforms
395 SkTDArray<GrGLuint> shadersToDelete;
396 fVS.finalize(kVertex_Visibility);
397 if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) {
398 this->cleanupProgram(programID, shadersToDelete);
402 // NVPR actually requires a vertex shader to compile
403 bool useNvpr = primitiveProcessor().isPathRendering();
405 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
407 int vaCount = primProc.numAttribs();
408 for (int i = 0; i < vaCount; i++) {
409 GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
413 fFS.finalize(kFragment_Visibility);
414 if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) {
415 this->cleanupProgram(programID, shadersToDelete);
419 this->bindProgramResourceLocations(programID);
421 GL_CALL(LinkProgram(programID));
423 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
424 bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
429 checkLinkStatus(programID);
431 this->resolveProgramResourceLocations(programID);
433 this->cleanupShaders(shadersToDelete);
435 return this->createProgram(programID);
438 void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
439 if (fGpu->glCaps().bindUniformLocationSupport()) {
440 int count = fUniforms.count();
441 for (int i = 0; i < count; ++i) {
442 GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str()));
443 fUniforms[i].fLocation = i;
447 const GrGLCaps& caps = this->gpu()->glCaps();
448 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
449 GL_CALL(BindFragDataLocation(programID, 0,
450 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
452 if (fFS.hasSecondaryOutput() && caps.glslCaps()->mustDeclareFragmentShaderOutput()) {
453 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
454 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
457 // handle NVPR separable varyings
458 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
459 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
462 int count = fSeparableVaryingInfos.count();
463 for (int i = 0; i < count; ++i) {
464 GL_CALL(BindFragmentInputLocation(programID,
466 fSeparableVaryingInfos[i].fVariable.c_str()));
467 fSeparableVaryingInfos[i].fLocation = i;
471 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
472 GrGLint linked = GR_GL_INIT_ZERO;
473 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
475 GrGLint infoLen = GR_GL_INIT_ZERO;
476 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
477 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
479 // retrieve length even though we don't need it to workaround
480 // bug in chrome cmd buffer param validation.
481 GrGLsizei length = GR_GL_INIT_ZERO;
482 GL_CALL(GetProgramInfoLog(programID,
486 SkDebugf("%s", (char*)log.get());
488 SkDEBUGFAIL("Error linking program");
489 GL_CALL(DeleteProgram(programID));
492 return SkToBool(linked);
495 void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
496 if (!fGpu->glCaps().bindUniformLocationSupport()) {
497 int count = fUniforms.count();
498 for (int i = 0; i < count; ++i) {
500 GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariable.c_str()));
501 fUniforms[i].fLocation = location;
505 // handle NVPR separable varyings
506 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
507 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
510 int count = fSeparableVaryingInfos.count();
511 for (int i = 0; i < count; ++i) {
513 GL_CALL_RET(location,
514 GetProgramResourceLocation(programID,
515 GR_GL_FRAGMENT_INPUT,
516 fSeparableVaryingInfos[i].fVariable.c_str()));
517 fSeparableVaryingInfos[i].fLocation = location;
521 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
522 GL_CALL(DeleteProgram(programID));
523 cleanupShaders(shaderIDs);
525 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
526 for (int i = 0; i < shaderIDs.count(); ++i) {
527 GL_CALL(DeleteShader(shaderIDs[i]));
531 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
532 return new GrGLProgram(fGpu, this->desc(), fUniformHandles, programID, fUniforms,
533 fSeparableVaryingInfos,
534 fGeometryProcessor, fXferProcessor, fFragmentProcessors.get(),
538 ///////////////////////////////////////////////////////////////////////////////////////////////////
540 GrGLInstalledFragProcs::~GrGLInstalledFragProcs() {
541 int numProcs = fProcs.count();
542 for (int i = 0; i < numProcs; ++i) {