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 namespace {
14 #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
15 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
16 // ES2 FS only guarantees mediump and lowp support
17 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
18 static const char kDstCopyColorName[] = "_dstColor";
declared_color_output_name()19 inline const char* declared_color_output_name() { return "fsColorOut"; }
dual_source_output_name()20 inline const char* dual_source_output_name() { return "dualSourceOut"; }
append_default_precision_qualifier(GrGLShaderVar::Precision p,GrGLStandard standard,SkString * str)21 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
22 GrGLStandard standard,
23 SkString* str) {
24 // Desktop GLSL has added precision qualifiers but they don't do anything.
25 if (kGLES_GrGLStandard == standard) {
26 switch (p) {
27 case GrGLShaderVar::kHigh_Precision:
28 str->append("precision highp float;\n");
29 break;
30 case GrGLShaderVar::kMedium_Precision:
31 str->append("precision mediump float;\n");
32 break;
33 case GrGLShaderVar::kLow_Precision:
34 str->append("precision lowp float;\n");
35 break;
36 case GrGLShaderVar::kDefault_Precision:
37 SkFAIL("Default precision now allowed.");
38 default:
39 SkFAIL("Unknown precision value.");
40 }
41 }
42 }
43 }
44
KeyForDstRead(const GrTexture * dstCopy,const GrGLCaps & caps)45 GrGLFragmentShaderBuilder::DstReadKey GrGLFragmentShaderBuilder::KeyForDstRead(
46 const GrTexture* dstCopy, const GrGLCaps& caps) {
47 uint32_t key = kYesDstRead_DstReadKeyBit;
48 if (caps.fbFetchSupport()) {
49 return key;
50 }
51 SkASSERT(dstCopy);
52 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
53 // The fact that the config is alpha-only must be considered when generating code.
54 key |= kUseAlphaConfig_DstReadKeyBit;
55 }
56 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
57 key |= kTopLeftOrigin_DstReadKeyBit;
58 }
59 SkASSERT(static_cast<DstReadKey>(key) == key);
60 return static_cast<DstReadKey>(key);
61 }
62
KeyForFragmentPosition(const GrRenderTarget * dst,const GrGLCaps &)63 GrGLFragmentShaderBuilder::FragPosKey GrGLFragmentShaderBuilder::KeyForFragmentPosition(
64 const GrRenderTarget* dst, const GrGLCaps&) {
65 if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
66 return kTopLeftFragPosRead_FragPosKey;
67 } else {
68 return kBottomLeftFragPosRead_FragPosKey;
69 }
70 }
71
GrGLFragmentShaderBuilder(GrGLProgramBuilder * program,const GrGLProgramDesc & desc)72 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
73 const GrGLProgramDesc& desc)
74 : INHERITED(program)
75 , fHasCustomColorOutput(false)
76 , fHasSecondaryOutput(false)
77 , fSetupFragPosition(false)
78 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey){
79 }
80
dstColor()81 const char* GrGLFragmentShaderBuilder::dstColor() {
82 if (fProgramBuilder->fCodeStage.inStageCode()) {
83 const GrProcessor* effect = fProgramBuilder->fCodeStage.effectStage()->getProcessor();
84 // TODO GPs can't read dst color, and full program builder only returns a pointer to the
85 // base fragment shader builder which does not have this function. Unfortunately,
86 // the code stage class only has a GrProcessor pointer so this is required for the time
87 // being
88 if (!static_cast<const GrFragmentProcessor*>(effect)->willReadDstColor()) {
89 SkDEBUGFAIL("GrGLProcessor asked for dst color but its generating GrProcessor "
90 "did not request access.");
91 return "";
92 }
93 }
94
95 GrGpuGL* gpu = fProgramBuilder->gpu();
96 if (gpu->glCaps().fbFetchSupport()) {
97 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
98 gpu->glCaps().fbFetchExtensionString());
99 return gpu->glCaps().fbFetchColorName();
100 } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) {
101 return kDstCopyColorName;
102 } else {
103 return "";
104 }
105 }
106
enableFeature(GLSLFeature feature)107 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
108 switch (feature) {
109 case kStandardDerivatives_GLSLFeature: {
110 GrGpuGL* gpu = fProgramBuilder->gpu();
111 if (!gpu->glCaps().shaderDerivativeSupport()) {
112 return false;
113 }
114 if (kGLES_GrGLStandard == gpu->glStandard()) {
115 this->addFeature(1 << kStandardDerivatives_GLSLFeature,
116 "GL_OES_standard_derivatives");
117 }
118 return true;
119 }
120 default:
121 SkFAIL("Unexpected GLSLFeature requested.");
122 return false;
123 }
124 }
125
ensureFSCoords2D(const GrGLProcessor::TransformedCoordsArray & coords,int index)126 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
127 const GrGLProcessor::TransformedCoordsArray& coords, int index) {
128 if (kVec3f_GrSLType != coords[index].getType()) {
129 SkASSERT(kVec2f_GrSLType == coords[index].getType());
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_str());
139 return coords2D;
140 }
141
fragmentPosition()142 const char* GrGLFragmentShaderBuilder::fragmentPosition() {
143 GrGLProgramBuilder::CodeStage* cs = &fProgramBuilder->fCodeStage;
144 if (cs->inStageCode()) {
145 const GrProcessor* effect = cs->effectStage()->getProcessor();
146 if (!effect->willReadFragmentPosition()) {
147 SkDEBUGFAIL("GrGLProcessor asked for frag position but its generating GrProcessor "
148 "did not request access.");
149 return "";
150 }
151 }
152
153 GrGpuGL* gpu = fProgramBuilder->gpu();
154 // We only declare "gl_FragCoord" when we're in the case where we want to use 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-stage code.
178 GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL);
179
180 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
181 const char* rtHeightName;
182
183 fProgramBuilder->fUniformHandles.fRTHeightUni =
184 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
185 kFloat_GrSLType,
186 "RTHeight",
187 &rtHeightName);
188
189 // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
190 // causes programs to fail to link. Making this function return a vec2() 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_FragCoord.y, 1.0, "
193 "1.0);\n", kCoordName, rtHeightName);
194 fSetupFragPosition = true;
195 }
196 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
197 return kCoordName;
198 }
199 }
200
addVarying(GrSLType type,const char * name,const char ** fsInName,GrGLShaderVar::Precision fsPrecision)201 void GrGLFragmentShaderBuilder::addVarying(GrSLType type,
202 const char* name,
203 const char** fsInName,
204 GrGLShaderVar::Precision fsPrecision) {
205 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name, fsPrecision);
206 if (fsInName) {
207 *fsInName = name;
208 }
209 }
210
bindProgramLocations(GrGLuint programId)211 void GrGLFragmentShaderBuilder::bindProgramLocations(GrGLuint programId) {
212 GrGpuGL* gpu = fProgramBuilder->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
compileAndAttachShaders(GrGLuint programId,SkTDArray<GrGLuint> * shaderIds) const221 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
222 SkTDArray<GrGLuint>* shaderIds) const {
223 GrGpuGL* gpu = fProgramBuilder->gpu();
224 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo()));
225 fragShaderSrc.append(fExtensions);
226 append_default_precision_qualifier(kDefaultFragmentPrecision,
227 gpu->glStandard(),
228 &fragShaderSrc);
229 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &fragShaderSrc);
230 fProgramBuilder->appendDecls(fInputs, &fragShaderSrc);
231 // We shouldn't have declared outputs on 1.10
232 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
233 fProgramBuilder->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(), programId,
240 GR_GL_FRAGMENT_SHADER, fragShaderSrc,
241 gpu->gpuStats());
242 if (!fragShaderId) {
243 return false;
244 }
245
246 *shaderIds->append() = fragShaderId;
247
248 return true;
249 }
250
emitCodeBeforeEffects()251 void GrGLFragmentShaderBuilder::emitCodeBeforeEffects() {
252 const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader();
253 GrGpuGL* gpu = fProgramBuilder->gpu();
254
255 ///////////////////////////////////////////////////////////////////////////
256 // emit code to read the dst copy texture, if necessary
257 if (kNoDstRead_DstReadKey != header.fDstReadKey && !gpu->glCaps().fbFetchSupport()) {
258 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey);
259 const char* dstCopyTopLeftName;
260 const char* dstCopyCoordScaleName;
261 const char* dstCopySamplerName;
262 uint32_t configMask;
263 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) {
264 configMask = kA_GrColorComponentFlag;
265 } else {
266 configMask = kRGBA_GrColorComponentFlags;
267 }
268 fProgramBuilder->fUniformHandles.fDstCopySamplerUni =
269 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
270 kSampler2D_GrSLType,
271 "DstCopySampler",
272 &dstCopySamplerName);
273 fProgramBuilder->fUniformHandles.fDstCopyTopLeftUni =
274 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
275 kVec2f_GrSLType,
276 "DstCopyUpperLeft",
277 &dstCopyTopLeftName);
278 fProgramBuilder->fUniformHandles.fDstCopyScaleUni =
279 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
280 kVec2f_GrSLType,
281 "DstCopyCoordScale",
282 &dstCopyCoordScaleName);
283 const char* fragPos = fragmentPosition();
284
285 this->codeAppend("// Read color from copy of the destination.\n");
286 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;",
287 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName);
288 if (!topDown) {
289 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;");
290 }
291 this->codeAppendf("vec4 %s = ", kDstCopyColorName);
292 this->appendTextureLookup(dstCopySamplerName,
293 "_dstTexCoord",
294 configMask,
295 "rgba");
296 this->codeAppend(";");
297 }
298
299 if (k110_GrGLSLGeneration != gpu->glslGeneration()) {
300 fOutputs.push_back().set(kVec4f_GrSLType,
301 GrGLShaderVar::kOut_TypeModifier,
302 declared_color_output_name());
303 fHasCustomColorOutput = true;
304 }
305 }
306
emitCodeAfterEffects(const GrGLSLExpr4 & inputColor,const GrGLSLExpr4 & inputCoverage)307 void GrGLFragmentShaderBuilder::emitCodeAfterEffects(const GrGLSLExpr4& inputColor, const GrGLSLExpr4& inputCoverage) {
308 const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader();
309
310 ///////////////////////////////////////////////////////////////////////////
311 // write the secondary color output if necessary
312 if (GrOptDrawState::kNone_SecondaryOutputType != header.fSecondaryOutputType) {
313 const char* secondaryOutputName = this->enableSecondaryOutput();
314 GrGLSLExpr4 coeff(1);
315 switch (header.fSecondaryOutputType) {
316 case GrOptDrawState::kCoverage_SecondaryOutputType:
317 break;
318 case GrOptDrawState::kCoverageISA_SecondaryOutputType:
319 // Get (1-A) into coeff
320 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a());
321 break;
322 case GrOptDrawState::kCoverageISC_SecondaryOutputType:
323 // Get (1-RGBA) into coeff
324 coeff = GrGLSLExpr4(1) - inputColor;
325 break;
326 default:
327 SkFAIL("Unexpected Secondary Output");
328 }
329 // Get coeff * coverage into modulate and then write that to the dual source output.
330 codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str());
331 }
332
333 ///////////////////////////////////////////////////////////////////////////
334 // combine color and coverage as frag color
335
336 // Get "color * coverage" into fragColor
337 GrGLSLExpr4 fragColor = inputColor * inputCoverage;
338 switch (header.fPrimaryOutputType) {
339 case GrOptDrawState::kModulate_PrimaryOutputType:
340 break;
341 case GrOptDrawState::kCombineWithDst_PrimaryOutputType:
342 {
343 // Tack on "+(1-coverage)dst onto the frag color.
344 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage;
345 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(dstColor());
346 fragColor = fragColor + dstContribution;
347 }
348 break;
349 default:
350 SkFAIL("Unknown Primary Output");
351 }
352 codeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str());
353 }
354
enableSecondaryOutput()355 const char* GrGLFragmentShaderBuilder::enableSecondaryOutput() {
356 if (!fHasSecondaryOutput) {
357 fOutputs.push_back().set(kVec4f_GrSLType,
358 GrGLShaderVar::kOut_TypeModifier,
359 dual_source_output_name());
360 fHasSecondaryOutput = true;
361 }
362 return dual_source_output_name();
363 }
364
getColorOutputName() const365 const char* GrGLFragmentShaderBuilder::getColorOutputName() const {
366 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
367 }
368
369