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 "effects/GrPorterDuffXferProcessor.h" | 8 #include "effects/GrPorterDuffXferProcessor.h" |
9 | 9 |
10 #include "GrBlend.h" | 10 #include "GrBlend.h" |
11 #include "GrCaps.h" | 11 #include "GrCaps.h" |
12 #include "GrProcessor.h" | 12 #include "GrProcessor.h" |
13 #include "GrProcOptInfo.h" | 13 #include "GrProcOptInfo.h" |
14 #include "GrTypes.h" | 14 #include "GrTypes.h" |
15 #include "GrXferProcessor.h" | 15 #include "GrXferProcessor.h" |
16 #include "gl/GrGLXferProcessor.h" | 16 #include "gl/GrGLXferProcessor.h" |
17 #include "gl/builders/GrGLFragmentShaderBuilder.h" | 17 #include "gl/builders/GrGLFragmentShaderBuilder.h" |
18 #include "gl/builders/GrGLProgramBuilder.h" | 18 #include "gl/builders/GrGLProgramBuilder.h" |
19 | 19 |
20 static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) { | 20 /** |
21 /* | 21 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend
mode with coverage. |
22 The fractional coverage is f. | 22 */ |
23 The src and dst coeffs are Cs and Cd. | 23 struct BlendFormula { |
24 The dst and src colors are S and D. | 24 public: |
25 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the sou
rce color's alpha | 25 /** |
26 we're replacing S with S'=fS. It's obvious that that first term will always
be ok. The second | 26 * Values the shader can write to primary and secondary outputs. These must
all be modulated by |
27 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various poss
ibilities for Cd we | 27 * coverage to support mixed samples. The XP will ignore the multiplies when
not using coverage. |
28 find that only 1, ISA, and ISC produce the correct destination when applied
to S' and D. | |
29 */ | 28 */ |
30 return kOne_GrBlendCoeff == dstCoeff || | 29 enum OutputType { |
31 kISA_GrBlendCoeff == dstCoeff || | 30 kNone_OutputType, //<! 0 |
32 kISC_GrBlendCoeff == dstCoeff; | 31 kCoverage_OutputType, //<! inputCoverage |
| 32 kModulate_OutputType, //<! inputColor * inputCoverage |
| 33 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage |
| 34 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage |
| 35 |
| 36 kLast_OutputType = kISCModulate_OutputType |
| 37 }; |
| 38 |
| 39 enum Properties { |
| 40 kModifiesDst_Property = 1, |
| 41 kUsesDstColor_Property = 1 << 1, |
| 42 kUsesInputColor_Property = 1 << 2, |
| 43 kCanTweakAlphaForCoverage_Property = 1 << 3, |
| 44 |
| 45 kLast_Property = kCanTweakAlphaForCoverage_Property |
| 46 }; |
| 47 |
| 48 BlendFormula& operator =(const BlendFormula& other) { |
| 49 fData = other.fData; |
| 50 return *this; |
| 51 } |
| 52 |
| 53 bool operator ==(const BlendFormula& other) const { |
| 54 return fData == other.fData; |
| 55 } |
| 56 |
| 57 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutpu
tType; } |
| 58 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property);
} |
| 59 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property)
; } |
| 60 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Prope
rty); } |
| 61 bool canTweakAlphaForCoverage() const { |
| 62 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property); |
| 63 } |
| 64 |
| 65 /** |
| 66 * Deduce the properties of a compile-time constant BlendFormula. |
| 67 */ |
| 68 template<OutputType PrimaryOut, OutputType SecondaryOut, |
| 69 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff
DstCoeff> |
| 70 struct get_properties : SkTIntegralConstant<Properties, static_cast<Properti
es>( |
| 71 |
| 72 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ? |
| 73 kModifiesDst_Property : 0) | |
| 74 |
| 75 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ? |
| 76 kUsesDstColor_Property : 0) | |
| 77 |
| 78 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(Sr
cCoeff,DstCoeff)) || |
| 79 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCo
eff)) ? |
| 80 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff do
esn't ref src2. |
| 81 |
| 82 (kModulate_OutputType == PrimaryOut && |
| 83 kNone_OutputType == SecondaryOut && |
| 84 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff
) ? |
| 85 kCanTweakAlphaForCoverage_Property : 0))> { |
| 86 |
| 87 // The provided formula should already be optimized. |
| 88 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) == |
| 89 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff)); |
| 90 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff)); |
| 91 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) == |
| 92 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff)); |
| 93 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == Prima
ryOut); |
| 94 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == S
econdaryOut); |
| 95 }; |
| 96 |
| 97 union { |
| 98 struct { |
| 99 // We allot the enums one more bit than they require because MSVC se
ems to sign-extend |
| 100 // them when the top bit is set. (This is in violation of the C++03
standard 9.6/4) |
| 101 OutputType fPrimaryOutputType : 4; |
| 102 OutputType fSecondaryOutputType : 4; |
| 103 GrBlendEquation fBlendEquation : 6; |
| 104 GrBlendCoeff fSrcCoeff : 6; |
| 105 GrBlendCoeff fDstCoeff : 6; |
| 106 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6); |
| 107 }; |
| 108 uint32_t fData; |
| 109 }; |
| 110 |
| 111 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3)); |
| 112 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5)); |
| 113 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5)); |
| 114 GR_STATIC_ASSERT(kLast_Property < (1 << 6)); |
| 115 }; |
| 116 |
| 117 GR_STATIC_ASSERT(4 == sizeof(BlendFormula)); |
| 118 |
| 119 GR_MAKE_BITFIELD_OPS(BlendFormula::Properties); |
| 120 |
| 121 /** |
| 122 * Initialize a compile-time constant BlendFormula and automatically deduce fPro
ps. |
| 123 */ |
| 124 #define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF
, DST_COEFF) \ |
| 125 {{{PRIMARY_OUT, \ |
| 126 SECONDARY_OUT, \ |
| 127 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \ |
| 128 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \ |
| 129 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value
}}} |
| 130 |
| 131 /** |
| 132 * When there is no coverage, or the blend mode can tweak alpha for coverage, we
use the standard |
| 133 * Porter Duff formula. |
| 134 */ |
| 135 #define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \ |
| 136 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \ |
| 137 BlendFormula::kNone_OutputType, \ |
| 138 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF) |
| 139 |
| 140 /** |
| 141 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own
macro so we can set |
| 142 * the primary output type to none. |
| 143 */ |
| 144 #define DST_CLEAR_FORMULA \ |
| 145 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \ |
| 146 BlendFormula::kNone_OutputType, \ |
| 147 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCo
eff) |
| 148 |
| 149 /** |
| 150 * When the coeffs are (Zero, One), we don't write to the dst at all. This formu
la has its own macro |
| 151 * so we can set the primary output type to none. |
| 152 */ |
| 153 #define NO_DST_WRITE_FORMULA \ |
| 154 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \ |
| 155 BlendFormula::kNone_OutputType, \ |
| 156 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoe
ff) |
| 157 |
| 158 /** |
| 159 * When there is coverage, the equation with f=coverage is: |
| 160 * |
| 161 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D |
| 162 * |
| 163 * This can be rewritten as: |
| 164 * |
| 165 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)]) |
| 166 * |
| 167 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary c
olor and replace the |
| 168 * HW dst coeff with IS2C. |
| 169 * |
| 170 * Xfer modes: dst-atop (Sa!=1) |
| 171 */ |
| 172 #define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \ |
| 173 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \ |
| 174 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \ |
| 175 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff) |
| 176 |
| 177 /** |
| 178 * When there is coverage and the src coeff is Zero, the equation with f=coverag
e becomes: |
| 179 * |
| 180 * D' = f * D * dstCoeff + (1-f) * D |
| 181 * |
| 182 * This can be rewritten as: |
| 183 * |
| 184 * D' = D - D * [f * (1 - dstCoeff)] |
| 185 * |
| 186 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary col
or and use a reverse |
| 187 * subtract HW blend equation with coeffs of (DC, One). |
| 188 * |
| 189 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1) |
| 190 */ |
| 191 #define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \ |
| 192 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \ |
| 193 BlendFormula::kNone_OutputType, \ |
| 194 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_
GrBlendCoeff) |
| 195 |
| 196 /** |
| 197 * When there is coverage and the dst coeff is Zero, the equation with f=coverag
e becomes: |
| 198 * |
| 199 * D' = f * S * srcCoeff + (1-f) * D |
| 200 * |
| 201 * To implement this formula, we output [f] for the secondary color and replace
the HW dst coeff |
| 202 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using IS
A.) |
| 203 * |
| 204 * Xfer modes (Sa!=1): src, src-in, src-out |
| 205 */ |
| 206 #define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \ |
| 207 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \ |
| 208 BlendFormula::kCoverage_OutputType, \ |
| 209 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff) |
| 210 |
| 211 /** |
| 212 * This table outlines the blend formulas we will use with each xfermode, with a
nd without coverage, |
| 213 * with and without an opaque input color. Optimization properties are deduced a
t compile time so we |
| 214 * can make runtime decisions quickly. RGB coverage is not supported. |
| 215 */ |
| 216 static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = { |
| 217 |
| 218 /*>> No coverage, input color unknown <<*/ {{ |
| 219 |
| 220 /* clear */ DST_CLEAR_FORMULA, |
| 221 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff), |
| 222 /* dst */ NO_DST_WRITE_FORMULA, |
| 223 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), |
| 224 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
| 225 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff), |
| 226 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff), |
| 227 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff), |
| 228 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff), |
| 229 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 230 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff), |
| 231 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 232 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), |
| 233 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff), |
| 234 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), |
| 235 |
| 236 }, /*>> Has coverage, input color unknown <<*/ { |
| 237 |
| 238 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out
putType), |
| 239 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff), |
| 240 /* dst */ NO_DST_WRITE_FORMULA, |
| 241 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), |
| 242 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
| 243 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff), |
| 244 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_
OutputType), |
| 245 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff), |
| 246 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff), |
| 247 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 248 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kID
A_GrBlendCoeff), |
| 249 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 250 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), |
| 251 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_
OutputType), |
| 252 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), |
| 253 |
| 254 }}, /*>> No coverage, input color opaque <<*/ {{ |
| 255 |
| 256 /* clear */ DST_CLEAR_FORMULA, |
| 257 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff), |
| 258 /* dst */ NO_DST_WRITE_FORMULA, |
| 259 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff), |
| 260 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
| 261 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff), |
| 262 /* dst-in */ NO_DST_WRITE_FORMULA, |
| 263 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff), |
| 264 /* dst-out */ DST_CLEAR_FORMULA, |
| 265 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff), |
| 266 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
| 267 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff), |
| 268 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), |
| 269 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff), |
| 270 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), |
| 271 |
| 272 }, /*>> Has coverage, input color opaque <<*/ { |
| 273 |
| 274 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out
putType), |
| 275 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), |
| 276 /* dst */ NO_DST_WRITE_FORMULA, |
| 277 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff), |
| 278 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
| 279 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 280 /* dst-in */ NO_DST_WRITE_FORMULA, |
| 281 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 282 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out
putType), |
| 283 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 284 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff), |
| 285 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff), |
| 286 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff), |
| 287 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_
OutputType), |
| 288 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff), |
| 289 }}}; |
| 290 |
| 291 static BlendFormula get_blend_formula(SkXfermode::Mode xfermode, |
| 292 const GrProcOptInfo& colorPOI, |
| 293 const GrProcOptInfo& coveragePOI) { |
| 294 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode); |
| 295 SkASSERT(!coveragePOI.isFourChannelOutput()); |
| 296 |
| 297 return gBlendTable[colorPOI.isOpaque()][!coveragePOI.isSolidWhite()][xfermod
e]; |
33 } | 298 } |
34 | 299 |
| 300 /////////////////////////////////////////////////////////////////////////////// |
| 301 |
35 class PorterDuffXferProcessor : public GrXferProcessor { | 302 class PorterDuffXferProcessor : public GrXferProcessor { |
36 public: | 303 public: |
37 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, | 304 static GrXferProcessor* Create(BlendFormula blendFormula) { |
38 GrColor constant, const DstTexture* dstTextur
e, | 305 return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula)); |
39 bool willReadDstColor) { | 306 } |
40 return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant
, dstTexture, | |
41 willReadDstColor)); | |
42 } | |
43 | |
44 ~PorterDuffXferProcessor() override; | |
45 | 307 |
46 const char* name() const override { return "Porter Duff"; } | 308 const char* name() const override { return "Porter Duff"; } |
| 309 bool hasSecondaryOutput() const override { return fBlendFormula.hasSecondary
Output(); } |
47 | 310 |
48 GrGLXferProcessor* createGLInstance() const override; | 311 GrGLXferProcessor* createGLInstance() const override; |
49 | 312 |
50 bool hasSecondaryOutput() const override; | 313 BlendFormula getBlendFormula() const { return fBlendFormula; } |
51 | |
52 /////////////////////////////////////////////////////////////////////////// | |
53 /// @name Stage Output Types | |
54 //// | |
55 | |
56 enum PrimaryOutputType { | |
57 kNone_PrimaryOutputType, | |
58 kColor_PrimaryOutputType, | |
59 kCoverage_PrimaryOutputType, | |
60 // Modulate color and coverage, write result as the color output. | |
61 kModulate_PrimaryOutputType, | |
62 // Custom Porter-Duff output, used for when we explictly are reading the
dst and blending | |
63 // in the shader. Secondary Output must be none if you use this. The cus
tom blend uses the | |
64 // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D | |
65 kCustom_PrimaryOutputType | |
66 }; | |
67 | |
68 enum SecondaryOutputType { | |
69 // There is no secondary output | |
70 kNone_SecondaryOutputType, | |
71 // Writes coverage as the secondary output. Only set if dual source blen
ding is supported | |
72 // and primary output is kModulate. | |
73 kCoverage_SecondaryOutputType, | |
74 // Writes coverage * (1 - colorA) as the secondary output. Only set if d
ual source blending | |
75 // is supported and primary output is kModulate. | |
76 kCoverageISA_SecondaryOutputType, | |
77 // Writes coverage * (1 - colorRGBA) as the secondary output. Only set i
f dual source | |
78 // blending is supported and primary output is kModulate. | |
79 kCoverageISC_SecondaryOutputType, | |
80 | |
81 kSecondaryOutputTypeCnt, | |
82 }; | |
83 | |
84 PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; } | |
85 SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputTyp
e; } | |
86 | |
87 GrBlendCoeff getSrcBlend() const { return fSrcBlend; } | |
88 GrBlendCoeff getDstBlend() const { return fDstBlend; } | |
89 | 314 |
90 private: | 315 private: |
91 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColo
r constant, | 316 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendForm
ula) { |
92 const DstTexture*, bool willReadDstColor); | 317 this->initClassID<PorterDuffXferProcessor>(); |
| 318 } |
93 | 319 |
94 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, | 320 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, |
95 const GrProcOptInfo& coveragePO
I, | 321 const GrProcOptInfo& coveragePO
I, |
96 bool doesStencilWrite, | 322 bool doesStencilWrite, |
97 GrColor* overrideColor, | 323 GrColor* overrideColor, |
98 const GrCaps& caps) override; | 324 const GrCaps& caps) override; |
99 | 325 |
100 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override; | 326 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override; |
101 | 327 |
102 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { | 328 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { |
103 if (!this->willReadDstColor()) { | 329 blendInfo->fEquation = fBlendFormula.fBlendEquation; |
104 blendInfo->fSrcBlend = fSrcBlend; | 330 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff; |
105 blendInfo->fDstBlend = fDstBlend; | 331 blendInfo->fDstBlend = fBlendFormula.fDstCoeff; |
106 } else { | 332 blendInfo->fWriteColor = fBlendFormula.modifiesDst(); |
107 blendInfo->fSrcBlend = kOne_GrBlendCoeff; | |
108 blendInfo->fDstBlend = kZero_GrBlendCoeff; | |
109 } | |
110 blendInfo->fBlendConstant = fBlendConstant; | |
111 } | 333 } |
112 | 334 |
113 bool onIsEqual(const GrXferProcessor& xpBase) const override { | 335 bool onIsEqual(const GrXferProcessor& xpBase) const override { |
114 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>
(); | 336 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>
(); |
115 if (fSrcBlend != xp.fSrcBlend || | 337 return fBlendFormula == xp.fBlendFormula; |
116 fDstBlend != xp.fDstBlend || | |
117 fBlendConstant != xp.fBlendConstant || | |
118 fPrimaryOutputType != xp.fPrimaryOutputType || | |
119 fSecondaryOutputType != xp.fSecondaryOutputType) { | |
120 return false; | |
121 } | |
122 return true; | |
123 } | 338 } |
124 | 339 |
125 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colo
rPOI, | 340 const BlendFormula fBlendFormula; |
126 const GrProcOptInfo& cove
ragePOI, | |
127 bool doesStencilWrite); | |
128 | |
129 void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrCaps& caps
, | |
130 bool hasSolidCoverage); | |
131 | |
132 GrBlendCoeff fSrcBlend; | |
133 GrBlendCoeff fDstBlend; | |
134 GrColor fBlendConstant; | |
135 PrimaryOutputType fPrimaryOutputType; | |
136 SecondaryOutputType fSecondaryOutputType; | |
137 | 341 |
138 typedef GrXferProcessor INHERITED; | 342 typedef GrXferProcessor INHERITED; |
139 }; | 343 }; |
140 | 344 |
141 /////////////////////////////////////////////////////////////////////////////// | 345 /////////////////////////////////////////////////////////////////////////////// |
142 | 346 |
143 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff
, | 347 static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmen
tBuilder* fsBuilder, |
144 const char* colorName, const char* srcColorName, | 348 BlendFormula::OutputType outputType, const char*
output, |
145 const char* dstColorName, bool hasPrevious) { | 349 const char* inColor, const char* inCoverage) { |
146 if (kZero_GrBlendCoeff == coeff) { | 350 switch (outputType) { |
147 return hasPrevious; | 351 case BlendFormula::kNone_OutputType: |
148 } else { | 352 fsBuilder->codeAppendf("%s = vec4(0.0);", output); |
149 if (hasPrevious) { | 353 break; |
150 fsBuilder->codeAppend(" + "); | 354 case BlendFormula::kCoverage_OutputType: |
151 } | 355 fsBuilder->codeAppendf("%s = %s;", |
152 fsBuilder->codeAppendf("%s", colorName); | 356 output, xp.readsCoverage() ? inCoverage : "ve
c4(1.0)"); |
153 switch (coeff) { | 357 break; |
154 case kOne_GrBlendCoeff: | 358 case BlendFormula::kModulate_OutputType: |
155 break; | 359 if (xp.readsCoverage()) { |
156 case kSC_GrBlendCoeff: | 360 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCover
age); |
157 fsBuilder->codeAppendf(" * %s", srcColorName); | 361 } else { |
158 break; | 362 fsBuilder->codeAppendf("%s = %s;", output, inColor); |
159 case kISC_GrBlendCoeff: | 363 } |
160 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); | 364 break; |
161 break; | 365 case BlendFormula::kISAModulate_OutputType: |
162 case kDC_GrBlendCoeff: | 366 if (xp.readsCoverage()) { |
163 fsBuilder->codeAppendf(" * %s", dstColorName); | 367 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColo
r, inCoverage); |
164 break; | 368 } else { |
165 case kIDC_GrBlendCoeff: | 369 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor
); |
166 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); | 370 } |
167 break; | 371 break; |
168 case kSA_GrBlendCoeff: | 372 case BlendFormula::kISCModulate_OutputType: |
169 fsBuilder->codeAppendf(" * %s.a", srcColorName); | 373 if (xp.readsCoverage()) { |
170 break; | 374 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, in
Color, inCoverage); |
171 case kISA_GrBlendCoeff: | 375 } else { |
172 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); | 376 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor); |
173 break; | 377 } |
174 case kDA_GrBlendCoeff: | 378 break; |
175 fsBuilder->codeAppendf(" * %s.a", dstColorName); | 379 default: |
176 break; | 380 SkFAIL("Unsupported output type."); |
177 case kIDA_GrBlendCoeff: | 381 break; |
178 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); | |
179 break; | |
180 default: | |
181 SkFAIL("Unsupported Blend Coeff"); | |
182 } | |
183 return true; | |
184 } | 382 } |
185 } | 383 } |
186 | 384 |
187 class GLPorterDuffXferProcessor : public GrGLXferProcessor { | 385 class GLPorterDuffXferProcessor : public GrGLXferProcessor { |
188 public: | 386 public: |
189 GLPorterDuffXferProcessor(const GrProcessor&) {} | 387 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) { |
190 | |
191 virtual ~GLPorterDuffXferProcessor() {} | |
192 | |
193 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, | |
194 GrProcessorKeyBuilder* b) { | |
195 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess
or>(); | 388 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess
or>(); |
196 b->add32(xp.primaryOutputType()); | 389 b->add32(SkToInt(xp.readsCoverage()) | |
197 b->add32(xp.secondaryOutputType()); | 390 (xp.getBlendFormula().fPrimaryOutputType << 1) | |
198 if (xp.willReadDstColor()) { | 391 (xp.getBlendFormula().fSecondaryOutputType << 4)); |
199 b->add32(xp.getSrcBlend()); | 392 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8); |
200 b->add32(xp.getDstBlend()); | |
201 } | |
202 }; | 393 }; |
203 | 394 |
204 private: | 395 private: |
205 void onEmitCode(const EmitArgs& args) override { | 396 void onEmitCode(const EmitArgs& args) override { |
206 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso
r>(); | 397 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso
r>(); |
207 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); | 398 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); |
208 if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutp
utType()) { | |
209 SkASSERT(!xp.willReadDstColor()); | |
210 switch(xp.secondaryOutputType()) { | |
211 case PorterDuffXferProcessor::kNone_SecondaryOutputType: | |
212 break; | |
213 case PorterDuffXferProcessor::kCoverage_SecondaryOutputType: | |
214 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, | |
215 args.fInputCoverage); | |
216 break; | |
217 case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType: | |
218 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", | |
219 args.fOutputSecondary, args.fInputCol
or, | |
220 args.fInputCoverage); | |
221 break; | |
222 case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType: | |
223 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", | |
224 args.fOutputSecondary, args.fInputCol
or, | |
225 args.fInputCoverage); | |
226 break; | |
227 default: | |
228 SkFAIL("Unexpected Secondary Output"); | |
229 } | |
230 | 399 |
231 switch (xp.primaryOutputType()) { | 400 BlendFormula blendFormula = xp.getBlendFormula(); |
232 case PorterDuffXferProcessor::kNone_PrimaryOutputType: | 401 if (blendFormula.hasSecondaryOutput()) { |
233 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary)
; | 402 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType
, |
234 break; | 403 args.fOutputSecondary, args.fInputColor, args.fI
nputCoverage); |
235 case PorterDuffXferProcessor::kColor_PrimaryOutputType: | |
236 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args
.fInputColor); | |
237 break; | |
238 case PorterDuffXferProcessor::kCoverage_PrimaryOutputType: | |
239 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args
.fInputCoverage); | |
240 break; | |
241 case PorterDuffXferProcessor::kModulate_PrimaryOutputType: | |
242 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary,
args.fInputColor, | |
243 args.fInputCoverage); | |
244 break; | |
245 default: | |
246 SkFAIL("Unexpected Primary Output"); | |
247 } | |
248 } else { | |
249 SkASSERT(xp.willReadDstColor()); | |
250 | |
251 const char* dstColor = fsBuilder->dstColor(); | |
252 | |
253 fsBuilder->codeAppend("vec4 colorBlend ="); | |
254 // append src blend | |
255 bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(), | |
256 args.fInputColor, args.fInpu
tColor, | |
257 dstColor, false); | |
258 // append dst blend | |
259 SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(), | |
260 dstColor, args.fInputColor, | |
261 dstColor, didAppend)); | |
262 fsBuilder->codeAppend(";"); | |
263 | |
264 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s
;", | |
265 args.fOutputPrimary, args.fInputCoverage, arg
s.fInputCoverage, | |
266 dstColor); | |
267 } | 404 } |
| 405 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType, |
| 406 args.fOutputPrimary, args.fInputColor, args.fInputCo
verage); |
268 } | 407 } |
269 | 408 |
270 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri
de {}; | 409 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri
de {} |
271 | 410 |
272 typedef GrGLXferProcessor INHERITED; | 411 typedef GrGLXferProcessor INHERITED; |
273 }; | 412 }; |
274 | 413 |
275 /////////////////////////////////////////////////////////////////////////////// | 414 /////////////////////////////////////////////////////////////////////////////// |
276 | 415 |
277 PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend, | 416 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&, |
278 GrBlendCoeff dstBlend, | |
279 GrColor constant, | |
280 const DstTexture* dstTexture, | |
281 bool willReadDstColor) | |
282 : INHERITED(dstTexture, willReadDstColor) | |
283 , fSrcBlend(srcBlend) | |
284 , fDstBlend(dstBlend) | |
285 , fBlendConstant(constant) | |
286 , fPrimaryOutputType(kModulate_PrimaryOutputType) | |
287 , fSecondaryOutputType(kNone_SecondaryOutputType) { | |
288 this->initClassID<PorterDuffXferProcessor>(); | |
289 } | |
290 | |
291 PorterDuffXferProcessor::~PorterDuffXferProcessor() { | |
292 } | |
293 | |
294 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps, | |
295 GrProcessorKeyBuilder* b) cons
t { | 417 GrProcessorKeyBuilder* b) cons
t { |
296 GLPorterDuffXferProcessor::GenKey(*this, caps, b); | 418 GLPorterDuffXferProcessor::GenKey(*this, b); |
297 } | 419 } |
298 | 420 |
299 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const { | 421 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const { |
300 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this)); | 422 return SkNEW(GLPorterDuffXferProcessor); |
301 } | 423 } |
302 | 424 |
303 GrXferProcessor::OptFlags | 425 GrXferProcessor::OptFlags |
304 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, | 426 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, |
305 const GrProcOptInfo& coveragePOI, | 427 const GrProcOptInfo& coveragePOI, |
306 bool doesStencilWrite, | 428 bool doesStencilWrite, |
307 GrColor* overrideColor, | 429 GrColor* overrideColor, |
308 const GrCaps& caps) { | 430 const GrCaps& caps) { |
309 GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI
, | 431 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt; |
310 coverage
POI, | 432 if (!fBlendFormula.modifiesDst()) { |
311 doesSten
cilWrite); | 433 if (!doesStencilWrite) { |
312 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite()); | 434 optFlags |= GrXferProcessor::kSkipDraw_OptFlag; |
| 435 } |
| 436 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag | |
| 437 GrXferProcessor::kIgnoreCoverage_OptFlag | |
| 438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag); |
| 439 } else { |
| 440 if (!fBlendFormula.usesInputColor()) { |
| 441 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag; |
| 442 } |
| 443 if (coveragePOI.isSolidWhite()) { |
| 444 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag; |
| 445 } |
| 446 if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForC
overage()) { |
| 447 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; |
| 448 } |
| 449 } |
313 return optFlags; | 450 return optFlags; |
314 } | 451 } |
315 | 452 |
316 void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags
, | 453 /////////////////////////////////////////////////////////////////////////////// |
317 const GrCaps& caps, | 454 |
318 bool hasSolidCoverage) { | 455 class ShaderPDXferProcessor : public GrXferProcessor { |
319 if (this->willReadDstColor()) { | 456 public: |
320 fPrimaryOutputType = kCustom_PrimaryOutputType; | 457 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture*
dstTexture) { |
321 return; | 458 return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture)); |
322 } | 459 } |
323 | 460 |
324 if (optFlags & kIgnoreColor_OptFlag) { | 461 const char* name() const override { return "Porter Duff Shader"; } |
325 if (optFlags & kIgnoreCoverage_OptFlag) { | 462 bool hasSecondaryOutput() const override { return false; } |
326 fPrimaryOutputType = kNone_PrimaryOutputType; | 463 |
327 return; | 464 GrGLXferProcessor* createGLInstance() const override; |
328 } else { | 465 |
329 fPrimaryOutputType = kCoverage_PrimaryOutputType; | 466 SkXfermode::Mode getXfermode() const { return fXfermode; } |
330 return; | 467 |
331 } | 468 private: |
332 } else if (optFlags & kIgnoreCoverage_OptFlag) { | 469 ShaderPDXferProcessor(SkXfermode::Mode xfermode, const DstTexture* dstTextur
e) |
333 fPrimaryOutputType = kColor_PrimaryOutputType; | 470 : INHERITED(dstTexture, true) |
334 return; | 471 , fXfermode(xfermode) { |
| 472 this->initClassID<ShaderPDXferProcessor>(); |
335 } | 473 } |
336 | 474 |
337 // If we do have coverage determine whether it matters. Dual source blendin
g is expensive so | 475 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrP
rocOptInfo&, |
338 // we don't do it if we are doing coverage drawing. If we aren't then We al
ways do dual source | 476 bool, GrColor*, const GrCaps&)
override { |
339 // blending if we have any effective coverage stages OR the geometry process
or doesn't emits | 477 return kNone_Opt; |
340 // solid coverage. | 478 } |
341 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) { | 479 |
342 if (caps.shaderCaps()->dualSourceBlendingSupport()) { | 480 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override; |
343 if (kZero_GrBlendCoeff == fDstBlend) { | 481 |
344 // write the coverage value to second color | 482 bool onIsEqual(const GrXferProcessor& xpBase) const override { |
345 fSecondaryOutputType = kCoverage_SecondaryOutputType; | 483 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>(); |
346 fDstBlend = kIS2C_GrBlendCoeff; | 484 return fXfermode == xp.fXfermode; |
347 } else if (kSA_GrBlendCoeff == fDstBlend) { | 485 } |
348 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
covered. | 486 |
349 fSecondaryOutputType = kCoverageISA_SecondaryOutputType; | 487 const SkXfermode::Mode fXfermode; |
350 fDstBlend = kIS2C_GrBlendCoeff; | 488 |
351 } else if (kSC_GrBlendCoeff == fDstBlend) { | 489 typedef GrXferProcessor INHERITED; |
352 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
covered. | 490 }; |
353 fSecondaryOutputType = kCoverageISC_SecondaryOutputType; | 491 |
354 fDstBlend = kIS2C_GrBlendCoeff; | 492 /////////////////////////////////////////////////////////////////////////////// |
355 } | 493 |
| 494 static bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode:
:Coeff coeff, |
| 495 const char* colorName, const char* srcColorNa
me, |
| 496 const char* dstColorName, bool hasPrevious) { |
| 497 if (SkXfermode::kZero_Coeff == coeff) { |
| 498 return hasPrevious; |
| 499 } else { |
| 500 if (hasPrevious) { |
| 501 fsBuilder->codeAppend(" + "); |
356 } | 502 } |
| 503 fsBuilder->codeAppendf("%s", colorName); |
| 504 switch (coeff) { |
| 505 case SkXfermode::kOne_Coeff: |
| 506 break; |
| 507 case SkXfermode::kSC_Coeff: |
| 508 fsBuilder->codeAppendf(" * %s", srcColorName); |
| 509 break; |
| 510 case SkXfermode::kISC_Coeff: |
| 511 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); |
| 512 break; |
| 513 case SkXfermode::kDC_Coeff: |
| 514 fsBuilder->codeAppendf(" * %s", dstColorName); |
| 515 break; |
| 516 case SkXfermode::kIDC_Coeff: |
| 517 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); |
| 518 break; |
| 519 case SkXfermode::kSA_Coeff: |
| 520 fsBuilder->codeAppendf(" * %s.a", srcColorName); |
| 521 break; |
| 522 case SkXfermode::kISA_Coeff: |
| 523 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); |
| 524 break; |
| 525 case SkXfermode::kDA_Coeff: |
| 526 fsBuilder->codeAppendf(" * %s.a", dstColorName); |
| 527 break; |
| 528 case SkXfermode::kIDA_Coeff: |
| 529 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); |
| 530 break; |
| 531 default: |
| 532 SkFAIL("Unsupported Blend Coeff"); |
| 533 } |
| 534 return true; |
357 } | 535 } |
358 } | 536 } |
359 | 537 |
360 GrXferProcessor::OptFlags | 538 class GLShaderPDXferProcessor : public GrGLXferProcessor { |
361 PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, | 539 public: |
362 const GrProcOptInfo& coverageP
OI, | 540 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) { |
363 bool doesStencilWrite) { | 541 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>(
); |
364 if (this->willReadDstColor()) { | 542 b->add32(xp.getXfermode()); |
365 return GrXferProcessor::kNone_Opt; | |
366 } | 543 } |
367 | 544 |
368 bool srcAIsOne = colorPOI.isOpaque(); | 545 private: |
369 bool hasCoverage = !coveragePOI.isSolidWhite(); | 546 void onEmitCode(const EmitArgs& args) override { |
| 547 const ShaderPDXferProcessor& xp = args.fXP.cast<ShaderPDXferProcessor>()
; |
| 548 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); |
370 | 549 |
371 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || | 550 SkXfermode::Coeff srcCoeff, dstCoeff; |
372 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); | 551 SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff); |
373 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend || | |
374 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne); | |
375 | 552 |
376 // When coeffs are (0,1) there is no reason to draw at all, unless | 553 const char* dstColor = fsBuilder->dstColor(); |
377 // stenciling is enabled. Having color writes disabled is effectively | 554 |
378 // (0,1). | 555 fsBuilder->codeAppend("vec4 colorBlend ="); |
379 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) { | 556 // append src blend |
380 if (doesStencilWrite) { | 557 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, |
381 return GrXferProcessor::kIgnoreColor_OptFlag | | 558 args.fInputColor, args.fInputCol
or, |
382 GrXferProcessor::kSetCoverageDrawing_OptFlag; | 559 dstColor, false); |
383 } else { | 560 // append dst blend |
384 fDstBlend = kOne_GrBlendCoeff; | 561 SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff, |
385 return GrXferProcessor::kSkipDraw_OptFlag; | 562 dstColor, args.fInputColor, |
386 } | 563 dstColor, didAppend)); |
| 564 fsBuilder->codeAppend(";"); |
| 565 |
| 566 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;", |
| 567 args.fOutputPrimary, args.fInputCoverage, args.fI
nputCoverage, |
| 568 dstColor); |
387 } | 569 } |
388 | 570 |
389 // if we don't have coverage we can check whether the dst | 571 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri
de {} |
390 // has to read at all. If not, we'll disable blending. | |
391 if (!hasCoverage) { | |
392 if (dstCoeffIsZero) { | |
393 if (kOne_GrBlendCoeff == fSrcBlend) { | |
394 // if there is no coverage and coeffs are (1,0) then we | |
395 // won't need to read the dst at all, it gets replaced by src | |
396 fDstBlend = kZero_GrBlendCoeff; | |
397 return GrXferProcessor::kNone_Opt | | |
398 GrXferProcessor::kIgnoreCoverage_OptFlag; | |
399 } else if (kZero_GrBlendCoeff == fSrcBlend) { | |
400 // if the op is "clear" then we don't need to emit a color | |
401 // or blend, just write transparent black into the dst. | |
402 fSrcBlend = kOne_GrBlendCoeff; | |
403 fDstBlend = kZero_GrBlendCoeff; | |
404 return GrXferProcessor::kIgnoreColor_OptFlag | | |
405 GrXferProcessor::kIgnoreCoverage_OptFlag; | |
406 } | |
407 } | |
408 return GrXferProcessor::kIgnoreCoverage_OptFlag; | |
409 } | |
410 | 572 |
411 // check whether coverage can be safely rolled into alpha | 573 typedef GrGLXferProcessor INHERITED; |
412 // of if we can skip color computation and just emit coverage | 574 }; |
413 if (can_tweak_alpha_for_coverage(fDstBlend)) { | |
414 if (colorPOI.allStagesMultiplyInput()) { | |
415 return GrXferProcessor::kSetCoverageDrawing_OptFlag | | |
416 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; | |
417 } else { | |
418 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
419 | 575 |
420 } | 576 /////////////////////////////////////////////////////////////////////////////// |
421 } | |
422 if (dstCoeffIsZero) { | |
423 if (kZero_GrBlendCoeff == fSrcBlend) { | |
424 // the source color is not included in the blend | |
425 // the dst coeff is effectively zero so blend works out to: | |
426 // (c)(0)D + (1-c)D = (1-c)D. | |
427 fDstBlend = kISA_GrBlendCoeff; | |
428 return GrXferProcessor::kIgnoreColor_OptFlag | | |
429 GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
430 } else if (srcAIsOne) { | |
431 // the dst coeff is effectively zero so blend works out to: | |
432 // cS + (c)(0)D + (1-c)D = cS + (1-c)D. | |
433 // If Sa is 1 then we can replace Sa with c | |
434 // and set dst coeff to 1-Sa. | |
435 fDstBlend = kISA_GrBlendCoeff; | |
436 if (colorPOI.allStagesMultiplyInput()) { | |
437 return GrXferProcessor::kSetCoverageDrawing_OptFlag | | |
438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; | |
439 } else { | |
440 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
441 | 577 |
442 } | 578 void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&, |
443 } | 579 GrProcessorKeyBuilder* b) cons
t { |
444 } else if (dstCoeffIsOne) { | 580 GLShaderPDXferProcessor::GenKey(*this, b); |
445 // the dst coeff is effectively one so blend works out to: | |
446 // cS + (c)(1)D + (1-c)D = cS + D. | |
447 fDstBlend = kOne_GrBlendCoeff; | |
448 if (colorPOI.allStagesMultiplyInput()) { | |
449 return GrXferProcessor::kSetCoverageDrawing_OptFlag | | |
450 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag; | |
451 } else { | |
452 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
453 | |
454 } | |
455 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
456 } | |
457 | |
458 return GrXferProcessor::kNone_Opt; | |
459 } | 581 } |
460 | 582 |
461 bool PorterDuffXferProcessor::hasSecondaryOutput() const { | 583 GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const { |
462 return kNone_SecondaryOutputType != fSecondaryOutputType; | 584 return SkNEW(GLShaderPDXferProcessor); |
463 } | 585 } |
464 | 586 |
465 /////////////////////////////////////////////////////////////////////////////// | 587 /////////////////////////////////////////////////////////////////////////////// |
466 | 588 |
467 class PDLCDXferProcessor : public GrXferProcessor { | 589 class PDLCDXferProcessor : public GrXferProcessor { |
468 public: | 590 public: |
469 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, | 591 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInf
o& colorPOI); |
470 const GrProcOptInfo& colorPOI); | |
471 | 592 |
472 ~PDLCDXferProcessor() override; | 593 ~PDLCDXferProcessor() override; |
473 | 594 |
474 const char* name() const override { return "Porter Duff LCD"; } | 595 const char* name() const override { return "Porter Duff LCD"; } |
475 | 596 |
476 GrGLXferProcessor* createGLInstance() const override; | 597 GrGLXferProcessor* createGLInstance() const override; |
477 | 598 |
478 bool hasSecondaryOutput() const override { return false; } | 599 bool hasSecondaryOutput() const override { return false; } |
479 | 600 |
480 private: | 601 private: |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
534 }; | 655 }; |
535 | 656 |
536 /////////////////////////////////////////////////////////////////////////////// | 657 /////////////////////////////////////////////////////////////////////////////// |
537 | 658 |
538 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha) | 659 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha) |
539 : fBlendConstant(blendConstant) | 660 : fBlendConstant(blendConstant) |
540 , fAlpha(alpha) { | 661 , fAlpha(alpha) { |
541 this->initClassID<PDLCDXferProcessor>(); | 662 this->initClassID<PDLCDXferProcessor>(); |
542 } | 663 } |
543 | 664 |
544 GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff
dstBlend, | 665 GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode, |
545 const GrProcOptInfo& colorPOI) { | 666 const GrProcOptInfo& colorPOI) { |
546 if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) { | 667 if (SkXfermode::kSrcOver_Mode != xfermode) { |
547 return NULL; | 668 return NULL; |
548 } | 669 } |
549 | 670 |
550 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) { | 671 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) { |
551 return NULL; | 672 return NULL; |
552 } | 673 } |
553 | 674 |
554 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); | 675 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); |
555 uint8_t alpha = GrColorUnpackA(blendConstant); | 676 uint8_t alpha = GrColorUnpackA(blendConstant); |
556 blendConstant |= (0xff << GrColor_SHIFT_A); | 677 blendConstant |= (0xff << GrColor_SHIFT_A); |
(...skipping 21 matching lines...) Expand all Loading... |
578 const GrCaps& caps) { | 699 const GrCaps& caps) { |
579 // We want to force our primary output to be alpha * Coverage, where alp
ha is the alpha | 700 // We want to force our primary output to be alpha * Coverage, where alp
ha is the alpha |
580 // value of the blend the constant. We should already have valid blend c
oeff's if we are at | 701 // value of the blend the constant. We should already have valid blend c
oeff's if we are at |
581 // a point where we have RGB coverage. We don't need any color stages si
nce the known color | 702 // a point where we have RGB coverage. We don't need any color stages si
nce the known color |
582 // output is already baked into the blendConstant. | 703 // output is already baked into the blendConstant. |
583 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha); | 704 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha); |
584 return GrXferProcessor::kOverrideColor_OptFlag; | 705 return GrXferProcessor::kOverrideColor_OptFlag; |
585 } | 706 } |
586 | 707 |
587 /////////////////////////////////////////////////////////////////////////////// | 708 /////////////////////////////////////////////////////////////////////////////// |
588 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) | 709 |
589 : fSrcCoeff(src), fDstCoeff(dst) { | 710 GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode) |
| 711 : fXfermode(xfermode) { |
590 this->initClassID<GrPorterDuffXPFactory>(); | 712 this->initClassID<GrPorterDuffXPFactory>(); |
591 } | 713 } |
592 | 714 |
593 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { | 715 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) { |
594 switch (mode) { | 716 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode); |
595 case SkXfermode::kClear_Mode: { | 717 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode); |
596 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G
rBlendCoeff); | 718 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode); |
597 return SkRef(&gClearPDXPF); | 719 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode); |
598 break; | 720 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode); |
599 } | 721 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode); |
600 case SkXfermode::kSrc_Mode: { | 722 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode); |
601 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBl
endCoeff); | 723 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode); |
602 return SkRef(&gSrcPDXPF); | 724 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode); |
603 break; | 725 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode); |
604 } | 726 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode); |
605 case SkXfermode::kDst_Mode: { | 727 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode); |
606 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBl
endCoeff); | 728 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode); |
607 return SkRef(&gDstPDXPF); | 729 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode); |
608 break; | 730 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode); |
609 } | 731 |
610 case SkXfermode::kSrcOver_Mode: { | 732 static GrPorterDuffXPFactory* gFactories[] = { |
611 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_G
rBlendCoeff); | 733 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &g
SrcInPDXPF, |
612 return SkRef(&gSrcOverPDXPF); | 734 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDX
PF, &gXorPDXPF, |
613 break; | 735 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF |
614 } | 736 }; |
615 case SkXfermode::kDstOver_Mode: { | 737 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode +
1); |
616 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_G
rBlendCoeff); | 738 |
617 return SkRef(&gDstOverPDXPF); | 739 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) { |
618 break; | 740 return NULL; |
619 } | |
620 case SkXfermode::kSrcIn_Mode: { | |
621 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrB
lendCoeff); | |
622 return SkRef(&gSrcInPDXPF); | |
623 break; | |
624 } | |
625 case SkXfermode::kDstIn_Mode: { | |
626 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrB
lendCoeff); | |
627 return SkRef(&gDstInPDXPF); | |
628 break; | |
629 } | |
630 case SkXfermode::kSrcOut_Mode: { | |
631 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_G
rBlendCoeff); | |
632 return SkRef(&gSrcOutPDXPF); | |
633 break; | |
634 } | |
635 case SkXfermode::kDstOut_Mode: { | |
636 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_G
rBlendCoeff); | |
637 return SkRef(&gDstOutPDXPF); | |
638 break; | |
639 } | |
640 case SkXfermode::kSrcATop_Mode: { | |
641 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_Gr
BlendCoeff); | |
642 return SkRef(&gSrcATopPDXPF); | |
643 break; | |
644 } | |
645 case SkXfermode::kDstATop_Mode: { | |
646 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_Gr
BlendCoeff); | |
647 return SkRef(&gDstATopPDXPF); | |
648 break; | |
649 } | |
650 case SkXfermode::kXor_Mode: { | |
651 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBle
ndCoeff); | |
652 return SkRef(&gXorPDXPF); | |
653 break; | |
654 } | |
655 case SkXfermode::kPlus_Mode: { | |
656 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBl
endCoeff); | |
657 return SkRef(&gPlusPDXPF); | |
658 break; | |
659 } | |
660 case SkXfermode::kModulate_Mode: { | |
661 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_
GrBlendCoeff); | |
662 return SkRef(&gModulatePDXPF); | |
663 break; | |
664 } | |
665 case SkXfermode::kScreen_Mode: { | |
666 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_Gr
BlendCoeff); | |
667 return SkRef(&gScreenPDXPF); | |
668 break; | |
669 } | |
670 default: | |
671 return NULL; | |
672 } | 741 } |
| 742 return SkRef(gFactories[xfermode]); |
673 } | 743 } |
674 | 744 |
675 GrXferProcessor* | 745 GrXferProcessor* |
676 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, | 746 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, |
677 const GrProcOptInfo& colorPOI, | 747 const GrProcOptInfo& colorPOI, |
678 const GrProcOptInfo& covPOI, | 748 const GrProcOptInfo& covPOI, |
679 const DstTexture* dstTexture) const
{ | 749 const DstTexture* dstTexture) const
{ |
680 if (covPOI.isFourChannelOutput()) { | 750 if (covPOI.isFourChannelOutput()) { |
681 return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI); | 751 SkASSERT(!dstTexture || !dstTexture->texture()); |
682 } else { | 752 return PDLCDXferProcessor::Create(fXfermode, colorPOI); |
683 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstTextu
re, | |
684 this->willReadDstColor(caps, colo
rPOI, covPOI)); | |
685 } | 753 } |
| 754 |
| 755 BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI); |
| 756 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlend
ingSupport()) { |
| 757 return ShaderPDXferProcessor::Create(fXfermode, dstTexture); |
| 758 } |
| 759 |
| 760 SkASSERT(!dstTexture || !dstTexture->texture()); |
| 761 return PorterDuffXferProcessor::Create(blendFormula); |
686 } | 762 } |
687 | 763 |
688 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, | 764 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, |
689 uint32_t knownColorFlags) const
{ | 765 uint32_t knownColorFlags) const
{ |
690 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && | 766 if (SkXfermode::kSrcOver_Mode == fXfermode && |
691 kRGBA_GrColorComponentFlags == knownColorFlags) { | 767 kRGBA_GrColorComponentFlags == knownColorFlags) { |
692 return true; | 768 return true; |
693 } | 769 } |
694 return false; | 770 return false; |
695 } | 771 } |
696 | 772 |
697 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, | 773 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, |
698 const GrProcOptInfo& coveragePOI, | 774 const GrProcOptInfo& coveragePOI, |
699 GrXPFactory::InvariantOutput* out
put) const { | 775 GrXPFactory::InvariantOutput* out
put) const { |
700 if (!coveragePOI.isSolidWhite()) { | 776 output->fWillBlendWithDst = true; |
701 output->fWillBlendWithDst = true; | 777 output->fBlendedColorFlags = kNone_GrColorComponentFlags; |
702 output->fBlendedColorFlags = 0; | 778 |
| 779 // The blend table doesn't support LCD coverage, but these formulas never ha
ve invariant output. |
| 780 if (coveragePOI.isFourChannelOutput()) { |
703 return; | 781 return; |
704 } | 782 } |
705 | 783 |
706 GrBlendCoeff srcCoeff = fSrcCoeff; | 784 const BlendFormula& blendFormula = get_blend_formula(fXfermode, colorPOI, co
veragePOI); |
707 GrBlendCoeff dstCoeff = fDstCoeff; | 785 if (blendFormula.usesDstColor()) { |
708 | |
709 // TODO: figure out to merge this simplify with other current optimization c
ode paths and | |
710 // eventually remove from GrBlend | |
711 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(
), | |
712 0, 0, 0); | |
713 | |
714 if (GrBlendCoeffRefsDst(srcCoeff)) { | |
715 output->fWillBlendWithDst = true; | |
716 output->fBlendedColorFlags = 0; | |
717 return; | 786 return; |
718 } | 787 } |
719 | 788 |
720 if (kZero_GrBlendCoeff != dstCoeff) { | 789 SkASSERT(coveragePOI.isSolidWhite()); |
721 bool srcAIsOne = colorPOI.isOpaque(); | 790 SkASSERT(kAdd_GrBlendEquation == blendFormula.fBlendEquation); |
722 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) { | |
723 output->fWillBlendWithDst = true; | |
724 } | |
725 output->fBlendedColorFlags = 0; | |
726 return; | |
727 } | |
728 | 791 |
729 switch (srcCoeff) { | 792 output->fWillBlendWithDst = false; |
| 793 |
| 794 switch (blendFormula.fSrcCoeff) { |
730 case kZero_GrBlendCoeff: | 795 case kZero_GrBlendCoeff: |
731 output->fBlendedColor = 0; | 796 output->fBlendedColor = 0; |
732 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags; | 797 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags; |
733 break; | 798 return; |
734 | 799 |
735 case kOne_GrBlendCoeff: | 800 case kOne_GrBlendCoeff: |
736 output->fBlendedColor = colorPOI.color(); | 801 output->fBlendedColor = colorPOI.color(); |
737 output->fBlendedColorFlags = colorPOI.validFlags(); | 802 output->fBlendedColorFlags = colorPOI.validFlags(); |
738 break; | 803 return; |
739 | 804 |
740 // The src coeff should never refer to the src and if it refers to d
st then opaque | 805 default: return; |
741 // should have been false. | |
742 case kSC_GrBlendCoeff: | |
743 case kISC_GrBlendCoeff: | |
744 case kDC_GrBlendCoeff: | |
745 case kIDC_GrBlendCoeff: | |
746 case kSA_GrBlendCoeff: | |
747 case kISA_GrBlendCoeff: | |
748 case kDA_GrBlendCoeff: | |
749 case kIDA_GrBlendCoeff: | |
750 default: | |
751 SkFAIL("srcCoeff should not refer to src or dst."); | |
752 break; | |
753 | |
754 // TODO: update this once GrPaint actually has a const color. | |
755 case kConstC_GrBlendCoeff: | |
756 case kIConstC_GrBlendCoeff: | |
757 case kConstA_GrBlendCoeff: | |
758 case kIConstA_GrBlendCoeff: | |
759 output->fBlendedColorFlags = 0; | |
760 break; | |
761 } | 806 } |
762 | |
763 output->fWillBlendWithDst = false; | |
764 } | 807 } |
765 | 808 |
766 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, | 809 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, |
767 const GrProcOptInfo& colorPOI, | 810 const GrProcOptInfo& colorPOI, |
768 const GrProcOptInfo& coveragePOI) c
onst { | 811 const GrProcOptInfo& coveragePOI) c
onst { |
769 // We can always blend correctly if we have dual source blending. | 812 if (coveragePOI.isFourChannelOutput()) { |
770 if (caps.shaderCaps()->dualSourceBlendingSupport()) { | 813 return false; // The LCD XP never does a dst read. |
771 return false; | |
772 } | 814 } |
773 | 815 |
774 if (can_tweak_alpha_for_coverage(fDstCoeff)) { | 816 // We fallback on the shader XP when the blend formula would use dual source
blending but we |
775 return false; | 817 // don't have support for it. |
776 } | 818 return !caps.shaderCaps()->dualSourceBlendingSupport() && |
777 | 819 get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutpu
t(); |
778 bool srcAIsOne = colorPOI.isOpaque(); | |
779 | |
780 if (kZero_GrBlendCoeff == fDstCoeff) { | |
781 if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) { | |
782 return false; | |
783 } | |
784 } | |
785 | |
786 // Reduces to: coeffS * (Cov*S) + D | |
787 if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) { | |
788 return false; | |
789 } | |
790 | |
791 // We can always blend correctly if we have solid coverage. | |
792 if (coveragePOI.isSolidWhite()) { | |
793 return false; | |
794 } | |
795 | |
796 return true; | |
797 } | 820 } |
798 | 821 |
799 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); | 822 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); |
800 | 823 |
801 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, | 824 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, |
802 GrContext*, | 825 GrContext*, |
803 const GrCaps&, | 826 const GrCaps&, |
804 GrTexture*[]) { | 827 GrTexture*[]) { |
805 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k
LastCoeffMode)); | 828 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k
LastCoeffMode)); |
806 return GrPorterDuffXPFactory::Create(mode); | 829 return GrPorterDuffXPFactory::Create(mode); |
807 } | 830 } |
808 | 831 |
| 832 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, |
| 833 int* outPrimary, |
| 834 int* outSecondary) { |
| 835 if (!!strcmp(xp->name(), "Porter Duff")) { |
| 836 *outPrimary = *outSecondary = -1; |
| 837 return; |
| 838 } |
| 839 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)-
>getBlendFormula(); |
| 840 *outPrimary = blendFormula.fPrimaryOutputType; |
| 841 *outSecondary = blendFormula.fSecondaryOutputType; |
| 842 } |
| 843 |
OLD | NEW |