OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrPorterDuffXferProcessor.h" | 8 #include "GrPorterDuffXferProcessor.h" |
9 | 9 |
10 #include "GrBackendProcessorFactory.h" | 10 #include "GrBackendProcessorFactory.h" |
| 11 #include "GrBlend.h" |
11 #include "GrDrawState.h" | 12 #include "GrDrawState.h" |
12 #include "GrInvariantOutput.h" | 13 #include "GrInvariantOutput.h" |
13 #include "GrProcessor.h" | 14 #include "GrProcessor.h" |
14 #include "GrTBackendProcessorFactory.h" | 15 #include "GrTBackendProcessorFactory.h" |
15 #include "GrTypes.h" | 16 #include "GrTypes.h" |
16 #include "GrXferProcessor.h" | 17 #include "GrXferProcessor.h" |
17 #include "gl/GrGLProcessor.h" | 18 #include "gl/GrGLProcessor.h" |
18 #include "gl/builders/GrGLFragmentShaderBuilder.h" | 19 #include "gl/builders/GrGLFragmentShaderBuilder.h" |
19 #include "gl/builders/GrGLProgramBuilder.h" | 20 #include "gl/builders/GrGLProgramBuilder.h" |
20 | 21 |
| 22 static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageD
rawing) { |
| 23 /* |
| 24 The fractional coverage is f. |
| 25 The src and dst coeffs are Cs and Cd. |
| 26 The dst and src colors are S and D. |
| 27 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the sou
rce color's alpha |
| 28 we're replacing S with S'=fS. It's obvious that that first term will always
be ok. The second |
| 29 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various poss
ibilities for Cd we |
| 30 find that only 1, ISA, and ISC produce the correct destination when applied
to S' and D. |
| 31 Also, if we're directly rendering coverage (isCoverageDrawing) then coverag
e is treated as |
| 32 color by definition. |
| 33 */ |
| 34 // TODO: Once we have a CoverageDrawing XP, we don't need to check is Covera
geDrawing here |
| 35 return kOne_GrBlendCoeff == dstCoeff || |
| 36 kISA_GrBlendCoeff == dstCoeff || |
| 37 kISC_GrBlendCoeff == dstCoeff || |
| 38 isCoverageDrawing; |
| 39 } |
| 40 |
21 class GrGLPorterDuffXferProcessor : public GrGLXferProcessor { | 41 class GrGLPorterDuffXferProcessor : public GrGLXferProcessor { |
22 public: | 42 public: |
23 GrGLPorterDuffXferProcessor(const GrBackendProcessorFactory& factory, const
GrProcessor&) | 43 GrGLPorterDuffXferProcessor(const GrBackendProcessorFactory& factory, const
GrProcessor&) |
24 : INHERITED(factory) {} | 44 : INHERITED(factory) {} |
25 | 45 |
26 virtual ~GrGLPorterDuffXferProcessor() {} | 46 virtual ~GrGLPorterDuffXferProcessor() {} |
27 | 47 |
28 virtual void emitCode(GrGLFPBuilder* builder, | 48 virtual void emitCode(GrGLFPBuilder* builder, |
29 const GrFragmentProcessor& fp, | 49 const GrFragmentProcessor& fp, |
30 const char* outputColor, | 50 const char* outputColor, |
31 const char* inputColor, | 51 const char* inputColor, |
32 const TransformedCoordsArray& coords, | 52 const TransformedCoordsArray& coords, |
33 const TextureSamplerArray& samplers) SK_OVERRIDE { | 53 const TextureSamplerArray& samplers) SK_OVERRIDE { |
34 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 54 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
35 fsBuilder->codeAppendf("%s = %s;", outputColor, inputColor); | 55 fsBuilder->codeAppendf("%s = %s;", outputColor, inputColor); |
36 } | 56 } |
37 | 57 |
38 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_O
VERRIDE {}; | 58 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_O
VERRIDE {}; |
39 | 59 |
40 static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyB
uilder* b) {}; | 60 static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyB
uilder* b) {}; |
41 | 61 |
42 private: | 62 private: |
43 typedef GrGLXferProcessor INHERITED; | 63 typedef GrGLXferProcessor INHERITED; |
44 }; | 64 }; |
45 | 65 |
46 /////////////////////////////////////////////////////////////////////////////// | 66 /////////////////////////////////////////////////////////////////////////////// |
47 | 67 |
48 GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBl
endCoeff dstBlend) | 68 GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBl
endCoeff dstBlend, |
49 : fSrcBlend(srcBlend), fDstBlend(dstBlend) {} | 69 GrColor constant) |
| 70 : fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) {} |
50 | 71 |
51 GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() { | 72 GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() { |
52 } | 73 } |
53 | 74 |
54 const GrBackendFragmentProcessorFactory& GrPorterDuffXferProcessor::getFactory()
const { | 75 const GrBackendFragmentProcessorFactory& GrPorterDuffXferProcessor::getFactory()
const { |
55 return GrTBackendFragmentProcessorFactory<GrPorterDuffXferProcessor>::getIns
tance(); | 76 return GrTBackendFragmentProcessorFactory<GrPorterDuffXferProcessor>::getIns
tance(); |
56 } | 77 } |
57 | 78 |
58 void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inou
t) const { | 79 void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inou
t) const { |
59 inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); | 80 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
60 } | 81 } |
61 | 82 |
| 83 GrXferProcessor::BlendOptFlags |
| 84 GrPorterDuffXferProcessor::getBlendOpts(const GrProcOptInfo& colorPOI, |
| 85 const GrProcOptInfo& coveragePOI, |
| 86 bool isCoverageDrawing, |
| 87 bool colorWriteDisabled, |
| 88 bool doesStencilWrite, |
| 89 GrColor* color, uint8_t* coverage) { |
| 90 if (colorWriteDisabled) { |
| 91 fSrcBlend = kZero_GrBlendCoeff; |
| 92 fDstBlend = kOne_GrBlendCoeff; |
| 93 } |
| 94 |
| 95 bool srcAIsOne; |
| 96 bool hasCoverage; |
| 97 if (isCoverageDrawing) { |
| 98 srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque(); |
| 99 hasCoverage = false; |
| 100 } else { |
| 101 srcAIsOne = colorPOI.isOpaque(); |
| 102 hasCoverage = !coveragePOI.isSolidWhite(); |
| 103 } |
| 104 |
| 105 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || |
| 106 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); |
| 107 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend || |
| 108 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne); |
| 109 |
| 110 // Optimizations when doing RGB Coverage |
| 111 if (!coveragePOI.isSingleComponent()) { |
| 112 // We want to force our primary output to be alpha * Coverage, where alp
ha is the alpha |
| 113 // value of the blend the constant. We should already have valid blend c
oeff's if we are at |
| 114 // a point where we have RGB coverage. We don't need any color stages si
nce the known color |
| 115 // output is already baked into the blendConstant. |
| 116 uint8_t alpha = GrColorUnpackA(fBlendConstant); |
| 117 *color = GrColorPackRGBA(alpha, alpha, alpha, alpha); |
| 118 return GrXferProcessor::kClearColorStages_BlendOptFlag; |
| 119 } |
| 120 |
| 121 // When coeffs are (0,1) there is no reason to draw at all, unless |
| 122 // stenciling is enabled. Having color writes disabled is effectively |
| 123 // (0,1). |
| 124 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) { |
| 125 if (doesStencilWrite) { |
| 126 *color = 0xffffffff; |
| 127 return GrXferProcessor::kClearColorStages_BlendOptFlag | |
| 128 GrXferProcessor::kSetCoverageDrawing_BlendOptFlag; |
| 129 } else { |
| 130 fDstBlend = kOne_GrBlendCoeff; |
| 131 return GrXferProcessor::kSkipDraw_BlendOptFlag; |
| 132 } |
| 133 } |
| 134 |
| 135 // if we don't have coverage we can check whether the dst |
| 136 // has to read at all. If not, we'll disable blending. |
| 137 if (!hasCoverage) { |
| 138 if (dstCoeffIsZero) { |
| 139 if (kOne_GrBlendCoeff == fSrcBlend) { |
| 140 // if there is no coverage and coeffs are (1,0) then we |
| 141 // won't need to read the dst at all, it gets replaced by src |
| 142 fDstBlend = kZero_GrBlendCoeff; |
| 143 return GrXferProcessor::kNone_BlendOpt; |
| 144 } else if (kZero_GrBlendCoeff == fSrcBlend) { |
| 145 // if the op is "clear" then we don't need to emit a color |
| 146 // or blend, just write transparent black into the dst. |
| 147 fSrcBlend = kOne_GrBlendCoeff; |
| 148 fDstBlend = kZero_GrBlendCoeff; |
| 149 *color = 0; |
| 150 *coverage = 0xff; |
| 151 return GrXferProcessor::kClearColorStages_BlendOptFlag | |
| 152 GrXferProcessor::kClearCoverageStages_BlendOptFlag; |
| 153 } |
| 154 } |
| 155 } else if (isCoverageDrawing) { |
| 156 // we have coverage but we aren't distinguishing it from alpha by reques
t. |
| 157 return GrXferProcessor::kSetCoverageDrawing_BlendOptFlag; |
| 158 } else { |
| 159 // check whether coverage can be safely rolled into alpha |
| 160 // of if we can skip color computation and just emit coverage |
| 161 if (can_tweak_alpha_for_coverage(fDstBlend, isCoverageDrawing)) { |
| 162 return GrXferProcessor::kSetCoverageDrawing_BlendOptFlag; |
| 163 } |
| 164 if (dstCoeffIsZero) { |
| 165 if (kZero_GrBlendCoeff == fSrcBlend) { |
| 166 // the source color is not included in the blend |
| 167 // the dst coeff is effectively zero so blend works out to: |
| 168 // (c)(0)D + (1-c)D = (1-c)D. |
| 169 fDstBlend = kISA_GrBlendCoeff; |
| 170 *color = 0xffffffff; |
| 171 return GrXferProcessor::kClearColorStages_BlendOptFlag | |
| 172 GrXferProcessor::kSetCoverageDrawing_BlendOptFlag; |
| 173 } else if (srcAIsOne) { |
| 174 // the dst coeff is effectively zero so blend works out to: |
| 175 // cS + (c)(0)D + (1-c)D = cS + (1-c)D. |
| 176 // If Sa is 1 then we can replace Sa with c |
| 177 // and set dst coeff to 1-Sa. |
| 178 fDstBlend = kISA_GrBlendCoeff; |
| 179 return GrXferProcessor::kSetCoverageDrawing_BlendOptFlag; |
| 180 } |
| 181 } else if (dstCoeffIsOne) { |
| 182 // the dst coeff is effectively one so blend works out to: |
| 183 // cS + (c)(1)D + (1-c)D = cS + D. |
| 184 fDstBlend = kOne_GrBlendCoeff; |
| 185 return GrXferProcessor::kSetCoverageDrawing_BlendOptFlag; |
| 186 } |
| 187 } |
| 188 |
| 189 return GrXferProcessor::kNone_BlendOpt; |
| 190 } |
62 /////////////////////////////////////////////////////////////////////////////// | 191 /////////////////////////////////////////////////////////////////////////////// |
63 | 192 |
64 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { | 193 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { |
65 switch (mode) { | 194 switch (mode) { |
66 case SkXfermode::kClear_Mode: { | 195 case SkXfermode::kClear_Mode: { |
67 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G
rBlendCoeff); | 196 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G
rBlendCoeff); |
68 return SkRef(&gClearPDXPF); | 197 return SkRef(&gClearPDXPF); |
69 break; | 198 break; |
70 } | 199 } |
71 case SkXfermode::kSrc_Mode: { | 200 case SkXfermode::kSrc_Mode: { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 case SkXfermode::kScreen_Mode: { | 265 case SkXfermode::kScreen_Mode: { |
137 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_Gr
BlendCoeff); | 266 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_Gr
BlendCoeff); |
138 return SkRef(&gScreenPDXPF); | 267 return SkRef(&gScreenPDXPF); |
139 break; | 268 break; |
140 } | 269 } |
141 default: | 270 default: |
142 return NULL; | 271 return NULL; |
143 } | 272 } |
144 } | 273 } |
145 | 274 |
146 const GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor() const { | 275 GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor(const GrProcOptInfo&
colorPOI, |
147 return GrPorterDuffXferProcessor::Create(fSrc, fDst); | 276 const GrProcOptInfo&
covPOI) const { |
| 277 if (covPOI.isSingleComponent()) { |
| 278 return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff); |
| 279 } else { |
| 280 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags()))
{ |
| 281 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags()); |
| 282 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); |
| 283 return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_
GrBlendCoeff, |
| 284 blendConstant); |
| 285 } else { |
| 286 return NULL; |
| 287 } |
| 288 } |
148 } | 289 } |
149 | 290 |
150 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, | 291 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, |
151 uint32_t knownColorFlags) const
{ | 292 uint32_t knownColorFlags) const
{ |
152 if (kOne_GrBlendCoeff == fSrc && kISA_GrBlendCoeff == fDst && | 293 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && |
153 kRGBA_GrColorComponentFlags == knownColorFlags) { | 294 kRGBA_GrColorComponentFlags == knownColorFlags) { |
154 return true; | 295 return true; |
155 } | 296 } |
156 return false; | 297 return false; |
157 } | 298 } |
158 | 299 |
| 300 bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI, |
| 301 const GrProcOptInfo& coveragePOI, |
| 302 bool isCoverageDrawing, |
| 303 bool colorWriteDisabled) const { |
| 304 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.i
sOpaque()); |
| 305 |
| 306 if (colorWriteDisabled) { |
| 307 return true; |
| 308 } |
| 309 |
| 310 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff || |
| 311 (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne); |
| 312 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff || |
| 313 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne); |
| 314 |
| 315 if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) { |
| 316 return true; |
| 317 } |
| 318 |
| 319 // if we don't have coverage we can check whether the dst |
| 320 // has to read at all. |
| 321 if (isCoverageDrawing) { |
| 322 // we have coverage but we aren't distinguishing it from alpha by reques
t. |
| 323 return true; |
| 324 } else { |
| 325 // check whether coverage can be safely rolled into alpha |
| 326 // of if we can skip color computation and just emit coverage |
| 327 if (this->canTweakAlphaForCoverage(isCoverageDrawing)) { |
| 328 return true; |
| 329 } |
| 330 if (dstCoeffIsZero) { |
| 331 if (kZero_GrBlendCoeff == fSrcCoeff) { |
| 332 return true; |
| 333 } else if (srcAIsOne) { |
| 334 return true; |
| 335 } |
| 336 } else if (dstCoeffIsOne) { |
| 337 return true; |
| 338 } |
| 339 } |
| 340 |
| 341 // TODO: once all SkXferEffects are XP's then we will never reads dst here s
ince only XP's |
| 342 // will readDst and PD XP's don't read dst. |
| 343 if ((colorPOI.readsDst() || coveragePOI.readsDst()) && |
| 344 kOne_GrBlendCoeff == fSrcCoeff && kZero_GrBlendCoeff == fDstCoeff) { |
| 345 return true; |
| 346 } |
| 347 |
| 348 return false; |
| 349 } |
| 350 |
| 351 bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI, |
| 352 const GrProcOptInfo& coveragePOI, |
| 353 bool isCoverageDrawing, |
| 354 bool colorWriteDisabled) const { |
| 355 if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) { |
| 356 return true; |
| 357 } |
| 358 |
| 359 // TODO: once all SkXferEffects are XP's then we will never reads dst here s
ince only XP's |
| 360 // will readDst and PD XP's don't read dst. |
| 361 if ((!colorWriteDisabled && colorPOI.readsDst()) || coveragePOI.readsDst())
{ |
| 362 return true; |
| 363 } |
| 364 |
| 365 if (GrBlendCoeffRefsDst(fSrcCoeff)) { |
| 366 return true; |
| 367 } |
| 368 |
| 369 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.i
sOpaque()); |
| 370 |
| 371 if (!(kZero_GrBlendCoeff == fDstCoeff || |
| 372 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) { |
| 373 return true; |
| 374 } |
| 375 |
| 376 return false; |
| 377 } |
| 378 |
| 379 bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) con
st { |
| 380 return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing); |
| 381 } |
| 382 |
| 383 bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI
, |
| 384 const GrProcOptInfo& coverage
POI, |
| 385 GrColor* solidColor, |
| 386 uint32_t* solidColorKnownComp
onents) const { |
| 387 if (!coveragePOI.isSolidWhite()) { |
| 388 return false; |
| 389 } |
| 390 |
| 391 SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents)); |
| 392 |
| 393 GrBlendCoeff srcCoeff = fSrcCoeff; |
| 394 GrBlendCoeff dstCoeff = fDstCoeff; |
| 395 |
| 396 // TODO: figure out to merge this simplify with other current optimization c
ode paths and |
| 397 // eventually remove from GrBlend |
| 398 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(
), |
| 399 0, 0, 0); |
| 400 |
| 401 bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoef
f); |
| 402 if (solidColor) { |
| 403 if (opaque) { |
| 404 switch (srcCoeff) { |
| 405 case kZero_GrBlendCoeff: |
| 406 *solidColor = 0; |
| 407 *solidColorKnownComponents = kRGBA_GrColorComponentFlags; |
| 408 break; |
| 409 |
| 410 case kOne_GrBlendCoeff: |
| 411 *solidColor = colorPOI.color(); |
| 412 *solidColorKnownComponents = colorPOI.validFlags(); |
| 413 break; |
| 414 |
| 415 // The src coeff should never refer to the src and if it refers
to dst then opaque |
| 416 // should have been false. |
| 417 case kSC_GrBlendCoeff: |
| 418 case kISC_GrBlendCoeff: |
| 419 case kDC_GrBlendCoeff: |
| 420 case kIDC_GrBlendCoeff: |
| 421 case kSA_GrBlendCoeff: |
| 422 case kISA_GrBlendCoeff: |
| 423 case kDA_GrBlendCoeff: |
| 424 case kIDA_GrBlendCoeff: |
| 425 default: |
| 426 SkFAIL("srcCoeff should not refer to src or dst."); |
| 427 break; |
| 428 |
| 429 // TODO: update this once GrPaint actually has a const color. |
| 430 case kConstC_GrBlendCoeff: |
| 431 case kIConstC_GrBlendCoeff: |
| 432 case kConstA_GrBlendCoeff: |
| 433 case kIConstA_GrBlendCoeff: |
| 434 *solidColorKnownComponents = 0; |
| 435 break; |
| 436 } |
| 437 } else { |
| 438 solidColorKnownComponents = 0; |
| 439 } |
| 440 } |
| 441 return opaque; |
| 442 } |
| 443 |
| 444 |
OLD | NEW |