OLD | NEW |
---|---|
(Empty) | |
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 "GrGLFragmentShaderBuilder.h" | |
9 #include "GrGLShaderStringBuilder.h" | |
10 #include "GrGLProgramBuilder.h" | |
11 #include "../GrGpuGL.h" | |
12 | |
13 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
bsalomon
2014/08/21 20:21:01
Having these local, static, private blocks is at o
| |
14 // local /////////////////////////////////////////////////////////////////////// //////////////////// | |
15 namespace { | |
16 #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X) | |
17 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X) | |
18 // ES2 FS only guarantees mediump and lowp support | |
19 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar: :kMedium_Precision; | |
20 static const char kDstCopyColorName[] = "_dstColor"; | |
21 inline const char* declared_color_output_name() { return "fsColorOut"; } | |
22 inline const char* dual_source_output_name() { return "dualSourceOut"; } | |
23 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, | |
24 GrGLStandard standard, | |
25 SkString* str) { | |
26 // Desktop GLSL has added precision qualifiers but they don't do anything. | |
27 if (kGLES_GrGLStandard == standard) { | |
28 switch (p) { | |
29 case GrGLShaderVar::kHigh_Precision: | |
30 str->append("precision highp float;\n"); | |
31 break; | |
32 case GrGLShaderVar::kMedium_Precision: | |
33 str->append("precision mediump float;\n"); | |
34 break; | |
35 case GrGLShaderVar::kLow_Precision: | |
36 str->append("precision lowp float;\n"); | |
37 break; | |
38 case GrGLShaderVar::kDefault_Precision: | |
39 SkFAIL("Default precision now allowed."); | |
40 default: | |
41 SkFAIL("Unknown precision value."); | |
42 } | |
43 } | |
44 } | |
45 } | |
46 | |
47 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
48 // GrGLFragmentShaderBuilder static //////////////////////////////////////////// //////////////////// | |
49 GrGLFragmentShaderBuilder::DstReadKey GrGLFragmentShaderBuilder::KeyForDstRead( | |
50 const GrTexture* dstCopy, const GrGLCaps& caps) { | |
51 uint32_t key = kYesDstRead_DstReadKeyBit; | |
52 if (caps.fbFetchSupport()) { | |
53 return key; | |
54 } | |
55 SkASSERT(NULL != dstCopy); | |
56 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->confi g())) { | |
57 // The fact that the config is alpha-only must be considered when genera ting code. | |
58 key |= kUseAlphaConfig_DstReadKeyBit; | |
59 } | |
60 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) { | |
61 key |= kTopLeftOrigin_DstReadKeyBit; | |
62 } | |
63 SkASSERT(static_cast<DstReadKey>(key) == key); | |
64 return static_cast<DstReadKey>(key); | |
65 } | |
66 | |
67 GrGLFragmentShaderBuilder::FragPosKey GrGLFragmentShaderBuilder::KeyForFragmentP osition( | |
68 const GrRenderTarget* dst, const GrGLCaps&) { | |
69 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { | |
70 return kTopLeftFragPosRead_FragPosKey; | |
71 } else { | |
72 return kBottomLeftFragPosRead_FragPosKey; | |
73 } | |
74 } | |
75 | |
76 // GrGLFragmentShaderBuilder public //////////////////////////////////////////// /////////////////// | |
77 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program , | |
78 const GrGLProgramDesc& desc ) | |
79 : INHERITED(program) | |
80 , fHasCustomColorOutput(false) | |
81 , fHasSecondaryOutput(false) | |
82 , fSetupFragPosition(false) | |
83 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFr agPosKey){ | |
84 } | |
85 | |
86 const char* GrGLFragmentShaderBuilder::dstColor() { | |
87 if (fProgram->fCodeStage.inStageCode()) { | |
88 const GrEffect* effect = fProgram->fCodeStage.effectStage()->getEffect() ; | |
89 if (!effect->willReadDstColor()) { | |
90 SkDEBUGFAIL("GrGLEffect asked for dst color but its generating GrEff ect " | |
91 "did not request access."); | |
92 return ""; | |
93 } | |
94 } | |
95 | |
96 GrGpuGL* gpu = fProgram->gpu(); | |
97 if (gpu->glCaps().fbFetchSupport()) { | |
98 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur e + 1), | |
99 gpu->glCaps().fbFetchExtensionString()); | |
100 return gpu->glCaps().fbFetchColorName(); | |
101 } else if (fProgram->fUniformHandles.fDstCopySamplerUni.isValid()) { | |
102 return kDstCopyColorName; | |
103 } else { | |
104 return ""; | |
105 } | |
106 } | |
107 | |
108 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { | |
109 switch (feature) { | |
110 case kStandardDerivatives_GLSLFeature: { | |
111 GrGpuGL* gpu = fProgram->gpu(); | |
112 if (!gpu->glCaps().shaderDerivativeSupport()) { | |
113 return false; | |
114 } | |
115 if (kGLES_GrGLStandard == gpu->glStandard()) { | |
116 this->addFeature(1 << kStandardDerivatives_GLSLFeature, | |
117 "GL_OES_standard_derivatives"); | |
118 } | |
119 return true; | |
120 } | |
121 default: | |
122 SkFAIL("Unexpected GLSLFeature requested."); | |
123 return false; | |
124 } | |
125 } | |
126 | |
127 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(const TransformedCoordsArra y& coords, int index) { | |
128 if (kVec3f_GrSLType != coords[index].type()) { | |
129 SkASSERT(kVec2f_GrSLType == coords[index].type()); | |
130 return coords[index].getName(); | |
131 } | |
132 | |
133 SkString coords2D("coords2D"); | |
134 if (0 != index) { | |
135 coords2D.appendf("_%i", index); | |
136 } | |
137 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", | |
138 coords2D.c_str(), coords[index].c_str(), coords[index].c_s tr()); | |
139 return coords2D; | |
140 } | |
141 | |
142 const char* GrGLFragmentShaderBuilder::fragmentPosition() { | |
143 GrGLProgramBuilder::CodeStage* cs = &fProgram->fCodeStage; | |
144 if (cs->inStageCode()) { | |
145 const GrEffect* effect = cs->effectStage()->getEffect(); | |
146 if (!effect->willReadFragmentPosition()) { | |
147 SkDEBUGFAIL("GrGLEffect asked for frag position but its generating G rEffect " | |
148 "did not request access."); | |
149 return ""; | |
150 } | |
151 } | |
152 | |
153 GrGpuGL* gpu = fProgram->gpu(); | |
154 // We only declare "gl_FragCoord" when we're in the case where we want to us e layout qualifiers | |
155 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the | |
156 // declaration varies in earlier GLSL specs. So it is simpler to omit it. | |
157 if (fTopLeftFragPosRead) { | |
158 fSetupFragPosition = true; | |
159 return "gl_FragCoord"; | |
160 } else if (gpu->glCaps().fragCoordConventionsSupport()) { | |
161 if (!fSetupFragPosition) { | |
162 if (gpu->glslGeneration() < k150_GrGLSLGeneration) { | |
163 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, | |
164 "GL_ARB_fragment_coord_conventions"); | |
165 } | |
166 fInputs.push_back().set(kVec4f_GrSLType, | |
167 GrGLShaderVar::kIn_TypeModifier, | |
168 "gl_FragCoord", | |
169 GrGLShaderVar::kDefault_Precision, | |
170 GrGLShaderVar::kUpperLeft_Origin); | |
171 fSetupFragPosition = true; | |
172 } | |
173 return "gl_FragCoord"; | |
174 } else { | |
175 static const char* kCoordName = "fragCoordYDown"; | |
176 if (!fSetupFragPosition) { | |
177 // temporarily change the stage index because we're inserting non-st age code. | |
178 GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL); | |
179 | |
180 SkASSERT(!fProgram->fUniformHandles.fRTHeightUni.isValid()); | |
181 const char* rtHeightName; | |
182 | |
183 fProgram->fUniformHandles.fRTHeightUni = | |
184 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibilit y, | |
185 kFloat_GrSLType, | |
186 "RTHeight", | |
187 &rtHeightName); | |
188 | |
189 // Using glFragCoord.zw for the last two components tickles an Adren o driver bug that | |
190 // causes programs to fail to link. Making this function return a ve c2() didn't fix the | |
191 // problem but using 1.0 for the last two components does. | |
192 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoo rd.y, 1.0, " | |
193 "1.0);\n", kCoordName, rtHeightName); | |
194 fSetupFragPosition = true; | |
195 } | |
196 SkASSERT(fProgram->fUniformHandles.fRTHeightUni.isValid()); | |
197 return kCoordName; | |
198 } | |
199 } | |
200 | |
201 // GrGLFragmentShaderBuilder private /////////////////////////////////////////// /////////////////// | |
202 void GrGLFragmentShaderBuilder::addVarying(GrSLType type, | |
203 const char* name, | |
204 const char** fsInName) { | |
205 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name); | |
206 if (fsInName) { | |
207 *fsInName = name; | |
208 } | |
209 } | |
210 | |
211 void GrGLFragmentShaderBuilder::bindProgramLocations(GrGLuint programId) { | |
212 GrGpuGL* gpu = fProgram->gpu(); | |
213 if (fHasCustomColorOutput) { | |
214 GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name()) ); | |
215 } | |
216 if (fHasSecondaryOutput) { | |
217 GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_ name())); | |
218 } | |
219 } | |
220 | |
221 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, | |
222 SkTDArray<GrGLuint>* sha derIds) const { | |
223 GrGpuGL* gpu = fProgram->gpu(); | |
224 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo())); | |
225 fragShaderSrc.append(fExtensions); | |
226 append_default_precision_qualifier(kDefaultFragmentPrecision, | |
227 gpu->glStandard(), | |
228 &fragShaderSrc); | |
229 fProgram->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &frag ShaderSrc); | |
230 fProgram->appendDecls(fInputs, &fragShaderSrc); | |
231 // We shouldn't have declared outputs on 1.10 | |
232 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty()) ; | |
233 fProgram->appendDecls(fOutputs, &fragShaderSrc); | |
234 fragShaderSrc.append(fFunctions); | |
235 fragShaderSrc.append("void main() {\n"); | |
236 fragShaderSrc.append(fCode); | |
237 fragShaderSrc.append("}\n"); | |
238 | |
239 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), | |
240 programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc); | |
241 if (!fragShaderId) { | |
242 return false; | |
243 } | |
244 | |
245 *shaderIds->append() = fragShaderId; | |
246 | |
247 return true; | |
248 } | |
249 | |
250 void GrGLFragmentShaderBuilder::emitCodeBeforeEffects() { | |
251 const GrGLProgramDesc::KeyHeader& header = fProgram->desc().getHeader(); | |
252 GrGpuGL* gpu = fProgram->gpu(); | |
253 | |
254 /////////////////////////////////////////////////////////////////////////// | |
255 // emit code to read the dst copy texture, if necessary | |
256 if (kNoDstRead_DstReadKey != header.fDstReadKey && !gpu->glCaps().fbFetchSup port()) { | |
257 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKe y); | |
258 const char* dstCopyTopLeftName; | |
259 const char* dstCopyCoordScaleName; | |
260 const char* dstCopySamplerName; | |
261 uint32_t configMask; | |
262 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { | |
263 configMask = kA_GrColorComponentFlag; | |
264 } else { | |
265 configMask = kRGBA_GrColorComponentFlags; | |
266 } | |
267 fProgram->fUniformHandles.fDstCopySamplerUni = | |
268 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
269 kSampler2D_GrSLType, | |
270 "DstCopySampler", | |
271 &dstCopySamplerName); | |
272 fProgram->fUniformHandles.fDstCopyTopLeftUni = | |
273 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
274 kVec2f_GrSLType, | |
275 "DstCopyUpperLeft", | |
276 &dstCopyTopLeftName); | |
277 fProgram->fUniformHandles.fDstCopyScaleUni = | |
278 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
279 kVec2f_GrSLType, | |
280 "DstCopyCoordScale", | |
281 &dstCopyCoordScaleName); | |
282 const char* fragPos = fragmentPosition(); | |
283 | |
284 this->codeAppend("// Read color from copy of the destination.\n"); | |
285 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;", | |
286 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); | |
287 if (!topDown) { | |
288 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); | |
289 } | |
290 this->codeAppendf("vec4 %s = ", kDstCopyColorName); | |
291 this->appendTextureLookup(dstCopySamplerName, | |
292 "_dstTexCoord", | |
293 configMask, | |
294 "rgba"); | |
295 this->codeAppend(";"); | |
296 } | |
297 | |
298 if (k110_GrGLSLGeneration != gpu->glslGeneration()) { | |
299 fOutputs.push_back().set(kVec4f_GrSLType, | |
300 GrGLShaderVar::kOut_TypeModifier, | |
301 declared_color_output_name()); | |
302 fHasCustomColorOutput = true; | |
303 } | |
304 } | |
305 | |
306 void GrGLFragmentShaderBuilder::emitCodeAfterEffects(const GrGLSLExpr4& inputCol or, const GrGLSLExpr4& inputCoverage) { | |
307 const GrGLProgramDesc::KeyHeader& header = fProgram->desc().getHeader(); | |
308 | |
309 /////////////////////////////////////////////////////////////////////////// | |
310 // write the secondary color output if necessary | |
311 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutpu t)) { | |
312 const char* secondaryOutputName = this->enableSecondaryOutput(); | |
313 | |
314 // default coeff to ones for kCoverage_DualSrcOutput | |
315 GrGLSLExpr4 coeff(1); | |
316 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCov erageOutput) { | |
317 // Get (1-A) into coeff | |
318 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); | |
319 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == | |
320 header.fCoverageOutput){ | |
321 // Get (1-RGBA) into coeff | |
322 coeff = GrGLSLExpr4(1) - inputColor; | |
323 } | |
324 // Get coeff * coverage into modulate and then write that to the dual so urce output. | |
325 codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage) .c_str()); | |
326 } | |
327 | |
328 /////////////////////////////////////////////////////////////////////////// | |
329 // combine color and coverage as frag color | |
330 | |
331 // Get "color * coverage" into fragColor | |
332 GrGLSLExpr4 fragColor = inputColor * inputCoverage; | |
333 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. | |
334 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutpu t) { | |
335 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; | |
336 | |
337 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(dstColor()); | |
338 | |
339 fragColor = fragColor + dstContribution; | |
340 } | |
341 codeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str()); | |
342 } | |
343 | |
344 const char* GrGLFragmentShaderBuilder::enableSecondaryOutput() { | |
345 if (!fHasSecondaryOutput) { | |
346 fOutputs.push_back().set(kVec4f_GrSLType, | |
347 GrGLShaderVar::kOut_TypeModifier, | |
348 dual_source_output_name()); | |
349 fHasSecondaryOutput = true; | |
350 } | |
351 return dual_source_output_name(); | |
352 } | |
353 | |
354 const char* GrGLFragmentShaderBuilder::getColorOutputName() const { | |
355 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor" ; | |
356 } | |
357 | |
OLD | NEW |