OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2012 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/GrGLShaderBuilder.h" | |
9 #include "gl/GrGLProgram.h" | |
10 #include "gl/GrGLSLPrettyPrint.h" | |
11 #include "gl/GrGLUniformHandle.h" | |
12 #include "GrCoordTransform.h" | |
13 #include "GrDrawEffect.h" | |
14 #include "GrGpuGL.h" | |
15 #include "GrTexture.h" | |
16 #include "SkRTConf.h" | |
17 #include "SkTraceEvent.h" | |
18 | |
19 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) | |
20 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X) | |
21 | |
22 // number of each input/output type in a single allocation block | |
23 static const int kVarsPerBlock = 8; | |
24 | |
25 // except FS outputs where we expect 2 at most. | |
26 static const int kMaxFSOutputs = 2; | |
27 | |
28 // ES2 FS only guarantees mediump and lowp support | |
29 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar:
:kMedium_Precision; | |
30 | |
31 typedef GrGLProgramDataManager::UniformHandle UniformHandle; | |
32 | |
33 SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, | |
34 "Print the source code for all shaders generated."); | |
35 | |
36 /////////////////////////////////////////////////////////////////////////////// | |
37 | |
38 namespace { | |
39 | |
40 inline const char* color_attribute_name() { return "aColor"; } | |
41 inline const char* coverage_attribute_name() { return "aCoverage"; } | |
42 inline const char* declared_color_output_name() { return "fsColorOut"; } | |
43 inline const char* dual_source_output_name() { return "dualSourceOut"; } | |
44 inline const char* sample_function_name(GrSLType type, GrGLSLGeneration glslGen)
{ | |
45 if (kVec2f_GrSLType == type) { | |
46 return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D"; | |
47 } else { | |
48 SkASSERT(kVec3f_GrSLType == type); | |
49 return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj
"; | |
50 } | |
51 } | |
52 | |
53 void append_texture_lookup(SkString* out, | |
54 GrGpuGL* gpu, | |
55 const char* samplerName, | |
56 const char* coordName, | |
57 uint32_t configComponentMask, | |
58 const char* swizzle, | |
59 GrSLType varyingType = kVec2f_GrSLType) { | |
60 SkASSERT(NULL != coordName); | |
61 | |
62 out->appendf("%s(%s, %s)", | |
63 sample_function_name(varyingType, gpu->glslGeneration()), | |
64 samplerName, | |
65 coordName); | |
66 | |
67 char mangledSwizzle[5]; | |
68 | |
69 // The swizzling occurs using texture params instead of shader-mangling if A
RB_texture_swizzle | |
70 // is available. | |
71 if (!gpu->glCaps().textureSwizzleSupport() && | |
72 (kA_GrColorComponentFlag == configComponentMask)) { | |
73 char alphaChar = gpu->glCaps().textureRedSupport() ? 'r' : 'a'; | |
74 int i; | |
75 for (i = 0; '\0' != swizzle[i]; ++i) { | |
76 mangledSwizzle[i] = alphaChar; | |
77 } | |
78 mangledSwizzle[i] ='\0'; | |
79 swizzle = mangledSwizzle; | |
80 } | |
81 // For shader prettiness we omit the swizzle rather than appending ".rgba". | |
82 if (memcmp(swizzle, "rgba", 4)) { | |
83 out->appendf(".%s", swizzle); | |
84 } | |
85 } | |
86 | |
87 } | |
88 | |
89 static const char kDstCopyColorName[] = "_dstColor"; | |
90 | |
91 /////////////////////////////////////////////////////////////////////////////// | |
92 | |
93 bool GrGLShaderBuilder::genProgram(const GrEffectStage* colorStages[], | |
94 const GrEffectStage* coverageStages[]) { | |
95 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); | |
96 | |
97 /////////////////////////////////////////////////////////////////////////// | |
98 // emit code to read the dst copy texture, if necessary | |
99 if (kNoDstRead_DstReadKey != header.fDstReadKey && !fGpu->glCaps().fbFetchSu
pport()) { | |
100 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKe
y); | |
101 const char* dstCopyTopLeftName; | |
102 const char* dstCopyCoordScaleName; | |
103 const char* dstCopySamplerName; | |
104 uint32_t configMask; | |
105 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { | |
106 configMask = kA_GrColorComponentFlag; | |
107 } else { | |
108 configMask = kRGBA_GrColorComponentFlags; | |
109 } | |
110 fUniformHandles.fDstCopySamplerUni = | |
111 this->addUniform(kFragment_Visibility, kSampler2D_GrSLType, "DstCopy
Sampler", | |
112 &dstCopySamplerName); | |
113 fUniformHandles.fDstCopyTopLeftUni = | |
114 this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyUppe
rLeft", | |
115 &dstCopyTopLeftName); | |
116 fUniformHandles.fDstCopyScaleUni = | |
117 this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyCoor
dScale", | |
118 &dstCopyCoordScaleName); | |
119 const char* fragPos = this->fragmentPosition(); | |
120 this->fsCodeAppend("\t// Read color from copy of the destination.\n"); | |
121 this->fsCodeAppendf("\tvec2 _dstTexCoord = (%s.xy - %s) * %s;\n", | |
122 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); | |
123 if (!topDown) { | |
124 this->fsCodeAppend("\t_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n"); | |
125 } | |
126 this->fsCodeAppendf("\tvec4 %s = ", kDstCopyColorName); | |
127 append_texture_lookup(&fFSCode, | |
128 fGpu, | |
129 dstCopySamplerName, | |
130 "_dstTexCoord", | |
131 configMask, | |
132 "rgba"); | |
133 this->fsCodeAppend(";\n\n"); | |
134 } | |
135 | |
136 /////////////////////////////////////////////////////////////////////////// | |
137 // get the initial color and coverage to feed into the first effect in each
effect chain | |
138 | |
139 GrGLSLExpr4 inputColor; | |
140 GrGLSLExpr4 inputCoverage; | |
141 | |
142 if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { | |
143 const char* name; | |
144 fUniformHandles.fColorUni = | |
145 this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrS
LType, "Color", | |
146 &name); | |
147 inputColor = GrGLSLExpr4(name); | |
148 } | |
149 | |
150 if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { | |
151 const char* name; | |
152 fUniformHandles.fCoverageUni = | |
153 this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrS
LType, "Coverage", | |
154 &name); | |
155 inputCoverage = GrGLSLExpr4(name); | |
156 } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput)
{ | |
157 inputCoverage = GrGLSLExpr4(1); | |
158 } | |
159 | |
160 if (k110_GrGLSLGeneration != fGpu->glslGeneration()) { | |
161 fFSOutputs.push_back().set(kVec4f_GrSLType, | |
162 GrGLShaderVar::kOut_TypeModifier, | |
163 declared_color_output_name()); | |
164 fHasCustomColorOutput = true; | |
165 } | |
166 | |
167 this->emitCodeBeforeEffects(&inputColor, &inputCoverage); | |
168 | |
169 /////////////////////////////////////////////////////////////////////////// | |
170 // emit the per-effect code for both color and coverage effects | |
171 | |
172 GrGLProgramDesc::EffectKeyProvider colorKeyProvider( | |
173 &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType); | |
174 fColorEffects.reset(this->createAndEmitEffects(colorStages, | |
175 this->desc().numColorEffects(
), | |
176 colorKeyProvider, | |
177 &inputColor)); | |
178 | |
179 GrGLProgramDesc::EffectKeyProvider coverageKeyProvider( | |
180 &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType)
; | |
181 fCoverageEffects.reset(this->createAndEmitEffects(coverageStages, | |
182 this->desc().numCoverageEf
fects(), | |
183 coverageKeyProvider, | |
184 &inputCoverage)); | |
185 | |
186 this->emitCodeAfterEffects(); | |
187 | |
188 /////////////////////////////////////////////////////////////////////////// | |
189 // write the secondary color output if necessary | |
190 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutpu
t)) { | |
191 const char* secondaryOutputName = this->enableSecondaryOutput(); | |
192 | |
193 // default coeff to ones for kCoverage_DualSrcOutput | |
194 GrGLSLExpr4 coeff(1); | |
195 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCov
erageOutput) { | |
196 // Get (1-A) into coeff | |
197 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); | |
198 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == | |
199 header.fCoverageOutput){ | |
200 // Get (1-RGBA) into coeff | |
201 coeff = GrGLSLExpr4(1) - inputColor; | |
202 } | |
203 // Get coeff * coverage into modulate and then write that to the dual so
urce output. | |
204 this->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputC
overage).c_str()); | |
205 } | |
206 | |
207 /////////////////////////////////////////////////////////////////////////// | |
208 // combine color and coverage as frag color | |
209 | |
210 // Get "color * coverage" into fragColor | |
211 GrGLSLExpr4 fragColor = inputColor * inputCoverage; | |
212 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do
so. | |
213 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutpu
t) { | |
214 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; | |
215 | |
216 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor()); | |
217 | |
218 fragColor = fragColor + dstContribution; | |
219 } | |
220 this->fsCodeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_
str()); | |
221 | |
222 if (!this->finish()) { | |
223 return false; | |
224 } | |
225 | |
226 return true; | |
227 } | |
228 | |
229 ////////////////////////////////////////////////////////////////////////////// | |
230 | |
231 GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu, | |
232 const GrGLProgramDesc& desc) | |
233 : fHasVertexShader(false) | |
234 , fTexCoordSetCnt(0) | |
235 , fProgramID(0) | |
236 , fDesc(desc) | |
237 , fGpu(gpu) | |
238 , fFSFeaturesAddedMask(0) | |
239 , fFSInputs(kVarsPerBlock) | |
240 , fFSOutputs(kMaxFSOutputs) | |
241 , fUniforms(kVarsPerBlock) | |
242 , fSetupFragPosition(false) | |
243 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFr
agPosKey) | |
244 , fHasCustomColorOutput(false) | |
245 , fHasSecondaryOutput(false) { | |
246 } | |
247 | |
248 bool GrGLShaderBuilder::enableFeature(GLSLFeature feature) { | |
249 switch (feature) { | |
250 case kStandardDerivatives_GLSLFeature: | |
251 if (!fGpu->glCaps().shaderDerivativeSupport()) { | |
252 return false; | |
253 } | |
254 if (kGLES_GrGLStandard == fGpu->glStandard()) { | |
255 this->addFSFeature(1 << kStandardDerivatives_GLSLFeature, | |
256 "GL_OES_standard_derivatives"); | |
257 } | |
258 return true; | |
259 default: | |
260 SkFAIL("Unexpected GLSLFeature requested."); | |
261 return false; | |
262 } | |
263 } | |
264 | |
265 void GrGLShaderBuilder::addFSFeature(uint32_t featureBit, const char* extensionN
ame) { | |
266 if (!(featureBit & fFSFeaturesAddedMask)) { | |
267 fFSExtensions.appendf("#extension %s: require\n", extensionName); | |
268 fFSFeaturesAddedMask |= featureBit; | |
269 } | |
270 } | |
271 | |
272 void GrGLShaderBuilder::nameVariable(SkString* out, char prefix, const char* nam
e) { | |
273 if ('\0' == prefix) { | |
274 *out = name; | |
275 } else { | |
276 out->printf("%c%s", prefix, name); | |
277 } | |
278 if (fCodeStage.inStageCode()) { | |
279 if (out->endsWith('_')) { | |
280 // Names containing "__" are reserved. | |
281 out->append("x"); | |
282 } | |
283 out->appendf("_Stage%d", fCodeStage.stageIndex()); | |
284 } | |
285 } | |
286 | |
287 const char* GrGLShaderBuilder::dstColor() { | |
288 if (fCodeStage.inStageCode()) { | |
289 const GrEffect* effect = fCodeStage.effectStage()->getEffect(); | |
290 if (!effect->willReadDstColor()) { | |
291 SkDEBUGFAIL("GrGLEffect asked for dst color but its generating GrEff
ect " | |
292 "did not request access."); | |
293 return ""; | |
294 } | |
295 } | |
296 | |
297 if (fGpu->glCaps().fbFetchSupport()) { | |
298 this->addFSFeature(1 << (kLastGLSLPrivateFeature + 1), | |
299 fGpu->glCaps().fbFetchExtensionString()); | |
300 return fGpu->glCaps().fbFetchColorName(); | |
301 } else if (fUniformHandles.fDstCopySamplerUni.isValid()) { | |
302 return kDstCopyColorName; | |
303 } else { | |
304 return ""; | |
305 } | |
306 } | |
307 | |
308 void GrGLShaderBuilder::appendTextureLookup(SkString* out, | |
309 const GrGLShaderBuilder::TextureSamp
ler& sampler, | |
310 const char* coordName, | |
311 GrSLType varyingType) const { | |
312 append_texture_lookup(out, | |
313 fGpu, | |
314 this->getUniformCStr(sampler.samplerUniform()), | |
315 coordName, | |
316 sampler.configComponentMask(), | |
317 sampler.swizzle(), | |
318 varyingType); | |
319 } | |
320 | |
321 void GrGLShaderBuilder::fsAppendTextureLookup(const GrGLShaderBuilder::TextureSa
mpler& sampler, | |
322 const char* coordName, | |
323 GrSLType varyingType) { | |
324 this->appendTextureLookup(&fFSCode, sampler, coordName, varyingType); | |
325 } | |
326 | |
327 void GrGLShaderBuilder::fsAppendTextureLookupAndModulate( | |
328 const char* modulation, | |
329 const GrGLShaderBuilder::TextureSamp
ler& sampler, | |
330 const char* coordName, | |
331 GrSLType varyingType) { | |
332 SkString lookup; | |
333 this->appendTextureLookup(&lookup, sampler, coordName, varyingType); | |
334 fFSCode.append((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str()); | |
335 } | |
336 | |
337 GrGLShaderBuilder::DstReadKey GrGLShaderBuilder::KeyForDstRead(const GrTexture*
dstCopy, | |
338 const GrGLCaps& c
aps) { | |
339 uint32_t key = kYesDstRead_DstReadKeyBit; | |
340 if (caps.fbFetchSupport()) { | |
341 return key; | |
342 } | |
343 SkASSERT(NULL != dstCopy); | |
344 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->confi
g())) { | |
345 // The fact that the config is alpha-only must be considered when genera
ting code. | |
346 key |= kUseAlphaConfig_DstReadKeyBit; | |
347 } | |
348 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) { | |
349 key |= kTopLeftOrigin_DstReadKeyBit; | |
350 } | |
351 SkASSERT(static_cast<DstReadKey>(key) == key); | |
352 return static_cast<DstReadKey>(key); | |
353 } | |
354 | |
355 GrGLShaderBuilder::FragPosKey GrGLShaderBuilder::KeyForFragmentPosition(const Gr
RenderTarget* dst, | |
356 const Gr
GLCaps&) { | |
357 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { | |
358 return kTopLeftFragPosRead_FragPosKey; | |
359 } else { | |
360 return kBottomLeftFragPosRead_FragPosKey; | |
361 } | |
362 } | |
363 | |
364 | |
365 const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, cons
t GrGLCaps& caps) { | |
366 if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) { | |
367 if (caps.textureRedSupport()) { | |
368 static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RE
D, GR_GL_RED }; | |
369 return gRedSmear; | |
370 } else { | |
371 static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA, | |
372 GR_GL_ALPHA, GR_GL_ALPHA }; | |
373 return gAlphaSmear; | |
374 } | |
375 } else { | |
376 static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE
, GR_GL_ALPHA }; | |
377 return gStraight; | |
378 } | |
379 } | |
380 | |
381 GrGLProgramDataManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_
t visibility, | |
382 GrSLTyp
e type, | |
383 const c
har* name, | |
384 int cou
nt, | |
385 const c
har** outName) { | |
386 SkASSERT(name && strlen(name)); | |
387 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFr
agment_Visibility); | |
388 SkASSERT(0 == (~kVisibilityMask & visibility)); | |
389 SkASSERT(0 != visibility); | |
390 | |
391 UniformInfo& uni = fUniforms.push_back(); | |
392 uni.fVariable.setType(type); | |
393 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier); | |
394 this->nameVariable(uni.fVariable.accessName(), 'u', name); | |
395 uni.fVariable.setArrayCount(count); | |
396 uni.fVisibility = visibility; | |
397 | |
398 // If it is visible in both the VS and FS, the precision must match. | |
399 // We declare a default FS precision, but not a default VS. So set the var | |
400 // to use the default FS precision. | |
401 if ((kVertex_Visibility | kFragment_Visibility) == visibility) { | |
402 // the fragment and vertex precisions must match | |
403 uni.fVariable.setPrecision(kDefaultFragmentPrecision); | |
404 } | |
405 | |
406 if (NULL != outName) { | |
407 *outName = uni.fVariable.c_str(); | |
408 } | |
409 return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUnifor
ms.count() - 1); | |
410 } | |
411 | |
412 SkString GrGLShaderBuilder::ensureFSCoords2D(const TransformedCoordsArray& coord
s, int index) { | |
413 if (kVec3f_GrSLType != coords[index].type()) { | |
414 SkASSERT(kVec2f_GrSLType == coords[index].type()); | |
415 return coords[index].getName(); | |
416 } | |
417 | |
418 SkString coords2D("coords2D"); | |
419 if (0 != index) { | |
420 coords2D.appendf("_%i", index); | |
421 } | |
422 this->fsCodeAppendf("\tvec2 %s = %s.xy / %s.z;", | |
423 coords2D.c_str(), coords[index].c_str(), coords[index].c
_str()); | |
424 return coords2D; | |
425 } | |
426 | |
427 const char* GrGLShaderBuilder::fragmentPosition() { | |
428 if (fCodeStage.inStageCode()) { | |
429 const GrEffect* effect = fCodeStage.effectStage()->getEffect(); | |
430 if (!effect->willReadFragmentPosition()) { | |
431 SkDEBUGFAIL("GrGLEffect asked for frag position but its generating G
rEffect " | |
432 "did not request access."); | |
433 return ""; | |
434 } | |
435 } | |
436 // We only declare "gl_FragCoord" when we're in the case where we want to us
e layout qualifiers | |
437 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier
appears in the | |
438 // declaration varies in earlier GLSL specs. So it is simpler to omit it. | |
439 if (fTopLeftFragPosRead) { | |
440 fSetupFragPosition = true; | |
441 return "gl_FragCoord"; | |
442 } else if (fGpu->glCaps().fragCoordConventionsSupport()) { | |
443 if (!fSetupFragPosition) { | |
444 if (fGpu->glslGeneration() < k150_GrGLSLGeneration) { | |
445 this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature
, | |
446 "GL_ARB_fragment_coord_conventions"); | |
447 } | |
448 fFSInputs.push_back().set(kVec4f_GrSLType, | |
449 GrGLShaderVar::kIn_TypeModifier, | |
450 "gl_FragCoord", | |
451 GrGLShaderVar::kDefault_Precision, | |
452 GrGLShaderVar::kUpperLeft_Origin); | |
453 fSetupFragPosition = true; | |
454 } | |
455 return "gl_FragCoord"; | |
456 } else { | |
457 static const char* kCoordName = "fragCoordYDown"; | |
458 if (!fSetupFragPosition) { | |
459 // temporarily change the stage index because we're inserting non-st
age code. | |
460 CodeStage::AutoStageRestore csar(&fCodeStage, NULL); | |
461 | |
462 SkASSERT(!fUniformHandles.fRTHeightUni.isValid()); | |
463 const char* rtHeightName; | |
464 | |
465 fUniformHandles.fRTHeightUni = | |
466 this->addUniform(kFragment_Visibility, kFloat_GrSLType, "RTHeigh
t", &rtHeightName); | |
467 | |
468 // Using glFragCoord.zw for the last two components tickles an Adren
o driver bug that | |
469 // causes programs to fail to link. Making this function return a ve
c2() didn't fix the | |
470 // problem but using 1.0 for the last two components does. | |
471 this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_Fra
gCoord.y, 1.0, " | |
472 "1.0);\n", kCoordName, rtHeightName); | |
473 fSetupFragPosition = true; | |
474 } | |
475 SkASSERT(fUniformHandles.fRTHeightUni.isValid()); | |
476 return kCoordName; | |
477 } | |
478 } | |
479 | |
480 void GrGLShaderBuilder::fsEmitFunction(GrSLType returnType, | |
481 const char* name, | |
482 int argCnt, | |
483 const GrGLShaderVar* args, | |
484 const char* body, | |
485 SkString* outName) { | |
486 fFSFunctions.append(GrGLSLTypeString(returnType)); | |
487 this->nameVariable(outName, '\0', name); | |
488 fFSFunctions.appendf(" %s", outName->c_str()); | |
489 fFSFunctions.append("("); | |
490 for (int i = 0; i < argCnt; ++i) { | |
491 args[i].appendDecl(this->ctxInfo(), &fFSFunctions); | |
492 if (i < argCnt - 1) { | |
493 fFSFunctions.append(", "); | |
494 } | |
495 } | |
496 fFSFunctions.append(") {\n"); | |
497 fFSFunctions.append(body); | |
498 fFSFunctions.append("}\n\n"); | |
499 } | |
500 | |
501 namespace { | |
502 | |
503 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, | |
504 GrGLStandard standard, | |
505 SkString* str) { | |
506 // Desktop GLSL has added precision qualifiers but they don't do anything. | |
507 if (kGLES_GrGLStandard == standard) { | |
508 switch (p) { | |
509 case GrGLShaderVar::kHigh_Precision: | |
510 str->append("precision highp float;\n"); | |
511 break; | |
512 case GrGLShaderVar::kMedium_Precision: | |
513 str->append("precision mediump float;\n"); | |
514 break; | |
515 case GrGLShaderVar::kLow_Precision: | |
516 str->append("precision lowp float;\n"); | |
517 break; | |
518 case GrGLShaderVar::kDefault_Precision: | |
519 SkFAIL("Default precision now allowed."); | |
520 default: | |
521 SkFAIL("Unknown precision value."); | |
522 } | |
523 } | |
524 } | |
525 } | |
526 | |
527 void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const { | |
528 for (int i = 0; i < vars.count(); ++i) { | |
529 vars[i].appendDecl(this->ctxInfo(), out); | |
530 out->append(";\n"); | |
531 } | |
532 } | |
533 | |
534 void GrGLShaderBuilder::appendUniformDecls(ShaderVisibility visibility, | |
535 SkString* out) const { | |
536 for (int i = 0; i < fUniforms.count(); ++i) { | |
537 if (fUniforms[i].fVisibility & visibility) { | |
538 fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out); | |
539 out->append(";\n"); | |
540 } | |
541 } | |
542 } | |
543 | |
544 void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programE
ffectsBuilder, | |
545 const GrEffectStage* effectStages[]
, | |
546 int effectCnt, | |
547 const GrGLProgramDesc::EffectKeyPro
vider& keyProvider, | |
548 GrGLSLExpr4* fsInOutColor) { | |
549 bool effectEmitted = false; | |
550 | |
551 GrGLSLExpr4 inColor = *fsInOutColor; | |
552 GrGLSLExpr4 outColor; | |
553 | |
554 for (int e = 0; e < effectCnt; ++e) { | |
555 SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect()
); | |
556 const GrEffectStage& stage = *effectStages[e]; | |
557 | |
558 CodeStage::AutoStageRestore csar(&fCodeStage, &stage); | |
559 | |
560 if (inColor.isZeros()) { | |
561 SkString inColorName; | |
562 | |
563 // Effects have no way to communicate zeros, they treat an empty str
ing as ones. | |
564 this->nameVariable(&inColorName, '\0', "input"); | |
565 this->fsCodeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColo
r.c_str()); | |
566 inColor = inColorName; | |
567 } | |
568 | |
569 // create var to hold stage result | |
570 SkString outColorName; | |
571 this->nameVariable(&outColorName, '\0', "output"); | |
572 this->fsCodeAppendf("\tvec4 %s;\n", outColorName.c_str()); | |
573 outColor = outColorName; | |
574 | |
575 | |
576 programEffectsBuilder->emitEffect(stage, | |
577 keyProvider.get(e), | |
578 outColor.c_str(), | |
579 inColor.isOnes() ? NULL : inColor.c_st
r(), | |
580 fCodeStage.stageIndex()); | |
581 | |
582 inColor = outColor; | |
583 effectEmitted = true; | |
584 } | |
585 | |
586 if (effectEmitted) { | |
587 *fsInOutColor = outColor; | |
588 } | |
589 } | |
590 | |
591 const char* GrGLShaderBuilder::getColorOutputName() const { | |
592 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor"
; | |
593 } | |
594 | |
595 const char* GrGLShaderBuilder::enableSecondaryOutput() { | |
596 if (!fHasSecondaryOutput) { | |
597 fFSOutputs.push_back().set(kVec4f_GrSLType, | |
598 GrGLShaderVar::kOut_TypeModifier, | |
599 dual_source_output_name()); | |
600 fHasSecondaryOutput = true; | |
601 } | |
602 return dual_source_output_name(); | |
603 } | |
604 | |
605 bool GrGLShaderBuilder::finish() { | |
606 SkASSERT(0 == fProgramID); | |
607 GL_CALL_RET(fProgramID, CreateProgram()); | |
608 if (!fProgramID) { | |
609 return false; | |
610 } | |
611 | |
612 SkTDArray<GrGLuint> shadersToDelete; | |
613 | |
614 if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) { | |
615 GL_CALL(DeleteProgram(fProgramID)); | |
616 return false; | |
617 } | |
618 | |
619 this->bindProgramLocations(fProgramID); | |
620 | |
621 GL_CALL(LinkProgram(fProgramID)); | |
622 | |
623 // Calling GetProgramiv is expensive in Chromium. Assume success in release
builds. | |
624 bool checkLinked = !fGpu->ctxInfo().isChromium(); | |
625 #ifdef SK_DEBUG | |
626 checkLinked = true; | |
627 #endif | |
628 if (checkLinked) { | |
629 GrGLint linked = GR_GL_INIT_ZERO; | |
630 GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked)); | |
631 if (!linked) { | |
632 GrGLint infoLen = GR_GL_INIT_ZERO; | |
633 GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen)); | |
634 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debug
ger | |
635 if (infoLen > 0) { | |
636 // retrieve length even though we don't need it to workaround | |
637 // bug in chrome cmd buffer param validation. | |
638 GrGLsizei length = GR_GL_INIT_ZERO; | |
639 GL_CALL(GetProgramInfoLog(fProgramID, | |
640 infoLen+1, | |
641 &length, | |
642 (char*)log.get())); | |
643 GrPrintf((char*)log.get()); | |
644 } | |
645 SkDEBUGFAIL("Error linking program"); | |
646 GL_CALL(DeleteProgram(fProgramID)); | |
647 fProgramID = 0; | |
648 return false; | |
649 } | |
650 } | |
651 | |
652 this->resolveProgramLocations(fProgramID); | |
653 | |
654 for (int i = 0; i < shadersToDelete.count(); ++i) { | |
655 GL_CALL(DeleteShader(shadersToDelete[i])); | |
656 } | |
657 | |
658 return true; | |
659 } | |
660 | |
661 // Compiles a GL shader and attaches it to a program. Returns the shader ID if | |
662 // successful, or 0 if not. | |
663 static GrGLuint attach_shader(const GrGLContext& glCtx, | |
664 GrGLuint programId, | |
665 GrGLenum type, | |
666 const SkString& shaderSrc) { | |
667 const GrGLInterface* gli = glCtx.interface(); | |
668 | |
669 GrGLuint shaderId; | |
670 GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); | |
671 if (0 == shaderId) { | |
672 return 0; | |
673 } | |
674 | |
675 #ifdef SK_DEBUG | |
676 SkString prettySource = GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, false)
; | |
677 const GrGLchar* sourceStr = prettySource.c_str(); | |
678 GrGLint sourceLength = static_cast<GrGLint>(prettySource.size()); | |
679 #else | |
680 GrGLint sourceLength = static_cast<GrGLint>(shaderSrc.size()); | |
681 const GrGLchar* sourceStr = shaderSrc.c_str(); | |
682 #endif | |
683 GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength)); | |
684 GR_GL_CALL(gli, CompileShader(shaderId)); | |
685 | |
686 // Calling GetShaderiv in Chromium is quite expensive. Assume success in rel
ease builds. | |
687 bool checkCompiled = !glCtx.isChromium(); | |
688 #ifdef SK_DEBUG | |
689 checkCompiled = true; | |
690 #endif | |
691 if (checkCompiled) { | |
692 GrGLint compiled = GR_GL_INIT_ZERO; | |
693 GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled)); | |
694 | |
695 if (!compiled) { | |
696 GrGLint infoLen = GR_GL_INIT_ZERO; | |
697 GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLe
n)); | |
698 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugg
er | |
699 if (infoLen > 0) { | |
700 // retrieve length even though we don't need it to workaround bu
g in Chromium cmd | |
701 // buffer param validation. | |
702 GrGLsizei length = GR_GL_INIT_ZERO; | |
703 GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, | |
704 &length, (char*)log.get())); | |
705 GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_s
tr()); | |
706 GrPrintf("\n%s", log.get()); | |
707 } | |
708 SkDEBUGFAIL("Shader compilation failed!"); | |
709 GR_GL_CALL(gli, DeleteShader(shaderId)); | |
710 return 0; | |
711 } | |
712 } | |
713 | |
714 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "skia_gpu::GLSha
der", | |
715 TRACE_EVENT_SCOPE_THREAD, "shader", TRACE_STR_COPY(shad
erSrc.c_str())); | |
716 if (c_PrintShaders) { | |
717 GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_str()); | |
718 GrPrintf("\n"); | |
719 } | |
720 | |
721 // Attach the shader, but defer deletion until after we have linked the prog
ram. | |
722 // This works around a bug in the Android emulator's GLES2 wrapper which | |
723 // will immediately delete the shader object and free its memory even though
it's | |
724 // attached to a program, which then causes glLinkProgram to fail. | |
725 GR_GL_CALL(gli, AttachShader(programId, shaderId)); | |
726 | |
727 return shaderId; | |
728 } | |
729 | |
730 bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<Gr
GLuint>* shaderIds) const { | |
731 SkString fragShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); | |
732 fragShaderSrc.append(fFSExtensions); | |
733 append_default_precision_qualifier(kDefaultFragmentPrecision, | |
734 fGpu->glStandard(), | |
735 &fragShaderSrc); | |
736 this->appendUniformDecls(kFragment_Visibility, &fragShaderSrc); | |
737 this->appendDecls(fFSInputs, &fragShaderSrc); | |
738 // We shouldn't have declared outputs on 1.10 | |
739 SkASSERT(k110_GrGLSLGeneration != fGpu->glslGeneration() || fFSOutputs.empty
()); | |
740 this->appendDecls(fFSOutputs, &fragShaderSrc); | |
741 fragShaderSrc.append(fFSFunctions); | |
742 fragShaderSrc.append("void main() {\n"); | |
743 fragShaderSrc.append(fFSCode); | |
744 fragShaderSrc.append("}\n"); | |
745 | |
746 GrGLuint fragShaderId = attach_shader(fGpu->glContext(), programId, GR_GL_FR
AGMENT_SHADER, fragShaderSrc); | |
747 if (!fragShaderId) { | |
748 return false; | |
749 } | |
750 | |
751 *shaderIds->append() = fragShaderId; | |
752 | |
753 return true; | |
754 } | |
755 | |
756 void GrGLShaderBuilder::bindProgramLocations(GrGLuint programId) { | |
757 if (fHasCustomColorOutput) { | |
758 GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name())
); | |
759 } | |
760 if (fHasSecondaryOutput) { | |
761 GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_
name())); | |
762 } | |
763 // skbug.com/2056 | |
764 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation
!= NULL; | |
765 if (usingBindUniform) { | |
766 int count = fUniforms.count(); | |
767 for (int i = 0; i < count; ++i) { | |
768 GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_s
tr())); | |
769 fUniforms[i].fLocation = i; | |
770 } | |
771 } | |
772 } | |
773 | |
774 void GrGLShaderBuilder::resolveProgramLocations(GrGLuint programId) { | |
775 bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation
!= NULL; | |
776 if (!usingBindUniform) { | |
777 int count = fUniforms.count(); | |
778 for (int i = 0; i < count; ++i) { | |
779 GrGLint location; | |
780 GL_CALL_RET(location, | |
781 GetUniformLocation(programId, fUniforms[i].fVariable.c_s
tr())); | |
782 fUniforms[i].fLocation = location; | |
783 } | |
784 } | |
785 } | |
786 | |
787 const GrGLContextInfo& GrGLShaderBuilder::ctxInfo() const { | |
788 return fGpu->ctxInfo(); | |
789 } | |
790 | |
791 //////////////////////////////////////////////////////////////////////////////// | |
792 | |
793 GrGLFullShaderBuilder::GrGLFullShaderBuilder(GrGpuGL* gpu, | |
794 const GrGLProgramDesc& desc) | |
795 : INHERITED(gpu, desc) | |
796 , fVSAttrs(kVarsPerBlock) | |
797 , fVSOutputs(kVarsPerBlock) | |
798 , fGSInputs(kVarsPerBlock) | |
799 , fGSOutputs(kVarsPerBlock) { | |
800 } | |
801 | |
802 void GrGLFullShaderBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr
4* coverage) { | |
803 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); | |
804 | |
805 fHasVertexShader = true; | |
806 | |
807 fPositionVar = &fVSAttrs.push_back(); | |
808 fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "
aPosition"); | |
809 if (-1 != header.fLocalCoordAttributeIndex) { | |
810 fLocalCoordsVar = &fVSAttrs.push_back(); | |
811 fLocalCoordsVar->set(kVec2f_GrSLType, | |
812 GrGLShaderVar::kAttribute_TypeModifier, | |
813 "aLocalCoords"); | |
814 } else { | |
815 fLocalCoordsVar = fPositionVar; | |
816 } | |
817 | |
818 const char* viewMName; | |
819 fUniformHandles.fViewMatrixUni = | |
820 this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kMat33f_GrSLType
, "ViewM", | |
821 &viewMName); | |
822 | |
823 // Transform the position into Skia's device coords. | |
824 this->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n", | |
825 viewMName, fPositionVar->c_str()); | |
826 | |
827 // we output point size in the GS if present | |
828 if (header.fEmitsPointSize | |
829 #if GR_GL_EXPERIMENTAL_GS | |
830 && !header.fExperimentalGS | |
831 #endif | |
832 ) { | |
833 this->vsCodeAppend("\tgl_PointSize = 1.0;\n"); | |
834 } | |
835 | |
836 if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) { | |
837 this->addAttribute(kVec4f_GrSLType, color_attribute_name()); | |
838 const char *vsName, *fsName; | |
839 this->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); | |
840 this->vsCodeAppendf("\t%s = %s;\n", vsName, color_attribute_name()); | |
841 *color = fsName; | |
842 } | |
843 | |
844 if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) { | |
845 this->addAttribute(kVec4f_GrSLType, coverage_attribute_name()); | |
846 const char *vsName, *fsName; | |
847 this->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); | |
848 this->vsCodeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name()); | |
849 *coverage = fsName; | |
850 } | |
851 } | |
852 | |
853 void GrGLFullShaderBuilder::emitCodeAfterEffects() { | |
854 const char* rtAdjustName; | |
855 fUniformHandles.fRTAdjustmentUni = | |
856 this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kVec4f_GrSLType,
"rtAdjustment", | |
857 &rtAdjustName); | |
858 | |
859 // Transform from Skia's device coords to GL's normalized device coords. | |
860 this->vsCodeAppendf( | |
861 "\tgl_Position = vec4(dot(pos3.xz, %s.xy), dot(pos3.yz, %s.zw), 0, pos3.
z);\n", | |
862 rtAdjustName, rtAdjustName); | |
863 } | |
864 | |
865 bool GrGLFullShaderBuilder::addAttribute(GrSLType type, const char* name) { | |
866 for (int i = 0; i < fVSAttrs.count(); ++i) { | |
867 const GrGLShaderVar& attr = fVSAttrs[i]; | |
868 // if attribute already added, don't add it again | |
869 if (attr.getName().equals(name)) { | |
870 SkASSERT(attr.getType() == type); | |
871 return false; | |
872 } | |
873 } | |
874 fVSAttrs.push_back().set(type, | |
875 GrGLShaderVar::kAttribute_TypeModifier, | |
876 name); | |
877 return true; | |
878 } | |
879 | |
880 bool GrGLFullShaderBuilder::addEffectAttribute(int attributeIndex, | |
881 GrSLType type, | |
882 const SkString& name) { | |
883 if (!this->addAttribute(type, name.c_str())) { | |
884 return false; | |
885 } | |
886 | |
887 fEffectAttributes.push_back().set(attributeIndex, name); | |
888 return true; | |
889 } | |
890 | |
891 void GrGLFullShaderBuilder::addVarying(GrSLType type, | |
892 const char* name, | |
893 const char** vsOutName, | |
894 const char** fsInName) { | |
895 fVSOutputs.push_back(); | |
896 fVSOutputs.back().setType(type); | |
897 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier); | |
898 this->nameVariable(fVSOutputs.back().accessName(), 'v', name); | |
899 | |
900 if (vsOutName) { | |
901 *vsOutName = fVSOutputs.back().getName().c_str(); | |
902 } | |
903 // input to FS comes either from VS or GS | |
904 const SkString* fsName; | |
905 #if GR_GL_EXPERIMENTAL_GS | |
906 if (this->desc().getHeader().fExperimentalGS) { | |
907 // if we have a GS take each varying in as an array | |
908 // and output as non-array. | |
909 fGSInputs.push_back(); | |
910 fGSInputs.back().setType(type); | |
911 fGSInputs.back().setTypeModifier(GrGLShaderVar::kVaryingIn_TypeModifier)
; | |
912 fGSInputs.back().setUnsizedArray(); | |
913 *fGSInputs.back().accessName() = fVSOutputs.back().getName(); | |
914 fGSOutputs.push_back(); | |
915 fGSOutputs.back().setType(type); | |
916 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifie
r); | |
917 this->nameVariable(fGSOutputs.back().accessName(), 'g', name); | |
918 fsName = fGSOutputs.back().accessName(); | |
919 } else | |
920 #endif | |
921 { | |
922 fsName = fVSOutputs.back().accessName(); | |
923 } | |
924 this->fsInputAppend().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, *fsN
ame); | |
925 if (fsInName) { | |
926 *fsInName = fsName->c_str(); | |
927 } | |
928 } | |
929 | |
930 const SkString* GrGLFullShaderBuilder::getEffectAttributeName(int attributeIndex
) const { | |
931 const AttributePair* attribEnd = fEffectAttributes.end(); | |
932 for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attr
ibEnd; ++attrib) { | |
933 if (attrib->fIndex == attributeIndex) { | |
934 return &attrib->fName; | |
935 } | |
936 } | |
937 | |
938 return NULL; | |
939 } | |
940 | |
941 GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects( | |
942 const GrEffectStage* effectStages[], | |
943 int effectCnt, | |
944 const GrGLProgramDesc::EffectKeyProvider& keyProvider, | |
945 GrGLSLExpr4* inOutFSColor) { | |
946 | |
947 GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt); | |
948 this->INHERITED::createAndEmitEffects(&programEffectsBuilder, | |
949 effectStages, | |
950 effectCnt, | |
951 keyProvider, | |
952 inOutFSColor); | |
953 return programEffectsBuilder.finish(); | |
954 } | |
955 | |
956 bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId, | |
957 SkTDArray<GrGLuint>* shaderI
ds) const { | |
958 const GrGLContext& glCtx = this->gpu()->glContext(); | |
959 SkString vertShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); | |
960 this->appendUniformDecls(kVertex_Visibility, &vertShaderSrc); | |
961 this->appendDecls(fVSAttrs, &vertShaderSrc); | |
962 this->appendDecls(fVSOutputs, &vertShaderSrc); | |
963 vertShaderSrc.append("void main() {\n"); | |
964 vertShaderSrc.append(fVSCode); | |
965 vertShaderSrc.append("}\n"); | |
966 GrGLuint vertShaderId = attach_shader(glCtx, programId, GR_GL_VERTEX_SHADER,
vertShaderSrc); | |
967 if (!vertShaderId) { | |
968 return false; | |
969 } | |
970 *shaderIds->append() = vertShaderId; | |
971 | |
972 #if GR_GL_EXPERIMENTAL_GS | |
973 if (this->desc().getHeader().fExperimentalGS) { | |
974 SkASSERT(this->ctxInfo().glslGeneration() >= k150_GrGLSLGeneration); | |
975 SkString geomShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); | |
976 geomShaderSrc.append("layout(triangles) in;\n" | |
977 "layout(triangle_strip, max_vertices = 6) out;\n"); | |
978 this->appendDecls(fGSInputs, &geomShaderSrc); | |
979 this->appendDecls(fGSOutputs, &geomShaderSrc); | |
980 geomShaderSrc.append("void main() {\n"); | |
981 geomShaderSrc.append("\tfor (int i = 0; i < 3; ++i) {\n" | |
982 "\t\tgl_Position = gl_in[i].gl_Position;\n"); | |
983 if (this->desc().getHeader().fEmitsPointSize) { | |
984 geomShaderSrc.append("\t\tgl_PointSize = 1.0;\n"); | |
985 } | |
986 SkASSERT(fGSInputs.count() == fGSOutputs.count()); | |
987 for (int i = 0; i < fGSInputs.count(); ++i) { | |
988 geomShaderSrc.appendf("\t\t%s = %s[i];\n", | |
989 fGSOutputs[i].getName().c_str(), | |
990 fGSInputs[i].getName().c_str()); | |
991 } | |
992 geomShaderSrc.append("\t\tEmitVertex();\n" | |
993 "\t}\n" | |
994 "\tEndPrimitive();\n"); | |
995 geomShaderSrc.append("}\n"); | |
996 GrGLuint geomShaderId = attach_shader(glCtx, programId, GR_GL_GEOMETRY_S
HADER, geomShaderSrc); | |
997 if (!geomShaderId) { | |
998 return false; | |
999 } | |
1000 *shaderIds->append() = geomShaderId; | |
1001 } | |
1002 #endif | |
1003 | |
1004 return this->INHERITED::compileAndAttachShaders(programId, shaderIds); | |
1005 } | |
1006 | |
1007 void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) { | |
1008 this->INHERITED::bindProgramLocations(programId); | |
1009 | |
1010 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); | |
1011 | |
1012 // Bind the attrib locations to same values for all shaders | |
1013 SkASSERT(-1 != header.fPositionAttributeIndex); | |
1014 GL_CALL(BindAttribLocation(programId, | |
1015 header.fPositionAttributeIndex, | |
1016 fPositionVar->c_str())); | |
1017 if (-1 != header.fLocalCoordAttributeIndex) { | |
1018 GL_CALL(BindAttribLocation(programId, | |
1019 header.fLocalCoordAttributeIndex, | |
1020 fLocalCoordsVar->c_str())); | |
1021 } | |
1022 if (-1 != header.fColorAttributeIndex) { | |
1023 GL_CALL(BindAttribLocation(programId, | |
1024 header.fColorAttributeIndex, | |
1025 color_attribute_name())); | |
1026 } | |
1027 if (-1 != header.fCoverageAttributeIndex) { | |
1028 GL_CALL(BindAttribLocation(programId, | |
1029 header.fCoverageAttributeIndex, | |
1030 coverage_attribute_name())); | |
1031 } | |
1032 | |
1033 const AttributePair* attribEnd = fEffectAttributes.end(); | |
1034 for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attr
ibEnd; ++attrib) { | |
1035 GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_s
tr())); | |
1036 } | |
1037 } | |
1038 | |
1039 //////////////////////////////////////////////////////////////////////////////// | |
1040 | |
1041 GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu, | |
1042 const GrGLProgramDe
sc& desc) | |
1043 : INHERITED(gpu, desc) { | |
1044 SkASSERT(!desc.getHeader().fHasVertexCode); | |
1045 SkASSERT(gpu->glCaps().pathRenderingSupport()); | |
1046 SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorIn
put); | |
1047 SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverag
eInput); | |
1048 } | |
1049 | |
1050 int GrGLFragmentOnlyShaderBuilder::addTexCoordSets(int count) { | |
1051 int firstFreeCoordSet = fTexCoordSetCnt; | |
1052 fTexCoordSetCnt += count; | |
1053 SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fTexCoordSetCnt)
; | |
1054 return firstFreeCoordSet; | |
1055 } | |
1056 | |
1057 GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects( | |
1058 const GrEffectStage* effectStages[], | |
1059 int effectCnt, | |
1060 const GrGLProgramDesc::EffectKeyProvider& keyProvider, | |
1061 GrGLSLExpr4* inOutFSColor) { | |
1062 | |
1063 GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this, | |
1064 effectCnt); | |
1065 this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder, | |
1066 effectStages, | |
1067 effectCnt, | |
1068 keyProvider, | |
1069 inOutFSColor); | |
1070 return pathTexGenEffectsBuilder.finish(); | |
1071 } | |
OLD | NEW |