blob: 46433f01c27ff7dcc2d14da3d377fb05ae474a1f [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"
jvanverth39edf762014-12-22 11:44:19 -080011#include "../GrGLGpu.h"
joshualitt30ba4362014-08-21 20:18:45 -070012
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
joshualitt47bb3822014-10-07 16:43:25 -070016const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor";
17static const char* declared_color_output_name() { return "fsColorOut"; }
18static const char* dual_source_output_name() { return "dualSourceOut"; }
bsalomonc0bd6482014-12-09 10:04:14 -080019static void append_default_precision_qualifier(GrSLPrecision p,
joshualitt30ba4362014-08-21 20:18:45 -070020 GrGLStandard standard,
21 SkString* str) {
22 // Desktop GLSL has added precision qualifiers but they don't do anything.
23 if (kGLES_GrGLStandard == standard) {
24 switch (p) {
bsalomonc0bd6482014-12-09 10:04:14 -080025 case kHigh_GrSLPrecision:
joshualitt30ba4362014-08-21 20:18:45 -070026 str->append("precision highp float;\n");
27 break;
bsalomonc0bd6482014-12-09 10:04:14 -080028 case kMedium_GrSLPrecision:
joshualitt30ba4362014-08-21 20:18:45 -070029 str->append("precision mediump float;\n");
30 break;
bsalomonc0bd6482014-12-09 10:04:14 -080031 case kLow_GrSLPrecision:
joshualitt30ba4362014-08-21 20:18:45 -070032 str->append("precision lowp float;\n");
33 break;
joshualitt30ba4362014-08-21 20:18:45 -070034 default:
35 SkFAIL("Unknown precision value.");
36 }
37 }
38}
joshualitt30ba4362014-08-21 20:18:45 -070039
joshualitt47bb3822014-10-07 16:43:25 -070040GrGLFragmentShaderBuilder::DstReadKey
rmistry63a9f842014-10-17 06:07:08 -070041GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps& caps) {
joshualitt30ba4362014-08-21 20:18:45 -070042 uint32_t key = kYesDstRead_DstReadKeyBit;
43 if (caps.fbFetchSupport()) {
44 return key;
45 }
bsalomon49f085d2014-09-05 13:34:00 -070046 SkASSERT(dstCopy);
joshualitt30ba4362014-08-21 20:18:45 -070047 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
48 // The fact that the config is alpha-only must be considered when generating code.
49 key |= kUseAlphaConfig_DstReadKeyBit;
50 }
51 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
52 key |= kTopLeftOrigin_DstReadKeyBit;
53 }
54 SkASSERT(static_cast<DstReadKey>(key) == key);
55 return static_cast<DstReadKey>(key);
56}
57
joshualitt47bb3822014-10-07 16:43:25 -070058GrGLFragmentShaderBuilder::FragPosKey
rmistry63a9f842014-10-17 06:07:08 -070059GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&) {
joshualitt30ba4362014-08-21 20:18:45 -070060 if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
61 return kTopLeftFragPosRead_FragPosKey;
62 } else {
63 return kBottomLeftFragPosRead_FragPosKey;
64 }
65}
66
67GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
joshualitt79f8fae2014-10-28 17:59:26 -070068 uint8_t fragPosKey)
joshualitt30ba4362014-08-21 20:18:45 -070069 : INHERITED(program)
70 , fHasCustomColorOutput(false)
71 , fHasSecondaryOutput(false)
72 , fSetupFragPosition(false)
joshualitt79f8fae2014-10-28 17:59:26 -070073 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
joshualittb4384b92014-10-21 12:53:15 -070074 , fCustomColorOutputIndex(-1)
joshualitt47bb3822014-10-07 16:43:25 -070075 , fHasReadDstColor(false)
76 , fHasReadFragmentPosition(false) {
joshualitt30ba4362014-08-21 20:18:45 -070077}
78
79bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
80 switch (feature) {
81 case kStandardDerivatives_GLSLFeature: {
bsalomon861e1032014-12-16 07:33:49 -080082 GrGLGpu* gpu = fProgramBuilder->gpu();
joshualitt30ba4362014-08-21 20:18:45 -070083 if (!gpu->glCaps().shaderDerivativeSupport()) {
84 return false;
85 }
rmistry63a9f842014-10-17 06:07:08 -070086 if (kGLES_GrGLStandard == gpu->glStandard() &&
87 k110_GrGLSLGeneration == gpu->glslGeneration()) {
joshualitt30ba4362014-08-21 20:18:45 -070088 this->addFeature(1 << kStandardDerivatives_GLSLFeature,
89 "GL_OES_standard_derivatives");
90 }
91 return true;
92 }
93 default:
94 SkFAIL("Unexpected GLSLFeature requested.");
95 return false;
96 }
97}
98
joshualittb0a8a372014-09-23 09:50:21 -070099SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
100 const GrGLProcessor::TransformedCoordsArray& coords, int index) {
joshualitt23e280d2014-09-18 12:26:38 -0700101 if (kVec3f_GrSLType != coords[index].getType()) {
102 SkASSERT(kVec2f_GrSLType == coords[index].getType());
joshualitt30ba4362014-08-21 20:18:45 -0700103 return coords[index].getName();
104 }
105
106 SkString coords2D("coords2D");
107 if (0 != index) {
108 coords2D.appendf("_%i", index);
109 }
110 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
111 coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
112 return coords2D;
113}
114
115const char* GrGLFragmentShaderBuilder::fragmentPosition() {
joshualitt47bb3822014-10-07 16:43:25 -0700116 fHasReadFragmentPosition = true;
joshualitt30ba4362014-08-21 20:18:45 -0700117
bsalomon861e1032014-12-16 07:33:49 -0800118 GrGLGpu* gpu = fProgramBuilder->gpu();
joshualitt30ba4362014-08-21 20:18:45 -0700119 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
120 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
121 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
122 if (fTopLeftFragPosRead) {
123 fSetupFragPosition = true;
124 return "gl_FragCoord";
125 } else if (gpu->glCaps().fragCoordConventionsSupport()) {
126 if (!fSetupFragPosition) {
127 if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
128 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
129 "GL_ARB_fragment_coord_conventions");
130 }
131 fInputs.push_back().set(kVec4f_GrSLType,
132 GrGLShaderVar::kIn_TypeModifier,
133 "gl_FragCoord",
bsalomonc0bd6482014-12-09 10:04:14 -0800134 kDefault_GrSLPrecision,
joshualitt30ba4362014-08-21 20:18:45 -0700135 GrGLShaderVar::kUpperLeft_Origin);
136 fSetupFragPosition = true;
137 }
138 return "gl_FragCoord";
139 } else {
140 static const char* kCoordName = "fragCoordYDown";
141 if (!fSetupFragPosition) {
142 // temporarily change the stage index because we're inserting non-stage code.
joshualitt47bb3822014-10-07 16:43:25 -0700143 GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
joshualitt30ba4362014-08-21 20:18:45 -0700144 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
145 const char* rtHeightName;
146
147 fProgramBuilder->fUniformHandles.fRTHeightUni =
148 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
joshualitt47bb3822014-10-07 16:43:25 -0700149 kFloat_GrSLType,
bsalomon422f56f2014-12-09 10:18:12 -0800150 kDefault_GrSLPrecision,
joshualitt47bb3822014-10-07 16:43:25 -0700151 "RTHeight",
152 &rtHeightName);
joshualitt30ba4362014-08-21 20:18:45 -0700153
154 // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
155 // causes programs to fail to link. Making this function return a vec2() didn't fix the
156 // problem but using 1.0 for the last two components does.
157 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
158 "1.0);\n", kCoordName, rtHeightName);
159 fSetupFragPosition = true;
160 }
161 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
162 return kCoordName;
163 }
164}
165
joshualitt47bb3822014-10-07 16:43:25 -0700166const char* GrGLFragmentShaderBuilder::dstColor() {
167 fHasReadDstColor = true;
168
bsalomon861e1032014-12-16 07:33:49 -0800169 GrGLGpu* gpu = fProgramBuilder->gpu();
joshualitt47bb3822014-10-07 16:43:25 -0700170 if (gpu->glCaps().fbFetchSupport()) {
171 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
172 gpu->glCaps().fbFetchExtensionString());
joshualittb4384b92014-10-21 12:53:15 -0700173
joshualitt3c1096f2015-01-13 13:13:59 -0800174 // Some versions of this extension string require declaring custom color output on ES 3.0+
joshualittb4384b92014-10-21 12:53:15 -0700175 const char* fbFetchColorName = gpu->glCaps().fbFetchColorName();
joshualitt3c1096f2015-01-13 13:13:59 -0800176 if (gpu->glCaps().fbFetchNeedsCustomOutput()) {
joshualittb4384b92014-10-21 12:53:15 -0700177 this->enableCustomOutput();
178 fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
179 fbFetchColorName = declared_color_output_name();
180 }
181 return fbFetchColorName;
joshualitt47bb3822014-10-07 16:43:25 -0700182 } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) {
183 return kDstCopyColorName;
184 } else {
185 return "";
joshualittdb0d3ca2014-10-07 12:42:26 -0700186 }
187}
joshualittfe1233c2014-10-07 12:16:35 -0700188
joshualitt47bb3822014-10-07 16:43:25 -0700189void GrGLFragmentShaderBuilder::emitCodeToReadDstTexture() {
190 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & fProgramBuilder->header().fDstReadKey);
191 const char* dstCopyTopLeftName;
192 const char* dstCopyCoordScaleName;
193 const char* dstCopySamplerName;
194 uint32_t configMask;
195 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & fProgramBuilder->header().fDstReadKey)) {
196 configMask = kA_GrColorComponentFlag;
197 } else {
198 configMask = kRGBA_GrColorComponentFlags;
joshualitt30ba4362014-08-21 20:18:45 -0700199 }
joshualitt47bb3822014-10-07 16:43:25 -0700200 fProgramBuilder->fUniformHandles.fDstCopySamplerUni =
201 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
202 kSampler2D_GrSLType,
bsalomon422f56f2014-12-09 10:18:12 -0800203 kDefault_GrSLPrecision,
joshualitt47bb3822014-10-07 16:43:25 -0700204 "DstCopySampler",
205 &dstCopySamplerName);
206 fProgramBuilder->fUniformHandles.fDstCopyTopLeftUni =
207 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
208 kVec2f_GrSLType,
bsalomon422f56f2014-12-09 10:18:12 -0800209 kDefault_GrSLPrecision,
joshualitt47bb3822014-10-07 16:43:25 -0700210 "DstCopyUpperLeft",
211 &dstCopyTopLeftName);
212 fProgramBuilder->fUniformHandles.fDstCopyScaleUni =
213 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
214 kVec2f_GrSLType,
bsalomon422f56f2014-12-09 10:18:12 -0800215 kDefault_GrSLPrecision,
joshualitt47bb3822014-10-07 16:43:25 -0700216 "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
joshualitt30ba4362014-08-21 20:18:45 -0700259bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
260 SkTDArray<GrGLuint>* shaderIds) const {
bsalomon861e1032014-12-16 07:33:49 -0800261 GrGLGpu* gpu = fProgramBuilder->gpu();
joshualitt30ba4362014-08-21 20:18:45 -0700262 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo()));
263 fragShaderSrc.append(fExtensions);
bsalomonc0bd6482014-12-09 10:04:14 -0800264 append_default_precision_qualifier(kDefault_GrSLPrecision,
joshualitt30ba4362014-08-21 20:18:45 -0700265 gpu->glStandard(),
266 &fragShaderSrc);
267 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &fragShaderSrc);
joshualitt47bb3822014-10-07 16:43:25 -0700268 this->appendDecls(fInputs, &fragShaderSrc);
joshualitt30ba4362014-08-21 20:18:45 -0700269 // We shouldn't have declared outputs on 1.10
270 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
joshualitt47bb3822014-10-07 16:43:25 -0700271 this->appendDecls(fOutputs, &fragShaderSrc);
joshualitt30ba4362014-08-21 20:18:45 -0700272 fragShaderSrc.append(fFunctions);
273 fragShaderSrc.append("void main() {\n");
274 fragShaderSrc.append(fCode);
275 fragShaderSrc.append("}\n");
276
robertphillips754f4e92014-09-18 13:52:08 -0700277 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), programId,
278 GR_GL_FRAGMENT_SHADER, fragShaderSrc,
279 gpu->gpuStats());
joshualitt30ba4362014-08-21 20:18:45 -0700280 if (!fragShaderId) {
281 return false;
282 }
283
284 *shaderIds->append() = fragShaderId;
285
286 return true;
287}
288
joshualitt47bb3822014-10-07 16:43:25 -0700289void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
rmistry63a9f842014-10-17 06:07:08 -0700290 // ES 3.00 requires custom color output but doesn't support bindFragDataLocation
291 if (fHasCustomColorOutput &&
292 kGLES_GrGLStandard != fProgramBuilder->gpu()->ctxInfo().standard()) {
joshualitt47bb3822014-10-07 16:43:25 -0700293 GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700294 }
joshualitt47bb3822014-10-07 16:43:25 -0700295 if (fHasSecondaryOutput) {
296 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700297 }
298}
299
bsalomonc0bd6482014-12-09 10:04:14 -0800300void GrGLFragmentShaderBuilder::addVarying(GrGLVarying* v, GrSLPrecision fsPrec) {
joshualitt74077b92014-10-24 11:26:03 -0700301 v->fFsIn = v->fVsOut;
302 if (v->fGsOut) {
303 v->fFsIn = v->fGsOut;
joshualitt30ba4362014-08-21 20:18:45 -0700304 }
joshualitt74077b92014-10-24 11:26:03 -0700305 fInputs.push_back().set(v->fType, GrGLShaderVar::kVaryingIn_TypeModifier, v->fFsIn, fsPrec);
joshualitt30ba4362014-08-21 20:18:45 -0700306}