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