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 "GrGLProgramBuilder.h"
10 #include "../GrGLGpu.h"
11
12 #define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X)
13 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(), R, X)
14
15 const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor";
declared_color_output_name()16 static const char* declared_color_output_name() { return "fsColorOut"; }
dual_source_output_name()17 static const char* dual_source_output_name() { return "dualSourceOut"; }
append_default_precision_qualifier(GrSLPrecision p,GrGLStandard standard,SkString * str)18 static void append_default_precision_qualifier(GrSLPrecision p,
19 GrGLStandard standard,
20 SkString* str) {
21 // Desktop GLSL has added precision qualifiers but they don't do anything.
22 if (kGLES_GrGLStandard == standard) {
23 switch (p) {
24 case kHigh_GrSLPrecision:
25 str->append("precision highp float;\n");
26 break;
27 case kMedium_GrSLPrecision:
28 str->append("precision mediump float;\n");
29 break;
30 case kLow_GrSLPrecision:
31 str->append("precision lowp float;\n");
32 break;
33 default:
34 SkFAIL("Unknown precision value.");
35 }
36 }
37 }
38
specific_layout_qualifier_name(GrBlendEquation equation)39 static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
40 SkASSERT(GrBlendEquationIsAdvanced(equation));
41
42 static const char* kLayoutQualifierNames[] = {
43 "blend_support_screen",
44 "blend_support_overlay",
45 "blend_support_darken",
46 "blend_support_lighten",
47 "blend_support_colordodge",
48 "blend_support_colorburn",
49 "blend_support_hardlight",
50 "blend_support_softlight",
51 "blend_support_difference",
52 "blend_support_exclusion",
53 "blend_support_multiply",
54 "blend_support_hsl_hue",
55 "blend_support_hsl_saturation",
56 "blend_support_hsl_color",
57 "blend_support_hsl_luminosity"
58 };
59 return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation];
60
61 GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation);
62 GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation);
63 GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation);
64 GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation);
65 GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation);
66 GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation);
67 GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
68 GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
69 GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation);
70 GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation);
71 GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation);
72 GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation);
73 GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation);
74 GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation);
75 GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation);
76 GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) ==
77 kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation);
78 }
79
80 GrGLFragmentShaderBuilder::DstReadKey
KeyForDstRead(const GrTexture * dstCopy,const GrGLCaps & caps)81 GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps& caps) {
82 uint32_t key = kYesDstRead_DstReadKeyBit;
83 if (caps.glslCaps()->fbFetchSupport()) {
84 return key;
85 }
86 SkASSERT(dstCopy);
87 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
88 // The fact that the config is alpha-only must be considered when generating code.
89 key |= kUseAlphaConfig_DstReadKeyBit;
90 }
91 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
92 key |= kTopLeftOrigin_DstReadKeyBit;
93 }
94 SkASSERT(static_cast<DstReadKey>(key) == key);
95 return static_cast<DstReadKey>(key);
96 }
97
98 GrGLFragmentShaderBuilder::FragPosKey
KeyForFragmentPosition(const GrRenderTarget * dst,const GrGLCaps &)99 GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&) {
100 if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
101 return kTopLeftFragPosRead_FragPosKey;
102 } else {
103 return kBottomLeftFragPosRead_FragPosKey;
104 }
105 }
106
GrGLFragmentShaderBuilder(GrGLProgramBuilder * program,uint8_t fragPosKey)107 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
108 uint8_t fragPosKey)
109 : INHERITED(program)
110 , fHasCustomColorOutput(false)
111 , fHasSecondaryOutput(false)
112 , fSetupFragPosition(false)
113 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
114 , fCustomColorOutputIndex(-1)
115 , fHasReadDstColor(false)
116 , fHasReadFragmentPosition(false) {
117 }
118
enableFeature(GLSLFeature feature)119 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
120 switch (feature) {
121 case kStandardDerivatives_GLSLFeature: {
122 GrGLGpu* gpu = fProgramBuilder->gpu();
123 if (!gpu->glCaps().shaderCaps()->shaderDerivativeSupport()) {
124 return false;
125 }
126 if (kGLES_GrGLStandard == gpu->glStandard() &&
127 k110_GrGLSLGeneration == gpu->glslGeneration()) {
128 this->addFeature(1 << kStandardDerivatives_GLSLFeature,
129 "GL_OES_standard_derivatives");
130 }
131 return true;
132 }
133 default:
134 SkFAIL("Unexpected GLSLFeature requested.");
135 return false;
136 }
137 }
138
ensureFSCoords2D(const GrGLProcessor::TransformedCoordsArray & coords,int index)139 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
140 const GrGLProcessor::TransformedCoordsArray& coords, int index) {
141 if (kVec3f_GrSLType != coords[index].getType()) {
142 SkASSERT(kVec2f_GrSLType == coords[index].getType());
143 return coords[index].getName();
144 }
145
146 SkString coords2D("coords2D");
147 if (0 != index) {
148 coords2D.appendf("_%i", index);
149 }
150 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
151 coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
152 return coords2D;
153 }
154
fragmentPosition()155 const char* GrGLFragmentShaderBuilder::fragmentPosition() {
156 fHasReadFragmentPosition = true;
157
158 GrGLGpu* gpu = fProgramBuilder->gpu();
159 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
160 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
161 // declaration varies in earlier GLSL specs. So it is simpler to omit it.
162 if (fTopLeftFragPosRead) {
163 fSetupFragPosition = true;
164 return "gl_FragCoord";
165 } else if (gpu->glCaps().fragCoordConventionsSupport()) {
166 if (!fSetupFragPosition) {
167 if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
168 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
169 "GL_ARB_fragment_coord_conventions");
170 }
171 fInputs.push_back().set(kVec4f_GrSLType,
172 GrGLShaderVar::kIn_TypeModifier,
173 "gl_FragCoord",
174 kDefault_GrSLPrecision,
175 GrGLShaderVar::kUpperLeft_Origin);
176 fSetupFragPosition = true;
177 }
178 return "gl_FragCoord";
179 } else {
180 static const char* kCoordName = "fragCoordYDown";
181 if (!fSetupFragPosition) {
182 // temporarily change the stage index because we're inserting non-stage code.
183 GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
184 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
185 const char* rtHeightName;
186
187 fProgramBuilder->fUniformHandles.fRTHeightUni =
188 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
189 kFloat_GrSLType,
190 kDefault_GrSLPrecision,
191 "RTHeight",
192 &rtHeightName);
193
194 // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
195 // causes programs to fail to link. Making this function return a vec2() didn't fix the
196 // problem but using 1.0 for the last two components does.
197 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
198 "1.0);\n", kCoordName, rtHeightName);
199 fSetupFragPosition = true;
200 }
201 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
202 return kCoordName;
203 }
204 }
205
dstColor()206 const char* GrGLFragmentShaderBuilder::dstColor() {
207 fHasReadDstColor = true;
208
209 GrGLGpu* gpu = fProgramBuilder->gpu();
210 if (gpu->glCaps().glslCaps()->fbFetchSupport()) {
211 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
212 gpu->glCaps().glslCaps()->fbFetchExtensionString());
213
214 // Some versions of this extension string require declaring custom color output on ES 3.0+
215 const char* fbFetchColorName = gpu->glCaps().glslCaps()->fbFetchColorName();
216 if (gpu->glCaps().glslCaps()->fbFetchNeedsCustomOutput()) {
217 this->enableCustomOutput();
218 fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
219 fbFetchColorName = declared_color_output_name();
220 }
221 return fbFetchColorName;
222 } else {
223 return kDstCopyColorName;
224 }
225 }
226
enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation)227 void GrGLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) {
228 SkASSERT(GrBlendEquationIsAdvanced(equation));
229
230 const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
231 if (!caps.mustEnableAdvBlendEqs()) {
232 return;
233 }
234
235 this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature,
236 "GL_KHR_blend_equation_advanced");
237 if (caps.mustEnableSpecificAdvBlendEqs()) {
238 this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier);
239 } else {
240 this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier);
241 }
242 }
243
enableCustomOutput()244 void GrGLFragmentShaderBuilder::enableCustomOutput() {
245 if (!fHasCustomColorOutput) {
246 fHasCustomColorOutput = true;
247 fCustomColorOutputIndex = fOutputs.count();
248 fOutputs.push_back().set(kVec4f_GrSLType,
249 GrGLShaderVar::kOut_TypeModifier,
250 declared_color_output_name());
251 }
252 }
253
enableSecondaryOutput()254 void GrGLFragmentShaderBuilder::enableSecondaryOutput() {
255 SkASSERT(!fHasSecondaryOutput);
256 fHasSecondaryOutput = true;
257 fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
258 dual_source_output_name());
259 }
260
getPrimaryColorOutputName() const261 const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
262 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
263 }
264
getSecondaryColorOutputName() const265 const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const {
266 return dual_source_output_name();
267 }
268
compileAndAttachShaders(GrGLuint programId,SkTDArray<GrGLuint> * shaderIds)269 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
270 SkTDArray<GrGLuint>* shaderIds) {
271 GrGLGpu* gpu = fProgramBuilder->gpu();
272 this->versionDecl() = GrGetGLSLVersionDecl(gpu->ctxInfo());
273 append_default_precision_qualifier(kDefault_GrSLPrecision,
274 gpu->glStandard(),
275 &this->precisionQualifier());
276 this->compileAndAppendLayoutQualifiers();
277 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility,
278 &this->uniforms());
279 this->appendDecls(fInputs, &this->inputs());
280 // We shouldn't have declared outputs on 1.10
281 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
282 this->appendDecls(fOutputs, &this->outputs());
283 return this->finalize(programId, GR_GL_FRAGMENT_SHADER, shaderIds);
284 }
285
bindFragmentShaderLocations(GrGLuint programID)286 void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
287 // ES 3.00 requires custom color output but doesn't support bindFragDataLocation
288 if (fHasCustomColorOutput &&
289 kGLES_GrGLStandard != fProgramBuilder->gpu()->ctxInfo().standard()) {
290 GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
291 }
292 if (fHasSecondaryOutput) {
293 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_name()));
294 }
295 }
296
addVarying(GrGLVarying * v,GrSLPrecision fsPrec)297 void GrGLFragmentShaderBuilder::addVarying(GrGLVarying* v, GrSLPrecision fsPrec) {
298 v->fFsIn = v->fVsOut;
299 if (v->fGsOut) {
300 v->fFsIn = v->fGsOut;
301 }
302 fInputs.push_back().set(v->fType, GrGLShaderVar::kVaryingIn_TypeModifier, v->fFsIn, fsPrec);
303 }
304