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 "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"
18 #include "SkTraceEvent.h"
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)
24 // number of each input/output type in a single allocation block
25 static const int kVarsPerBlock = 8;
27 // ES2 FS only guarantees mediump and lowp support
28 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
31 ///////////////////////////////////////////////////////////////////////////////////////////////////
33 bool GrGLProgramBuilder::genProgram(const GrGeometryStage* geometryProcessor,
34 const GrFragmentStage* colorStages[],
35 const GrFragmentStage* coverageStages[]) {
36 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
38 fFS.emitCodeBeforeEffects();
40 ///////////////////////////////////////////////////////////////////////////
41 // get the initial color and coverage to feed into the first effect in each effect chain
43 GrGLSLExpr4 inputColor;
44 GrGLSLExpr4 inputCoverage;
46 if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
48 fUniformHandles.fColorUni =
49 this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
53 inputColor = GrGLSLExpr4(name);
54 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) {
55 inputColor = GrGLSLExpr4(1);
58 if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
60 fUniformHandles.fCoverageUni =
61 this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
65 inputCoverage = GrGLSLExpr4(name);
66 } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) {
67 inputCoverage = GrGLSLExpr4(1);
70 // Subclasses drive effect emitting
71 this->createAndEmitEffects(geometryProcessor, colorStages, coverageStages, &inputColor,
74 fFS.emitCodeAfterEffects(inputColor, inputCoverage);
76 if (!this->finish()) {
83 //////////////////////////////////////////////////////////////////////////////
85 GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu,
86 const GrGLProgramDesc& desc)
87 : fEffectEmitter(NULL)
88 , fFragOnly(SkToBool(desc.getHeader().fUseFragShaderOnly))
92 , fSeparableVaryingInfos(kVarsPerBlock)
93 , fGrProcessorEmitter(this)
96 , fUniforms(kVarsPerBlock) {
99 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
100 if ('\0' == prefix) {
103 out->printf("%c%s", prefix, name);
105 if (fCodeStage.inStageCode()) {
106 if (out->endsWith('_')) {
107 // Names containing "__" are reserved.
110 out->appendf("_Stage%d", fCodeStage.stageIndex());
114 GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32_t visibility,
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);
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;
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);
140 *outName = uni.fVariable.c_str();
142 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
145 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);
152 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);
162 void GrGLProgramBuilder::createAndEmitEffects(const GrFragmentStage* effectStages[],
164 const GrGLProgramDesc::EffectKeyProvider& keyProvider,
165 GrGLSLExpr4* fsInOutColor) {
166 bool effectEmitted = false;
168 GrGLSLExpr4 inColor = *fsInOutColor;
169 GrGLSLExpr4 outColor;
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;
180 *fsInOutColor = outColor;
184 void GrGLProgramBuilder::emitEffect(const GrProcessorStage& effectStage,
186 const GrGLProgramDesc::EffectKeyProvider& keyProvider,
187 GrGLSLExpr4* inColor,
188 GrGLSLExpr4* outColor) {
189 SkASSERT(effectStage.getProcessor());
190 CodeStage::AutoStageRestore csar(&fCodeStage, &effectStage);
192 if (inColor->isZeros()) {
193 SkString inColorName;
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;
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;
207 this->emitEffect(effectStage, keyProvider.get(effectIndex), outColor->c_str(),
208 inColor->isOnes() ? NULL : inColor->c_str(), fCodeStage.stageIndex());
210 *inColor = *outColor;
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);
220 for (int t = 0; t < numTextures; ++t) {
221 name.printf("Sampler%d", t);
222 samplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
225 SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
226 (samplers[t].fUniform, effect.textureAccess(t)));
230 bool GrGLProgramBuilder::finish() {
231 SkASSERT(0 == fProgramID);
232 GL_CALL_RET(fProgramID, CreateProgram());
237 SkTDArray<GrGLuint> shadersToDelete;
239 if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) {
240 GL_CALL(DeleteProgram(fProgramID));
244 this->bindProgramLocations(fProgramID);
246 GL_CALL(LinkProgram(fProgramID));
248 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
249 bool checkLinked = !fGpu->ctxInfo().isChromium();
254 GrGLint linked = GR_GL_INIT_ZERO;
255 GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &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
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,
268 GrPrintf((char*)log.get());
270 SkDEBUGFAIL("Error linking program");
271 GL_CALL(DeleteProgram(fProgramID));
277 this->resolveProgramLocations(fProgramID);
279 for (int i = 0; i < shadersToDelete.count(); ++i) {
280 GL_CALL(DeleteShader(shadersToDelete[i]));
286 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId,
287 SkTDArray<GrGLuint>* shaderIds) const {
288 return fFS.compileAndAttachShaders(programId, shaderIds);
291 void GrGLProgramBuilder::bindProgramLocations(GrGLuint programId) {
292 fFS.bindProgramLocations(programId);
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;
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) {
311 GL_CALL_RET(location,
312 GetUniformLocation(programId, fUniforms[i].fVariable.c_str()));
313 fUniforms[i].fLocation = location;
317 int count = fSeparableVaryingInfos.count();
318 for (int i = 0; i < count; ++i) {
320 GL_CALL_RET(location,
321 GetProgramResourceLocation(programId,
322 GR_GL_FRAGMENT_INPUT,
323 fSeparableVaryingInfos[i].fVariable.c_str()));
324 fSeparableVaryingInfos[i].fLocation = location;
328 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
329 return fGpu->ctxInfo();