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