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