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 "src/gpu/GrRenderTarget.h" |
9 | #include "src/gpu/GrShaderCaps.h" |
10 | #include "src/gpu/gl/GrGLGpu.h" |
11 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
12 | #include "src/gpu/glsl/GrGLSLProgramBuilder.h" |
13 | #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
14 | #include "src/gpu/glsl/GrGLSLVarying.h" |
15 | |
16 | const char* GrGLSLFragmentShaderBuilder::kDstColorName = "_dstColor" ; |
17 | |
18 | static const char* specific_layout_qualifier_name(GrBlendEquation equation) { |
19 | SkASSERT(GrBlendEquationIsAdvanced(equation)); |
20 | |
21 | static const char* kLayoutQualifierNames[] = { |
22 | "blend_support_screen" , |
23 | "blend_support_overlay" , |
24 | "blend_support_darken" , |
25 | "blend_support_lighten" , |
26 | "blend_support_colordodge" , |
27 | "blend_support_colorburn" , |
28 | "blend_support_hardlight" , |
29 | "blend_support_softlight" , |
30 | "blend_support_difference" , |
31 | "blend_support_exclusion" , |
32 | "blend_support_multiply" , |
33 | "blend_support_hsl_hue" , |
34 | "blend_support_hsl_saturation" , |
35 | "blend_support_hsl_color" , |
36 | "blend_support_hsl_luminosity" |
37 | }; |
38 | return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation]; |
39 | |
40 | static_assert(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
41 | static_assert(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
42 | static_assert(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
43 | static_assert(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
44 | static_assert(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
45 | static_assert(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
46 | static_assert(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
47 | static_assert(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
48 | static_assert(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
49 | static_assert(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
50 | static_assert(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
51 | static_assert(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
52 | static_assert(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
53 | static_assert(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
54 | static_assert(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
55 | // There's an illegal GrBlendEquation at the end there, hence the -1. |
56 | static_assert(SK_ARRAY_COUNT(kLayoutQualifierNames) == |
57 | kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation - 1); |
58 | } |
59 | |
60 | uint8_t GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(GrSurfaceOrigin origin) { |
61 | SkASSERT(kTopLeft_GrSurfaceOrigin == origin || kBottomLeft_GrSurfaceOrigin == origin); |
62 | return origin + 1; |
63 | |
64 | static_assert(0 == kTopLeft_GrSurfaceOrigin); |
65 | static_assert(1 == kBottomLeft_GrSurfaceOrigin); |
66 | } |
67 | |
68 | GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program) |
69 | : GrGLSLShaderBuilder(program) { |
70 | fSubstageIndices.push_back(0); |
71 | } |
72 | |
73 | const char* GrGLSLFragmentShaderBuilder::sampleOffsets() { |
74 | SkASSERT(CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()); |
75 | SkDEBUGCODE(fUsedProcessorFeaturesThisStage_DebugOnly |= CustomFeatures::kSampleLocations); |
76 | SkDEBUGCODE(fUsedProcessorFeaturesAllStages_DebugOnly |= CustomFeatures::kSampleLocations); |
77 | return "_sampleOffsets" ; |
78 | } |
79 | |
80 | void GrGLSLFragmentShaderBuilder::maskOffMultisampleCoverage( |
81 | const char* mask, ScopeFlags scopeFlags) { |
82 | const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); |
83 | if (!shaderCaps.sampleMaskSupport()) { |
84 | SkDEBUGFAIL("Attempted to mask sample coverage without support." ); |
85 | return; |
86 | } |
87 | if (const char* extension = shaderCaps.sampleVariablesExtensionString()) { |
88 | this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension); |
89 | } |
90 | |
91 | if (!fHasModifiedSampleMask) { |
92 | fHasModifiedSampleMask = true; |
93 | if (ScopeFlags::kTopLevel != scopeFlags) { |
94 | this->codePrependf("sk_SampleMask[0] = ~0;" ); |
95 | } |
96 | if (!(ScopeFlags::kInsideLoop & scopeFlags)) { |
97 | this->codeAppendf("sk_SampleMask[0] = (%s);" , mask); |
98 | return; |
99 | } |
100 | } |
101 | |
102 | this->codeAppendf("sk_SampleMask[0] &= (%s);" , mask); |
103 | } |
104 | |
105 | void GrGLSLFragmentShaderBuilder::applyFnToMultisampleMask( |
106 | const char* fn, const char* grad, ScopeFlags scopeFlags) { |
107 | SkASSERT(CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()); |
108 | SkDEBUGCODE(fUsedProcessorFeaturesThisStage_DebugOnly |= CustomFeatures::kSampleLocations); |
109 | SkDEBUGCODE(fUsedProcessorFeaturesAllStages_DebugOnly |= CustomFeatures::kSampleLocations); |
110 | |
111 | int sampleCnt = fProgramBuilder->effectiveSampleCnt(); |
112 | SkASSERT(sampleCnt > 1); |
113 | |
114 | this->codeAppendf("{" ); |
115 | |
116 | if (!grad) { |
117 | SkASSERT(fProgramBuilder->shaderCaps()->shaderDerivativeSupport()); |
118 | // In order to use HW derivatives, our neighbors within the same primitive must also be |
119 | // executing the same code. A per-pixel branch makes this pre-condition impossible to |
120 | // fulfill. |
121 | SkASSERT(!(ScopeFlags::kInsidePerPixelBranch & scopeFlags)); |
122 | this->codeAppendf("float2 grad = float2(dFdx(%s), dFdy(%s));" , fn, fn); |
123 | this->codeAppendf("float fnwidth = fwidth(%s);" , fn); |
124 | grad = "grad" ; |
125 | } else { |
126 | this->codeAppendf("float fnwidth = abs(%s.x) + abs(%s.y);" , grad, grad); |
127 | } |
128 | |
129 | this->codeAppendf("int mask = 0;" ); |
130 | this->codeAppendf("if (%s*2 < fnwidth) {" , fn); // Are ANY samples inside the implicit fn? |
131 | this->codeAppendf( "if (%s*-2 >= fnwidth) {" , fn); // Are ALL samples inside the implicit? |
132 | this->codeAppendf( "mask = ~0;" ); |
133 | this->codeAppendf( "} else for (int i = 0; i < %i; ++i) {" , sampleCnt); |
134 | this->codeAppendf( "float fnsample = dot(%s, _sampleOffsets[i]) + %s;" , grad, fn); |
135 | this->codeAppendf( "if (fnsample < 0) {" ); |
136 | this->codeAppendf( "mask |= (1 << i);" ); |
137 | this->codeAppendf( "}" ); |
138 | this->codeAppendf( "}" ); |
139 | this->codeAppendf("}" ); |
140 | this->maskOffMultisampleCoverage("mask" , scopeFlags); |
141 | |
142 | this->codeAppendf("}" ); |
143 | } |
144 | |
145 | SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor* fp, |
146 | GrGLSLFragmentProcessor::EmitArgs& args) { |
147 | this->onBeforeChildProcEmitCode(); |
148 | this->nextStage(); |
149 | |
150 | // An FP's function signature is theoretically always main(half4 color, float2 _coords). |
151 | // However, if it is only sampled by a chain of uniform matrix expressions (or legacy coord |
152 | // transforms), the value that would have been passed to _coords is lifted to the vertex shader |
153 | // and stored in a unique varying. In that case it uses that variable and does not have a |
154 | // second actual argument for _coords. |
155 | // FIXME: An alternative would be to have all FP functions have a float2 argument, and the |
156 | // parent FP invokes it with the varying reference when it's been lifted to the vertex shader. |
157 | int paramCount = 2; |
158 | GrShaderVar params[] = { GrShaderVar(args.fInputColor, kHalf4_GrSLType), |
159 | GrShaderVar(args.fSampleCoord, kFloat2_GrSLType) }; |
160 | |
161 | if (!args.fFp.isSampledWithExplicitCoords()) { |
162 | // Sampled with a uniform matrix expression and/or a legacy coord transform. The actual |
163 | // transformation code is emitted in the vertex shader, so this only has to access it. |
164 | // Add a float2 _coords variable that maps to the associated varying and replaces the |
165 | // absent 2nd argument to the fp's function. |
166 | paramCount = 1; |
167 | |
168 | if (args.fFp.referencesSampleCoords()) { |
169 | const GrShaderVar& varying = args.fTransformedCoords[0]; |
170 | switch(varying.getType()) { |
171 | case kFloat2_GrSLType: |
172 | // Just point the local coords to the varying |
173 | args.fSampleCoord = varying.getName().c_str(); |
174 | break; |
175 | case kFloat3_GrSLType: |
176 | // Must perform the perspective divide in the frag shader based on the varying, |
177 | // and since we won't actually have a function parameter for local coords, add |
178 | // it as a local variable. |
179 | this->codeAppendf("float2 %s = %s.xy / %s.z;\n" , args.fSampleCoord, |
180 | varying.getName().c_str(), varying.getName().c_str()); |
181 | break; |
182 | default: |
183 | SkDEBUGFAILF("Unexpected varying type for coord: %s %d\n" , |
184 | varying.getName().c_str(), (int) varying.getType()); |
185 | break; |
186 | } |
187 | } |
188 | } // else the function keeps its two arguments |
189 | |
190 | this->codeAppendf("half4 %s;\n" , args.fOutputColor); |
191 | fp->emitCode(args); |
192 | this->codeAppendf("return %s;\n" , args.fOutputColor); |
193 | |
194 | SkString result; |
195 | this->emitFunction(kHalf4_GrSLType, args.fFp.name(), paramCount, params, |
196 | this->code().c_str(), &result); |
197 | this->deleteStage(); |
198 | this->onAfterChildProcEmitCode(); |
199 | return result; |
200 | } |
201 | |
202 | const char* GrGLSLFragmentShaderBuilder::dstColor() { |
203 | SkDEBUGCODE(fHasReadDstColorThisStage_DebugOnly = true;) |
204 | |
205 | const GrShaderCaps* shaderCaps = fProgramBuilder->shaderCaps(); |
206 | if (shaderCaps->fbFetchSupport()) { |
207 | this->addFeature(1 << kFramebufferFetch_GLSLPrivateFeature, |
208 | shaderCaps->fbFetchExtensionString()); |
209 | |
210 | // Some versions of this extension string require declaring custom color output on ES 3.0+ |
211 | const char* fbFetchColorName = "sk_LastFragColor" ; |
212 | if (shaderCaps->fbFetchNeedsCustomOutput()) { |
213 | this->enableCustomOutput(); |
214 | fCustomColorOutput->setTypeModifier(GrShaderVar::TypeModifier::InOut); |
215 | fbFetchColorName = DeclaredColorOutputName(); |
216 | // Set the dstColor to an intermediate variable so we don't override it with the output |
217 | this->codeAppendf("half4 %s = %s;" , kDstColorName, fbFetchColorName); |
218 | } else { |
219 | return fbFetchColorName; |
220 | } |
221 | } |
222 | return kDstColorName; |
223 | } |
224 | |
225 | void GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) { |
226 | SkASSERT(GrBlendEquationIsAdvanced(equation)); |
227 | |
228 | const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); |
229 | if (!caps.mustEnableAdvBlendEqs()) { |
230 | return; |
231 | } |
232 | |
233 | this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature, |
234 | "GL_KHR_blend_equation_advanced" ); |
235 | if (caps.mustEnableSpecificAdvBlendEqs()) { |
236 | this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier); |
237 | } else { |
238 | this->addLayoutQualifier("blend_support_all_equations" , kOut_InterfaceQualifier); |
239 | } |
240 | } |
241 | |
242 | void GrGLSLFragmentShaderBuilder::enableCustomOutput() { |
243 | if (!fCustomColorOutput) { |
244 | fCustomColorOutput = &fOutputs.emplace_back(DeclaredColorOutputName(), kHalf4_GrSLType, |
245 | GrShaderVar::TypeModifier::Out); |
246 | fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back()); |
247 | } |
248 | } |
249 | |
250 | void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() { |
251 | SkASSERT(!fHasSecondaryOutput); |
252 | fHasSecondaryOutput = true; |
253 | const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); |
254 | if (const char* extension = caps.secondaryOutputExtensionString()) { |
255 | this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension); |
256 | } |
257 | |
258 | // If the primary output is declared, we must declare also the secondary output |
259 | // and vice versa, since it is not allowed to use a built-in gl_FragColor and a custom |
260 | // output. The condition also co-incides with the condition in whici GLES SL 2.0 |
261 | // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a custom output. |
262 | if (caps.mustDeclareFragmentShaderOutput()) { |
263 | fOutputs.emplace_back(DeclaredSecondaryColorOutputName(), kHalf4_GrSLType, |
264 | GrShaderVar::TypeModifier::Out); |
265 | fProgramBuilder->finalizeFragmentSecondaryColor(fOutputs.back()); |
266 | } |
267 | } |
268 | |
269 | const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const { |
270 | return this->hasCustomColorOutput() ? DeclaredColorOutputName() : "sk_FragColor" ; |
271 | } |
272 | |
273 | bool GrGLSLFragmentShaderBuilder::primaryColorOutputIsInOut() const { |
274 | return fCustomColorOutput && |
275 | fCustomColorOutput->getTypeModifier() == GrShaderVar::TypeModifier::InOut; |
276 | } |
277 | |
278 | const char* GrGLSLFragmentShaderBuilder::getSecondaryColorOutputName() const { |
279 | if (this->hasSecondaryOutput()) { |
280 | return (fProgramBuilder->shaderCaps()->mustDeclareFragmentShaderOutput()) |
281 | ? DeclaredSecondaryColorOutputName() |
282 | : "gl_SecondaryFragColorEXT" ; |
283 | } |
284 | return nullptr; |
285 | } |
286 | |
287 | GrSurfaceOrigin GrGLSLFragmentShaderBuilder::getSurfaceOrigin() const { |
288 | return fProgramBuilder->origin(); |
289 | } |
290 | |
291 | void GrGLSLFragmentShaderBuilder::onFinalize() { |
292 | SkASSERT(fProgramBuilder->processorFeatures() == fUsedProcessorFeaturesAllStages_DebugOnly); |
293 | |
294 | if (CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()) { |
295 | const SkTArray<SkPoint>& sampleLocations = fProgramBuilder->getSampleLocations(); |
296 | this->definitions().appendf("const float2 _sampleOffsets[%i] = float2[%i](" , |
297 | sampleLocations.count(), sampleLocations.count()); |
298 | for (int i = 0; i < sampleLocations.count(); ++i) { |
299 | SkPoint offset = sampleLocations[i] - SkPoint::Make(.5f, .5f); |
300 | if (kBottomLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) { |
301 | offset.fY = -offset.fY; |
302 | } |
303 | this->definitions().appendf("float2(%f, %f)" , offset.x(), offset.y()); |
304 | this->definitions().append((i + 1 != sampleLocations.count()) ? ", " : ");" ); |
305 | } |
306 | } |
307 | |
308 | fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs()); |
309 | } |
310 | |
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 | |
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 | |