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/GrRenderTargetPriv.h" |
10 | #include "src/gpu/GrShaderCaps.h" |
11 | #include "src/gpu/gl/GrGLGpu.h" |
12 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
13 | #include "src/gpu/glsl/GrGLSLProgramBuilder.h" |
14 | #include "src/gpu/glsl/GrGLSLUniformHandler.h" |
15 | #include "src/gpu/glsl/GrGLSLVarying.h" |
16 | |
17 | const char* GrGLSLFragmentShaderBuilder::kDstColorName = "_dstColor" ; |
18 | |
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 | static_assert(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
42 | static_assert(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
43 | static_assert(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
44 | static_assert(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
45 | static_assert(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
46 | static_assert(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
47 | static_assert(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
48 | static_assert(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
49 | static_assert(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
50 | static_assert(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
51 | static_assert(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
52 | static_assert(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
53 | static_assert(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
54 | static_assert(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
55 | static_assert(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation); |
56 | // There's an illegal GrBlendEquation at the end there, hence the -1. |
57 | static_assert(SK_ARRAY_COUNT(kLayoutQualifierNames) == |
58 | kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation - 1); |
59 | } |
60 | |
61 | uint8_t GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(GrSurfaceOrigin origin) { |
62 | SkASSERT(kTopLeft_GrSurfaceOrigin == origin || kBottomLeft_GrSurfaceOrigin == origin); |
63 | return origin + 1; |
64 | |
65 | static_assert(0 == kTopLeft_GrSurfaceOrigin); |
66 | static_assert(1 == kBottomLeft_GrSurfaceOrigin); |
67 | } |
68 | |
69 | GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* program) |
70 | : GrGLSLFragmentBuilder(program) { |
71 | fSubstageIndices.push_back(0); |
72 | } |
73 | |
74 | SkString GrGLSLFragmentShaderBuilder::ensureCoords2D(const GrShaderVar& coords) { |
75 | if (!coords.getName().size()) { |
76 | return SkString("_coords" ); |
77 | } |
78 | if (kFloat3_GrSLType != coords.getType() && kHalf3_GrSLType != coords.getType()) { |
79 | SkASSERT(kFloat2_GrSLType == coords.getType() || kHalf2_GrSLType == coords.getType()); |
80 | return coords.getName(); |
81 | } |
82 | |
83 | SkString coords2D; |
84 | coords2D.printf("%s_ensure2D" , coords.c_str()); |
85 | this->codeAppendf("\tfloat2 %s = %s.xy / %s.z;" , coords2D.c_str(), coords.c_str(), |
86 | coords.c_str()); |
87 | return coords2D; |
88 | } |
89 | |
90 | const char* GrGLSLFragmentShaderBuilder::sampleOffsets() { |
91 | SkASSERT(CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()); |
92 | SkDEBUGCODE(fUsedProcessorFeaturesThisStage_DebugOnly |= CustomFeatures::kSampleLocations); |
93 | SkDEBUGCODE(fUsedProcessorFeaturesAllStages_DebugOnly |= CustomFeatures::kSampleLocations); |
94 | return "_sampleOffsets" ; |
95 | } |
96 | |
97 | void GrGLSLFragmentShaderBuilder::maskOffMultisampleCoverage( |
98 | const char* mask, ScopeFlags scopeFlags) { |
99 | const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); |
100 | if (!shaderCaps.sampleMaskSupport()) { |
101 | SkDEBUGFAIL("Attempted to mask sample coverage without support." ); |
102 | return; |
103 | } |
104 | if (const char* extension = shaderCaps.sampleVariablesExtensionString()) { |
105 | this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension); |
106 | } |
107 | |
108 | if (!fHasModifiedSampleMask) { |
109 | fHasModifiedSampleMask = true; |
110 | if (ScopeFlags::kTopLevel != scopeFlags) { |
111 | this->codePrependf("sk_SampleMask[0] = ~0;" ); |
112 | } |
113 | if (!(ScopeFlags::kInsideLoop & scopeFlags)) { |
114 | this->codeAppendf("sk_SampleMask[0] = (%s);" , mask); |
115 | return; |
116 | } |
117 | } |
118 | |
119 | this->codeAppendf("sk_SampleMask[0] &= (%s);" , mask); |
120 | } |
121 | |
122 | void GrGLSLFragmentShaderBuilder::applyFnToMultisampleMask( |
123 | const char* fn, const char* grad, ScopeFlags scopeFlags) { |
124 | SkASSERT(CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()); |
125 | SkDEBUGCODE(fUsedProcessorFeaturesThisStage_DebugOnly |= CustomFeatures::kSampleLocations); |
126 | SkDEBUGCODE(fUsedProcessorFeaturesAllStages_DebugOnly |= CustomFeatures::kSampleLocations); |
127 | |
128 | int sampleCnt = fProgramBuilder->effectiveSampleCnt(); |
129 | SkASSERT(sampleCnt > 1); |
130 | |
131 | this->codeAppendf("{" ); |
132 | |
133 | if (!grad) { |
134 | SkASSERT(fProgramBuilder->shaderCaps()->shaderDerivativeSupport()); |
135 | // In order to use HW derivatives, our neighbors within the same primitive must also be |
136 | // executing the same code. A per-pixel branch makes this pre-condition impossible to |
137 | // fulfill. |
138 | SkASSERT(!(ScopeFlags::kInsidePerPixelBranch & scopeFlags)); |
139 | this->codeAppendf("float2 grad = float2(dFdx(%s), dFdy(%s));" , fn, fn); |
140 | this->codeAppendf("float fnwidth = fwidth(%s);" , fn); |
141 | grad = "grad" ; |
142 | } else { |
143 | this->codeAppendf("float fnwidth = abs(%s.x) + abs(%s.y);" , grad, grad); |
144 | } |
145 | |
146 | this->codeAppendf("int mask = 0;" ); |
147 | this->codeAppendf("if (%s*2 < fnwidth) {" , fn); // Are ANY samples inside the implicit fn? |
148 | this->codeAppendf( "if (%s*-2 >= fnwidth) {" , fn); // Are ALL samples inside the implicit? |
149 | this->codeAppendf( "mask = ~0;" ); |
150 | this->codeAppendf( "} else for (int i = 0; i < %i; ++i) {" , sampleCnt); |
151 | this->codeAppendf( "float fnsample = dot(%s, _sampleOffsets[i]) + %s;" , grad, fn); |
152 | this->codeAppendf( "if (fnsample < 0) {" ); |
153 | this->codeAppendf( "mask |= (1 << i);" ); |
154 | this->codeAppendf( "}" ); |
155 | this->codeAppendf( "}" ); |
156 | this->codeAppendf("}" ); |
157 | this->maskOffMultisampleCoverage("mask" , scopeFlags); |
158 | |
159 | this->codeAppendf("}" ); |
160 | } |
161 | |
162 | SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor* fp, |
163 | GrGLSLFragmentProcessor::EmitArgs& args) { |
164 | this->onBeforeChildProcEmitCode(); |
165 | this->nextStage(); |
166 | if (args.fFp.isSampledWithExplicitCoords() && args.fTransformedCoords.count() > 0) { |
167 | // we currently only support overriding a single coordinate pair |
168 | SkASSERT(args.fTransformedCoords.count() == 1); |
169 | const GrShaderVar& transform = args.fTransformedCoords[0].fTransform; |
170 | switch (transform.getType()) { |
171 | case kFloat4_GrSLType: |
172 | this->codeAppendf("_coords = _coords * %s.xz + %s.yw;\n" , transform.c_str(), |
173 | transform.c_str()); |
174 | break; |
175 | case kFloat3x3_GrSLType: |
176 | this->codeAppendf("_coords = (%s * float3(_coords, 1)).xy;\n" , transform.c_str()); |
177 | break; |
178 | default: |
179 | SkASSERT(transform.getType() == kVoid_GrSLType); |
180 | break; |
181 | } |
182 | } |
183 | this->codeAppendf("half4 %s;\n" , args.fOutputColor); |
184 | fp->emitCode(args); |
185 | this->codeAppendf("return %s;\n" , args.fOutputColor); |
186 | GrShaderVar params[] = { GrShaderVar(args.fInputColor, kHalf4_GrSLType), |
187 | GrShaderVar("_coords" , kFloat2_GrSLType) }; |
188 | SkString result; |
189 | this->emitFunction(kHalf4_GrSLType, |
190 | args.fFp.name(), |
191 | args.fFp.isSampledWithExplicitCoords() ? 2 : 1, |
192 | params, |
193 | this->code().c_str(), |
194 | &result); |
195 | this->deleteStage(); |
196 | this->onAfterChildProcEmitCode(); |
197 | return result; |
198 | } |
199 | |
200 | const char* GrGLSLFragmentShaderBuilder::dstColor() { |
201 | SkDEBUGCODE(fHasReadDstColorThisStage_DebugOnly = true;) |
202 | |
203 | const GrShaderCaps* shaderCaps = fProgramBuilder->shaderCaps(); |
204 | if (shaderCaps->fbFetchSupport()) { |
205 | this->addFeature(1 << kFramebufferFetch_GLSLPrivateFeature, |
206 | shaderCaps->fbFetchExtensionString()); |
207 | |
208 | // Some versions of this extension string require declaring custom color output on ES 3.0+ |
209 | const char* fbFetchColorName = "sk_LastFragColor" ; |
210 | if (shaderCaps->fbFetchNeedsCustomOutput()) { |
211 | this->enableCustomOutput(); |
212 | fCustomColorOutput->setTypeModifier(GrShaderVar::TypeModifier::InOut); |
213 | fbFetchColorName = DeclaredColorOutputName(); |
214 | // Set the dstColor to an intermediate variable so we don't override it with the output |
215 | this->codeAppendf("half4 %s = %s;" , kDstColorName, fbFetchColorName); |
216 | } else { |
217 | return fbFetchColorName; |
218 | } |
219 | } |
220 | return kDstColorName; |
221 | } |
222 | |
223 | void GrGLSLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) { |
224 | SkASSERT(GrBlendEquationIsAdvanced(equation)); |
225 | |
226 | const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); |
227 | if (!caps.mustEnableAdvBlendEqs()) { |
228 | return; |
229 | } |
230 | |
231 | this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature, |
232 | "GL_KHR_blend_equation_advanced" ); |
233 | if (caps.mustEnableSpecificAdvBlendEqs()) { |
234 | this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier); |
235 | } else { |
236 | this->addLayoutQualifier("blend_support_all_equations" , kOut_InterfaceQualifier); |
237 | } |
238 | } |
239 | |
240 | void GrGLSLFragmentShaderBuilder::enableCustomOutput() { |
241 | if (!fCustomColorOutput) { |
242 | fCustomColorOutput = &fOutputs.emplace_back(DeclaredColorOutputName(), kHalf4_GrSLType, |
243 | GrShaderVar::TypeModifier::Out); |
244 | fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back()); |
245 | } |
246 | } |
247 | |
248 | void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() { |
249 | SkASSERT(!fHasSecondaryOutput); |
250 | fHasSecondaryOutput = true; |
251 | const GrShaderCaps& caps = *fProgramBuilder->shaderCaps(); |
252 | if (const char* extension = caps.secondaryOutputExtensionString()) { |
253 | this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension); |
254 | } |
255 | |
256 | // If the primary output is declared, we must declare also the secondary output |
257 | // and vice versa, since it is not allowed to use a built-in gl_FragColor and a custom |
258 | // output. The condition also co-incides with the condition in whici GLES SL 2.0 |
259 | // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a custom output. |
260 | if (caps.mustDeclareFragmentShaderOutput()) { |
261 | fOutputs.emplace_back(DeclaredSecondaryColorOutputName(), kHalf4_GrSLType, |
262 | GrShaderVar::TypeModifier::Out); |
263 | fProgramBuilder->finalizeFragmentSecondaryColor(fOutputs.back()); |
264 | } |
265 | } |
266 | |
267 | const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const { |
268 | return this->hasCustomColorOutput() ? DeclaredColorOutputName() : "sk_FragColor" ; |
269 | } |
270 | |
271 | bool GrGLSLFragmentShaderBuilder::primaryColorOutputIsInOut() const { |
272 | return fCustomColorOutput && |
273 | fCustomColorOutput->getTypeModifier() == GrShaderVar::TypeModifier::InOut; |
274 | } |
275 | |
276 | void GrGLSLFragmentBuilder::declAppendf(const char* fmt, ...) { |
277 | va_list argp; |
278 | va_start(argp, fmt); |
279 | inputs().appendVAList(fmt, argp); |
280 | va_end(argp); |
281 | } |
282 | |
283 | const char* GrGLSLFragmentShaderBuilder::getSecondaryColorOutputName() const { |
284 | if (this->hasSecondaryOutput()) { |
285 | return (fProgramBuilder->shaderCaps()->mustDeclareFragmentShaderOutput()) |
286 | ? DeclaredSecondaryColorOutputName() |
287 | : "gl_SecondaryFragColorEXT" ; |
288 | } |
289 | return nullptr; |
290 | } |
291 | |
292 | GrSurfaceOrigin GrGLSLFragmentShaderBuilder::getSurfaceOrigin() const { |
293 | return fProgramBuilder->origin(); |
294 | } |
295 | |
296 | void GrGLSLFragmentShaderBuilder::onFinalize() { |
297 | SkASSERT(fProgramBuilder->processorFeatures() == fUsedProcessorFeaturesAllStages_DebugOnly); |
298 | |
299 | if (CustomFeatures::kSampleLocations & fProgramBuilder->processorFeatures()) { |
300 | const SkTArray<SkPoint>& sampleLocations = fProgramBuilder->getSampleLocations(); |
301 | this->definitions().appendf("const float2 _sampleOffsets[%i] = float2[%i](" , |
302 | sampleLocations.count(), sampleLocations.count()); |
303 | for (int i = 0; i < sampleLocations.count(); ++i) { |
304 | SkPoint offset = sampleLocations[i] - SkPoint::Make(.5f, .5f); |
305 | if (kBottomLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) { |
306 | offset.fY = -offset.fY; |
307 | } |
308 | this->definitions().appendf("float2(%f, %f)" , offset.x(), offset.y()); |
309 | this->definitions().append((i + 1 != sampleLocations.count()) ? ", " : ");" ); |
310 | } |
311 | } |
312 | |
313 | fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs()); |
314 | } |
315 | |
316 | void GrGLSLFragmentShaderBuilder::onBeforeChildProcEmitCode() { |
317 | SkASSERT(fSubstageIndices.count() >= 1); |
318 | fSubstageIndices.push_back(0); |
319 | // second-to-last value in the fSubstageIndices stack is the index of the child proc |
320 | // at that level which is currently emitting code. |
321 | fMangleString.appendf("_c%d" , fSubstageIndices[fSubstageIndices.count() - 2]); |
322 | } |
323 | |
324 | void GrGLSLFragmentShaderBuilder::onAfterChildProcEmitCode() { |
325 | SkASSERT(fSubstageIndices.count() >= 2); |
326 | fSubstageIndices.pop_back(); |
327 | fSubstageIndices.back()++; |
328 | int removeAt = fMangleString.findLastOf('_'); |
329 | fMangleString.remove(removeAt, fMangleString.size() - removeAt); |
330 | } |
331 | |