Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / gl / builders / GrGLProgramBuilder.cpp
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
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
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
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
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
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);
148         out->append(";\n");
149     }
150 }
151
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);
157             out->append(";\n");
158         }
159     }
160 }
161
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
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
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
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
286 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId,
287                                                  SkTDArray<GrGLuint>* shaderIds) const {
288     return fFS.compileAndAttachShaders(programId, shaderIds);
289 }
290
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
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
328 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
329     return fGpu->ctxInfo();
330 }