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 "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"
22 #include "SkTraceEvent.h"
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)
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
29 class GrGLNvprProgramBuilder : public GrGLProgramBuilder {
31 GrGLNvprProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
32 : INHERITED(gpu, args) {}
34 GrGLProgram* createProgram(GrGLuint programID) override {
35 // this is just for nvpr es, which has separable varyings that are plugged in after
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,
43 fXferProcessor, fFragmentProcessors.get()));
47 typedef GrGLProgramBuilder INHERITED;
52 //////////////////////////////////////////////////////////////////////////////
54 const int GrGLProgramBuilder::kVarsPerBlock = 8;
56 GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gpu) {
57 GrAutoLocaleSetter als("C");
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));
63 GrGLProgramBuilder* pb = builder.get();
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;
70 pb->emitAndInstallProcs(&inputColor, &inputCoverage);
72 return pb->finalize();
75 GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const DrawArgs& args,
77 if (args.fPrimitiveProcessor->isPathRendering()) {
78 SkASSERT(gpu->glCaps().pathRenderingSupport() &&
79 !args.fPrimitiveProcessor->willUseGeoShader() &&
80 args.fPrimitiveProcessor->numAttribs() == 0);
81 return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, args));
83 return SkNEW_ARGS(GrGLProgramBuilder, (gpu, args));
87 /////////////////////////////////////////////////////////////////////////////
89 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
92 , fFS(this, args.fDesc->header().fFragPosKey)
95 , fGeometryProcessor(NULL)
96 , fXferProcessor(NULL)
99 , fUniforms(kVarsPerBlock) {
102 void GrGLProgramBuilder::addVarying(const char* name,
103 GrGLVarying* varying,
104 GrSLPrecision fsPrecision) {
106 if (varying->vsVarying()) {
107 fVS.addVarying(name, varying);
109 if (this->primitiveProcessor().willUseGeoShader()) {
110 fGS.addVarying(name, varying);
112 if (varying->fsVarying()) {
113 fFS.addVarying(varying, fsPrecision);
117 void GrGLProgramBuilder::addPassThroughAttribute(const GrPrimitiveProcessor::Attribute* input,
118 const char* output) {
119 GrSLType type = GrVertexAttribTypeToSLType(input->fType);
120 GrGLVertToFrag v(type);
121 this->addVarying(input->fName, &v);
122 fVS.codeAppendf("%s = %s;", v.vsOut(), input->fName);
123 fFS.codeAppendf("%s = %s;", output, v.fsIn());
126 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
127 if ('\0' == prefix) {
130 out->printf("%c%s", prefix, name);
133 if (out->endsWith('_')) {
134 // Names containing "__" are reserved.
137 out->appendf("_Stage%d", fStageIndex);
141 GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(
144 GrSLPrecision precision,
147 const char** outName) {
148 SkASSERT(name && strlen(name));
149 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
150 SkASSERT(0 == (~kVisibilityMask & visibility));
151 SkASSERT(0 != visibility);
152 SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
154 UniformInfo& uni = fUniforms.push_back();
155 uni.fVariable.setType(type);
156 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
157 // TODO this is a bit hacky, lets think of a better way. Basically we need to be able to use
158 // the uniform view matrix name in the GP, and the GP is immutable so it has to tell the PB
159 // exactly what name it wants to use for the uniform view matrix. If we prefix anythings, then
160 // the names will mismatch. I think the correct solution is to have all GPs which need the
161 // uniform view matrix, they should upload the view matrix in their setData along with regular
164 if ('u' == name[0]) {
167 this->nameVariable(uni.fVariable.accessName(), prefix, name);
168 uni.fVariable.setArrayCount(count);
169 uni.fVisibility = visibility;
170 uni.fVariable.setPrecision(precision);
173 *outName = uni.fVariable.c_str();
175 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
178 void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
179 SkString* out) const {
180 for (int i = 0; i < fUniforms.count(); ++i) {
181 if (fUniforms[i].fVisibility & visibility) {
182 fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out);
188 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
189 return fGpu->ctxInfo();
192 void GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) {
193 // First we loop over all of the installed processors and collect coord transforms. These will
194 // be sent to the GrGLPrimitiveProcessor in its emitCode function
195 SkSTArray<8, GrGLProcessor::TransformedCoordsArray> outCoords;
196 for (int i = 0; i < this->pipeline().numFragmentStages(); i++) {
197 const GrFragmentProcessor* processor = this->pipeline().getFragmentStage(i).processor();
198 SkSTArray<2, const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
199 for (int t = 0; t < processor->numTransforms(); t++) {
200 procCoords.push_back(&processor->coordTransform(t));
204 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
205 this->emitAndInstallProc(primProc, inputColor, inputCoverage);
207 fFragmentProcessors.reset(SkNEW(GrGLInstalledFragProcs));
208 int numProcs = this->pipeline().numFragmentStages();
209 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentStages(), inputColor);
210 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentStages(), numProcs,
212 this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage);
215 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
217 GrGLSLExpr4* inOut) {
218 for (int e = procOffset; e < numProcs; ++e) {
220 const GrPendingFragmentStage& stage = this->pipeline().getFragmentStage(e);
221 this->emitAndInstallProc(stage, e, *inOut, &output);
226 void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
227 // create var to hold stage result. If we already have a valid output name, just use that
228 // otherwise create a new mangled one. This name is only valid if we are reordering stages
229 // and have to tell stage exactly where to put its output.
231 if (output->isValid()) {
232 outName = output->c_str();
234 this->nameVariable(&outName, '\0', baseName);
236 fFS.codeAppendf("vec4 %s;", outName.c_str());
240 // TODO Processors cannot output zeros because an empty string is all 1s
241 // the fix is to allow effects to take the GrGLSLExpr4 directly
242 void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& proc,
244 const GrGLSLExpr4& input,
245 GrGLSLExpr4* output) {
246 // Program builders have a bit of state we need to clear with each effect
247 AutoStageAdvance adv(this);
248 this->nameExpression(output, "output");
250 // Enclose custom code in a block to avoid namespace conflicts
252 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
253 fFS.codeAppend(openBrace.c_str());
255 this->emitAndInstallProc(proc, index, output->c_str(), input.isOnes() ? NULL : input.c_str());
260 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc,
261 GrGLSLExpr4* outputColor,
262 GrGLSLExpr4* outputCoverage) {
263 // Program builders have a bit of state we need to clear with each effect
264 AutoStageAdvance adv(this);
265 this->nameExpression(outputColor, "outputColor");
266 this->nameExpression(outputCoverage, "outputCoverage");
268 // Enclose custom code in a block to avoid namespace conflicts
270 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
271 fFS.codeAppend(openBrace.c_str());
273 this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str());
278 void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& fs,
280 const char* outColor,
281 const char* inColor) {
282 GrGLInstalledFragProc* ifp = SkNEW(GrGLInstalledFragProc);
284 const GrFragmentProcessor& fp = *fs.processor();
285 ifp->fGLProc.reset(fp.createGLInstance());
287 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(fp.numTextures());
288 this->emitSamplers(fp, &samplers, ifp);
290 ifp->fGLProc->emitCode(this, fp, outColor, inColor, fOutCoords[index], samplers);
292 // We have to check that effects and the code they emit are consistent, ie if an effect
293 // asks for dst color, then the emit code needs to follow suit
295 fFragmentProcessors->fProcs.push_back(ifp);
298 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp,
299 const char* outColor,
300 const char* outCoverage) {
301 SkASSERT(!fGeometryProcessor);
302 fGeometryProcessor = SkNEW(GrGLInstalledGeoProc);
304 const GrBatchTracker& bt = this->batchTracker();
305 fGeometryProcessor->fGLProc.reset(gp.createGLInstance(bt, fGpu->glCaps()));
307 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(gp.numTextures());
308 this->emitSamplers(gp, &samplers, fGeometryProcessor);
310 GrGLGeometryProcessor::EmitArgs args(this, gp, bt, outColor, outCoverage, samplers,
311 fCoordTransforms, &fOutCoords);
312 fGeometryProcessor->fGLProc->emitCode(args);
314 // We have to check that effects and the code they emit are consistent, ie if an effect
315 // asks for dst color, then the emit code needs to follow suit
319 void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
320 const GrGLSLExpr4& colorIn,
321 const GrGLSLExpr4& coverageIn) {
322 // Program builders have a bit of state we need to clear with each effect
323 AutoStageAdvance adv(this);
325 SkASSERT(!fXferProcessor);
326 fXferProcessor = SkNEW(GrGLInstalledXferProc);
328 fXferProcessor->fGLProc.reset(xp.createGLInstance());
330 // Enable dual source secondary output if we have one
331 if (xp.hasSecondaryOutput()) {
332 fFS.enableSecondaryOutput();
335 // On any post 1.10 GLSL supporting GPU, we declare custom output
336 if (k110_GrGLSLGeneration != fFS.fProgramBuilder->gpu()->glslGeneration()) {
337 fFS.enableCustomOutput();
341 openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
342 fFS.codeAppend(openBrace.c_str());
344 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(xp.numTextures());
345 this->emitSamplers(xp, &samplers, fXferProcessor);
347 GrGLXferProcessor::EmitArgs args(this, xp, colorIn.c_str(), coverageIn.c_str(),
348 fFS.getPrimaryColorOutputName(),
349 fFS.getSecondaryColorOutputName(), samplers);
350 fXferProcessor->fGLProc->emitCode(args);
352 // We have to check that effects and the code they emit are consistent, ie if an effect
353 // asks for dst color, then the emit code needs to follow suit
358 void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
359 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
362 void GrGLProgramBuilder::verify(const GrXferProcessor& xp) {
363 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
366 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
367 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
370 template <class Proc>
371 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
372 GrGLProcessor::TextureSamplerArray* outSamplers,
373 GrGLInstalledProc<Proc>* ip) {
374 int numTextures = processor.numTextures();
375 ip->fSamplers.push_back_n(numTextures);
377 for (int t = 0; t < numTextures; ++t) {
378 name.printf("Sampler%d", t);
379 ip->fSamplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
380 kSampler2D_GrSLType, kDefault_GrSLPrecision,
382 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
383 (ip->fSamplers[t].fUniform, processor.textureAccess(t)));
387 GrGLProgram* GrGLProgramBuilder::finalize() {
388 // verify we can get a program id
390 GL_CALL_RET(programID, CreateProgram());
391 if (0 == programID) {
395 // compile shaders and bind attributes / uniforms
396 SkTDArray<GrGLuint> shadersToDelete;
398 // Legacy nvpr will not compile with a vertex shader, but newer nvpr requires a dummy vertex
400 bool useNvpr = primitiveProcessor().isPathRendering();
401 if (!(useNvpr && fGpu->glCaps().nvprSupport() == GrGLCaps::kLegacy_NvprSupport)) {
402 if (!fVS.compileAndAttachShaders(programID, &shadersToDelete)) {
403 this->cleanupProgram(programID, shadersToDelete);
407 // Non fixed function NVPR actually requires a vertex shader to compile
409 fVS.bindVertexAttributes(programID);
413 if (!fFS.compileAndAttachShaders(programID, &shadersToDelete)) {
414 this->cleanupProgram(programID, shadersToDelete);
418 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
419 if (usingBindUniform) {
420 this->bindUniformLocations(programID);
422 fFS.bindFragmentShaderLocations(programID);
423 GL_CALL(LinkProgram(programID));
425 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
426 bool checkLinked = !fGpu->ctxInfo().isChromium();
431 checkLinkStatus(programID);
433 if (!usingBindUniform) {
434 this->resolveUniformLocations(programID);
437 this->cleanupShaders(shadersToDelete);
439 return this->createProgram(programID);
442 void GrGLProgramBuilder::bindUniformLocations(GrGLuint programID) {
443 int count = fUniforms.count();
444 for (int i = 0; i < count; ++i) {
445 GL_CALL(BindUniformLocation(programID, i, fUniforms[i].fVariable.c_str()));
446 fUniforms[i].fLocation = i;
450 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
451 GrGLint linked = GR_GL_INIT_ZERO;
452 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
454 GrGLint infoLen = GR_GL_INIT_ZERO;
455 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
456 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
458 // retrieve length even though we don't need it to workaround
459 // bug in chrome cmd buffer param validation.
460 GrGLsizei length = GR_GL_INIT_ZERO;
461 GL_CALL(GetProgramInfoLog(programID,
465 SkDebugf("%s", (char*)log.get());
467 SkDEBUGFAIL("Error linking program");
468 GL_CALL(DeleteProgram(programID));
471 return SkToBool(linked);
474 void GrGLProgramBuilder::resolveUniformLocations(GrGLuint programID) {
475 int count = fUniforms.count();
476 for (int i = 0; i < count; ++i) {
478 GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariable.c_str()));
479 fUniforms[i].fLocation = location;
483 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
484 GL_CALL(DeleteProgram(programID));
485 cleanupShaders(shaderIDs);
487 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
488 for (int i = 0; i < shaderIDs.count(); ++i) {
489 GL_CALL(DeleteShader(shaderIDs[i]));
493 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
494 return SkNEW_ARGS(GrGLProgram, (fGpu, this->desc(), fUniformHandles, programID, fUniforms,
495 fGeometryProcessor, fXferProcessor, fFragmentProcessors.get()));
498 ///////////////////////////////////////////////////////////////////////////////////////////////////
500 GrGLInstalledFragProcs::~GrGLInstalledFragProcs() {
501 int numProcs = fProcs.count();
502 for (int e = 0; e < numProcs; ++e) {