blob: 488d07b8dbd21f0de7c8d2db4e9bd7ff722668af [file] [log] [blame]
joshualitt30ba4362014-08-21 20:18:45 -07001/*
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
joshualitt47bb3822014-10-07 16:43:25 -070013#define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X)
14#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(), R, X)
15
joshualitt30ba4362014-08-21 20:18:45 -070016// ES2 FS only guarantees mediump and lowp support
17static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
joshualitt47bb3822014-10-07 16:43:25 -070018const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor";
19static const char* declared_color_output_name() { return "fsColorOut"; }
20static const char* dual_source_output_name() { return "dualSourceOut"; }
21static void append_default_precision_qualifier(GrGLShaderVar::Precision p,
joshualitt30ba4362014-08-21 20:18:45 -070022 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}
joshualitt30ba4362014-08-21 20:18:45 -070043
joshualitt47bb3822014-10-07 16:43:25 -070044GrGLFragmentShaderBuilder::DstReadKey
45GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy,
46 const GrGLCaps& caps) {
joshualitt30ba4362014-08-21 20:18:45 -070047 uint32_t key = kYesDstRead_DstReadKeyBit;
48 if (caps.fbFetchSupport()) {
49 return key;
50 }
bsalomon49f085d2014-09-05 13:34:00 -070051 SkASSERT(dstCopy);
joshualitt30ba4362014-08-21 20:18:45 -070052 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
joshualitt47bb3822014-10-07 16:43:25 -070063GrGLFragmentShaderBuilder::FragPosKey
64GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst,
65 const GrGLCaps&) {
joshualitt30ba4362014-08-21 20:18:45 -070066 if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
67 return kTopLeftFragPosRead_FragPosKey;
68 } else {
69 return kBottomLeftFragPosRead_FragPosKey;
70 }
71}
72
73GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
74 const GrGLProgramDesc& desc)
75 : INHERITED(program)
76 , fHasCustomColorOutput(false)
77 , fHasSecondaryOutput(false)
78 , fSetupFragPosition(false)
joshualitt47bb3822014-10-07 16:43:25 -070079 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey)
80 , fHasReadDstColor(false)
81 , fHasReadFragmentPosition(false) {
joshualitt30ba4362014-08-21 20:18:45 -070082}
83
84bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
85 switch (feature) {
86 case kStandardDerivatives_GLSLFeature: {
87 GrGpuGL* gpu = fProgramBuilder->gpu();
88 if (!gpu->glCaps().shaderDerivativeSupport()) {
89 return false;
90 }
91 if (kGLES_GrGLStandard == gpu->glStandard()) {
92 this->addFeature(1 << kStandardDerivatives_GLSLFeature,
93 "GL_OES_standard_derivatives");
94 }
95 return true;
96 }
97 default:
98 SkFAIL("Unexpected GLSLFeature requested.");
99 return false;
100 }
101}
102
joshualittb0a8a372014-09-23 09:50:21 -0700103SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
104 const GrGLProcessor::TransformedCoordsArray& coords, int index) {
joshualitt23e280d2014-09-18 12:26:38 -0700105 if (kVec3f_GrSLType != coords[index].getType()) {
106 SkASSERT(kVec2f_GrSLType == coords[index].getType());
joshualitt30ba4362014-08-21 20:18:45 -0700107 return coords[index].getName();
108 }
109
110 SkString coords2D("coords2D");
111 if (0 != index) {
112 coords2D.appendf("_%i", index);
113 }
114 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
115 coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
116 return coords2D;
117}
118
119const char* GrGLFragmentShaderBuilder::fragmentPosition() {
joshualitt47bb3822014-10-07 16:43:25 -0700120 fHasReadFragmentPosition = true;
joshualitt30ba4362014-08-21 20:18:45 -0700121
122 GrGpuGL* gpu = fProgramBuilder->gpu();
123 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
124 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
125 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
126 if (fTopLeftFragPosRead) {
127 fSetupFragPosition = true;
128 return "gl_FragCoord";
129 } else if (gpu->glCaps().fragCoordConventionsSupport()) {
130 if (!fSetupFragPosition) {
131 if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
132 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
133 "GL_ARB_fragment_coord_conventions");
134 }
135 fInputs.push_back().set(kVec4f_GrSLType,
136 GrGLShaderVar::kIn_TypeModifier,
137 "gl_FragCoord",
138 GrGLShaderVar::kDefault_Precision,
139 GrGLShaderVar::kUpperLeft_Origin);
140 fSetupFragPosition = true;
141 }
142 return "gl_FragCoord";
143 } else {
144 static const char* kCoordName = "fragCoordYDown";
145 if (!fSetupFragPosition) {
146 // temporarily change the stage index because we're inserting non-stage code.
joshualitt47bb3822014-10-07 16:43:25 -0700147 GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
joshualitt30ba4362014-08-21 20:18:45 -0700148 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
149 const char* rtHeightName;
150
151 fProgramBuilder->fUniformHandles.fRTHeightUni =
152 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
joshualitt47bb3822014-10-07 16:43:25 -0700153 kFloat_GrSLType,
154 "RTHeight",
155 &rtHeightName);
joshualitt30ba4362014-08-21 20:18:45 -0700156
157 // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
158 // causes programs to fail to link. Making this function return a vec2() didn't fix the
159 // problem but using 1.0 for the last two components does.
160 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
161 "1.0);\n", kCoordName, rtHeightName);
162 fSetupFragPosition = true;
163 }
164 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
165 return kCoordName;
166 }
167}
168
joshualitt47bb3822014-10-07 16:43:25 -0700169const char* GrGLFragmentShaderBuilder::dstColor() {
170 fHasReadDstColor = true;
171
172 GrGpuGL* gpu = fProgramBuilder->gpu();
173 if (gpu->glCaps().fbFetchSupport()) {
174 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
175 gpu->glCaps().fbFetchExtensionString());
176 return gpu->glCaps().fbFetchColorName();
177 } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) {
178 return kDstCopyColorName;
179 } else {
180 return "";
joshualittdb0d3ca2014-10-07 12:42:26 -0700181 }
182}
joshualittfe1233c2014-10-07 12:16:35 -0700183
joshualitt47bb3822014-10-07 16:43:25 -0700184void GrGLFragmentShaderBuilder::emitCodeToReadDstTexture() {
185 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & fProgramBuilder->header().fDstReadKey);
186 const char* dstCopyTopLeftName;
187 const char* dstCopyCoordScaleName;
188 const char* dstCopySamplerName;
189 uint32_t configMask;
190 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & fProgramBuilder->header().fDstReadKey)) {
191 configMask = kA_GrColorComponentFlag;
192 } else {
193 configMask = kRGBA_GrColorComponentFlags;
joshualitt30ba4362014-08-21 20:18:45 -0700194 }
joshualitt47bb3822014-10-07 16:43:25 -0700195 fProgramBuilder->fUniformHandles.fDstCopySamplerUni =
196 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
197 kSampler2D_GrSLType,
198 "DstCopySampler",
199 &dstCopySamplerName);
200 fProgramBuilder->fUniformHandles.fDstCopyTopLeftUni =
201 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
202 kVec2f_GrSLType,
203 "DstCopyUpperLeft",
204 &dstCopyTopLeftName);
205 fProgramBuilder->fUniformHandles.fDstCopyScaleUni =
206 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
207 kVec2f_GrSLType,
208 "DstCopyCoordScale",
209 &dstCopyCoordScaleName);
210 const char* fragPos = this->fragmentPosition();
211
212 this->codeAppend("// Read color from copy of the destination.\n");
213 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;",
214 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName);
215 if (!topDown) {
216 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;");
joshualitt30ba4362014-08-21 20:18:45 -0700217 }
joshualitt47bb3822014-10-07 16:43:25 -0700218 this->codeAppendf("vec4 %s = ", GrGLFragmentShaderBuilder::kDstCopyColorName);
219 this->appendTextureLookup(dstCopySamplerName,
220 "_dstTexCoord",
221 configMask,
222 "rgba");
223 this->codeAppend(";");
224}
225
226void GrGLFragmentShaderBuilder::enableCustomOutput() {
227 SkASSERT(!fHasCustomColorOutput);
228 fHasCustomColorOutput = true;
229 fOutputs.push_back().set(kVec4f_GrSLType,
230 GrGLShaderVar::kOut_TypeModifier,
231 declared_color_output_name());
232}
233
234void GrGLFragmentShaderBuilder::enableSecondaryOutput() {
235 SkASSERT(!fHasSecondaryOutput);
236 fHasSecondaryOutput = true;
237 fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
238 dual_source_output_name());
239}
240
241const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
242 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
243}
244
245const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const {
246 return dual_source_output_name();
247}
248
249void GrGLFragmentShaderBuilder::enableSecondaryOutput(const GrGLSLExpr4& inputColor,
250 const GrGLSLExpr4& inputCoverage) {
251 this->enableSecondaryOutput();
252 const char* secondaryOutputName = this->getSecondaryColorOutputName();
253 GrGLSLExpr4 coeff(1);
254 switch (fProgramBuilder->header().fSecondaryOutputType) {
255 case GrOptDrawState::kCoverage_SecondaryOutputType:
256 break;
257 case GrOptDrawState::kCoverageISA_SecondaryOutputType:
258 // Get (1-A) into coeff
259 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a());
260 break;
261 case GrOptDrawState::kCoverageISC_SecondaryOutputType:
262 // Get (1-RGBA) into coeff
263 coeff = GrGLSLExpr4(1) - inputColor;
264 break;
265 default:
266 SkFAIL("Unexpected Secondary Output");
267 }
268 // Get coeff * coverage into modulate and then write that to the dual source output.
269 this->codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str());
270}
271
272void GrGLFragmentShaderBuilder::combineColorAndCoverage(const GrGLSLExpr4& inputColor,
273 const GrGLSLExpr4& inputCoverage) {
274 GrGLSLExpr4 fragColor = inputColor * inputCoverage;
275 switch (fProgramBuilder->header().fPrimaryOutputType) {
276 case GrOptDrawState::kModulate_PrimaryOutputType:
277 break;
278 case GrOptDrawState::kCombineWithDst_PrimaryOutputType:
279 {
280 // Tack on "+(1-coverage)dst onto the frag color.
281 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage;
282 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor());
283 fragColor = fragColor + dstContribution;
284 }
285 break;
286 default:
287 SkFAIL("Unknown Primary Output");
288 }
289
290 // On any post 1.10 GLSL supporting GPU, we declare custom output
291 if (k110_GrGLSLGeneration != fProgramBuilder->gpu()->glslGeneration()) {
292 this->enableCustomOutput();
293 }
294
295 this->codeAppendf("\t%s = %s;\n", this->getPrimaryColorOutputName(), fragColor.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700296}
297
298bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
299 SkTDArray<GrGLuint>* shaderIds) const {
300 GrGpuGL* gpu = fProgramBuilder->gpu();
301 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo()));
302 fragShaderSrc.append(fExtensions);
303 append_default_precision_qualifier(kDefaultFragmentPrecision,
304 gpu->glStandard(),
305 &fragShaderSrc);
306 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &fragShaderSrc);
joshualitt47bb3822014-10-07 16:43:25 -0700307 this->appendDecls(fInputs, &fragShaderSrc);
joshualitt30ba4362014-08-21 20:18:45 -0700308 // We shouldn't have declared outputs on 1.10
309 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
joshualitt47bb3822014-10-07 16:43:25 -0700310 this->appendDecls(fOutputs, &fragShaderSrc);
joshualitt30ba4362014-08-21 20:18:45 -0700311 fragShaderSrc.append(fFunctions);
312 fragShaderSrc.append("void main() {\n");
313 fragShaderSrc.append(fCode);
314 fragShaderSrc.append("}\n");
315
robertphillips754f4e92014-09-18 13:52:08 -0700316 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), programId,
317 GR_GL_FRAGMENT_SHADER, fragShaderSrc,
318 gpu->gpuStats());
joshualitt30ba4362014-08-21 20:18:45 -0700319 if (!fragShaderId) {
320 return false;
321 }
322
323 *shaderIds->append() = fragShaderId;
324
325 return true;
326}
327
joshualitt47bb3822014-10-07 16:43:25 -0700328void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
329 if (fHasCustomColorOutput) {
330 GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700331 }
joshualitt47bb3822014-10-07 16:43:25 -0700332 if (fHasSecondaryOutput) {
333 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700334 }
335}
336
joshualitt47bb3822014-10-07 16:43:25 -0700337void GrGLFragmentShaderBuilder::addVarying(GrSLType type,
338 const char* name,
339 const char** fsInName,
340 GrGLShaderVar::Precision fsPrecision) {
341 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name, fsPrecision);
342 if (fsInName) {
343 *fsInName = name;
joshualitt30ba4362014-08-21 20:18:45 -0700344 }
joshualitt30ba4362014-08-21 20:18:45 -0700345}