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 "gl/GrGLProgram.h"
9 #include "gl/GrGLSLPrettyPrint.h"
10 #include "gl/GrGLUniformHandle.h"
11 #include "GrCoordTransform.h"
12 #include "../GrGpuGL.h"
13 #include "GrGLFragmentShaderBuilder.h"
14 #include "GrGLProgramBuilder.h"
15 #include "GrTexture.h"
16 #include "GrGLVertexShaderBuilder.h"
17 #include "SkRTConf.h"
18 #include "SkTraceEvent.h"
19
20 namespace {
21 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
22 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
23
24 // number of each input/output type in a single allocation block
25 static const int kVarsPerBlock = 8;
26
27 // ES2 FS only guarantees mediump and lowp support
28 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
29 }
30
31 ///////////////////////////////////////////////////////////////////////////////////////////////////
32
genProgram(const GrGeometryStage * geometryProcessor,const GrFragmentStage * colorStages[],const GrFragmentStage * coverageStages[])33 bool GrGLProgramBuilder::genProgram(const GrGeometryStage* geometryProcessor,
34 const GrFragmentStage* colorStages[],
35 const GrFragmentStage* coverageStages[]) {
36 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
37
38 fFS.emitCodeBeforeEffects();
39
40 ///////////////////////////////////////////////////////////////////////////
41 // get the initial color and coverage to feed into the first effect in each effect chain
42
43 GrGLSLExpr4 inputColor;
44 GrGLSLExpr4 inputCoverage;
45
46 if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
47 const char* name;
48 fUniformHandles.fColorUni =
49 this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
50 kVec4f_GrSLType,
51 "Color",
52 &name);
53 inputColor = GrGLSLExpr4(name);
54 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) {
55 inputColor = GrGLSLExpr4(1);
56 }
57
58 if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
59 const char* name;
60 fUniformHandles.fCoverageUni =
61 this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
62 kVec4f_GrSLType,
63 "Coverage",
64 &name);
65 inputCoverage = GrGLSLExpr4(name);
66 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) {
67 inputCoverage = GrGLSLExpr4(1);
68 }
69
70 // Subclasses drive effect emitting
71 this->createAndEmitEffects(geometryProcessor, colorStages, coverageStages, &inputColor,
72 &inputCoverage);
73
74 fFS.emitCodeAfterEffects(inputColor, inputCoverage);
75
76 if (!this->finish()) {
77 return false;
78 }
79
80 return true;
81 }
82
83 //////////////////////////////////////////////////////////////////////////////
84
GrGLProgramBuilder(GrGpuGL * gpu,const GrGLProgramDesc & desc)85 GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu,
86 const GrGLProgramDesc& desc)
87 : fEffectEmitter(NULL)
88 , fFragOnly(SkToBool(desc.getHeader().fUseFragShaderOnly))
89 , fTexCoordSetCnt(0)
90 , fProgramID(0)
91 , fFS(this, desc)
92 , fSeparableVaryingInfos(kVarsPerBlock)
93 , fGrProcessorEmitter(this)
94 , fDesc(desc)
95 , fGpu(gpu)
96 , fUniforms(kVarsPerBlock) {
97 }
98
nameVariable(SkString * out,char prefix,const char * name)99 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
100 if ('\0' == prefix) {
101 *out = name;
102 } else {
103 out->printf("%c%s", prefix, name);
104 }
105 if (fCodeStage.inStageCode()) {
106 if (out->endsWith('_')) {
107 // Names containing "__" are reserved.
108 out->append("x");
109 }
110 out->appendf("_Stage%d", fCodeStage.stageIndex());
111 }
112 }
113
addUniformArray(uint32_t visibility,GrSLType type,const char * name,int count,const char ** outName)114 GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32_t visibility,
115 GrSLType type,
116 const char* name,
117 int count,
118 const char** outName) {
119 SkASSERT(name && strlen(name));
120 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
121 SkASSERT(0 == (~kVisibilityMask & visibility));
122 SkASSERT(0 != visibility);
123
124 UniformInfo& uni = fUniforms.push_back();
125 uni.fVariable.setType(type);
126 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
127 this->nameVariable(uni.fVariable.accessName(), 'u', name);
128 uni.fVariable.setArrayCount(count);
129 uni.fVisibility = visibility;
130
131 // If it is visible in both the VS and FS, the precision must match.
132 // We declare a default FS precision, but not a default VS. So set the var
133 // to use the default FS precision.
134 if ((kVertex_Visibility | kFragment_Visibility) == visibility) {
135 // the fragment and vertex precisions must match
136 uni.fVariable.setPrecision(kDefaultFragmentPrecision);
137 }
138
139 if (outName) {
140 *outName = uni.fVariable.c_str();
141 }
142 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
143 }
144
appendDecls(const VarArray & vars,SkString * out) const145 void GrGLProgramBuilder::appendDecls(const VarArray& vars, SkString* out) const {
146 for (int i = 0; i < vars.count(); ++i) {
147 vars[i].appendDecl(this->ctxInfo(), out);
148 out->append(";\n");
149 }
150 }
151
appendUniformDecls(ShaderVisibility visibility,SkString * out) const152 void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
153 SkString* out) const {
154 for (int i = 0; i < fUniforms.count(); ++i) {
155 if (fUniforms[i].fVisibility & visibility) {
156 fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out);
157 out->append(";\n");
158 }
159 }
160 }
161
createAndEmitEffects(const GrFragmentStage * effectStages[],int effectCnt,const GrGLProgramDesc::EffectKeyProvider & keyProvider,GrGLSLExpr4 * fsInOutColor)162 void GrGLProgramBuilder::createAndEmitEffects(const GrFragmentStage* effectStages[],
163 int effectCnt,
164 const GrGLProgramDesc::EffectKeyProvider& keyProvider,
165 GrGLSLExpr4* fsInOutColor) {
166 bool effectEmitted = false;
167
168 GrGLSLExpr4 inColor = *fsInOutColor;
169 GrGLSLExpr4 outColor;
170
171 for (int e = 0; e < effectCnt; ++e) {
172 fGrProcessorEmitter.set(effectStages[e]->getFragmentProcessor());
173 fEffectEmitter = &fGrProcessorEmitter;
174 // calls into the subclass to emit the actual effect into the program effect object
175 this->emitEffect(*effectStages[e], e, keyProvider, &inColor, &outColor);
176 effectEmitted = true;
177 }
178
179 if (effectEmitted) {
180 *fsInOutColor = outColor;
181 }
182 }
183
emitEffect(const GrProcessorStage & effectStage,int effectIndex,const GrGLProgramDesc::EffectKeyProvider & keyProvider,GrGLSLExpr4 * inColor,GrGLSLExpr4 * outColor)184 void GrGLProgramBuilder::emitEffect(const GrProcessorStage& effectStage,
185 int effectIndex,
186 const GrGLProgramDesc::EffectKeyProvider& keyProvider,
187 GrGLSLExpr4* inColor,
188 GrGLSLExpr4* outColor) {
189 SkASSERT(effectStage.getProcessor());
190 CodeStage::AutoStageRestore csar(&fCodeStage, &effectStage);
191
192 if (inColor->isZeros()) {
193 SkString inColorName;
194
195 // Effects have no way to communicate zeros, they treat an empty string as ones.
196 this->nameVariable(&inColorName, '\0', "input");
197 fFS.codeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor->c_str());
198 *inColor = inColorName;
199 }
200
201 // create var to hold stage result
202 SkString outColorName;
203 this->nameVariable(&outColorName, '\0', "output");
204 fFS.codeAppendf("\tvec4 %s;\n", outColorName.c_str());
205 *outColor = outColorName;
206
207 this->emitEffect(effectStage, keyProvider.get(effectIndex), outColor->c_str(),
208 inColor->isOnes() ? NULL : inColor->c_str(), fCodeStage.stageIndex());
209
210 *inColor = *outColor;
211 }
212
emitSamplers(const GrProcessor & effect,GrGLProcessor::TextureSamplerArray * outSamplers)213 void GrGLProgramBuilder::emitSamplers(const GrProcessor& effect,
214 GrGLProcessor::TextureSamplerArray* outSamplers) {
215 SkTArray<GrGLProgramEffects::Sampler, true>& samplers =
216 this->getProgramEffects()->addSamplers();
217 int numTextures = effect.numTextures();
218 samplers.push_back_n(numTextures);
219 SkString name;
220 for (int t = 0; t < numTextures; ++t) {
221 name.printf("Sampler%d", t);
222 samplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
223 kSampler2D_GrSLType,
224 name.c_str());
225 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
226 (samplers[t].fUniform, effect.textureAccess(t)));
227 }
228 }
229
finish()230 bool GrGLProgramBuilder::finish() {
231 SkASSERT(0 == fProgramID);
232 GL_CALL_RET(fProgramID, CreateProgram());
233 if (!fProgramID) {
234 return false;
235 }
236
237 SkTDArray<GrGLuint> shadersToDelete;
238
239 if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) {
240 GL_CALL(DeleteProgram(fProgramID));
241 return false;
242 }
243
244 this->bindProgramLocations(fProgramID);
245
246 GL_CALL(LinkProgram(fProgramID));
247
248 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
249 bool checkLinked = !fGpu->ctxInfo().isChromium();
250 #ifdef SK_DEBUG
251 checkLinked = true;
252 #endif
253 if (checkLinked) {
254 GrGLint linked = GR_GL_INIT_ZERO;
255 GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked));
256 if (!linked) {
257 GrGLint infoLen = GR_GL_INIT_ZERO;
258 GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen));
259 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
260 if (infoLen > 0) {
261 // retrieve length even though we don't need it to workaround
262 // bug in chrome cmd buffer param validation.
263 GrGLsizei length = GR_GL_INIT_ZERO;
264 GL_CALL(GetProgramInfoLog(fProgramID,
265 infoLen+1,
266 &length,
267 (char*)log.get()));
268 GrPrintf((char*)log.get());
269 }
270 SkDEBUGFAIL("Error linking program");
271 GL_CALL(DeleteProgram(fProgramID));
272 fProgramID = 0;
273 return false;
274 }
275 }
276
277 this->resolveProgramLocations(fProgramID);
278
279 for (int i = 0; i < shadersToDelete.count(); ++i) {
280 GL_CALL(DeleteShader(shadersToDelete[i]));
281 }
282
283 return true;
284 }
285
compileAndAttachShaders(GrGLuint programId,SkTDArray<GrGLuint> * shaderIds) const286 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId,
287 SkTDArray<GrGLuint>* shaderIds) const {
288 return fFS.compileAndAttachShaders(programId, shaderIds);
289 }
290
bindProgramLocations(GrGLuint programId)291 void GrGLProgramBuilder::bindProgramLocations(GrGLuint programId) {
292 fFS.bindProgramLocations(programId);
293
294 // skbug.com/2056
295 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
296 if (usingBindUniform) {
297 int count = fUniforms.count();
298 for (int i = 0; i < count; ++i) {
299 GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_str()));
300 fUniforms[i].fLocation = i;
301 }
302 }
303 }
304
resolveProgramLocations(GrGLuint programId)305 void GrGLProgramBuilder::resolveProgramLocations(GrGLuint programId) {
306 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
307 if (!usingBindUniform) {
308 int count = fUniforms.count();
309 for (int i = 0; i < count; ++i) {
310 GrGLint location;
311 GL_CALL_RET(location,
312 GetUniformLocation(programId, fUniforms[i].fVariable.c_str()));
313 fUniforms[i].fLocation = location;
314 }
315 }
316
317 int count = fSeparableVaryingInfos.count();
318 for (int i = 0; i < count; ++i) {
319 GrGLint location;
320 GL_CALL_RET(location,
321 GetProgramResourceLocation(programId,
322 GR_GL_FRAGMENT_INPUT,
323 fSeparableVaryingInfos[i].fVariable.c_str()));
324 fSeparableVaryingInfos[i].fLocation = location;
325 }
326 }
327
ctxInfo() const328 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
329 return fGpu->ctxInfo();
330 }
331