• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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/GrXferProcessor.h"
9 
10 #include "src/gpu/GrCaps.h"
11 #include "src/gpu/GrPipeline.h"
12 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
13 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
14 
GrXferProcessor(ClassID classID)15 GrXferProcessor::GrXferProcessor(ClassID classID)
16         : INHERITED(classID)
17         , fWillReadDstColor(false)
18         , fIsLCD(false) {}
19 
GrXferProcessor(ClassID classID,bool willReadDstColor,GrProcessorAnalysisCoverage coverage)20 GrXferProcessor::GrXferProcessor(ClassID classID, bool willReadDstColor,
21                                  GrProcessorAnalysisCoverage coverage)
22         : INHERITED(classID)
23         , fWillReadDstColor(willReadDstColor)
24         , fIsLCD(GrProcessorAnalysisCoverage::kLCD == coverage) {}
25 
hasSecondaryOutput() const26 bool GrXferProcessor::hasSecondaryOutput() const {
27     if (!this->willReadDstColor()) {
28         return this->onHasSecondaryOutput();
29     }
30     return false;
31 }
32 
addToKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b,const GrSurfaceOrigin * originIfDstTexture,bool usesInputAttachmentForDstRead) const33 void GrXferProcessor::addToKey(const GrShaderCaps& caps,
34                                GrProcessorKeyBuilder* b,
35                                const GrSurfaceOrigin* originIfDstTexture,
36                                bool usesInputAttachmentForDstRead) const {
37     uint32_t key = this->willReadDstColor() ? 0x1 : 0x0;
38     if (key) {
39         if (originIfDstTexture) {
40             key |= 0x2;
41             if (kTopLeft_GrSurfaceOrigin == *originIfDstTexture) {
42                 key |= 0x4;
43             }
44             if (usesInputAttachmentForDstRead) {
45                 key |= 0x8;
46             }
47         }
48     }
49     if (fIsLCD) {
50         key |= 0x10;
51     }
52     b->add32(key);
53     this->onAddToKey(caps, b);
54 }
55 
56 #ifdef SK_DEBUG
equation_string(GrBlendEquation eq)57 static const char* equation_string(GrBlendEquation eq) {
58     switch (eq) {
59         case kAdd_GrBlendEquation:
60             return "add";
61         case kSubtract_GrBlendEquation:
62             return "subtract";
63         case kReverseSubtract_GrBlendEquation:
64             return "reverse_subtract";
65         case kScreen_GrBlendEquation:
66             return "screen";
67         case kOverlay_GrBlendEquation:
68             return "overlay";
69         case kDarken_GrBlendEquation:
70             return "darken";
71         case kLighten_GrBlendEquation:
72             return "lighten";
73         case kColorDodge_GrBlendEquation:
74             return "color_dodge";
75         case kColorBurn_GrBlendEquation:
76             return "color_burn";
77         case kHardLight_GrBlendEquation:
78             return "hard_light";
79         case kSoftLight_GrBlendEquation:
80             return "soft_light";
81         case kDifference_GrBlendEquation:
82             return "difference";
83         case kExclusion_GrBlendEquation:
84             return "exclusion";
85         case kMultiply_GrBlendEquation:
86             return "multiply";
87         case kHSLHue_GrBlendEquation:
88             return "hsl_hue";
89         case kHSLSaturation_GrBlendEquation:
90             return "hsl_saturation";
91         case kHSLColor_GrBlendEquation:
92             return "hsl_color";
93         case kHSLLuminosity_GrBlendEquation:
94             return "hsl_luminosity";
95         case kIllegal_GrBlendEquation:
96             SkASSERT(false);
97             return "<illegal>";
98     }
99     return "";
100 }
101 
coeff_string(GrBlendCoeff coeff)102 static const char* coeff_string(GrBlendCoeff coeff) {
103     switch (coeff) {
104         case kZero_GrBlendCoeff:
105             return "zero";
106         case kOne_GrBlendCoeff:
107             return "one";
108         case kSC_GrBlendCoeff:
109             return "src_color";
110         case kISC_GrBlendCoeff:
111             return "inv_src_color";
112         case kDC_GrBlendCoeff:
113             return "dst_color";
114         case kIDC_GrBlendCoeff:
115             return "inv_dst_color";
116         case kSA_GrBlendCoeff:
117             return "src_alpha";
118         case kISA_GrBlendCoeff:
119             return "inv_src_alpha";
120         case kDA_GrBlendCoeff:
121             return "dst_alpha";
122         case kIDA_GrBlendCoeff:
123             return "inv_dst_alpha";
124         case kConstC_GrBlendCoeff:
125             return "const_color";
126         case kIConstC_GrBlendCoeff:
127             return "inv_const_color";
128         case kS2C_GrBlendCoeff:
129             return "src2_color";
130         case kIS2C_GrBlendCoeff:
131             return "inv_src2_color";
132         case kS2A_GrBlendCoeff:
133             return "src2_alpha";
134         case kIS2A_GrBlendCoeff:
135             return "inv_src2_alpha";
136         case kIllegal_GrBlendCoeff:
137             SkASSERT(false);
138             return "<illegal>";
139     }
140     return "";
141 }
142 
dump() const143 SkString GrXferProcessor::BlendInfo::dump() const {
144     SkString out;
145     out.printf("write_color(%d) equation(%s) src_coeff(%s) dst_coeff:(%s) const(0x%08x)",
146                fWriteColor, equation_string(fEquation), coeff_string(fSrcBlend),
147                coeff_string(fDstBlend), fBlendConstant.toBytes_RGBA());
148     return out;
149 }
150 #endif
151 
152 ///////////////////////////////////////////////////////////////////////////////
153 
GetAnalysisProperties(const GrXPFactory * factory,const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType)154 GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties(
155         const GrXPFactory* factory,
156         const GrProcessorAnalysisColor& color,
157         const GrProcessorAnalysisCoverage& coverage,
158         const GrCaps& caps,
159         GrClampType clampType) {
160     AnalysisProperties result;
161     if (factory) {
162         result = factory->analysisProperties(color, coverage, caps, clampType);
163     } else {
164         result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps, clampType);
165     }
166     if (coverage == GrProcessorAnalysisCoverage::kNone) {
167         result |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
168     }
169     SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture));
170     if ((result & AnalysisProperties::kReadsDstInShader) &&
171         !caps.shaderCaps()->dstReadInShaderSupport()) {
172         result |= AnalysisProperties::kRequiresDstTexture |
173                   AnalysisProperties::kRequiresNonOverlappingDraws;
174     }
175     return result;
176 }
177 
MakeXferProcessor(const GrXPFactory * factory,const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType)178 sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory,
179                                                             const GrProcessorAnalysisColor& color,
180                                                             GrProcessorAnalysisCoverage coverage,
181                                                             const GrCaps& caps,
182                                                             GrClampType clampType) {
183     if (factory) {
184         return factory->makeXferProcessor(color, coverage, caps, clampType);
185     } else {
186         return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, caps);
187     }
188 }
189 
190 //////////////////////////////////////////////////////////////////////////////
191 
192 using ProgramImpl = GrXferProcessor::ProgramImpl;
193 
194 // This is only called for cases where we are doing LCD coverage and not using in shader blending.
195 // For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha
196 // coverage since src alpha will always be greater than or equal to dst alpha.
adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder * fragBuilder,const char * srcCoverage,const GrXferProcessor & proc)197 static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder,
198                                     const char* srcCoverage,
199                                     const GrXferProcessor& proc) {
200     if (srcCoverage && proc.isLCD()) {
201         fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);",
202                                  srcCoverage,
203                                  srcCoverage,
204                                  srcCoverage,
205                                  srcCoverage);
206     }
207 }
208 
emitCode(const EmitArgs & args)209 void ProgramImpl::emitCode(const EmitArgs& args) {
210     if (!args.fXP.willReadDstColor()) {
211         adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP);
212         this->emitOutputsForBlendState(args);
213     } else {
214         GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
215         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
216         const char* dstColor = fragBuilder->dstColor();
217 
218         bool needsLocalOutColor = false;
219 
220         if (args.fDstTextureSamplerHandle.isValid()) {
221             if (args.fInputCoverage) {
222                 // We don't think any shaders actually output negative coverage, but just as a
223                 // safety check for floating point precision errors, we compare with <= here. We
224                 // just check the RGB values of the coverage, since the alpha may not have been set
225                 // when using LCD. If we are using single-channel coverage, alpha will be equal to
226                 // RGB anyway.
227                 //
228                 // The discard here also helps for batching text-draws together, which need to read
229                 // from a dst copy for blends. However, this only helps the case where the outer
230                 // bounding boxes of each letter overlap and not two actually parts of the text.
231                 fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, half3(0)))) {"
232                                          "    discard;"
233                                          "}",
234                                          args.fInputCoverage);
235             }
236         } else {
237             needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch();
238         }
239 
240         const char* outColor = "_localColorOut";
241         if (!needsLocalOutColor) {
242             outColor = args.fOutputPrimary;
243         } else {
244             fragBuilder->codeAppendf("half4 %s;", outColor);
245         }
246 
247         this->emitBlendCodeForDstRead(fragBuilder,
248                                       uniformHandler,
249                                       args.fInputColor,
250                                       args.fInputCoverage,
251                                       dstColor,
252                                       outColor,
253                                       args.fOutputSecondary,
254                                       args.fXP);
255         if (needsLocalOutColor) {
256             fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor);
257         }
258     }
259 
260     // Swizzle the fragment shader outputs if necessary.
261     this->emitWriteSwizzle(args.fXPFragBuilder,
262                            args.fWriteSwizzle,
263                            args.fOutputPrimary,
264                            args.fOutputSecondary);
265 }
266 
emitWriteSwizzle(GrGLSLXPFragmentBuilder * x,const GrSwizzle & swizzle,const char * outColor,const char * outColorSecondary) const267 void ProgramImpl::emitWriteSwizzle(GrGLSLXPFragmentBuilder* x,
268                                    const GrSwizzle& swizzle,
269                                    const char* outColor,
270                                    const char* outColorSecondary) const {
271     if (GrSwizzle::RGBA() != swizzle) {
272         x->codeAppendf("%s = %s.%s;", outColor, outColor, swizzle.asString().c_str());
273         if (outColorSecondary) {
274             x->codeAppendf("%s = %s.%s;",
275                            outColorSecondary,
276                            outColorSecondary,
277                            swizzle.asString().c_str());
278         }
279     }
280 }
281 
setData(const GrGLSLProgramDataManager & pdm,const GrXferProcessor & xp)282 void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
283     this->onSetData(pdm, xp);
284 }
285 
DefaultCoverageModulation(GrGLSLXPFragmentBuilder * fragBuilder,const char * srcCoverage,const char * dstColor,const char * outColor,const char * outColorSecondary,const GrXferProcessor & proc)286 void ProgramImpl::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
287                                             const char* srcCoverage,
288                                             const char* dstColor,
289                                             const char* outColor,
290                                             const char* outColorSecondary,
291                                             const GrXferProcessor& proc) {
292     if (srcCoverage) {
293         if (proc.isLCD()) {
294             fragBuilder->codeAppendf("half3 lerpRGB = mix(%s.aaa, %s.aaa, %s.rgb);",
295                                      dstColor,
296                                      outColor,
297                                      srcCoverage);
298         }
299         fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;",
300                                  outColor,
301                                  srcCoverage,
302                                  outColor,
303                                  srcCoverage,
304                                  dstColor);
305         if (proc.isLCD()) {
306             fragBuilder->codeAppendf("%s.a = max(max(lerpRGB.r, lerpRGB.b), lerpRGB.g);", outColor);
307         }
308     }
309 }
310