OLD | NEW |
| (Empty) |
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 "GrRenderTarget.h" | |
10 #include "glsl/GrGLSL.h" | |
11 #include "glsl/GrGLSLCaps.h" | |
12 #include "glsl/GrGLSLProgramBuilder.h" | |
13 | |
14 const char* GrGLFragmentShaderBuilder::kDstTextureColorName = "_dstColor"; | |
15 | |
16 static const char* specific_layout_qualifier_name(GrBlendEquation equation) { | |
17 SkASSERT(GrBlendEquationIsAdvanced(equation)); | |
18 | |
19 static const char* kLayoutQualifierNames[] = { | |
20 "blend_support_screen", | |
21 "blend_support_overlay", | |
22 "blend_support_darken", | |
23 "blend_support_lighten", | |
24 "blend_support_colordodge", | |
25 "blend_support_colorburn", | |
26 "blend_support_hardlight", | |
27 "blend_support_softlight", | |
28 "blend_support_difference", | |
29 "blend_support_exclusion", | |
30 "blend_support_multiply", | |
31 "blend_support_hsl_hue", | |
32 "blend_support_hsl_saturation", | |
33 "blend_support_hsl_color", | |
34 "blend_support_hsl_luminosity" | |
35 }; | |
36 return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation]; | |
37 | |
38 GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquatio
n); | |
39 GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquati
on); | |
40 GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquatio
n); | |
41 GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquati
on); | |
42 GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEqu
ation); | |
43 GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
44 GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
45 GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
46 GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEqu
ation); | |
47 GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
48 GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
49 GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquati
on); | |
50 GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlen
dEquation); | |
51 GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
52 GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlen
dEquation); | |
53 GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) == | |
54 kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation); | |
55 } | |
56 | |
57 GrGLFragmentShaderBuilder::FragPosKey | |
58 GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst) { | |
59 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { | |
60 return kTopLeftFragPosRead_FragPosKey; | |
61 } else { | |
62 return kBottomLeftFragPosRead_FragPosKey; | |
63 } | |
64 } | |
65 | |
66 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLSLProgramBuilder* progr
am, | |
67 uint8_t fragPosKey) | |
68 : INHERITED(program) | |
69 , fSetupFragPosition(false) | |
70 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey) | |
71 , fCustomColorOutputIndex(-1) | |
72 , fHasReadDstColor(false) | |
73 , fHasReadFragmentPosition(false) { | |
74 } | |
75 | |
76 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { | |
77 switch (feature) { | |
78 case kStandardDerivatives_GLSLFeature: { | |
79 if (!fProgramBuilder->glslCaps()->shaderDerivativeSupport()) { | |
80 return false; | |
81 } | |
82 const char* extension = fProgramBuilder->glslCaps()->shaderDerivativ
eExtensionString(); | |
83 if (extension) { | |
84 this->addFeature(1 << kStandardDerivatives_GLSLFeature, extensio
n); | |
85 } | |
86 return true; | |
87 } | |
88 default: | |
89 SkFAIL("Unexpected GLSLFeature requested."); | |
90 return false; | |
91 } | |
92 } | |
93 | |
94 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(const GrGLSLTransformedCoor
dsArray& coords, | |
95 int index) { | |
96 if (kVec3f_GrSLType != coords[index].getType()) { | |
97 SkASSERT(kVec2f_GrSLType == coords[index].getType()); | |
98 return coords[index].getName(); | |
99 } | |
100 | |
101 SkString coords2D("coords2D"); | |
102 if (0 != index) { | |
103 coords2D.appendf("_%i", index); | |
104 } | |
105 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", | |
106 coords2D.c_str(), coords[index].c_str(), coords[index].c_s
tr()); | |
107 return coords2D; | |
108 } | |
109 | |
110 const char* GrGLFragmentShaderBuilder::fragmentPosition() { | |
111 fHasReadFragmentPosition = true; | |
112 | |
113 const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); | |
114 // We only declare "gl_FragCoord" when we're in the case where we want to us
e layout qualifiers | |
115 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier
appears in the | |
116 // declaration varies in earlier GLSL specs. So it is simpler to omit it. | |
117 if (fTopLeftFragPosRead) { | |
118 fSetupFragPosition = true; | |
119 return "gl_FragCoord"; | |
120 } else if (const char* extension = glslCaps->fragCoordConventionsExtensionSt
ring()) { | |
121 if (!fSetupFragPosition) { | |
122 if (glslCaps->generation() < k150_GrGLSLGeneration) { | |
123 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, | |
124 extension); | |
125 } | |
126 fInputs.push_back().set(kVec4f_GrSLType, | |
127 GrGLSLShaderVar::kIn_TypeModifier, | |
128 "gl_FragCoord", | |
129 kDefault_GrSLPrecision, | |
130 GrGLSLShaderVar::kUpperLeft_Origin); | |
131 fSetupFragPosition = true; | |
132 } | |
133 return "gl_FragCoord"; | |
134 } else { | |
135 static const char* kTempName = "tmpXYFragCoord"; | |
136 static const char* kCoordName = "fragCoordYDown"; | |
137 if (!fSetupFragPosition) { | |
138 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | |
139 const char* rtHeightName; | |
140 | |
141 fProgramBuilder->fUniformHandles.fRTHeightUni = | |
142 fProgramBuilder->addFragPosUniform(GrGLSLProgramBuilder::kFr
agment_Visibility, | |
143 kFloat_GrSLType, | |
144 kDefault_GrSLPrecision, | |
145 "RTHeight", | |
146 &rtHeightName); | |
147 | |
148 // The Adreno compiler seems to be very touchy about access to "gl_F
ragCoord". | |
149 // Accessing glFragCoord.zw can cause a program to fail to link. Add
itionally, | |
150 // depending on the surrounding code, accessing .xy with a uniform i
nvolved can | |
151 // do the same thing. Copying gl_FragCoord.xy into a temp vec2 befor
ehand | |
152 // (and only accessing .xy) seems to "fix" things. | |
153 this->codePrependf("\tvec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", | |
154 kCoordName, kTempName, rtHeightName, kTempName); | |
155 this->codePrependf("vec2 %s = gl_FragCoord.xy;", kTempName); | |
156 fSetupFragPosition = true; | |
157 } | |
158 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | |
159 return kCoordName; | |
160 } | |
161 } | |
162 | |
163 const char* GrGLFragmentShaderBuilder::dstColor() { | |
164 fHasReadDstColor = true; | |
165 | |
166 const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); | |
167 if (glslCaps->fbFetchSupport()) { | |
168 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur
e + 1), | |
169 glslCaps->fbFetchExtensionString()); | |
170 | |
171 // Some versions of this extension string require declaring custom color
output on ES 3.0+ | |
172 const char* fbFetchColorName = glslCaps->fbFetchColorName(); | |
173 if (glslCaps->fbFetchNeedsCustomOutput()) { | |
174 this->enableCustomOutput(); | |
175 fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOu
t_TypeModifier); | |
176 fbFetchColorName = DeclaredColorOutputName(); | |
177 } | |
178 return fbFetchColorName; | |
179 } else { | |
180 return kDstTextureColorName; | |
181 } | |
182 } | |
183 | |
184 void GrGLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquat
ion equation) { | |
185 SkASSERT(GrBlendEquationIsAdvanced(equation)); | |
186 | |
187 const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); | |
188 if (!caps.mustEnableAdvBlendEqs()) { | |
189 return; | |
190 } | |
191 | |
192 this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature, | |
193 "GL_KHR_blend_equation_advanced"); | |
194 if (caps.mustEnableSpecificAdvBlendEqs()) { | |
195 this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_
InterfaceQualifier); | |
196 } else { | |
197 this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQu
alifier); | |
198 } | |
199 } | |
200 | |
201 void GrGLFragmentShaderBuilder::enableCustomOutput() { | |
202 if (!fHasCustomColorOutput) { | |
203 fHasCustomColorOutput = true; | |
204 fCustomColorOutputIndex = fOutputs.count(); | |
205 fOutputs.push_back().set(kVec4f_GrSLType, | |
206 GrGLSLShaderVar::kOut_TypeModifier, | |
207 DeclaredColorOutputName()); | |
208 } | |
209 } | |
210 | |
211 void GrGLFragmentShaderBuilder::enableSecondaryOutput() { | |
212 SkASSERT(!fHasSecondaryOutput); | |
213 fHasSecondaryOutput = true; | |
214 const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); | |
215 if (const char* extension = caps.secondaryOutputExtensionString()) { | |
216 this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension); | |
217 } | |
218 | |
219 // If the primary output is declared, we must declare also the secondary out
put | |
220 // and vice versa, since it is not allowed to use a built-in gl_FragColor an
d a custom | |
221 // output. The condition also co-incides with the condition in whici GLES SL
2.0 | |
222 // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a c
ustom output. | |
223 if (caps.mustDeclareFragmentShaderOutput()) { | |
224 fOutputs.push_back().set(kVec4f_GrSLType, GrGLSLShaderVar::kOut_TypeModi
fier, | |
225 DeclaredSecondaryColorOutputName()); | |
226 } | |
227 } | |
228 | |
229 const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const { | |
230 return fHasCustomColorOutput ? DeclaredColorOutputName() : "gl_FragColor"; | |
231 } | |
232 | |
233 const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const { | |
234 const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); | |
235 return caps.mustDeclareFragmentShaderOutput() ? DeclaredSecondaryColorOutput
Name() | |
236 : "gl_SecondaryFragColorEXT"; | |
237 } | |
238 | |
239 void GrGLFragmentShaderBuilder::onFinalize() { | |
240 GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, | |
241 *fProgramBuilder->glslCaps(), | |
242 &this->precisionQualifier()); | |
243 } | |
244 | |
245 void GrGLFragmentShaderBuilder::addVarying(GrGLSLVarying* v, GrSLPrecision fsPre
c) { | |
246 v->fFsIn = v->fVsOut; | |
247 if (v->fGsOut) { | |
248 v->fFsIn = v->fGsOut; | |
249 } | |
250 fInputs.push_back().set(v->fType, GrGLSLShaderVar::kVaryingIn_TypeModifier,
v->fFsIn, fsPrec); | |
251 } | |
252 | |
253 void GrGLFragmentBuilder::onBeforeChildProcEmitCode() { | |
254 SkASSERT(fSubstageIndices.count() >= 1); | |
255 fSubstageIndices.push_back(0); | |
256 // second-to-last value in the fSubstageIndices stack is the index of the ch
ild proc | |
257 // at that level which is currently emitting code. | |
258 fMangleString.appendf("_c%d", fSubstageIndices[fSubstageIndices.count() - 2]
); | |
259 } | |
260 | |
261 void GrGLFragmentBuilder::onAfterChildProcEmitCode() { | |
262 SkASSERT(fSubstageIndices.count() >= 2); | |
263 fSubstageIndices.pop_back(); | |
264 fSubstageIndices.back()++; | |
265 int removeAt = fMangleString.findLastOf('_'); | |
266 fMangleString.remove(removeAt, fMangleString.size() - removeAt); | |
267 } | |
268 | |
OLD | NEW |