blob: c36048a1a64121bca4f1a06e79e9b484e4cce891 [file] [log] [blame]
bsalomon50785a32015-02-06 07:02:37 -08001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/GrXferProcessor.h"
Robert Phillipsbe77a022018-04-03 17:17:05 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/gpu/GrCaps.h"
11#include "src/gpu/GrPipeline.h"
Brian Salomon48959462021-08-11 13:01:06 -040012#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
13#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
bsalomon50785a32015-02-06 07:02:37 -080014
Ethan Nicholasabff9562017-10-09 10:54:08 -040015GrXferProcessor::GrXferProcessor(ClassID classID)
16 : INHERITED(classID)
17 , fWillReadDstColor(false)
Greg Daniel6ebe4b92017-05-19 10:56:46 -040018 , fIsLCD(false) {}
bsalomon50785a32015-02-06 07:02:37 -080019
Chris Dalton57ab06c2021-04-22 12:57:28 -060020GrXferProcessor::GrXferProcessor(ClassID classID, bool willReadDstColor,
Greg Daniel6ebe4b92017-05-19 10:56:46 -040021 GrProcessorAnalysisCoverage coverage)
Ethan Nicholasabff9562017-10-09 10:54:08 -040022 : INHERITED(classID)
23 , fWillReadDstColor(willReadDstColor)
Greg Daniel6ebe4b92017-05-19 10:56:46 -040024 , fIsLCD(GrProcessorAnalysisCoverage::kLCD == coverage) {}
bsalomon50785a32015-02-06 07:02:37 -080025
cdaltonedbb31f2015-06-08 12:14:44 -070026bool GrXferProcessor::hasSecondaryOutput() const {
27 if (!this->willReadDstColor()) {
28 return this->onHasSecondaryOutput();
29 }
Chris Dalton57ab06c2021-04-22 12:57:28 -060030 return false;
cdaltonedbb31f2015-06-08 12:14:44 -070031}
32
Brian Salomon13b28732021-08-06 15:33:58 -040033void GrXferProcessor::addToKey(const GrShaderCaps& caps,
34 GrProcessorKeyBuilder* b,
35 const GrSurfaceOrigin* originIfDstTexture,
36 bool usesInputAttachmentForDstRead) const {
bsalomon50785a32015-02-06 07:02:37 -080037 uint32_t key = this->willReadDstColor() ? 0x1 : 0x0;
cdaltonedbb31f2015-06-08 12:14:44 -070038 if (key) {
Brian Salomon18dfa982017-04-03 16:57:43 -040039 if (originIfDstTexture) {
cdaltonedbb31f2015-06-08 12:14:44 -070040 key |= 0x2;
Brian Salomon18dfa982017-04-03 16:57:43 -040041 if (kTopLeft_GrSurfaceOrigin == *originIfDstTexture) {
cdalton827bae12015-06-08 13:43:33 -070042 key |= 0x4;
43 }
Greg Daniel87fab9f2021-06-07 15:18:23 -040044 if (usesInputAttachmentForDstRead) {
Greg Daniel70dd6a92020-10-09 10:09:06 -040045 key |= 0x8;
46 }
cdaltonedbb31f2015-06-08 12:14:44 -070047 }
bsalomon50785a32015-02-06 07:02:37 -080048 }
Greg Daniel6ebe4b92017-05-19 10:56:46 -040049 if (fIsLCD) {
Chris Dalton57ab06c2021-04-22 12:57:28 -060050 key |= 0x10;
Greg Daniel6ebe4b92017-05-19 10:56:46 -040051 }
bsalomon50785a32015-02-06 07:02:37 -080052 b->add32(key);
Brian Salomon13b28732021-08-06 15:33:58 -040053 this->onAddToKey(caps, b);
bsalomon50785a32015-02-06 07:02:37 -080054}
55
bsalomonf7cc8772015-05-11 11:21:14 -070056#ifdef SK_DEBUG
57static 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";
Mike Klein36743362018-11-06 08:23:30 -050095 case kIllegal_GrBlendEquation:
96 SkASSERT(false);
97 return "<illegal>";
Brian Salomon23356442018-11-30 15:33:19 -050098 }
bsalomonf7cc8772015-05-11 11:21:14 -070099 return "";
100}
101
102static 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";
bsalomonf7cc8772015-05-11 11:21:14 -0700128 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";
Mike Klein36743362018-11-06 08:23:30 -0500136 case kIllegal_GrBlendCoeff:
137 SkASSERT(false);
138 return "<illegal>";
bsalomonf7cc8772015-05-11 11:21:14 -0700139 }
140 return "";
141}
142
143SkString 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),
Brian Osman422f95b2018-11-05 16:49:04 -0500147 coeff_string(fDstBlend), fBlendConstant.toBytes_RGBA());
bsalomonf7cc8772015-05-11 11:21:14 -0700148 return out;
149}
150#endif
151
bsalomon50785a32015-02-06 07:02:37 -0800152///////////////////////////////////////////////////////////////////////////////
153
Brian Salomon31853842017-03-28 16:32:05 -0400154GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties(
155 const GrXPFactory* factory,
Brian Salomona811b122017-03-30 08:21:32 -0400156 const GrProcessorAnalysisColor& color,
157 const GrProcessorAnalysisCoverage& coverage,
Brian Osman5ced0bf2019-03-15 10:15:29 -0400158 const GrCaps& caps,
159 GrClampType clampType) {
Brian Salomon31853842017-03-28 16:32:05 -0400160 AnalysisProperties result;
Brian Salomon5298dc82017-02-22 11:52:03 -0500161 if (factory) {
Chris Dalton57ab06c2021-04-22 12:57:28 -0600162 result = factory->analysisProperties(color, coverage, caps, clampType);
Brian Salomon5298dc82017-02-22 11:52:03 -0500163 } else {
Chris Dalton57ab06c2021-04-22 12:57:28 -0600164 result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps, clampType);
Brian Salomon31853842017-03-28 16:32:05 -0400165 }
Greg Danielc5296812020-02-28 13:06:02 -0500166 if (coverage == GrProcessorAnalysisCoverage::kNone) {
167 result |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
168 }
Brian Salomon31853842017-03-28 16:32:05 -0400169 SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture));
170 if ((result & AnalysisProperties::kReadsDstInShader) &&
171 !caps.shaderCaps()->dstReadInShaderSupport()) {
Chris Dalton945ee652019-01-23 09:10:36 -0700172 result |= AnalysisProperties::kRequiresDstTexture |
173 AnalysisProperties::kRequiresNonOverlappingDraws;
Brian Salomon5298dc82017-02-22 11:52:03 -0500174 }
Brian Salomon5298dc82017-02-22 11:52:03 -0500175 return result;
Brian Salomon9a514982017-02-14 10:28:22 -0500176}
177
Brian Salomond61c9d92017-04-10 10:54:25 -0400178sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory,
179 const GrProcessorAnalysisColor& color,
180 GrProcessorAnalysisCoverage coverage,
Brian Osman5ced0bf2019-03-15 10:15:29 -0400181 const GrCaps& caps,
182 GrClampType clampType) {
Brian Salomona076d872017-04-04 15:17:03 -0400183 if (factory) {
Chris Dalton57ab06c2021-04-22 12:57:28 -0600184 return factory->makeXferProcessor(color, coverage, caps, clampType);
Brian Salomona076d872017-04-04 15:17:03 -0400185 } else {
Chris Dalton57ab06c2021-04-22 12:57:28 -0600186 return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, caps);
Brian Salomona076d872017-04-04 15:17:03 -0400187 }
bsalomon50785a32015-02-06 07:02:37 -0800188}
Brian Salomon48959462021-08-11 13:01:06 -0400189
190//////////////////////////////////////////////////////////////////////////////
191
192using 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.
197static 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
209void 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
267void 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
282void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
283 this->onSetData(pdm, xp);
284}
285
286void 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}