• 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/ganesh/GrXferProcessor.h"
9 
10 #include "src/gpu/KeyBuilder.h"
11 #include "src/gpu/ganesh/GrCaps.h"
12 #include "src/gpu/ganesh/GrPipeline.h"
13 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
14 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
15 
GrXferProcessor(ClassID classID)16 GrXferProcessor::GrXferProcessor(ClassID classID)
17         : INHERITED(classID)
18         , fWillReadDstColor(false)
19         , fIsLCD(false) {}
20 
GrXferProcessor(ClassID classID,bool willReadDstColor,GrProcessorAnalysisCoverage coverage)21 GrXferProcessor::GrXferProcessor(ClassID classID, bool willReadDstColor,
22                                  GrProcessorAnalysisCoverage coverage)
23         : INHERITED(classID)
24         , fWillReadDstColor(willReadDstColor)
25         , fIsLCD(GrProcessorAnalysisCoverage::kLCD == coverage) {}
26 
hasSecondaryOutput() const27 bool GrXferProcessor::hasSecondaryOutput() const {
28     if (!this->willReadDstColor()) {
29         return this->onHasSecondaryOutput();
30     }
31     return false;
32 }
33 
addToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b,const GrSurfaceOrigin * originIfDstTexture,bool usesInputAttachmentForDstRead) const34 void GrXferProcessor::addToKey(const GrShaderCaps& caps,
35                                skgpu::KeyBuilder* b,
36                                const GrSurfaceOrigin* originIfDstTexture,
37                                bool usesInputAttachmentForDstRead) const {
38     uint32_t key = this->willReadDstColor() ? 0x1 : 0x0;
39     if (key) {
40         if (originIfDstTexture) {
41             key |= 0x2;
42             if (kTopLeft_GrSurfaceOrigin == *originIfDstTexture) {
43                 key |= 0x4;
44             }
45             if (usesInputAttachmentForDstRead) {
46                 key |= 0x8;
47             }
48         }
49     }
50     if (fIsLCD) {
51         key |= 0x10;
52     }
53     b->add32(key);
54     this->onAddToKey(caps, b);
55 }
56 
57 ///////////////////////////////////////////////////////////////////////////////
58 
GetAnalysisProperties(const GrXPFactory * factory,const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType)59 GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties(
60         const GrXPFactory* factory,
61         const GrProcessorAnalysisColor& color,
62         const GrProcessorAnalysisCoverage& coverage,
63         const GrCaps& caps,
64         GrClampType clampType) {
65     AnalysisProperties result;
66     if (factory) {
67         result = factory->analysisProperties(color, coverage, caps, clampType);
68     } else {
69         result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps, clampType);
70     }
71     if (coverage == GrProcessorAnalysisCoverage::kNone) {
72         result |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
73     }
74     SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture));
75     if ((result & AnalysisProperties::kReadsDstInShader) &&
76         !caps.shaderCaps()->fDstReadInShaderSupport) {
77         result |= AnalysisProperties::kRequiresDstTexture |
78                   AnalysisProperties::kRequiresNonOverlappingDraws;
79     }
80     return result;
81 }
82 
MakeXferProcessor(const GrXPFactory * factory,const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType)83 sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory,
84                                                             const GrProcessorAnalysisColor& color,
85                                                             GrProcessorAnalysisCoverage coverage,
86                                                             const GrCaps& caps,
87                                                             GrClampType clampType) {
88     if (factory) {
89         return factory->makeXferProcessor(color, coverage, caps, clampType);
90     } else {
91         return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, caps);
92     }
93 }
94 
95 //////////////////////////////////////////////////////////////////////////////
96 
97 using ProgramImpl = GrXferProcessor::ProgramImpl;
98 
99 // This is only called for cases where we are doing LCD coverage and not using in shader blending.
100 // For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha
101 // 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)102 static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder,
103                                     const char* srcCoverage,
104                                     const GrXferProcessor& proc) {
105     if (srcCoverage && proc.isLCD()) {
106         fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);",
107                                  srcCoverage,
108                                  srcCoverage,
109                                  srcCoverage,
110                                  srcCoverage);
111     }
112 }
113 
emitCode(const EmitArgs & args)114 void ProgramImpl::emitCode(const EmitArgs& args) {
115     if (!args.fXP.willReadDstColor()) {
116         adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP);
117         this->emitOutputsForBlendState(args);
118     } else {
119         GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
120         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
121         const char* dstColor = fragBuilder->dstColor();
122 
123         bool needsLocalOutColor = false;
124 
125         if (args.fDstTextureSamplerHandle.isValid()) {
126             if (args.fInputCoverage) {
127                 // We don't think any shaders actually output negative coverage, but just as a
128                 // safety check for floating point precision errors, we compare with <= here. We
129                 // just check the RGB values of the coverage, since the alpha may not have been set
130                 // when using LCD. If we are using single-channel coverage, alpha will be equal to
131                 // RGB anyway.
132                 //
133                 // The discard here also helps for batching text-draws together, which need to read
134                 // from a dst copy for blends. However, this only helps the case where the outer
135                 // bounding boxes of each letter overlap and not two actually parts of the text.
136                 fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, half3(0)))) {"
137                                          "    discard;"
138                                          "}",
139                                          args.fInputCoverage);
140             }
141         } else {
142             needsLocalOutColor = args.fShaderCaps->fRequiresLocalOutputColorForFBFetch;
143         }
144 
145         const char* outColor = "_localColorOut";
146         if (!needsLocalOutColor) {
147             outColor = args.fOutputPrimary;
148         } else {
149             fragBuilder->codeAppendf("half4 %s;", outColor);
150         }
151 
152         this->emitBlendCodeForDstRead(fragBuilder,
153                                       uniformHandler,
154                                       args.fInputColor,
155                                       args.fInputCoverage,
156                                       dstColor,
157                                       outColor,
158                                       args.fOutputSecondary,
159                                       args.fXP);
160         if (needsLocalOutColor) {
161             fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor);
162         }
163     }
164 
165     // Swizzle the fragment shader outputs if necessary.
166     this->emitWriteSwizzle(args.fXPFragBuilder,
167                            args.fWriteSwizzle,
168                            args.fOutputPrimary,
169                            args.fOutputSecondary);
170 }
171 
emitWriteSwizzle(GrGLSLXPFragmentBuilder * x,const skgpu::Swizzle & swizzle,const char * outColor,const char * outColorSecondary) const172 void ProgramImpl::emitWriteSwizzle(GrGLSLXPFragmentBuilder* x,
173                                    const skgpu::Swizzle& swizzle,
174                                    const char* outColor,
175                                    const char* outColorSecondary) const {
176     if (skgpu::Swizzle::RGBA() != swizzle) {
177         x->codeAppendf("%s = %s.%s;", outColor, outColor, swizzle.asString().c_str());
178         if (outColorSecondary) {
179             x->codeAppendf("%s = %s.%s;",
180                            outColorSecondary,
181                            outColorSecondary,
182                            swizzle.asString().c_str());
183         }
184     }
185 }
186 
setData(const GrGLSLProgramDataManager & pdm,const GrXferProcessor & xp)187 void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
188     this->onSetData(pdm, xp);
189 }
190 
DefaultCoverageModulation(GrGLSLXPFragmentBuilder * fragBuilder,const char * srcCoverage,const char * dstColor,const char * outColor,const char * outColorSecondary,const GrXferProcessor & proc)191 void ProgramImpl::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
192                                             const char* srcCoverage,
193                                             const char* dstColor,
194                                             const char* outColor,
195                                             const char* outColorSecondary,
196                                             const GrXferProcessor& proc) {
197     if (srcCoverage) {
198         if (proc.isLCD()) {
199             fragBuilder->codeAppendf("half3 lerpRGB = mix(%s.aaa, %s.aaa, %s.rgb);",
200                                      dstColor,
201                                      outColor,
202                                      srcCoverage);
203         }
204         fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;",
205                                  outColor,
206                                  srcCoverage,
207                                  outColor,
208                                  srcCoverage,
209                                  dstColor);
210         if (proc.isLCD()) {
211             fragBuilder->codeAppendf("%s.a = max(max(lerpRGB.r, lerpRGB.b), lerpRGB.g);", outColor);
212         }
213     }
214 }
215