• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrGLSLFragmentShaderBuilder.h"
9 #include "GrRenderTarget.h"
10 #include "gl/GrGLGpu.h"
11 #include "glsl/GrGLSL.h"
12 #include "glsl/GrGLSLCaps.h"
13 #include "glsl/GrGLSLProgramBuilder.h"
14 #include "glsl/GrGLSLUniformHandler.h"
15 #include "glsl/GrGLSLVarying.h"
16 
17 const char* GrGLSLFragmentShaderBuilder::kDstTextureColorName = "_dstColor";
18 
specific_layout_qualifier_name(GrBlendEquation equation)19 static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
20     SkASSERT(GrBlendEquationIsAdvanced(equation));
21 
22     static const char* kLayoutQualifierNames[] = {
23         "blend_support_screen",
24         "blend_support_overlay",
25         "blend_support_darken",
26         "blend_support_lighten",
27         "blend_support_colordodge",
28         "blend_support_colorburn",
29         "blend_support_hardlight",
30         "blend_support_softlight",
31         "blend_support_difference",
32         "blend_support_exclusion",
33         "blend_support_multiply",
34         "blend_support_hsl_hue",
35         "blend_support_hsl_saturation",
36         "blend_support_hsl_color",
37         "blend_support_hsl_luminosity"
38     };
39     return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation];
40 
41     GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation);
42     GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation);
43     GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation);
44     GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation);
45     GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation);
46     GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation);
47     GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
48     GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
49     GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation);
50     GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation);
51     GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation);
52     GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation);
53     GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation);
54     GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation);
55     GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation);
56     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) ==
57                      kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation);
58 }
59 
60 GrGLSLFragmentShaderBuilder::FragPosKey
KeyForFragmentPosition(const GrRenderTarget * dst)61 GrGLSLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst) {
62     if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
63         return kTopLeftFragPosRead_FragPosKey;
64     } else {
65         return kBottomLeftFragPosRead_FragPosKey;
66     }
67 }
68 
GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder * program,uint8_t fragPosKey)69 GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program,
70                                                          uint8_t fragPosKey)
71     : GrGLSLFragmentBuilder(program)
72     , fSetupFragPosition(false)
73     , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
74     , fHasCustomColorOutput(false)
75     , fCustomColorOutputIndex(-1)
76     , fHasSecondaryOutput(false)
77     , fHasInitializedSampleMask(false)
78     , fHasReadDstColor(false)
79     , fHasReadFragmentPosition(false) {
80     fSubstageIndices.push_back(0);
81 }
82 
enableFeature(GLSLFeature feature)83 bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
84     switch (feature) {
85         case kStandardDerivatives_GLSLFeature: {
86             if (!fProgramBuilder->glslCaps()->shaderDerivativeSupport()) {
87                 return false;
88             }
89             const char* extension = fProgramBuilder->glslCaps()->shaderDerivativeExtensionString();
90             if (extension) {
91                 this->addFeature(1 << kStandardDerivatives_GLSLFeature, extension);
92             }
93             return true;
94         }
95         case kPixelLocalStorage_GLSLFeature: {
96             if (fProgramBuilder->glslCaps()->pixelLocalStorageSize() <= 0) {
97                 return false;
98             }
99             this->addFeature(1 << kPixelLocalStorage_GLSLFeature,
100                              "GL_EXT_shader_pixel_local_storage");
101             return true;
102         }
103         default:
104             SkFAIL("Unexpected GLSLFeature requested.");
105             return false;
106     }
107 }
108 
ensureFSCoords2D(const GrGLSLTransformedCoordsArray & coords,int index)109 SkString GrGLSLFragmentShaderBuilder::ensureFSCoords2D(const GrGLSLTransformedCoordsArray& coords,
110                                                        int index) {
111     if (kVec3f_GrSLType != coords[index].getType()) {
112         SkASSERT(kVec2f_GrSLType == coords[index].getType());
113         return coords[index].getName();
114     }
115 
116     SkString coords2D("coords2D");
117     if (0 != index) {
118         coords2D.appendf("_%i", index);
119     }
120     this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
121                       coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
122     return coords2D;
123 }
124 
fragmentPosition()125 const char* GrGLSLFragmentShaderBuilder::fragmentPosition() {
126     fHasReadFragmentPosition = true;
127 
128     const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
129     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
130     // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
131     // declaration varies in earlier GLSL specs. So it is simpler to omit it.
132     if (fTopLeftFragPosRead) {
133         fSetupFragPosition = true;
134         return "gl_FragCoord";
135     } else if (const char* extension = glslCaps->fragCoordConventionsExtensionString()) {
136         if (!fSetupFragPosition) {
137             if (glslCaps->generation() < k150_GrGLSLGeneration) {
138                 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
139                                  extension);
140             }
141             fInputs.push_back().set(kVec4f_GrSLType,
142                                     GrGLSLShaderVar::kIn_TypeModifier,
143                                     "gl_FragCoord",
144                                     kDefault_GrSLPrecision,
145                                     "origin_upper_left");
146             fSetupFragPosition = true;
147         }
148         return "gl_FragCoord";
149     } else {
150         static const char* kTempName = "tmpXYFragCoord";
151         static const char* kCoordName = "fragCoordYDown";
152         if (!fSetupFragPosition) {
153             const char* rtHeightName;
154 
155             fProgramBuilder->addRTHeightUniform("RTHeight", &rtHeightName);
156 
157             // The Adreno compiler seems to be very touchy about access to "gl_FragCoord".
158             // Accessing glFragCoord.zw can cause a program to fail to link. Additionally,
159             // depending on the surrounding code, accessing .xy with a uniform involved can
160             // do the same thing. Copying gl_FragCoord.xy into a temp vec2 beforehand
161             // (and only accessing .xy) seems to "fix" things.
162             const char* precision = glslCaps->usesPrecisionModifiers() ? "highp " : "";
163             this->codePrependf("\t%svec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n",
164                                precision, kCoordName, kTempName, rtHeightName, kTempName);
165             this->codePrependf("%svec2 %s = gl_FragCoord.xy;", precision, kTempName);
166             fSetupFragPosition = true;
167         }
168         SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
169         return kCoordName;
170     }
171 }
172 
maskSampleCoverage(const char * mask,bool invert)173 void GrGLSLFragmentShaderBuilder::maskSampleCoverage(const char* mask, bool invert) {
174     const GrGLSLCaps& glslCaps = *fProgramBuilder->glslCaps();
175     if (!glslCaps.sampleVariablesSupport()) {
176         SkDEBUGFAIL("Attempted to mask sample coverage without support.");
177         return;
178     }
179     if (const char* extension = glslCaps.sampleVariablesExtensionString()) {
180         this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension);
181     }
182     if (!fHasInitializedSampleMask) {
183         this->codePrependf("gl_SampleMask[0] = -1;");
184         fHasInitializedSampleMask = true;
185     }
186     if (invert) {
187         this->codeAppendf("gl_SampleMask[0] &= ~(%s);", mask);
188     } else {
189         this->codeAppendf("gl_SampleMask[0] &= %s;", mask);
190     }
191 }
192 
overrideSampleCoverage(const char * mask)193 void GrGLSLFragmentShaderBuilder::overrideSampleCoverage(const char* mask) {
194     const GrGLSLCaps& glslCaps = *fProgramBuilder->glslCaps();
195     if (!glslCaps.sampleMaskOverrideCoverageSupport()) {
196         SkDEBUGFAIL("Attempted to override sample coverage without support.");
197         return;
198     }
199     SkASSERT(glslCaps.sampleVariablesSupport());
200     if (const char* extension = glslCaps.sampleVariablesExtensionString()) {
201         this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension);
202     }
203     if (this->addFeature(1 << kSampleMaskOverrideCoverage_GLSLPrivateFeature,
204                          "GL_NV_sample_mask_override_coverage")) {
205         // Redeclare gl_SampleMask with layout(override_coverage) if we haven't already.
206         fOutputs.push_back().set(kInt_GrSLType, GrShaderVar::kOut_TypeModifier,
207                                  "gl_SampleMask", 1, kHigh_GrSLPrecision,
208                                  "override_coverage");
209     }
210     this->codeAppendf("gl_SampleMask[0] = %s;", mask);
211     fHasInitializedSampleMask = true;
212 }
213 
dstColor()214 const char* GrGLSLFragmentShaderBuilder::dstColor() {
215     fHasReadDstColor = true;
216 
217     const char* override = fProgramBuilder->primitiveProcessor().getDestColorOverride();
218     if (override != nullptr) {
219         return override;
220     }
221 
222     const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
223     if (glslCaps->fbFetchSupport()) {
224         this->addFeature(1 << kFramebufferFetch_GLSLPrivateFeature,
225                          glslCaps->fbFetchExtensionString());
226 
227         // Some versions of this extension string require declaring custom color output on ES 3.0+
228         const char* fbFetchColorName = glslCaps->fbFetchColorName();
229         if (glslCaps->fbFetchNeedsCustomOutput()) {
230             this->enableCustomOutput();
231             fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
232             fbFetchColorName = DeclaredColorOutputName();
233         }
234         return fbFetchColorName;
235     } else {
236         return kDstTextureColorName;
237     }
238 }
239 
enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation)240 void GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) {
241     SkASSERT(GrBlendEquationIsAdvanced(equation));
242 
243     const GrGLSLCaps& caps = *fProgramBuilder->glslCaps();
244     if (!caps.mustEnableAdvBlendEqs()) {
245         return;
246     }
247 
248     this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature,
249                      "GL_KHR_blend_equation_advanced");
250     if (caps.mustEnableSpecificAdvBlendEqs()) {
251         this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier);
252     } else {
253         this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier);
254     }
255 }
256 
enableCustomOutput()257 void GrGLSLFragmentShaderBuilder::enableCustomOutput() {
258     if (!fHasCustomColorOutput) {
259         fHasCustomColorOutput = true;
260         fCustomColorOutputIndex = fOutputs.count();
261         fOutputs.push_back().set(kVec4f_GrSLType,
262                                  GrGLSLShaderVar::kOut_TypeModifier,
263                                  DeclaredColorOutputName());
264         fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back());
265     }
266 }
267 
enableSecondaryOutput()268 void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() {
269     SkASSERT(!fHasSecondaryOutput);
270     fHasSecondaryOutput = true;
271     const GrGLSLCaps& caps = *fProgramBuilder->glslCaps();
272     if (const char* extension = caps.secondaryOutputExtensionString()) {
273         this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension);
274     }
275 
276     // If the primary output is declared, we must declare also the secondary output
277     // and vice versa, since it is not allowed to use a built-in gl_FragColor and a custom
278     // output. The condition also co-incides with the condition in whici GLES SL 2.0
279     // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a custom output.
280     if (caps.mustDeclareFragmentShaderOutput()) {
281         fOutputs.push_back().set(kVec4f_GrSLType, GrGLSLShaderVar::kOut_TypeModifier,
282                                  DeclaredSecondaryColorOutputName());
283         fProgramBuilder->finalizeFragmentSecondaryColor(fOutputs.back());
284     }
285 }
286 
getPrimaryColorOutputName() const287 const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const {
288     return fHasCustomColorOutput ? DeclaredColorOutputName() : "gl_FragColor";
289 }
290 
declAppendf(const char * fmt,...)291 void GrGLSLFragmentBuilder::declAppendf(const char* fmt, ...) {
292     va_list argp;
293     va_start(argp, fmt);
294     inputs().appendVAList(fmt, argp);
295     va_end(argp);
296 }
297 
getSecondaryColorOutputName() const298 const char* GrGLSLFragmentShaderBuilder::getSecondaryColorOutputName() const {
299     const GrGLSLCaps& caps = *fProgramBuilder->glslCaps();
300     return caps.mustDeclareFragmentShaderOutput() ? DeclaredSecondaryColorOutputName()
301                                                   : "gl_SecondaryFragColorEXT";
302 }
303 
onFinalize()304 void GrGLSLFragmentShaderBuilder::onFinalize() {
305     fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs());
306     GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
307                                                  *fProgramBuilder->glslCaps(),
308                                                  &this->precisionQualifier());
309 }
310 
onBeforeChildProcEmitCode()311 void GrGLSLFragmentShaderBuilder::onBeforeChildProcEmitCode() {
312     SkASSERT(fSubstageIndices.count() >= 1);
313     fSubstageIndices.push_back(0);
314     // second-to-last value in the fSubstageIndices stack is the index of the child proc
315     // at that level which is currently emitting code.
316     fMangleString.appendf("_c%d", fSubstageIndices[fSubstageIndices.count() - 2]);
317 }
318 
onAfterChildProcEmitCode()319 void GrGLSLFragmentShaderBuilder::onAfterChildProcEmitCode() {
320     SkASSERT(fSubstageIndices.count() >= 2);
321     fSubstageIndices.pop_back();
322     fSubstageIndices.back()++;
323     int removeAt = fMangleString.findLastOf('_');
324     fMangleString.remove(removeAt, fMangleString.size() - removeAt);
325 }
326 
327