blob: 28e1fba20cfca8eaf70e671414576be9bb6b48a6 [file] [log] [blame]
joshualitt30ba4362014-08-21 20:18:45 -07001/*
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
joshualitt47bb3822014-10-07 16:43:25 -07008#include "GrGLProgramBuilder.h"
joshualitt8072caa2015-02-12 14:20:52 -08009
10#include "gl/GrGLGeometryProcessor.h"
11#include "gl/GrGLGpu.h"
12#include "gl/GrGLPathProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -070013#include "gl/GrGLProgram.h"
14#include "gl/GrGLSLPrettyPrint.h"
15#include "gl/GrGLUniformHandle.h"
joshualitt8072caa2015-02-12 14:20:52 -080016#include "gl/GrGLXferProcessor.h"
bsalomon6f7f2012015-03-16 14:00:52 -070017#include "GrAutoLocaleSetter.h"
joshualitt47bb3822014-10-07 16:43:25 -070018#include "GrCoordTransform.h"
joshualitt30ba4362014-08-21 20:18:45 -070019#include "GrGLProgramBuilder.h"
20#include "GrTexture.h"
joshualitt30ba4362014-08-21 20:18:45 -070021#include "SkRTConf.h"
22#include "SkTraceEvent.h"
23
joshualitt30ba4362014-08-21 20:18:45 -070024#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
joshualittabb52a12015-01-13 15:02:10 -080027///////////////////////////////////////////////////////////////////////////////////////////////////
28
29class GrGLNvprProgramBuilder : public GrGLProgramBuilder {
30public:
joshualitt873ad0e2015-01-20 09:08:51 -080031 GrGLNvprProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
32 : INHERITED(gpu, args) {}
joshualittabb52a12015-01-13 15:02:10 -080033
mtklein36352bf2015-03-25 18:17:31 -070034 GrGLProgram* createProgram(GrGLuint programID) override {
joshualittabb52a12015-01-13 15:02:10 -080035 // 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);
joshualitt873ad0e2015-01-20 09:08:51 -080040 return SkNEW_ARGS(GrGLNvprProgram, (fGpu, this->desc(), fUniformHandles, programID,
41 fUniforms,
joshualittabb52a12015-01-13 15:02:10 -080042 fGeometryProcessor,
43 fXferProcessor, fFragmentProcessors.get()));
44 }
45
46private:
47 typedef GrGLProgramBuilder INHERITED;
48};
49
50
51
joshualitt30ba4362014-08-21 20:18:45 -070052//////////////////////////////////////////////////////////////////////////////
53
joshualitt47bb3822014-10-07 16:43:25 -070054const int GrGLProgramBuilder::kVarsPerBlock = 8;
55
joshualitt873ad0e2015-01-20 09:08:51 -080056GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gpu) {
bsalomon3318ee72015-03-16 11:56:29 -070057 GrAutoLocaleSetter als("C");
58
joshualitt47bb3822014-10-07 16:43:25 -070059 // create a builder. This will be handed off to effects so they can use it to add
60 // uniforms, varyings, textures, etc
joshualitt873ad0e2015-01-20 09:08:51 -080061 SkAutoTDelete<GrGLProgramBuilder> builder(CreateProgramBuilder(args, gpu));
joshualitt47bb3822014-10-07 16:43:25 -070062
63 GrGLProgramBuilder* pb = builder.get();
joshualitt47bb3822014-10-07 16:43:25 -070064
egdaniel37b4d862014-11-03 10:07:07 -080065 // TODO: Once all stages can handle taking a float or vec4 and correctly handling them we can
joshualitt9b989322014-12-15 14:16:27 -080066 // seed correctly here
67 GrGLSLExpr4 inputColor;
68 GrGLSLExpr4 inputCoverage;
egdaniel37b4d862014-11-03 10:07:07 -080069
joshualitt6c891102015-05-13 08:51:49 -070070 if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) {
71 return NULL;
72 }
joshualitt47bb3822014-10-07 16:43:25 -070073
joshualitt47bb3822014-10-07 16:43:25 -070074 return pb->finalize();
75}
76
joshualitt873ad0e2015-01-20 09:08:51 -080077GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const DrawArgs& args,
bsalomon861e1032014-12-16 07:33:49 -080078 GrGLGpu* gpu) {
joshualitt17e73142015-01-21 11:52:36 -080079 if (args.fPrimitiveProcessor->isPathRendering()) {
jvanverthe9c0fc62015-04-29 11:18:05 -070080 SkASSERT(gpu->glCaps().shaderCaps()->pathRenderingSupport() &&
joshualitt873ad0e2015-01-20 09:08:51 -080081 !args.fPrimitiveProcessor->willUseGeoShader() &&
82 args.fPrimitiveProcessor->numAttribs() == 0);
83 return SkNEW_ARGS(GrGLNvprProgramBuilder, (gpu, args));
joshualitt47bb3822014-10-07 16:43:25 -070084 } else {
joshualitt873ad0e2015-01-20 09:08:51 -080085 return SkNEW_ARGS(GrGLProgramBuilder, (gpu, args));
joshualitt47bb3822014-10-07 16:43:25 -070086 }
87}
88
89/////////////////////////////////////////////////////////////////////////////
90
joshualitt873ad0e2015-01-20 09:08:51 -080091GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args)
joshualitt47bb3822014-10-07 16:43:25 -070092 : fVS(this)
93 , fGS(this)
joshualitt873ad0e2015-01-20 09:08:51 -080094 , fFS(this, args.fDesc->header().fFragPosKey)
joshualitt47bb3822014-10-07 16:43:25 -070095 , fOutOfStage(true)
96 , fStageIndex(-1)
joshualitta5305a12014-10-10 17:47:00 -070097 , fGeometryProcessor(NULL)
egdanielc2304142014-12-11 13:15:13 -080098 , fXferProcessor(NULL)
joshualitt873ad0e2015-01-20 09:08:51 -080099 , fArgs(args)
joshualitt30ba4362014-08-21 20:18:45 -0700100 , fGpu(gpu)
101 , fUniforms(kVarsPerBlock) {
102}
103
joshualitt74077b92014-10-24 11:26:03 -0700104void GrGLProgramBuilder::addVarying(const char* name,
105 GrGLVarying* varying,
bsalomonc0bd6482014-12-09 10:04:14 -0800106 GrSLPrecision fsPrecision) {
joshualitt74077b92014-10-24 11:26:03 -0700107 SkASSERT(varying);
108 if (varying->vsVarying()) {
109 fVS.addVarying(name, varying);
110 }
joshualitt873ad0e2015-01-20 09:08:51 -0800111 if (this->primitiveProcessor().willUseGeoShader()) {
joshualitt74077b92014-10-24 11:26:03 -0700112 fGS.addVarying(name, varying);
113 }
114 if (varying->fsVarying()) {
115 fFS.addVarying(varying, fsPrecision);
116 }
joshualitt47bb3822014-10-07 16:43:25 -0700117}
118
joshualitt71c92602015-01-14 08:12:47 -0800119void GrGLProgramBuilder::addPassThroughAttribute(const GrPrimitiveProcessor::Attribute* input,
joshualitt2dd1ae02014-12-03 06:24:10 -0800120 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
joshualitt30ba4362014-08-21 20:18:45 -0700128void 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 }
joshualitt47bb3822014-10-07 16:43:25 -0700134 if (!fOutOfStage) {
joshualitt30ba4362014-08-21 20:18:45 -0700135 if (out->endsWith('_')) {
136 // Names containing "__" are reserved.
137 out->append("x");
138 }
joshualitt47bb3822014-10-07 16:43:25 -0700139 out->appendf("_Stage%d", fStageIndex);
joshualitt30ba4362014-08-21 20:18:45 -0700140 }
141}
142
bsalomon422f56f2014-12-09 10:18:12 -0800143GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(
144 uint32_t visibility,
145 GrSLType type,
146 GrSLPrecision precision,
147 const char* name,
148 int count,
149 const char** outName) {
joshualitt30ba4362014-08-21 20:18:45 -0700150 SkASSERT(name && strlen(name));
151 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
152 SkASSERT(0 == (~kVisibilityMask & visibility));
153 SkASSERT(0 != visibility);
bsalomon422f56f2014-12-09 10:18:12 -0800154 SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeIsFloatType(type));
joshualitt30ba4362014-08-21 20:18:45 -0700155
156 UniformInfo& uni = fUniforms.push_back();
157 uni.fVariable.setType(type);
158 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
joshualitt4973d9d2014-11-08 09:24:25 -0800159 // 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);
joshualitt30ba4362014-08-21 20:18:45 -0700170 uni.fVariable.setArrayCount(count);
171 uni.fVisibility = visibility;
bsalomon422f56f2014-12-09 10:18:12 -0800172 uni.fVariable.setPrecision(precision);
joshualitt30ba4362014-08-21 20:18:45 -0700173
bsalomon49f085d2014-09-05 13:34:00 -0700174 if (outName) {
joshualitt30ba4362014-08-21 20:18:45 -0700175 *outName = uni.fVariable.c_str();
176 }
177 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
178}
179
joshualitt30ba4362014-08-21 20:18:45 -0700180void 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
joshualitt47bb3822014-10-07 16:43:25 -0700190const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
191 return fGpu->ctxInfo();
192}
193
joshualitt6c891102015-05-13 08:51:49 -0700194bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) {
joshualittabb52a12015-01-13 15:02:10 -0800195 // 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
joshualitt6c891102015-05-13 08:51:49 -0700197 const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
198 int totalTextures = primProc.numTextures();
199 const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits();
joshualittabb52a12015-01-13 15:02:10 -0800200 SkSTArray<8, GrGLProcessor::TransformedCoordsArray> outCoords;
egdaniel8dd688b2015-01-22 10:16:09 -0800201 for (int i = 0; i < this->pipeline().numFragmentStages(); i++) {
202 const GrFragmentProcessor* processor = this->pipeline().getFragmentStage(i).processor();
joshualittabb52a12015-01-13 15:02:10 -0800203 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 }
joshualitt6c891102015-05-13 08:51:49 -0700207
208 totalTextures += processor->numTextures();
209 if (totalTextures >= maxTextureUnits) {
210 GrContextDebugf(fGpu->getContext(), "Program would use too many texture units\n");
211 return false;
212 }
joshualitt2dd1ae02014-12-03 06:24:10 -0800213 }
214
joshualitt9b989322014-12-15 14:16:27 -0800215 this->emitAndInstallProc(primProc, inputColor, inputCoverage);
216
joshualitta5305a12014-10-10 17:47:00 -0700217 fFragmentProcessors.reset(SkNEW(GrGLInstalledFragProcs));
egdaniel8dd688b2015-01-22 10:16:09 -0800218 int numProcs = this->pipeline().numFragmentStages();
bsalomon6be6f7c2015-02-26 13:05:21 -0800219 this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentStages(), inputColor);
220 this->emitAndInstallFragProcs(this->pipeline().numColorFragmentStages(), numProcs,
221 inputCoverage);
egdaniel8dd688b2015-01-22 10:16:09 -0800222 this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage);
joshualitt6c891102015-05-13 08:51:49 -0700223 return true;
joshualitt47bb3822014-10-07 16:43:25 -0700224}
225
joshualitt2dd1ae02014-12-03 06:24:10 -0800226void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
227 int numProcs,
228 GrGLSLExpr4* inOut) {
joshualitta5305a12014-10-10 17:47:00 -0700229 for (int e = procOffset; e < numProcs; ++e) {
230 GrGLSLExpr4 output;
egdaniel8dd688b2015-01-22 10:16:09 -0800231 const GrPendingFragmentStage& stage = this->pipeline().getFragmentStage(e);
joshualitt2dd1ae02014-12-03 06:24:10 -0800232 this->emitAndInstallProc(stage, e, *inOut, &output);
joshualitta5305a12014-10-10 17:47:00 -0700233 *inOut = output;
joshualitt30ba4362014-08-21 20:18:45 -0700234 }
joshualitta5305a12014-10-10 17:47:00 -0700235}
joshualitt30ba4362014-08-21 20:18:45 -0700236
joshualitt2dd1ae02014-12-03 06:24:10 -0800237void 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
joshualitta5305a12014-10-10 17:47:00 -0700251// TODO Processors cannot output zeros because an empty string is all 1s
252// the fix is to allow effects to take the GrGLSLExpr4 directly
joshualitt2dd1ae02014-12-03 06:24:10 -0800253void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& proc,
joshualitta5305a12014-10-10 17:47:00 -0700254 int index,
joshualitta5305a12014-10-10 17:47:00 -0700255 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);
joshualitt2dd1ae02014-12-03 06:24:10 -0800259 this->nameExpression(output, "output");
joshualitta5305a12014-10-10 17:47:00 -0700260
261 // Enclose custom code in a block to avoid namespace conflicts
262 SkString openBrace;
egdanielec03a462014-11-19 06:22:39 -0800263 openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
joshualitta5305a12014-10-10 17:47:00 -0700264 fFS.codeAppend(openBrace.c_str());
265
joshualittabb52a12015-01-13 15:02:10 -0800266 this->emitAndInstallProc(proc, index, output->c_str(), input.isOnes() ? NULL : input.c_str());
joshualitta5305a12014-10-10 17:47:00 -0700267
268 fFS.codeAppend("}");
269}
270
joshualitt9b989322014-12-15 14:16:27 -0800271void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc,
joshualitt2dd1ae02014-12-03 06:24:10 -0800272 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
bsalomonae59b772014-11-19 08:23:49 -0800289void GrGLProgramBuilder::emitAndInstallProc(const GrPendingFragmentStage& fs,
joshualittabb52a12015-01-13 15:02:10 -0800290 int index,
joshualitta5305a12014-10-10 17:47:00 -0700291 const char* outColor,
292 const char* inColor) {
joshualitt2dd1ae02014-12-03 06:24:10 -0800293 GrGLInstalledFragProc* ifp = SkNEW(GrGLInstalledFragProc);
joshualitta5305a12014-10-10 17:47:00 -0700294
joshualitt40d4bd82014-12-29 09:04:40 -0800295 const GrFragmentProcessor& fp = *fs.processor();
joshualitteb2a6762014-12-04 11:35:33 -0800296 ifp->fGLProc.reset(fp.createGLInstance());
joshualitta5305a12014-10-10 17:47:00 -0700297
298 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(fp.numTextures());
299 this->emitSamplers(fp, &samplers, ifp);
300
joshualittabb52a12015-01-13 15:02:10 -0800301 ifp->fGLProc->emitCode(this, fp, outColor, inColor, fOutCoords[index], samplers);
joshualitta5305a12014-10-10 17:47:00 -0700302
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
joshualitt9b989322014-12-15 14:16:27 -0800309void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp,
joshualitt2dd1ae02014-12-03 06:24:10 -0800310 const char* outColor,
311 const char* outCoverage) {
joshualitta5305a12014-10-10 17:47:00 -0700312 SkASSERT(!fGeometryProcessor);
313 fGeometryProcessor = SkNEW(GrGLInstalledGeoProc);
314
joshualitt873ad0e2015-01-20 09:08:51 -0800315 const GrBatchTracker& bt = this->batchTracker();
jvanverthe9c0fc62015-04-29 11:18:05 -0700316 fGeometryProcessor->fGLProc.reset(gp.createGLInstance(bt, *fGpu->glCaps().glslCaps()));
joshualitta5305a12014-10-10 17:47:00 -0700317
318 SkSTArray<4, GrGLProcessor::TextureSampler> samplers(gp.numTextures());
319 this->emitSamplers(gp, &samplers, fGeometryProcessor);
320
joshualittabb52a12015-01-13 15:02:10 -0800321 GrGLGeometryProcessor::EmitArgs args(this, gp, bt, outColor, outCoverage, samplers,
322 fCoordTransforms, &fOutCoords);
joshualittc369e7c2014-10-22 10:56:26 -0700323 fGeometryProcessor->fGLProc->emitCode(args);
joshualitta5305a12014-10-10 17:47:00 -0700324
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);
joshualitt30ba4362014-08-21 20:18:45 -0700328}
329
egdanielc2304142014-12-11 13:15:13 -0800330void 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
joshualitt9b989322014-12-15 14:16:27 -0800369void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
joshualitt47bb3822014-10-07 16:43:25 -0700370 SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
joshualittfe1233c2014-10-07 12:16:35 -0700371}
372
egdanielc2304142014-12-11 13:15:13 -0800373void GrGLProgramBuilder::verify(const GrXferProcessor& xp) {
egdaniel71e236c2015-01-20 06:34:51 -0800374 SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
egdanielc2304142014-12-11 13:15:13 -0800375}
376
joshualitt47bb3822014-10-07 16:43:25 -0700377void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
378 SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
joshualitt47bb3822014-10-07 16:43:25 -0700379}
380
joshualittabb52a12015-01-13 15:02:10 -0800381template <class Proc>
joshualitt47bb3822014-10-07 16:43:25 -0700382void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
383 GrGLProcessor::TextureSamplerArray* outSamplers,
joshualittabb52a12015-01-13 15:02:10 -0800384 GrGLInstalledProc<Proc>* ip) {
joshualitt47bb3822014-10-07 16:43:25 -0700385 int numTextures = processor.numTextures();
joshualitta5305a12014-10-10 17:47:00 -0700386 ip->fSamplers.push_back_n(numTextures);
joshualitt23e280d2014-09-18 12:26:38 -0700387 SkString name;
388 for (int t = 0; t < numTextures; ++t) {
389 name.printf("Sampler%d", t);
joshualitta5305a12014-10-10 17:47:00 -0700390 ip->fSamplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800391 kSampler2D_GrSLType, kDefault_GrSLPrecision,
joshualitta5305a12014-10-10 17:47:00 -0700392 name.c_str());
joshualittb0a8a372014-09-23 09:50:21 -0700393 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
joshualitta5305a12014-10-10 17:47:00 -0700394 (ip->fSamplers[t].fUniform, processor.textureAccess(t)));
joshualitt23e280d2014-09-18 12:26:38 -0700395 }
396}
397
joshualitt47bb3822014-10-07 16:43:25 -0700398GrGLProgram* 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;
joshualitt30ba4362014-08-21 20:18:45 -0700404 }
405
joshualitt47bb3822014-10-07 16:43:25 -0700406 // compile shaders and bind attributes / uniforms
joshualitt30ba4362014-08-21 20:18:45 -0700407 SkTDArray<GrGLuint> shadersToDelete;
joshualitt71c92602015-01-14 08:12:47 -0800408
jvanverth50530632015-04-27 10:36:27 -0700409 if (!fVS.compileAndAttachShaders(programID, &shadersToDelete)) {
410 this->cleanupProgram(programID, shadersToDelete);
411 return NULL;
412 }
joshualitt2dd1ae02014-12-03 06:24:10 -0800413
jvanverth50530632015-04-27 10:36:27 -0700414 // NVPR actually requires a vertex shader to compile
415 bool useNvpr = primitiveProcessor().isPathRendering();
416 if (!useNvpr) {
417 fVS.bindVertexAttributes(programID);
joshualitt47bb3822014-10-07 16:43:25 -0700418 }
joshualitt9b989322014-12-15 14:16:27 -0800419
420 if (!fFS.compileAndAttachShaders(programID, &shadersToDelete)) {
421 this->cleanupProgram(programID, shadersToDelete);
422 return NULL;
423 }
424
joshualitt47bb3822014-10-07 16:43:25 -0700425 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
426 if (usingBindUniform) {
427 this->bindUniformLocations(programID);
428 }
429 fFS.bindFragmentShaderLocations(programID);
430 GL_CALL(LinkProgram(programID));
joshualitt30ba4362014-08-21 20:18:45 -0700431
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) {
joshualitt47bb3822014-10-07 16:43:25 -0700438 checkLinkStatus(programID);
joshualittfe1233c2014-10-07 12:16:35 -0700439 }
joshualittdb0d3ca2014-10-07 12:42:26 -0700440 if (!usingBindUniform) {
joshualitt47bb3822014-10-07 16:43:25 -0700441 this->resolveUniformLocations(programID);
joshualittdb0d3ca2014-10-07 12:42:26 -0700442 }
443
joshualitt47bb3822014-10-07 16:43:25 -0700444 this->cleanupShaders(shadersToDelete);
445
446 return this->createProgram(programID);
447}
448
449void 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
457bool 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()));
kkinnunen297aaf92015-02-19 06:32:12 -0800472 SkDebugf("%s", (char*)log.get());
joshualitt47bb3822014-10-07 16:43:25 -0700473 }
474 SkDEBUGFAIL("Error linking program");
475 GL_CALL(DeleteProgram(programID));
476 programID = 0;
477 }
478 return SkToBool(linked);
479}
480
481void GrGLProgramBuilder::resolveUniformLocations(GrGLuint programID) {
482 int count = fUniforms.count();
kkinnunenec56e452014-08-25 22:21:16 -0700483 for (int i = 0; i < count; ++i) {
484 GrGLint location;
joshualitt47bb3822014-10-07 16:43:25 -0700485 GL_CALL_RET(location, GetUniformLocation(programID, fUniforms[i].fVariable.c_str()));
486 fUniforms[i].fLocation = location;
kkinnunenec56e452014-08-25 22:21:16 -0700487 }
joshualitt30ba4362014-08-21 20:18:45 -0700488}
489
joshualitt47bb3822014-10-07 16:43:25 -0700490void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
491 GL_CALL(DeleteProgram(programID));
492 cleanupShaders(shaderIDs);
493}
494void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
495 for (int i = 0; i < shaderIDs.count(); ++i) {
496 GL_CALL(DeleteShader(shaderIDs[i]));
497 }
498}
499
500GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
joshualitt873ad0e2015-01-20 09:08:51 -0800501 return SkNEW_ARGS(GrGLProgram, (fGpu, this->desc(), fUniformHandles, programID, fUniforms,
egdanielc2304142014-12-11 13:15:13 -0800502 fGeometryProcessor, fXferProcessor, fFragmentProcessors.get()));
joshualitt47bb3822014-10-07 16:43:25 -0700503}
504
joshualitta5305a12014-10-10 17:47:00 -0700505///////////////////////////////////////////////////////////////////////////////////////////////////
joshualitt47bb3822014-10-07 16:43:25 -0700506
joshualitta5305a12014-10-10 17:47:00 -0700507GrGLInstalledFragProcs::~GrGLInstalledFragProcs() {
508 int numProcs = fProcs.count();
509 for (int e = 0; e < numProcs; ++e) {
510 SkDELETE(fProcs[e]);
joshualitt47bb3822014-10-07 16:43:25 -0700511 }
joshualitt30ba4362014-08-21 20:18:45 -0700512}