blob: 76558d8875fc9be54a772790a3c7bd87ff56c50c [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
rmistry63a9f842014-10-17 06:07:08 -070045GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps& caps) {
joshualitt30ba4362014-08-21 20:18:45 -070046 uint32_t key = kYesDstRead_DstReadKeyBit;
47 if (caps.fbFetchSupport()) {
48 return key;
49 }
bsalomon49f085d2014-09-05 13:34:00 -070050 SkASSERT(dstCopy);
joshualitt30ba4362014-08-21 20:18:45 -070051 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
52 // The fact that the config is alpha-only must be considered when generating code.
53 key |= kUseAlphaConfig_DstReadKeyBit;
54 }
55 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
56 key |= kTopLeftOrigin_DstReadKeyBit;
57 }
58 SkASSERT(static_cast<DstReadKey>(key) == key);
59 return static_cast<DstReadKey>(key);
60}
61
joshualitt47bb3822014-10-07 16:43:25 -070062GrGLFragmentShaderBuilder::FragPosKey
rmistry63a9f842014-10-17 06:07:08 -070063GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&) {
joshualitt30ba4362014-08-21 20:18:45 -070064 if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
65 return kTopLeftFragPosRead_FragPosKey;
66 } else {
67 return kBottomLeftFragPosRead_FragPosKey;
68 }
69}
70
71GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
72 const GrGLProgramDesc& desc)
73 : INHERITED(program)
74 , fHasCustomColorOutput(false)
75 , fHasSecondaryOutput(false)
76 , fSetupFragPosition(false)
joshualitt47bb3822014-10-07 16:43:25 -070077 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey)
joshualittb4384b92014-10-21 12:53:15 -070078 , fCustomColorOutputIndex(-1)
joshualitt47bb3822014-10-07 16:43:25 -070079 , fHasReadDstColor(false)
80 , fHasReadFragmentPosition(false) {
joshualitt30ba4362014-08-21 20:18:45 -070081}
82
83bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
84 switch (feature) {
85 case kStandardDerivatives_GLSLFeature: {
86 GrGpuGL* gpu = fProgramBuilder->gpu();
87 if (!gpu->glCaps().shaderDerivativeSupport()) {
88 return false;
89 }
rmistry63a9f842014-10-17 06:07:08 -070090 if (kGLES_GrGLStandard == gpu->glStandard() &&
91 k110_GrGLSLGeneration == gpu->glslGeneration()) {
joshualitt30ba4362014-08-21 20:18:45 -070092 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());
joshualittb4384b92014-10-21 12:53:15 -0700176
177 // On ES 3.0 we have to declare this, and use the custom color output name
178 const char* fbFetchColorName = gpu->glCaps().fbFetchColorName();
179 if (gpu->glslGeneration() >= k330_GrGLSLGeneration) {
180 this->enableCustomOutput();
181 fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
182 fbFetchColorName = declared_color_output_name();
183 }
184 return fbFetchColorName;
joshualitt47bb3822014-10-07 16:43:25 -0700185 } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) {
186 return kDstCopyColorName;
187 } else {
188 return "";
joshualittdb0d3ca2014-10-07 12:42:26 -0700189 }
190}
joshualittfe1233c2014-10-07 12:16:35 -0700191
joshualitt47bb3822014-10-07 16:43:25 -0700192void GrGLFragmentShaderBuilder::emitCodeToReadDstTexture() {
193 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & fProgramBuilder->header().fDstReadKey);
194 const char* dstCopyTopLeftName;
195 const char* dstCopyCoordScaleName;
196 const char* dstCopySamplerName;
197 uint32_t configMask;
198 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & fProgramBuilder->header().fDstReadKey)) {
199 configMask = kA_GrColorComponentFlag;
200 } else {
201 configMask = kRGBA_GrColorComponentFlags;
joshualitt30ba4362014-08-21 20:18:45 -0700202 }
joshualitt47bb3822014-10-07 16:43:25 -0700203 fProgramBuilder->fUniformHandles.fDstCopySamplerUni =
204 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
205 kSampler2D_GrSLType,
206 "DstCopySampler",
207 &dstCopySamplerName);
208 fProgramBuilder->fUniformHandles.fDstCopyTopLeftUni =
209 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
210 kVec2f_GrSLType,
211 "DstCopyUpperLeft",
212 &dstCopyTopLeftName);
213 fProgramBuilder->fUniformHandles.fDstCopyScaleUni =
214 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
215 kVec2f_GrSLType,
216 "DstCopyCoordScale",
217 &dstCopyCoordScaleName);
218 const char* fragPos = this->fragmentPosition();
219
220 this->codeAppend("// Read color from copy of the destination.\n");
221 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;",
222 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName);
223 if (!topDown) {
224 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;");
joshualitt30ba4362014-08-21 20:18:45 -0700225 }
joshualitt47bb3822014-10-07 16:43:25 -0700226 this->codeAppendf("vec4 %s = ", GrGLFragmentShaderBuilder::kDstCopyColorName);
227 this->appendTextureLookup(dstCopySamplerName,
228 "_dstTexCoord",
229 configMask,
230 "rgba");
231 this->codeAppend(";");
232}
233
234void GrGLFragmentShaderBuilder::enableCustomOutput() {
joshualittb4384b92014-10-21 12:53:15 -0700235 if (!fHasCustomColorOutput) {
236 fHasCustomColorOutput = true;
237 fCustomColorOutputIndex = fOutputs.count();
238 fOutputs.push_back().set(kVec4f_GrSLType,
239 GrGLShaderVar::kOut_TypeModifier,
240 declared_color_output_name());
241 }
joshualitt47bb3822014-10-07 16:43:25 -0700242}
243
244void GrGLFragmentShaderBuilder::enableSecondaryOutput() {
245 SkASSERT(!fHasSecondaryOutput);
246 fHasSecondaryOutput = true;
247 fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
248 dual_source_output_name());
249}
250
251const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
252 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
253}
254
255const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const {
256 return dual_source_output_name();
257}
258
259void GrGLFragmentShaderBuilder::enableSecondaryOutput(const GrGLSLExpr4& inputColor,
260 const GrGLSLExpr4& inputCoverage) {
261 this->enableSecondaryOutput();
262 const char* secondaryOutputName = this->getSecondaryColorOutputName();
263 GrGLSLExpr4 coeff(1);
264 switch (fProgramBuilder->header().fSecondaryOutputType) {
265 case GrOptDrawState::kCoverage_SecondaryOutputType:
266 break;
267 case GrOptDrawState::kCoverageISA_SecondaryOutputType:
268 // Get (1-A) into coeff
269 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a());
270 break;
271 case GrOptDrawState::kCoverageISC_SecondaryOutputType:
272 // Get (1-RGBA) into coeff
273 coeff = GrGLSLExpr4(1) - inputColor;
274 break;
275 default:
276 SkFAIL("Unexpected Secondary Output");
277 }
278 // Get coeff * coverage into modulate and then write that to the dual source output.
279 this->codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str());
280}
281
282void GrGLFragmentShaderBuilder::combineColorAndCoverage(const GrGLSLExpr4& inputColor,
283 const GrGLSLExpr4& inputCoverage) {
284 GrGLSLExpr4 fragColor = inputColor * inputCoverage;
285 switch (fProgramBuilder->header().fPrimaryOutputType) {
286 case GrOptDrawState::kModulate_PrimaryOutputType:
287 break;
288 case GrOptDrawState::kCombineWithDst_PrimaryOutputType:
289 {
290 // Tack on "+(1-coverage)dst onto the frag color.
291 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage;
292 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor());
293 fragColor = fragColor + dstContribution;
294 }
295 break;
296 default:
297 SkFAIL("Unknown Primary Output");
298 }
299
300 // On any post 1.10 GLSL supporting GPU, we declare custom output
301 if (k110_GrGLSLGeneration != fProgramBuilder->gpu()->glslGeneration()) {
302 this->enableCustomOutput();
303 }
304
305 this->codeAppendf("\t%s = %s;\n", this->getPrimaryColorOutputName(), fragColor.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700306}
307
308bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
309 SkTDArray<GrGLuint>* shaderIds) const {
310 GrGpuGL* gpu = fProgramBuilder->gpu();
311 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo()));
312 fragShaderSrc.append(fExtensions);
313 append_default_precision_qualifier(kDefaultFragmentPrecision,
314 gpu->glStandard(),
315 &fragShaderSrc);
316 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &fragShaderSrc);
joshualitt47bb3822014-10-07 16:43:25 -0700317 this->appendDecls(fInputs, &fragShaderSrc);
joshualitt30ba4362014-08-21 20:18:45 -0700318 // We shouldn't have declared outputs on 1.10
319 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
joshualitt47bb3822014-10-07 16:43:25 -0700320 this->appendDecls(fOutputs, &fragShaderSrc);
joshualitt30ba4362014-08-21 20:18:45 -0700321 fragShaderSrc.append(fFunctions);
322 fragShaderSrc.append("void main() {\n");
323 fragShaderSrc.append(fCode);
324 fragShaderSrc.append("}\n");
325
robertphillips754f4e92014-09-18 13:52:08 -0700326 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), programId,
327 GR_GL_FRAGMENT_SHADER, fragShaderSrc,
328 gpu->gpuStats());
joshualitt30ba4362014-08-21 20:18:45 -0700329 if (!fragShaderId) {
330 return false;
331 }
332
333 *shaderIds->append() = fragShaderId;
334
335 return true;
336}
337
joshualitt47bb3822014-10-07 16:43:25 -0700338void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
rmistry63a9f842014-10-17 06:07:08 -0700339 // ES 3.00 requires custom color output but doesn't support bindFragDataLocation
340 if (fHasCustomColorOutput &&
341 kGLES_GrGLStandard != fProgramBuilder->gpu()->ctxInfo().standard()) {
joshualitt47bb3822014-10-07 16:43:25 -0700342 GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700343 }
joshualitt47bb3822014-10-07 16:43:25 -0700344 if (fHasSecondaryOutput) {
345 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700346 }
347}
348
joshualitt47bb3822014-10-07 16:43:25 -0700349void GrGLFragmentShaderBuilder::addVarying(GrSLType type,
350 const char* name,
351 const char** fsInName,
352 GrGLShaderVar::Precision fsPrecision) {
353 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name, fsPrecision);
354 if (fsInName) {
355 *fsInName = name;
joshualitt30ba4362014-08-21 20:18:45 -0700356 }
joshualitt30ba4362014-08-21 20:18:45 -0700357}