blob: 2b4b1334f89828b96cc142a688f8492437f7dcfa [file] [log] [blame]
egdaniel378092f2014-12-03 10:40:13 -08001/*
2 * Copyright 2014 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
egdanielced90102014-12-05 12:40:52 -08008#include "effects/GrPorterDuffXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -08009
egdaniel95131432014-12-09 11:15:43 -080010#include "GrBlend.h"
egdaniel378092f2014-12-03 10:40:13 -080011#include "GrDrawState.h"
12#include "GrInvariantOutput.h"
13#include "GrProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -080014#include "GrTypes.h"
15#include "GrXferProcessor.h"
16#include "gl/GrGLProcessor.h"
17#include "gl/builders/GrGLFragmentShaderBuilder.h"
18#include "gl/builders/GrGLProgramBuilder.h"
19
egdaniel95131432014-12-09 11:15:43 -080020static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageDrawing) {
21 /*
22 The fractional coverage is f.
23 The src and dst coeffs are Cs and Cd.
24 The dst and src colors are S and D.
25 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
26 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
27 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
28 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
29 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
30 color by definition.
31 */
32 // TODO: Once we have a CoverageDrawing XP, we don't need to check is CoverageDrawing here
33 return kOne_GrBlendCoeff == dstCoeff ||
34 kISA_GrBlendCoeff == dstCoeff ||
35 kISC_GrBlendCoeff == dstCoeff ||
36 isCoverageDrawing;
37}
38
egdaniel378092f2014-12-03 10:40:13 -080039class GrGLPorterDuffXferProcessor : public GrGLXferProcessor {
40public:
joshualitteb2a6762014-12-04 11:35:33 -080041 GrGLPorterDuffXferProcessor(const GrProcessor&) {}
egdaniel378092f2014-12-03 10:40:13 -080042
43 virtual ~GrGLPorterDuffXferProcessor() {}
44
45 virtual void emitCode(GrGLFPBuilder* builder,
46 const GrFragmentProcessor& fp,
47 const char* outputColor,
48 const char* inputColor,
49 const TransformedCoordsArray& coords,
50 const TextureSamplerArray& samplers) SK_OVERRIDE {
51 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
52 fsBuilder->codeAppendf("%s = %s;", outputColor, inputColor);
53 }
54
55 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {};
56
57 static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyBuilder* b) {};
58
59private:
60 typedef GrGLXferProcessor INHERITED;
61};
62
63///////////////////////////////////////////////////////////////////////////////
64
egdaniel95131432014-12-09 11:15:43 -080065GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
66 GrColor constant)
67 : fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) {
joshualitteb2a6762014-12-04 11:35:33 -080068 this->initClassID<GrPorterDuffXferProcessor>();
69}
egdaniel378092f2014-12-03 10:40:13 -080070
71GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() {
72}
73
joshualitteb2a6762014-12-04 11:35:33 -080074void GrPorterDuffXferProcessor::getGLProcessorKey(const GrGLCaps& caps,
75 GrProcessorKeyBuilder* b) const {
76 GrGLPorterDuffXferProcessor::GenKey(*this, caps, b);
77}
78
79GrGLFragmentProcessor* GrPorterDuffXferProcessor::createGLInstance() const {
80 return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this));
egdaniel378092f2014-12-03 10:40:13 -080081}
82
83void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const {
egdaniel95131432014-12-09 11:15:43 -080084 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
egdaniel378092f2014-12-03 10:40:13 -080085}
86
egdaniel95131432014-12-09 11:15:43 -080087GrXferProcessor::OptFlags
88GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
89 const GrProcOptInfo& coveragePOI,
90 bool isCoverageDrawing,
91 bool colorWriteDisabled,
92 bool doesStencilWrite,
93 GrColor* color, uint8_t* coverage) {
94 if (colorWriteDisabled) {
95 fSrcBlend = kZero_GrBlendCoeff;
96 fDstBlend = kOne_GrBlendCoeff;
97 }
98
99 bool srcAIsOne;
100 bool hasCoverage;
101 if (isCoverageDrawing) {
102 srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque();
103 hasCoverage = false;
104 } else {
105 srcAIsOne = colorPOI.isOpaque();
106 hasCoverage = !coveragePOI.isSolidWhite();
107 }
108
109 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
110 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
111 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
112 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
113
114 // Optimizations when doing RGB Coverage
115 if (coveragePOI.isFourChannelOutput()) {
116 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
117 // value of the blend the constant. We should already have valid blend coeff's if we are at
118 // a point where we have RGB coverage. We don't need any color stages since the known color
119 // output is already baked into the blendConstant.
120 uint8_t alpha = GrColorUnpackA(fBlendConstant);
121 *color = GrColorPackRGBA(alpha, alpha, alpha, alpha);
122 return GrXferProcessor::kClearColorStages_OptFlag;
123 }
124
125 // When coeffs are (0,1) there is no reason to draw at all, unless
126 // stenciling is enabled. Having color writes disabled is effectively
127 // (0,1).
128 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
129 if (doesStencilWrite) {
130 *color = 0xffffffff;
131 return GrXferProcessor::kClearColorStages_OptFlag |
132 GrXferProcessor::kSetCoverageDrawing_OptFlag;
133 } else {
134 fDstBlend = kOne_GrBlendCoeff;
135 return GrXferProcessor::kSkipDraw_OptFlag;
136 }
137 }
138
139 // if we don't have coverage we can check whether the dst
140 // has to read at all. If not, we'll disable blending.
141 if (!hasCoverage) {
142 if (dstCoeffIsZero) {
143 if (kOne_GrBlendCoeff == fSrcBlend) {
144 // if there is no coverage and coeffs are (1,0) then we
145 // won't need to read the dst at all, it gets replaced by src
146 fDstBlend = kZero_GrBlendCoeff;
147 return GrXferProcessor::kNone_Opt;
148 } else if (kZero_GrBlendCoeff == fSrcBlend) {
149 // if the op is "clear" then we don't need to emit a color
150 // or blend, just write transparent black into the dst.
151 fSrcBlend = kOne_GrBlendCoeff;
152 fDstBlend = kZero_GrBlendCoeff;
153 *color = 0;
154 *coverage = 0xff;
155 return GrXferProcessor::kClearColorStages_OptFlag |
156 GrXferProcessor::kClearCoverageStages_OptFlag;
157 }
158 }
159 } else if (isCoverageDrawing) {
160 // we have coverage but we aren't distinguishing it from alpha by request.
161 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
162 } else {
163 // check whether coverage can be safely rolled into alpha
164 // of if we can skip color computation and just emit coverage
165 if (can_tweak_alpha_for_coverage(fDstBlend, isCoverageDrawing)) {
166 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
167 }
168 if (dstCoeffIsZero) {
169 if (kZero_GrBlendCoeff == fSrcBlend) {
170 // the source color is not included in the blend
171 // the dst coeff is effectively zero so blend works out to:
172 // (c)(0)D + (1-c)D = (1-c)D.
173 fDstBlend = kISA_GrBlendCoeff;
174 *color = 0xffffffff;
175 return GrXferProcessor::kClearColorStages_OptFlag |
176 GrXferProcessor::kSetCoverageDrawing_OptFlag;
177 } else if (srcAIsOne) {
178 // the dst coeff is effectively zero so blend works out to:
179 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
180 // If Sa is 1 then we can replace Sa with c
181 // and set dst coeff to 1-Sa.
182 fDstBlend = kISA_GrBlendCoeff;
183 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
184 }
185 } else if (dstCoeffIsOne) {
186 // the dst coeff is effectively one so blend works out to:
187 // cS + (c)(1)D + (1-c)D = cS + D.
188 fDstBlend = kOne_GrBlendCoeff;
189 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
190 }
191 }
192
193 return GrXferProcessor::kNone_Opt;
194}
egdaniel378092f2014-12-03 10:40:13 -0800195///////////////////////////////////////////////////////////////////////////////
196
egdaniel915187b2014-12-05 12:58:28 -0800197GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800198 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800199 this->initClassID<GrPorterDuffXPFactory>();
200}
201
egdanielc016fb82014-12-03 11:41:54 -0800202GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
203 switch (mode) {
204 case SkXfermode::kClear_Mode: {
205 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
206 return SkRef(&gClearPDXPF);
207 break;
208 }
209 case SkXfermode::kSrc_Mode: {
210 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
211 return SkRef(&gSrcPDXPF);
212 break;
213 }
214 case SkXfermode::kDst_Mode: {
215 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
216 return SkRef(&gDstPDXPF);
217 break;
218 }
219 case SkXfermode::kSrcOver_Mode: {
220 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
221 return SkRef(&gSrcOverPDXPF);
222 break;
223 }
224 case SkXfermode::kDstOver_Mode: {
225 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
226 return SkRef(&gDstOverPDXPF);
227 break;
228 }
229 case SkXfermode::kSrcIn_Mode: {
230 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
231 return SkRef(&gSrcInPDXPF);
232 break;
233 }
234 case SkXfermode::kDstIn_Mode: {
235 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
236 return SkRef(&gDstInPDXPF);
237 break;
238 }
239 case SkXfermode::kSrcOut_Mode: {
240 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
241 return SkRef(&gSrcOutPDXPF);
242 break;
243 }
244 case SkXfermode::kDstOut_Mode: {
245 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
246 return SkRef(&gDstOutPDXPF);
247 break;
248 }
249 case SkXfermode::kSrcATop_Mode: {
250 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
251 return SkRef(&gSrcATopPDXPF);
252 break;
253 }
254 case SkXfermode::kDstATop_Mode: {
255 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
256 return SkRef(&gDstATopPDXPF);
257 break;
258 }
259 case SkXfermode::kXor_Mode: {
260 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
261 return SkRef(&gXorPDXPF);
262 break;
263 }
264 case SkXfermode::kPlus_Mode: {
265 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
266 return SkRef(&gPlusPDXPF);
267 break;
268 }
269 case SkXfermode::kModulate_Mode: {
270 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
271 return SkRef(&gModulatePDXPF);
272 break;
273 }
274 case SkXfermode::kScreen_Mode: {
275 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
276 return SkRef(&gScreenPDXPF);
277 break;
278 }
279 default:
280 return NULL;
281 }
282}
283
egdaniel95131432014-12-09 11:15:43 -0800284GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI,
285 const GrProcOptInfo& covPOI) const {
286 if (!covPOI.isFourChannelOutput()) {
287 return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff);
288 } else {
289 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
290 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
291 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
292 return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
293 blendConstant);
294 } else {
295 return NULL;
296 }
297 }
egdaniel378092f2014-12-03 10:40:13 -0800298}
299
300bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
301 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800302 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800303 kRGBA_GrColorComponentFlags == knownColorFlags) {
304 return true;
305 }
306 return false;
307}
308
egdaniel95131432014-12-09 11:15:43 -0800309bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI,
310 const GrProcOptInfo& coveragePOI,
311 bool isCoverageDrawing,
312 bool colorWriteDisabled) const {
313 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
314
315 if (colorWriteDisabled) {
316 return true;
317 }
318
319 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff ||
320 (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne);
321 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff ||
322 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne);
323
324 if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) {
325 return true;
326 }
327
328 // if we don't have coverage we can check whether the dst
329 // has to read at all.
330 if (isCoverageDrawing) {
331 // we have coverage but we aren't distinguishing it from alpha by request.
332 return true;
333 } else {
334 // check whether coverage can be safely rolled into alpha
335 // of if we can skip color computation and just emit coverage
336 if (this->canTweakAlphaForCoverage(isCoverageDrawing)) {
337 return true;
338 }
339 if (dstCoeffIsZero) {
340 if (kZero_GrBlendCoeff == fSrcCoeff) {
341 return true;
342 } else if (srcAIsOne) {
343 return true;
344 }
345 } else if (dstCoeffIsOne) {
346 return true;
347 }
348 }
349
350 // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
351 // will readDst and PD XP's don't read dst.
352 if ((colorPOI.readsDst() || coveragePOI.readsDst()) &&
353 kOne_GrBlendCoeff == fSrcCoeff && kZero_GrBlendCoeff == fDstCoeff) {
354 return true;
355 }
356
357 return false;
358}
359
360bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI,
361 const GrProcOptInfo& coveragePOI,
362 bool isCoverageDrawing,
363 bool colorWriteDisabled) const {
364 if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) {
365 return true;
366 }
367
368 // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
369 // will readDst and PD XP's don't read dst.
370 if ((!colorWriteDisabled && colorPOI.readsDst()) || coveragePOI.readsDst()) {
371 return true;
372 }
373
374 if (GrBlendCoeffRefsDst(fSrcCoeff)) {
375 return true;
376 }
377
378 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
379
380 if (!(kZero_GrBlendCoeff == fDstCoeff ||
381 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) {
382 return true;
383 }
384
385 return false;
386}
387
388bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) const {
389 return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing);
390}
391
392bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
393 const GrProcOptInfo& coveragePOI,
394 GrColor* solidColor,
395 uint32_t* solidColorKnownComponents) const {
396 if (!coveragePOI.isSolidWhite()) {
397 return false;
398 }
399
400 SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents));
401
402 GrBlendCoeff srcCoeff = fSrcCoeff;
403 GrBlendCoeff dstCoeff = fDstCoeff;
404
405 // TODO: figure out to merge this simplify with other current optimization code paths and
406 // eventually remove from GrBlend
407 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
408 0, 0, 0);
409
410 bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff);
411 if (solidColor) {
412 if (opaque) {
413 switch (srcCoeff) {
414 case kZero_GrBlendCoeff:
415 *solidColor = 0;
416 *solidColorKnownComponents = kRGBA_GrColorComponentFlags;
417 break;
418
419 case kOne_GrBlendCoeff:
420 *solidColor = colorPOI.color();
421 *solidColorKnownComponents = colorPOI.validFlags();
422 break;
423
424 // The src coeff should never refer to the src and if it refers to dst then opaque
425 // should have been false.
426 case kSC_GrBlendCoeff:
427 case kISC_GrBlendCoeff:
428 case kDC_GrBlendCoeff:
429 case kIDC_GrBlendCoeff:
430 case kSA_GrBlendCoeff:
431 case kISA_GrBlendCoeff:
432 case kDA_GrBlendCoeff:
433 case kIDA_GrBlendCoeff:
434 default:
435 SkFAIL("srcCoeff should not refer to src or dst.");
436 break;
437
438 // TODO: update this once GrPaint actually has a const color.
439 case kConstC_GrBlendCoeff:
440 case kIConstC_GrBlendCoeff:
441 case kConstA_GrBlendCoeff:
442 case kIConstA_GrBlendCoeff:
443 *solidColorKnownComponents = 0;
444 break;
445 }
446 } else {
447 solidColorKnownComponents = 0;
448 }
449 }
450 return opaque;
451}
452
453