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