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/GrGLGpu.h"
17 #include "gl/GrGLProgram.h"
18 #include "gl/GrGLSLPrettyPrint.h"
19 #include "gl/builders/GrGLShaderStringBuilder.h"
20 #include "glsl/GrGLSLCaps.h"
21 #include "glsl/GrGLSLFragmentProcessor.h"
22 #include "glsl/GrGLSLGeometryProcessor.h"
23 #include "glsl/GrGLSLProgramDataManager.h"
24 #include "glsl/GrGLSLTextureSampler.h"
25 #include "glsl/GrGLSLXferProcessor.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)
59 , fVaryingHandler(this)
60 , fUniformHandler(this) {
63 const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const {
64 return this->fGpu->ctxInfo().caps()->glslCaps();
67 bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) {
68 // First we loop over all of the installed processors and collect coord transforms. These will
69 // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
70 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
71 int totalTextures = primProc.numTextures();
72 const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits();
74 for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
75 const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
77 if (!primProc.hasTransformedLocalCoords()) {
78 SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
79 processor.gatherCoordTransforms(&procCoords);
82 totalTextures += processor.numTextures();
83 if (totalTextures >= maxTextureUnits) {
84 GrCapsDebugf(fGpu->caps(), "Program would use too many texture units\n");
89 this->emitAndInstallProc(primProc, inputColor, inputCoverage);
91 fFragmentProcessors.reset(new GrGLInstalledFragProcs);
92 int numProcs = this->pipeline().numFragmentProcessors();
93 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
94 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
96 this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
97 this->pipeline().ignoresCoverage());
101 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
103 GrGLSLExpr4* inOut) {
104 for (int i = procOffset; i < numProcs; ++i) {
106 const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
107 this->emitAndInstallProc(fp, i, *inOut, &output);
112 void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
113 // create var to hold stage result. If we already have a valid output name, just use that
114 // otherwise create a new mangled one. This name is only valid if we are reordering stages
115 // and have to tell stage exactly where to put its output.
117 if (output->isValid()) {
118 outName = output->c_str();
120 this->nameVariable(&outName, '\0', baseName);
122 fFS.codeAppendf("vec4 %s;", outName.c_str());
126 // TODO Processors cannot output zeros because an empty string is all 1s
127 // the fix is to allow effects to take the GrGLSLExpr4 directly
128 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp,
130 const GrGLSLExpr4& input,
131 GrGLSLExpr4* output) {
132 // Program builders have a bit of state we need to clear with each effect
133 AutoStageAdvance adv(this);
134 this->nameExpression(output, "output");
136 // Enclose custom code in a block to avoid namespace conflicts
138 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
139 fFS.codeAppend(openBrace.c_str());
141 this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullptr : input.c_str());
146 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc,
147 GrGLSLExpr4* outputColor,
148 GrGLSLExpr4* outputCoverage) {
149 // Program builders have a bit of state we need to clear with each effect
150 AutoStageAdvance adv(this);
151 this->nameExpression(outputColor, "outputColor");
152 this->nameExpression(outputCoverage, "outputCoverage");
154 // Enclose custom code in a block to avoid namespace conflicts
156 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
157 fFS.codeAppend(openBrace.c_str());
158 fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
160 this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str());
165 void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp,
167 const char* outColor,
168 const char* inColor) {
169 GrGLInstalledFragProc* ifp = new GrGLInstalledFragProc;
171 ifp->fGLProc.reset(fp.createGLSLInstance());
173 SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures());
174 this->emitSamplers(fp, &samplers, ifp);
176 GrGLSLFragmentProcessor::EmitArgs args(&fFS,
184 ifp->fGLProc->emitCode(args);
186 // We have to check that effects and the code they emit are consistent, ie if an effect
187 // asks for dst color, then the emit code needs to follow suit
189 fFragmentProcessors->fProcs.push_back(ifp);
192 void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp,
193 const char* outColor,
194 const char* outCoverage) {
195 SkASSERT(!fGeometryProcessor);
196 fGeometryProcessor = new GrGLInstalledGeoProc;
198 fGeometryProcessor->fGLProc.reset(gp.createGLSLInstance(*fGpu->glCaps().glslCaps()));
200 SkSTArray<4, GrGLSLTextureSampler> samplers(gp.numTextures());
201 this->emitSamplers(gp, &samplers, fGeometryProcessor);
203 GrGLSLGeometryProcessor::EmitArgs args(&fVS,
214 fGeometryProcessor->fGLProc->emitCode(args);
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
221 void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
222 const GrGLSLExpr4& colorIn,
223 const GrGLSLExpr4& coverageIn,
224 bool ignoresCoverage) {
225 // Program builders have a bit of state we need to clear with each effect
226 AutoStageAdvance adv(this);
228 SkASSERT(!fXferProcessor);
229 fXferProcessor = new GrGLInstalledXferProc;
231 fXferProcessor->fGLProc.reset(xp.createGLSLInstance());
233 // Enable dual source secondary output if we have one
234 if (xp.hasSecondaryOutput()) {
235 fFS.enableSecondaryOutput();
238 if (this->glslCaps()->mustDeclareFragmentShaderOutput()) {
239 fFS.enableCustomOutput();
243 openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
244 fFS.codeAppend(openBrace.c_str());
246 SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures());
247 this->emitSamplers(xp, &samplers, fXferProcessor);
249 GrGLSLXferProcessor::EmitArgs args(&fFS,
253 ignoresCoverage ? nullptr : coverageIn.c_str(),
254 fFS.getPrimaryColorOutputName(),
255 fFS.getSecondaryColorOutputName(),
257 fXferProcessor->fGLProc->emitCode(args);
259 // We have to check that effects and the code they emit are consistent, ie if an effect
260 // asks for dst color, then the emit code needs to follow suit
265 void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
266 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
269 void GrGLProgramBuilder::verify(const GrXferProcessor& xp) {
270 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
273 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
274 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
277 static GrSLType get_sampler_type(const GrTextureAccess& access) {
278 GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture());
279 if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) {
280 return kSamplerExternal_GrSLType;
282 SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D);
283 return kSampler2D_GrSLType;
287 template <class Proc>
288 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
289 GrGLSLTextureSampler::TextureSamplerArray* outSamplers,
290 GrGLInstalledProc<Proc>* ip) {
291 SkDEBUGCODE(ip->fSamplersIdx = fSamplerUniforms.count();)
292 int numTextures = processor.numTextures();
293 UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures);
295 for (int t = 0; t < numTextures; ++t) {
296 name.printf("Sampler%d", t);
297 GrSLType samplerType = get_sampler_type(processor.textureAccess(t));
298 localSamplerUniforms[t] =
299 fUniformHandler.addUniform(GrGLSLUniformHandler::kFragment_Visibility,
300 samplerType, kDefault_GrSLPrecision,
302 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLSLTextureSampler,
303 (localSamplerUniforms[t], processor.textureAccess(t)));
304 if (kSamplerExternal_GrSLType == samplerType) {
305 const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
306 // We shouldn't ever create a GrGLTexture that requires external sampler type
307 SkASSERT(externalFeatureString);
308 fFS.addFeature(1 << GrGLSLFragmentShaderBuilder::kExternalTexture_GLSLPrivateFeature,
309 externalFeatureString);
314 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
317 SkTDArray<GrGLuint>* shaderIds) {
318 GrGLGpu* gpu = this->gpu();
319 GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
322 shader.fCompilerStrings.begin(),
323 shader.fCompilerStringLengths.begin(),
324 shader.fCompilerStrings.count(),
331 *shaderIds->append() = shaderId;
336 GrGLProgram* GrGLProgramBuilder::finalize() {
337 // verify we can get a program id
339 GL_CALL_RET(programID, CreateProgram());
340 if (0 == programID) {
344 // compile shaders and bind attributes / uniforms
345 SkTDArray<GrGLuint> shadersToDelete;
346 fVS.finalize(GrGLSLUniformHandler::kVertex_Visibility);
347 if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete)) {
348 this->cleanupProgram(programID, shadersToDelete);
352 // NVPR actually requires a vertex shader to compile
353 bool useNvpr = primitiveProcessor().isPathRendering();
355 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
357 int vaCount = primProc.numAttribs();
358 for (int i = 0; i < vaCount; i++) {
359 GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
363 fFS.finalize(GrGLSLUniformHandler::kFragment_Visibility);
364 if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete)) {
365 this->cleanupProgram(programID, shadersToDelete);
369 this->bindProgramResourceLocations(programID);
371 GL_CALL(LinkProgram(programID));
373 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
374 bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
379 checkLinkStatus(programID);
381 this->resolveProgramResourceLocations(programID);
383 this->cleanupShaders(shadersToDelete);
385 return this->createProgram(programID);
388 void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
389 fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
391 const GrGLCaps& caps = this->gpu()->glCaps();
392 if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
393 GL_CALL(BindFragDataLocation(programID, 0,
394 GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
396 if (fFS.hasSecondaryOutput() && caps.glslCaps()->mustDeclareFragmentShaderOutput()) {
397 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
398 GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
401 // handle NVPR separable varyings
402 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
403 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
406 int count = fVaryingHandler.fPathProcVaryingInfos.count();
407 for (int i = 0; i < count; ++i) {
408 GL_CALL(BindFragmentInputLocation(programID, i,
409 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
410 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
414 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
415 GrGLint linked = GR_GL_INIT_ZERO;
416 GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
418 GrGLint infoLen = GR_GL_INIT_ZERO;
419 GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
420 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
422 // retrieve length even though we don't need it to workaround
423 // bug in chrome cmd buffer param validation.
424 GrGLsizei length = GR_GL_INIT_ZERO;
425 GL_CALL(GetProgramInfoLog(programID,
429 SkDebugf("%s", (char*)log.get());
431 SkDEBUGFAIL("Error linking program");
432 GL_CALL(DeleteProgram(programID));
435 return SkToBool(linked);
438 void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
439 fUniformHandler.getUniformLocations(programID, fGpu->glCaps());
441 // handle NVPR separable varyings
442 if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
443 !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
446 int count = fVaryingHandler.fPathProcVaryingInfos.count();
447 for (int i = 0; i < count; ++i) {
449 GL_CALL_RET(location, GetProgramResourceLocation(
451 GR_GL_FRAGMENT_INPUT,
452 fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
453 fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
457 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
458 GL_CALL(DeleteProgram(programID));
459 cleanupShaders(shaderIDs);
461 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
462 for (int i = 0; i < shaderIDs.count(); ++i) {
463 GL_CALL(DeleteShader(shaderIDs[i]));
467 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
468 return new GrGLProgram(fGpu,
472 fUniformHandler.fUniforms,
473 fVaryingHandler.fPathProcVaryingInfos,
476 fFragmentProcessors.get(),
480 ///////////////////////////////////////////////////////////////////////////////////////////////////
482 GrGLInstalledFragProcs::~GrGLInstalledFragProcs() {
483 int numProcs = fProcs.count();
484 for (int i = 0; i < numProcs; ++i) {