2 * Copyright 2015 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "src/gpu/ganesh/GrXferProcessor.h"
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"
16 GrXferProcessor::GrXferProcessor(ClassID classID)
18 , fWillReadDstColor(false)
21 GrXferProcessor::GrXferProcessor(ClassID classID, bool willReadDstColor,
22 GrProcessorAnalysisCoverage coverage)
24 , fWillReadDstColor(willReadDstColor)
25 , fIsLCD(GrProcessorAnalysisCoverage::kLCD == coverage) {}
27 bool GrXferProcessor::hasSecondaryOutput() const {
28 if (!this->willReadDstColor()) {
29 return this->onHasSecondaryOutput();
34 void GrXferProcessor::addToKey(const GrShaderCaps& caps,
36 const GrSurfaceOrigin* originIfDstTexture,
37 bool usesInputAttachmentForDstRead) const {
38 uint32_t key = this->willReadDstColor() ? 0x1 : 0x0;
40 if (originIfDstTexture) {
42 if (kTopLeft_GrSurfaceOrigin == *originIfDstTexture) {
45 if (usesInputAttachmentForDstRead) {
54 this->onAddToKey(caps, b);
58 static const char* equation_string(skgpu::BlendEquation eq) {
60 case skgpu::BlendEquation::kAdd:
62 case skgpu::BlendEquation::kSubtract:
64 case skgpu::BlendEquation::kReverseSubtract:
65 return "reverse_subtract";
66 case skgpu::BlendEquation::kScreen:
68 case skgpu::BlendEquation::kOverlay:
70 case skgpu::BlendEquation::kDarken:
72 case skgpu::BlendEquation::kLighten:
74 case skgpu::BlendEquation::kColorDodge:
76 case skgpu::BlendEquation::kColorBurn:
78 case skgpu::BlendEquation::kHardLight:
80 case skgpu::BlendEquation::kSoftLight:
82 case skgpu::BlendEquation::kDifference:
84 case skgpu::BlendEquation::kExclusion:
86 case skgpu::BlendEquation::kMultiply:
88 case skgpu::BlendEquation::kHSLHue:
90 case skgpu::BlendEquation::kHSLSaturation:
91 return "hsl_saturation";
92 case skgpu::BlendEquation::kHSLColor:
94 case skgpu::BlendEquation::kHSLLuminosity:
95 return "hsl_luminosity";
96 case skgpu::BlendEquation::kIllegal:
103 static const char* coeff_string(skgpu::BlendCoeff coeff) {
105 case skgpu::BlendCoeff::kZero:
107 case skgpu::BlendCoeff::kOne:
109 case skgpu::BlendCoeff::kSC:
111 case skgpu::BlendCoeff::kISC:
112 return "inv_src_color";
113 case skgpu::BlendCoeff::kDC:
115 case skgpu::BlendCoeff::kIDC:
116 return "inv_dst_color";
117 case skgpu::BlendCoeff::kSA:
119 case skgpu::BlendCoeff::kISA:
120 return "inv_src_alpha";
121 case skgpu::BlendCoeff::kDA:
123 case skgpu::BlendCoeff::kIDA:
124 return "inv_dst_alpha";
125 case skgpu::BlendCoeff::kConstC:
126 return "const_color";
127 case skgpu::BlendCoeff::kIConstC:
128 return "inv_const_color";
129 case skgpu::BlendCoeff::kS2C:
131 case skgpu::BlendCoeff::kIS2C:
132 return "inv_src2_color";
133 case skgpu::BlendCoeff::kS2A:
135 case skgpu::BlendCoeff::kIS2A:
136 return "inv_src2_alpha";
137 case skgpu::BlendCoeff::kIllegal:
144 SkString GrXferProcessor::BlendInfo::dump() const {
146 out.printf("write_color(%d) equation(%s) src_coeff(%s) dst_coeff:(%s) const(0x%08x)",
147 fWriteColor, equation_string(fEquation), coeff_string(fSrcBlend),
148 coeff_string(fDstBlend), fBlendConstant.toBytes_RGBA());
153 ///////////////////////////////////////////////////////////////////////////////
155 GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties(
156 const GrXPFactory* factory,
157 const GrProcessorAnalysisColor& color,
158 const GrProcessorAnalysisCoverage& coverage,
160 GrClampType clampType) {
161 AnalysisProperties result;
163 result = factory->analysisProperties(color, coverage, caps, clampType);
165 result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps, clampType);
167 if (coverage == GrProcessorAnalysisCoverage::kNone) {
168 result |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
170 SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture));
171 if ((result & AnalysisProperties::kReadsDstInShader) &&
172 !caps.shaderCaps()->dstReadInShaderSupport()) {
173 result |= AnalysisProperties::kRequiresDstTexture |
174 AnalysisProperties::kRequiresNonOverlappingDraws;
179 sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory,
180 const GrProcessorAnalysisColor& color,
181 GrProcessorAnalysisCoverage coverage,
183 GrClampType clampType) {
185 return factory->makeXferProcessor(color, coverage, caps, clampType);
187 return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, caps);
191 //////////////////////////////////////////////////////////////////////////////
193 using ProgramImpl = GrXferProcessor::ProgramImpl;
195 // This is only called for cases where we are doing LCD coverage and not using in shader blending.
196 // For these cases we assume the the src alpha is 1, thus we can just use the max for the alpha
197 // coverage since src alpha will always be greater than or equal to dst alpha.
198 static void adjust_for_lcd_coverage(GrGLSLXPFragmentBuilder* fragBuilder,
199 const char* srcCoverage,
200 const GrXferProcessor& proc) {
201 if (srcCoverage && proc.isLCD()) {
202 fragBuilder->codeAppendf("%s.a = max(max(%s.r, %s.g), %s.b);",
210 void ProgramImpl::emitCode(const EmitArgs& args) {
211 if (!args.fXP.willReadDstColor()) {
212 adjust_for_lcd_coverage(args.fXPFragBuilder, args.fInputCoverage, args.fXP);
213 this->emitOutputsForBlendState(args);
215 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
216 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
217 const char* dstColor = fragBuilder->dstColor();
219 bool needsLocalOutColor = false;
221 if (args.fDstTextureSamplerHandle.isValid()) {
222 if (args.fInputCoverage) {
223 // We don't think any shaders actually output negative coverage, but just as a
224 // safety check for floating point precision errors, we compare with <= here. We
225 // just check the RGB values of the coverage, since the alpha may not have been set
226 // when using LCD. If we are using single-channel coverage, alpha will be equal to
229 // The discard here also helps for batching text-draws together, which need to read
230 // from a dst copy for blends. However, this only helps the case where the outer
231 // bounding boxes of each letter overlap and not two actually parts of the text.
232 fragBuilder->codeAppendf("if (all(lessThanEqual(%s.rgb, half3(0)))) {"
235 args.fInputCoverage);
238 needsLocalOutColor = args.fShaderCaps->requiresLocalOutputColorForFBFetch();
241 const char* outColor = "_localColorOut";
242 if (!needsLocalOutColor) {
243 outColor = args.fOutputPrimary;
245 fragBuilder->codeAppendf("half4 %s;", outColor);
248 this->emitBlendCodeForDstRead(fragBuilder,
254 args.fOutputSecondary,
256 if (needsLocalOutColor) {
257 fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, outColor);
261 // Swizzle the fragment shader outputs if necessary.
262 this->emitWriteSwizzle(args.fXPFragBuilder,
265 args.fOutputSecondary);
268 void ProgramImpl::emitWriteSwizzle(GrGLSLXPFragmentBuilder* x,
269 const skgpu::Swizzle& swizzle,
270 const char* outColor,
271 const char* outColorSecondary) const {
272 if (skgpu::Swizzle::RGBA() != swizzle) {
273 x->codeAppendf("%s = %s.%s;", outColor, outColor, swizzle.asString().c_str());
274 if (outColorSecondary) {
275 x->codeAppendf("%s = %s.%s;",
278 swizzle.asString().c_str());
283 void ProgramImpl::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
284 this->onSetData(pdm, xp);
287 void ProgramImpl::DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder,
288 const char* srcCoverage,
289 const char* dstColor,
290 const char* outColor,
291 const char* outColorSecondary,
292 const GrXferProcessor& proc) {
295 fragBuilder->codeAppendf("half3 lerpRGB = mix(%s.aaa, %s.aaa, %s.rgb);",
300 fragBuilder->codeAppendf("%s = %s * %s + (half4(1.0) - %s) * %s;",
307 fragBuilder->codeAppendf("%s.a = max(max(lerpRGB.r, lerpRGB.b), lerpRGB.g);", outColor);