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