blob: a7a35e3676f41c4eaf1657864c4238a1a7a8d0a3 [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"
joshualitt30ba4362014-08-21 20:18:45 -07009#include "GrGLProgramBuilder.h"
jvanverthcba99b82015-06-24 06:59:57 -070010#include "gl/GrGLGpu.h"
11#include "gl/GrGLGLSL.h"
12#include "glsl/GrGLSLCaps.h"
joshualitt30ba4362014-08-21 20:18:45 -070013
joshualitt47bb3822014-10-07 16:43:25 -070014#define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X)
15#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(), R, X)
16
bsalomon6a44c6a2015-05-26 09:49:05 -070017const char* GrGLFragmentShaderBuilder::kDstTextureColorName = "_dstColor";
joshualitt47bb3822014-10-07 16:43:25 -070018static const char* declared_color_output_name() { return "fsColorOut"; }
kkinnunend94708e2015-07-30 22:47:04 -070019static const char* declared_secondary_color_output_name() { return "fsSecondaryColorOut"; }
joshualitt30ba4362014-08-21 20:18:45 -070020
cdalton8917d622015-05-06 13:40:21 -070021static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
22 SkASSERT(GrBlendEquationIsAdvanced(equation));
23
24 static const char* kLayoutQualifierNames[] = {
25 "blend_support_screen",
26 "blend_support_overlay",
27 "blend_support_darken",
28 "blend_support_lighten",
29 "blend_support_colordodge",
30 "blend_support_colorburn",
31 "blend_support_hardlight",
32 "blend_support_softlight",
33 "blend_support_difference",
34 "blend_support_exclusion",
35 "blend_support_multiply",
36 "blend_support_hsl_hue",
37 "blend_support_hsl_saturation",
38 "blend_support_hsl_color",
39 "blend_support_hsl_luminosity"
40 };
41 return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation];
42
43 GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation);
44 GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation);
45 GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation);
46 GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation);
47 GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation);
48 GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation);
49 GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
50 GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
51 GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation);
52 GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation);
53 GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation);
54 GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation);
55 GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation);
56 GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation);
57 GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation);
58 GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) ==
bsalomonf7cc8772015-05-11 11:21:14 -070059 kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation);
cdalton8917d622015-05-06 13:40:21 -070060}
61
joshualitt47bb3822014-10-07 16:43:25 -070062GrGLFragmentShaderBuilder::DstReadKey
bsalomon6a44c6a2015-05-26 09:49:05 -070063GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstTexture, const GrGLCaps& caps) {
joshualitt30ba4362014-08-21 20:18:45 -070064 uint32_t key = kYesDstRead_DstReadKeyBit;
jvanverthe9c0fc62015-04-29 11:18:05 -070065 if (caps.glslCaps()->fbFetchSupport()) {
joshualitt30ba4362014-08-21 20:18:45 -070066 return key;
67 }
bsalomon6a44c6a2015-05-26 09:49:05 -070068 SkASSERT(dstTexture);
69 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstTexture->config())) {
joshualitt30ba4362014-08-21 20:18:45 -070070 // The fact that the config is alpha-only must be considered when generating code.
71 key |= kUseAlphaConfig_DstReadKeyBit;
72 }
bsalomon6a44c6a2015-05-26 09:49:05 -070073 if (kTopLeft_GrSurfaceOrigin == dstTexture->origin()) {
joshualitt30ba4362014-08-21 20:18:45 -070074 key |= kTopLeftOrigin_DstReadKeyBit;
75 }
76 SkASSERT(static_cast<DstReadKey>(key) == key);
77 return static_cast<DstReadKey>(key);
78}
79
joshualitt47bb3822014-10-07 16:43:25 -070080GrGLFragmentShaderBuilder::FragPosKey
rmistry63a9f842014-10-17 06:07:08 -070081GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&) {
joshualitt30ba4362014-08-21 20:18:45 -070082 if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
83 return kTopLeftFragPosRead_FragPosKey;
84 } else {
85 return kBottomLeftFragPosRead_FragPosKey;
86 }
87}
88
89GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
joshualitt79f8fae2014-10-28 17:59:26 -070090 uint8_t fragPosKey)
joshualitt30ba4362014-08-21 20:18:45 -070091 : INHERITED(program)
92 , fHasCustomColorOutput(false)
93 , fHasSecondaryOutput(false)
94 , fSetupFragPosition(false)
joshualitt79f8fae2014-10-28 17:59:26 -070095 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
joshualittb4384b92014-10-21 12:53:15 -070096 , fCustomColorOutputIndex(-1)
joshualitt47bb3822014-10-07 16:43:25 -070097 , fHasReadDstColor(false)
98 , fHasReadFragmentPosition(false) {
joshualitt30ba4362014-08-21 20:18:45 -070099}
100
101bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
102 switch (feature) {
103 case kStandardDerivatives_GLSLFeature: {
bsalomon861e1032014-12-16 07:33:49 -0800104 GrGLGpu* gpu = fProgramBuilder->gpu();
jvanverthe9c0fc62015-04-29 11:18:05 -0700105 if (!gpu->glCaps().shaderCaps()->shaderDerivativeSupport()) {
joshualitt30ba4362014-08-21 20:18:45 -0700106 return false;
107 }
rmistry63a9f842014-10-17 06:07:08 -0700108 if (kGLES_GrGLStandard == gpu->glStandard() &&
109 k110_GrGLSLGeneration == gpu->glslGeneration()) {
joshualitt30ba4362014-08-21 20:18:45 -0700110 this->addFeature(1 << kStandardDerivatives_GLSLFeature,
111 "GL_OES_standard_derivatives");
112 }
113 return true;
114 }
115 default:
116 SkFAIL("Unexpected GLSLFeature requested.");
117 return false;
118 }
119}
120
joshualittb0a8a372014-09-23 09:50:21 -0700121SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
122 const GrGLProcessor::TransformedCoordsArray& coords, int index) {
joshualitt23e280d2014-09-18 12:26:38 -0700123 if (kVec3f_GrSLType != coords[index].getType()) {
124 SkASSERT(kVec2f_GrSLType == coords[index].getType());
joshualitt30ba4362014-08-21 20:18:45 -0700125 return coords[index].getName();
126 }
127
128 SkString coords2D("coords2D");
129 if (0 != index) {
130 coords2D.appendf("_%i", index);
131 }
132 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
133 coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
134 return coords2D;
135}
136
137const char* GrGLFragmentShaderBuilder::fragmentPosition() {
joshualitt47bb3822014-10-07 16:43:25 -0700138 fHasReadFragmentPosition = true;
joshualitt30ba4362014-08-21 20:18:45 -0700139
bsalomon861e1032014-12-16 07:33:49 -0800140 GrGLGpu* gpu = fProgramBuilder->gpu();
joshualitt30ba4362014-08-21 20:18:45 -0700141 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
142 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
143 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
144 if (fTopLeftFragPosRead) {
145 fSetupFragPosition = true;
146 return "gl_FragCoord";
147 } else if (gpu->glCaps().fragCoordConventionsSupport()) {
148 if (!fSetupFragPosition) {
149 if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
150 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
151 "GL_ARB_fragment_coord_conventions");
152 }
153 fInputs.push_back().set(kVec4f_GrSLType,
154 GrGLShaderVar::kIn_TypeModifier,
155 "gl_FragCoord",
bsalomonc0bd6482014-12-09 10:04:14 -0800156 kDefault_GrSLPrecision,
joshualitt30ba4362014-08-21 20:18:45 -0700157 GrGLShaderVar::kUpperLeft_Origin);
158 fSetupFragPosition = true;
159 }
160 return "gl_FragCoord";
161 } else {
robertphillips18c58c72015-07-21 12:06:52 -0700162 static const char* kTempName = "tmpXYFragCoord";
joshualitt30ba4362014-08-21 20:18:45 -0700163 static const char* kCoordName = "fragCoordYDown";
164 if (!fSetupFragPosition) {
165 // temporarily change the stage index because we're inserting non-stage code.
joshualitt47bb3822014-10-07 16:43:25 -0700166 GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
joshualitt30ba4362014-08-21 20:18:45 -0700167 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
168 const char* rtHeightName;
169
170 fProgramBuilder->fUniformHandles.fRTHeightUni =
171 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
joshualitt47bb3822014-10-07 16:43:25 -0700172 kFloat_GrSLType,
bsalomon422f56f2014-12-09 10:18:12 -0800173 kDefault_GrSLPrecision,
joshualitt47bb3822014-10-07 16:43:25 -0700174 "RTHeight",
175 &rtHeightName);
joshualitt30ba4362014-08-21 20:18:45 -0700176
robertphillips18c58c72015-07-21 12:06:52 -0700177 // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
178 // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
179 // depending on the surrounding code, accessing .xy with a uniform involved can
180 // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
181 // (and only accessing .xy) seems to "fix" things.
182 this->codePrependf("\tvec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n",
183 kCoordName, kTempName, rtHeightName, kTempName);
184 this->codePrependf("vec2 %s = gl_FragCoord.xy;", kTempName);
joshualitt30ba4362014-08-21 20:18:45 -0700185 fSetupFragPosition = true;
186 }
187 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
188 return kCoordName;
189 }
190}
191
joshualitt47bb3822014-10-07 16:43:25 -0700192const char* GrGLFragmentShaderBuilder::dstColor() {
193 fHasReadDstColor = true;
194
bsalomon861e1032014-12-16 07:33:49 -0800195 GrGLGpu* gpu = fProgramBuilder->gpu();
jvanverthe9c0fc62015-04-29 11:18:05 -0700196 if (gpu->glCaps().glslCaps()->fbFetchSupport()) {
joshualitt47bb3822014-10-07 16:43:25 -0700197 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
jvanverthe9c0fc62015-04-29 11:18:05 -0700198 gpu->glCaps().glslCaps()->fbFetchExtensionString());
joshualittb4384b92014-10-21 12:53:15 -0700199
joshualitt3c1096f2015-01-13 13:13:59 -0800200 // Some versions of this extension string require declaring custom color output on ES 3.0+
jvanverthe9c0fc62015-04-29 11:18:05 -0700201 const char* fbFetchColorName = gpu->glCaps().glslCaps()->fbFetchColorName();
202 if (gpu->glCaps().glslCaps()->fbFetchNeedsCustomOutput()) {
joshualittb4384b92014-10-21 12:53:15 -0700203 this->enableCustomOutput();
204 fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
205 fbFetchColorName = declared_color_output_name();
206 }
207 return fbFetchColorName;
bsalomon50785a32015-02-06 07:02:37 -0800208 } else {
bsalomon6a44c6a2015-05-26 09:49:05 -0700209 return kDstTextureColorName;
bsalomon50785a32015-02-06 07:02:37 -0800210 }
joshualitt47bb3822014-10-07 16:43:25 -0700211}
212
cdalton8917d622015-05-06 13:40:21 -0700213void GrGLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) {
214 SkASSERT(GrBlendEquationIsAdvanced(equation));
215
216 const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
217 if (!caps.mustEnableAdvBlendEqs()) {
218 return;
219 }
220
221 this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature,
222 "GL_KHR_blend_equation_advanced");
223 if (caps.mustEnableSpecificAdvBlendEqs()) {
224 this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier);
225 } else {
226 this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier);
227 }
228}
229
joshualitt47bb3822014-10-07 16:43:25 -0700230void GrGLFragmentShaderBuilder::enableCustomOutput() {
joshualittb4384b92014-10-21 12:53:15 -0700231 if (!fHasCustomColorOutput) {
232 fHasCustomColorOutput = true;
233 fCustomColorOutputIndex = fOutputs.count();
234 fOutputs.push_back().set(kVec4f_GrSLType,
235 GrGLShaderVar::kOut_TypeModifier,
236 declared_color_output_name());
237 }
joshualitt47bb3822014-10-07 16:43:25 -0700238}
239
240void GrGLFragmentShaderBuilder::enableSecondaryOutput() {
241 SkASSERT(!fHasSecondaryOutput);
242 fHasSecondaryOutput = true;
kkinnunend94708e2015-07-30 22:47:04 -0700243 if (kGLES_GrGLStandard == fProgramBuilder->gpu()->ctxInfo().standard()) {
244 this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, "GL_EXT_blend_func_extended");
245 }
246
247 // If the primary output is declared, we must declare also the secondary output
248 // and vice versa, since it is not allowed to use a built-in gl_FragColor and a custom
249 // output. The condition also co-incides with the condition in whici GLES SL 2.0
250 // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a custom output.
251 const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
252 if (caps.mustDeclareFragmentShaderOutput()) {
253 fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
254 declared_secondary_color_output_name());
255 }
joshualitt47bb3822014-10-07 16:43:25 -0700256}
257
258const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
259 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
260}
261
262const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const {
kkinnunend94708e2015-07-30 22:47:04 -0700263 const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
264 return caps.mustDeclareFragmentShaderOutput() ? declared_secondary_color_output_name()
265 : "gl_SecondaryFragColorEXT";
joshualitt47bb3822014-10-07 16:43:25 -0700266}
267
joshualitt30ba4362014-08-21 20:18:45 -0700268bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
joshualitt43466a12015-02-13 17:18:27 -0800269 SkTDArray<GrGLuint>* shaderIds) {
bsalomon861e1032014-12-16 07:33:49 -0800270 GrGLGpu* gpu = fProgramBuilder->gpu();
jvanverthcba99b82015-06-24 06:59:57 -0700271 this->versionDecl() = GrGLGetGLSLVersionDecl(gpu->ctxInfo());
272 GrGLAppendGLSLDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
273 gpu->glStandard(),
274 &this->precisionQualifier());
cdaltone4017d82015-05-06 11:48:56 -0700275 this->compileAndAppendLayoutQualifiers();
joshualitt43466a12015-02-13 17:18:27 -0800276 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility,
277 &this->uniforms());
278 this->appendDecls(fInputs, &this->inputs());
joshualitt30ba4362014-08-21 20:18:45 -0700279 // We shouldn't have declared outputs on 1.10
280 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
joshualitt43466a12015-02-13 17:18:27 -0800281 this->appendDecls(fOutputs, &this->outputs());
282 return this->finalize(programId, GR_GL_FRAGMENT_SHADER, shaderIds);
joshualitt30ba4362014-08-21 20:18:45 -0700283}
284
joshualitt47bb3822014-10-07 16:43:25 -0700285void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
kkinnunend94708e2015-07-30 22:47:04 -0700286 const GrGLCaps& caps = fProgramBuilder->gpu()->glCaps();
287 if (fHasCustomColorOutput && caps.bindFragDataLocationSupport()) {
joshualitt47bb3822014-10-07 16:43:25 -0700288 GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700289 }
kkinnunend94708e2015-07-30 22:47:04 -0700290 if (fHasSecondaryOutput && caps.glslCaps()->mustDeclareFragmentShaderOutput()) {
291 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
292 declared_secondary_color_output_name()));
joshualitt30ba4362014-08-21 20:18:45 -0700293 }
294}
295
bsalomonc0bd6482014-12-09 10:04:14 -0800296void GrGLFragmentShaderBuilder::addVarying(GrGLVarying* v, GrSLPrecision fsPrec) {
joshualitt74077b92014-10-24 11:26:03 -0700297 v->fFsIn = v->fVsOut;
298 if (v->fGsOut) {
299 v->fFsIn = v->fGsOut;
joshualitt30ba4362014-08-21 20:18:45 -0700300 }
joshualitt74077b92014-10-24 11:26:03 -0700301 fInputs.push_back().set(v->fType, GrGLShaderVar::kVaryingIn_TypeModifier, v->fFsIn, fsPrec);
joshualitt30ba4362014-08-21 20:18:45 -0700302}