1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "src/gpu/effects/GrPorterDuffXferProcessor.h" 9 10 #include "include/gpu/GrTypes.h" 11 #include "include/private/SkMacros.h" 12 #include "include/private/SkTo.h" 13 #include "src/gpu/GrBlend.h" 14 #include "src/gpu/GrCaps.h" 15 #include "src/gpu/GrPipeline.h" 16 #include "src/gpu/GrProcessor.h" 17 #include "src/gpu/GrProcessorAnalysis.h" 18 #include "src/gpu/GrXferProcessor.h" 19 #include "src/gpu/glsl/GrGLSLBlend.h" 20 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 21 #include "src/gpu/glsl/GrGLSLProgramDataManager.h" 22 #include "src/gpu/glsl/GrGLSLUniformHandler.h" 23 24 /** 25 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage. 26 */ 27 class BlendFormula { 28 public: 29 /** 30 * Values the shader can write to primary and secondary outputs. These are all modulated by 31 * coverage. The XP will ignore the multiplies when not using coverage. 32 */ 33 enum OutputType { 34 kNone_OutputType, //<! 0 35 kCoverage_OutputType, //<! inputCoverage 36 kModulate_OutputType, //<! inputColor * inputCoverage 37 kSAModulate_OutputType, //<! inputColor.a * inputCoverage 38 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage 39 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage 40 41 kLast_OutputType = kISCModulate_OutputType 42 }; 43 BlendFormula(OutputType primaryOut, OutputType secondaryOut, GrBlendEquation equation, GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff)44 constexpr BlendFormula(OutputType primaryOut, OutputType secondaryOut, GrBlendEquation equation, 45 GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) 46 : fPrimaryOutputType(primaryOut) 47 , fSecondaryOutputType(secondaryOut) 48 , fBlendEquation(equation) 49 , fSrcCoeff(srcCoeff) 50 , fDstCoeff(dstCoeff) 51 , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {} 52 53 BlendFormula(const BlendFormula&) = default; 54 BlendFormula& operator=(const BlendFormula&) = default; 55 operator ==(const BlendFormula& that) const56 bool operator==(const BlendFormula& that) const { 57 return fPrimaryOutputType == that.fPrimaryOutputType && 58 fSecondaryOutputType == that. fSecondaryOutputType && 59 fBlendEquation == that.fBlendEquation && 60 fSrcCoeff == that.fSrcCoeff && 61 fDstCoeff == that.fDstCoeff && 62 fProps == that.fProps; 63 } 64 hasSecondaryOutput() const65 bool hasSecondaryOutput() const { 66 return kNone_OutputType != fSecondaryOutputType; 67 } modifiesDst() const68 bool modifiesDst() const { 69 return SkToBool(fProps & kModifiesDst_Property); 70 } unaffectedByDst() const71 bool unaffectedByDst() const { 72 return SkToBool(fProps & kUnaffectedByDst_Property); 73 } 74 // We don't always fully optimize the blend formula (e.g., for opaque src-over), so we include 75 // an "IfOpaque" variant to help set AnalysisProperties::kUnaffectedByDstValue in those cases. unaffectedByDstIfOpaque() const76 bool unaffectedByDstIfOpaque() const { 77 return SkToBool(fProps & kUnaffectedByDstIfOpaque_Property); 78 } usesInputColor() const79 bool usesInputColor() const { 80 return SkToBool(fProps & kUsesInputColor_Property); 81 } canTweakAlphaForCoverage() const82 bool canTweakAlphaForCoverage() const { 83 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property); 84 } 85 equation() const86 GrBlendEquation equation() const { 87 return fBlendEquation; 88 } 89 srcCoeff() const90 GrBlendCoeff srcCoeff() const { 91 return fSrcCoeff; 92 } 93 dstCoeff() const94 GrBlendCoeff dstCoeff() const { 95 return fDstCoeff; 96 } 97 primaryOutput() const98 OutputType primaryOutput() const { 99 return fPrimaryOutputType; 100 } 101 secondaryOutput() const102 OutputType secondaryOutput() const { 103 return fSecondaryOutputType; 104 } 105 106 private: 107 enum Properties { 108 kModifiesDst_Property = 1 << 0, 109 kUnaffectedByDst_Property = 1 << 1, 110 kUnaffectedByDstIfOpaque_Property = 1 << 2, 111 kUsesInputColor_Property = 1 << 3, 112 kCanTweakAlphaForCoverage_Property = 1 << 4, 113 114 kLast_Property = kCanTweakAlphaForCoverage_Property 115 }; 116 SK_DECL_BITFIELD_OPS_FRIENDS(Properties) 117 118 /** 119 * Deduce the properties of a BlendFormula. 120 */ 121 static constexpr Properties GetProperties(OutputType PrimaryOut, OutputType SecondaryOut, 122 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, 123 GrBlendCoeff DstCoeff); 124 125 struct { 126 // We allot the enums one more bit than they require because MSVC seems to sign-extend 127 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4) 128 OutputType fPrimaryOutputType : 4; 129 OutputType fSecondaryOutputType : 4; 130 GrBlendEquation fBlendEquation : 6; 131 GrBlendCoeff fSrcCoeff : 6; 132 GrBlendCoeff fDstCoeff : 6; 133 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6); 134 }; 135 136 static_assert(kLast_OutputType < (1 << 3)); 137 static_assert(kLast_GrBlendEquation < (1 << 5)); 138 static_assert(kLast_GrBlendCoeff < (1 << 5)); 139 static_assert(kLast_Property < (1 << 6)); 140 }; 141 142 static_assert(4 == sizeof(BlendFormula)); 143 144 SK_MAKE_BITFIELD_OPS(BlendFormula::Properties) 145 146 constexpr BlendFormula::Properties BlendFormula::GetProperties(OutputType PrimaryOut, 147 OutputType SecondaryOut, 148 GrBlendEquation BlendEquation, 149 GrBlendCoeff SrcCoeff, 150 GrBlendCoeff DstCoeff) { 151 return 152 // The provided formula should already be optimized before a BlendFormula is constructed. 153 // Assert that here while setting up the properties in the constexpr constructor. 154 SkASSERT((kNone_OutputType == PrimaryOut) == !GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)), 155 SkASSERT(!GrBlendCoeffRefsSrc2(SrcCoeff)), 156 SkASSERT((kNone_OutputType == SecondaryOut) == !GrBlendCoeffRefsSrc2(DstCoeff)), 157 SkASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut), 158 SkASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut), 159 160 static_cast<Properties>( 161 (GrBlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) | 162 (!GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff, false/*srcColorIsOpaque*/) 163 ? kUnaffectedByDst_Property 164 : 0) | 165 (!GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff, true/*srcColorIsOpaque*/) 166 ? kUnaffectedByDstIfOpaque_Property 167 : 0) | 168 ((PrimaryOut >= kModulate_OutputType && GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) || 169 (SecondaryOut >= kModulate_OutputType && 170 GrBlendCoeffRefsSrc2(DstCoeff)) 171 ? kUsesInputColor_Property 172 : 0) | // We assert later that SrcCoeff doesn't ref src2. 173 ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) && 174 kNone_OutputType == SecondaryOut && 175 GrBlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff) 176 ? kCanTweakAlphaForCoverage_Property 177 : 0)); 178 } 179 180 /** 181 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard 182 * Porter Duff formula. 183 */ 184 static constexpr BlendFormula MakeCoeffFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { 185 // When the coeffs are (Zero, Zero) or (Zero, One) we set the primary output to none. 186 return (kZero_GrBlendCoeff == srcCoeff && 187 (kZero_GrBlendCoeff == dstCoeff || kOne_GrBlendCoeff == dstCoeff)) 188 ? BlendFormula(BlendFormula::kNone_OutputType, BlendFormula::kNone_OutputType, 189 kAdd_GrBlendEquation, kZero_GrBlendCoeff, dstCoeff) 190 : BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kNone_OutputType, 191 kAdd_GrBlendEquation, srcCoeff, dstCoeff); 192 } 193 194 /** 195 * Basic coeff formula similar to MakeCoeffFormula but we will make the src f*Sa. This is used in 196 * LCD dst-out. 197 */ 198 static constexpr BlendFormula MakeSAModulateFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) { 199 return BlendFormula(BlendFormula::kSAModulate_OutputType, BlendFormula::kNone_OutputType, 200 kAdd_GrBlendEquation, srcCoeff, dstCoeff); 201 } 202 203 /** 204 * When there is coverage, the equation with f=coverage is: 205 * 206 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D 207 * 208 * This can be rewritten as: 209 * 210 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)]) 211 * 212 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the 213 * HW dst coeff with IS2C. 214 * 215 * Xfer modes: dst-atop (Sa!=1) 216 */ 217 static constexpr BlendFormula MakeCoverageFormula( 218 BlendFormula::OutputType oneMinusDstCoeffModulateOutput, GrBlendCoeff srcCoeff) { 219 return BlendFormula(BlendFormula::kModulate_OutputType, oneMinusDstCoeffModulateOutput, 220 kAdd_GrBlendEquation, srcCoeff, kIS2C_GrBlendCoeff); 221 } 222 223 /** 224 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes: 225 * 226 * D' = f * D * dstCoeff + (1-f) * D 227 * 228 * This can be rewritten as: 229 * 230 * D' = D - D * [f * (1 - dstCoeff)] 231 * 232 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse 233 * subtract HW blend equation with coeffs of (DC, One). 234 * 235 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1) 236 */ 237 static constexpr BlendFormula MakeCoverageSrcCoeffZeroFormula( 238 BlendFormula::OutputType oneMinusDstCoeffModulateOutput) { 239 return BlendFormula(oneMinusDstCoeffModulateOutput, BlendFormula::kNone_OutputType, 240 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff); 241 } 242 243 /** 244 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes: 245 * 246 * D' = f * S * srcCoeff + (1-f) * D 247 * 248 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff 249 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.) 250 * 251 * Xfer modes (Sa!=1): src, src-in, src-out 252 */ 253 static constexpr BlendFormula MakeCoverageDstCoeffZeroFormula(GrBlendCoeff srcCoeff) { 254 return BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kCoverage_OutputType, 255 kAdd_GrBlendEquation, srcCoeff, kIS2A_GrBlendCoeff); 256 } 257 258 /** 259 * This table outlines the blend formulas we will use with each xfermode, with and without coverage, 260 * with and without an opaque input color. Optimization properties are deduced at compile time so we 261 * can make runtime decisions quickly. RGB coverage is not supported. 262 */ 263 static constexpr BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = { 264 /*>> No coverage, input color unknown <<*/ {{ 265 266 /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff), 267 /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff), 268 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), 269 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), 270 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), 271 /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff), 272 /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kSA_GrBlendCoeff), 273 /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff), 274 /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff), 275 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), 276 /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kSA_GrBlendCoeff), 277 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), 278 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), 279 /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff), 280 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), 281 282 }, /*>> Has coverage, input color unknown <<*/ { 283 284 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), 285 /* src */ MakeCoverageDstCoeffZeroFormula(kOne_GrBlendCoeff), 286 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), 287 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), 288 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), 289 /* src-in */ MakeCoverageDstCoeffZeroFormula(kDA_GrBlendCoeff), 290 /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType), 291 /* src-out */ MakeCoverageDstCoeffZeroFormula(kIDA_GrBlendCoeff), 292 /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff), 293 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), 294 /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff), 295 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), 296 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), 297 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType), 298 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), 299 300 }}, /*>> No coverage, input color opaque <<*/ {{ 301 302 /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff), 303 /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff), 304 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), 305 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), // see comment below 306 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), 307 /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff), 308 /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), 309 /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff), 310 /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff), 311 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff), 312 /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), 313 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff), 314 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), 315 /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff), 316 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), 317 318 }, /*>> Has coverage, input color opaque <<*/ { 319 320 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), 321 /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), 322 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), 323 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), 324 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), 325 /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), 326 /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), 327 /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), 328 /* dst-out */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), 329 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff), 330 /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), 331 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff), 332 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), 333 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType), 334 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), 335 }}}; 336 // In the above table src-over is not optimized to src mode when the color is opaque because we 337 // found no advantage to doing so. Also, we are using a global src-over XP in most cases which is 338 // not specialized for opaque input. For GPUs where dropping to src (and thus able to disable 339 // blending) is an advantage we change the blend mode to src before getitng the blend formula from 340 // this table. 341 static constexpr BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = { 342 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType), 343 /* src */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff), 344 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff), 345 /* src-over */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff), 346 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff), 347 /* src-in */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff), 348 /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType), 349 /* src-out */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff), 350 /* dst-out */ MakeSAModulateFormula(kZero_GrBlendCoeff, kISC_GrBlendCoeff), 351 /* src-atop */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff), 352 /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff), 353 /* xor */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff), 354 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff), 355 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType), 356 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff), 357 }; 358 359 static BlendFormula get_blend_formula(bool isOpaque, 360 bool hasCoverage, 361 SkBlendMode xfermode) { 362 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode); 363 return gBlendTable[isOpaque][hasCoverage][(int)xfermode]; 364 } 365 366 static BlendFormula get_lcd_blend_formula(SkBlendMode xfermode) { 367 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode); 368 369 return gLCDBlendTable[(int)xfermode]; 370 } 371 372 /////////////////////////////////////////////////////////////////////////////// 373 374 class PorterDuffXferProcessor : public GrXferProcessor { 375 public: 376 PorterDuffXferProcessor(BlendFormula blendFormula, GrProcessorAnalysisCoverage coverage) 377 : INHERITED(kPorterDuffXferProcessor_ClassID, /*willReadDstColor=*/false, coverage) 378 , fBlendFormula(blendFormula) { 379 } 380 381 const char* name() const override { return "Porter Duff"; } 382 383 SkString getShaderDfxInfo() const override; 384 385 std::unique_ptr<ProgramImpl> makeProgramImpl() const override; 386 387 BlendFormula getBlendFormula() const { return fBlendFormula; } 388 389 private: 390 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 391 392 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); } 393 394 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { 395 blendInfo->fEquation = fBlendFormula.equation(); 396 blendInfo->fSrcBlend = fBlendFormula.srcCoeff(); 397 blendInfo->fDstBlend = fBlendFormula.dstCoeff(); 398 blendInfo->fWriteColor = fBlendFormula.modifiesDst(); 399 } 400 401 bool onIsEqual(const GrXferProcessor& xpBase) const override { 402 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>(); 403 return fBlendFormula == xp.fBlendFormula; 404 } 405 406 const BlendFormula fBlendFormula; 407 408 using INHERITED = GrXferProcessor; 409 }; 410 411 /////////////////////////////////////////////////////////////////////////////// 412 413 static void append_color_output(const PorterDuffXferProcessor& xp, 414 GrGLSLXPFragmentBuilder* fragBuilder, 415 BlendFormula::OutputType outputType, const char* output, 416 const char* inColor, const char* inCoverage) { 417 SkASSERT(inCoverage); 418 SkASSERT(inColor); 419 switch (outputType) { 420 case BlendFormula::kNone_OutputType: 421 fragBuilder->codeAppendf("%s = half4(0.0);", output); 422 break; 423 case BlendFormula::kCoverage_OutputType: 424 fragBuilder->codeAppendf("%s = %s;", output, inCoverage); 425 break; 426 case BlendFormula::kModulate_OutputType: 427 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage); 428 break; 429 case BlendFormula::kSAModulate_OutputType: 430 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage); 431 break; 432 case BlendFormula::kISAModulate_OutputType: 433 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage); 434 break; 435 case BlendFormula::kISCModulate_OutputType: 436 fragBuilder->codeAppendf("%s = (half4(1.0) - %s) * %s;", output, inColor, inCoverage); 437 break; 438 default: 439 SK_ABORT("Unsupported output type."); 440 break; 441 } 442 } 443 444 SkString PorterDuffXferProcessor::getShaderDfxInfo() const 445 { 446 SkString format; 447 format.printf("ShaderDfx_PorterDuffXfer_%d_%d", fBlendFormula.primaryOutput(), fBlendFormula.secondaryOutput()); 448 return format; 449 } 450 451 void PorterDuffXferProcessor::onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { 452 b->add32(fBlendFormula.primaryOutput() | (fBlendFormula.secondaryOutput() << 3)); 453 static_assert(BlendFormula::kLast_OutputType < 8); 454 } 455 456 std::unique_ptr<GrXferProcessor::ProgramImpl> PorterDuffXferProcessor::makeProgramImpl() const { 457 class Impl : public ProgramImpl { 458 private: 459 void emitOutputsForBlendState(const EmitArgs& args) override { 460 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>(); 461 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; 462 463 const BlendFormula& blendFormula = xp.fBlendFormula; 464 if (blendFormula.hasSecondaryOutput()) { 465 append_color_output(xp, 466 fragBuilder, 467 blendFormula.secondaryOutput(), 468 args.fOutputSecondary, 469 args.fInputColor, 470 args.fInputCoverage); 471 } 472 append_color_output(xp, 473 fragBuilder, 474 blendFormula.primaryOutput(), 475 args.fOutputPrimary, 476 args.fInputColor, 477 args.fInputCoverage); 478 } 479 }; 480 481 return std::make_unique<Impl>(); 482 } 483 484 /////////////////////////////////////////////////////////////////////////////// 485 486 class ShaderPDXferProcessor : public GrXferProcessor { 487 public: 488 ShaderPDXferProcessor(SkBlendMode xfermode, GrProcessorAnalysisCoverage coverage) 489 : INHERITED(kShaderPDXferProcessor_ClassID, /*willReadDstColor=*/true, coverage) 490 , fXfermode(xfermode) { 491 } 492 493 const char* name() const override { return "Porter Duff Shader"; } 494 495 SkString getShaderDfxInfo() const override; 496 497 std::unique_ptr<ProgramImpl> makeProgramImpl() const override; 498 499 private: 500 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 501 502 bool onIsEqual(const GrXferProcessor& xpBase) const override { 503 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>(); 504 return fXfermode == xp.fXfermode; 505 } 506 507 const SkBlendMode fXfermode; 508 509 using INHERITED = GrXferProcessor; 510 }; 511 512 /////////////////////////////////////////////////////////////////////////////// 513 514 SkString ShaderPDXferProcessor::getShaderDfxInfo() const 515 { 516 SkString format; 517 format.printf("ShaderDfx_ShaderPDXfer_%d", fXfermode); 518 return format; 519 } 520 521 void ShaderPDXferProcessor::onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { 522 b->add32(static_cast<int>(fXfermode)); 523 } 524 525 std::unique_ptr<GrXferProcessor::ProgramImpl> ShaderPDXferProcessor::makeProgramImpl() const { 526 class Impl : public ProgramImpl { 527 private: 528 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, 529 GrGLSLUniformHandler* uniformHandler, 530 const char* srcColor, 531 const char* srcCoverage, 532 const char* dstColor, 533 const char* outColor, 534 const char* outColorSecondary, 535 const GrXferProcessor& proc) override { 536 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>(); 537 538 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.fXfermode); 539 540 // Apply coverage. 541 DefaultCoverageModulation(fragBuilder, 542 srcCoverage, 543 dstColor, 544 outColor, 545 outColorSecondary, 546 xp); 547 } 548 }; 549 550 return std::make_unique<Impl>(); 551 } 552 553 /////////////////////////////////////////////////////////////////////////////// 554 555 class PDLCDXferProcessor : public GrXferProcessor { 556 public: 557 static sk_sp<const GrXferProcessor> Make(SkBlendMode mode, 558 const GrProcessorAnalysisColor& inputColor); 559 560 const char* name() const override { return "Porter Duff LCD"; } 561 562 SkString getShaderDfxInfo() const override { return SkString("ShaderDfx_PDLCDXfer"); } 563 564 std::unique_ptr<ProgramImpl> makeProgramImpl() const override; 565 566 private: 567 PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha); 568 569 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} 570 571 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { 572 blendInfo->fSrcBlend = kConstC_GrBlendCoeff; 573 blendInfo->fDstBlend = kISC_GrBlendCoeff; 574 blendInfo->fBlendConstant = fBlendConstant; 575 } 576 577 bool onIsEqual(const GrXferProcessor& xpBase) const override { 578 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>(); 579 if (fBlendConstant != xp.fBlendConstant || fAlpha != xp.fAlpha) { 580 return false; 581 } 582 return true; 583 } 584 585 SkPMColor4f fBlendConstant; 586 float fAlpha; 587 588 using INHERITED = GrXferProcessor; 589 }; 590 591 PDLCDXferProcessor::PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha) 592 : INHERITED(kPDLCDXferProcessor_ClassID, /*willReadDstColor=*/false, 593 GrProcessorAnalysisCoverage::kLCD) 594 , fBlendConstant(blendConstant) 595 , fAlpha(alpha) { 596 } 597 598 sk_sp<const GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode mode, 599 const GrProcessorAnalysisColor& color) { 600 if (SkBlendMode::kSrcOver != mode) { 601 return nullptr; 602 } 603 SkPMColor4f blendConstantPM; 604 if (!color.isConstant(&blendConstantPM)) { 605 return nullptr; 606 } 607 SkColor4f blendConstantUPM = blendConstantPM.unpremul(); 608 float alpha = blendConstantUPM.fA; 609 blendConstantPM = { blendConstantUPM.fR, blendConstantUPM.fG, blendConstantUPM.fB, 1 }; 610 return sk_sp<GrXferProcessor>(new PDLCDXferProcessor(blendConstantPM, alpha)); 611 } 612 613 std::unique_ptr<GrXferProcessor::ProgramImpl> PDLCDXferProcessor::makeProgramImpl() const { 614 class Impl : public ProgramImpl { 615 private: 616 void emitOutputsForBlendState(const EmitArgs& args) override { 617 const char* alpha; 618 fAlphaUniform = args.fUniformHandler->addUniform(nullptr, 619 kFragment_GrShaderFlag, 620 kHalf_GrSLType, 621 "alpha", 622 &alpha); 623 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder; 624 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha 625 // value of the src color. We know that there are no color stages (or we wouldn't have 626 // created this xp) and the r,g, and b channels of the op's input color are baked into 627 // the blend constant. 628 SkASSERT(args.fInputCoverage); 629 fragBuilder->codeAppendf("%s = %s * %s;", 630 args.fOutputPrimary, 631 alpha, args.fInputCoverage); 632 } 633 634 void onSetData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) override { 635 float alpha = xp.cast<PDLCDXferProcessor>().fAlpha; 636 if (fLastAlpha != alpha) { 637 pdm.set1f(fAlphaUniform, alpha); 638 fLastAlpha = alpha; 639 } 640 } 641 642 GrGLSLUniformHandler::UniformHandle fAlphaUniform; 643 float fLastAlpha = SK_FloatNaN; 644 }; 645 646 return std::make_unique<Impl>(); 647 } 648 649 /////////////////////////////////////////////////////////////////////////////// 650 651 constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode) 652 : fBlendMode(xfermode) {} 653 654 const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) { 655 SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode); 656 657 static constexpr const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear); 658 static constexpr const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc); 659 static constexpr const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst); 660 static constexpr const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver); 661 static constexpr const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver); 662 static constexpr const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn); 663 static constexpr const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn); 664 static constexpr const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut); 665 static constexpr const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut); 666 static constexpr const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop); 667 static constexpr const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop); 668 static constexpr const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor); 669 static constexpr const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus); 670 static constexpr const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate); 671 static constexpr const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen); 672 673 switch (blendMode) { 674 case SkBlendMode::kClear: 675 return &gClearPDXPF; 676 case SkBlendMode::kSrc: 677 return &gSrcPDXPF; 678 case SkBlendMode::kDst: 679 return &gDstPDXPF; 680 case SkBlendMode::kSrcOver: 681 return &gSrcOverPDXPF; 682 case SkBlendMode::kDstOver: 683 return &gDstOverPDXPF; 684 case SkBlendMode::kSrcIn: 685 return &gSrcInPDXPF; 686 case SkBlendMode::kDstIn: 687 return &gDstInPDXPF; 688 case SkBlendMode::kSrcOut: 689 return &gSrcOutPDXPF; 690 case SkBlendMode::kDstOut: 691 return &gDstOutPDXPF; 692 case SkBlendMode::kSrcATop: 693 return &gSrcATopPDXPF; 694 case SkBlendMode::kDstATop: 695 return &gDstATopPDXPF; 696 case SkBlendMode::kXor: 697 return &gXorPDXPF; 698 case SkBlendMode::kPlus: 699 return &gPlusPDXPF; 700 case SkBlendMode::kModulate: 701 return &gModulatePDXPF; 702 case SkBlendMode::kScreen: 703 return &gScreenPDXPF; 704 default: 705 SK_ABORT("Unexpected blend mode."); 706 } 707 } 708 709 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor( 710 const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage, 711 const GrCaps& caps, GrClampType clampType) const { 712 bool isLCD = coverage == GrProcessorAnalysisCoverage::kLCD; 713 // See comment in MakeSrcOverXferProcessor about color.isOpaque here 714 if (isLCD && 715 SkBlendMode::kSrcOver == fBlendMode && color.isConstant() && /*color.isOpaque() &&*/ 716 !caps.shaderCaps()->dualSourceBlendingSupport() && 717 !caps.shaderCaps()->dstReadInShaderSupport()) { 718 // If we don't have dual source blending or in shader dst reads, we fall back to this 719 // trick for rendering SrcOver LCD text instead of doing a dst copy. 720 return PDLCDXferProcessor::Make(fBlendMode, color); 721 } 722 BlendFormula blendFormula = [&](){ 723 if (isLCD) { 724 return get_lcd_blend_formula(fBlendMode); 725 } 726 if (fBlendMode == SkBlendMode::kSrcOver && color.isOpaque() && 727 coverage == GrProcessorAnalysisCoverage::kNone && 728 caps.shouldCollapseSrcOverToSrcWhenAble()) 729 { 730 return get_blend_formula(true, false, SkBlendMode::kSrc); 731 } 732 return get_blend_formula(color.isOpaque(), GrProcessorAnalysisCoverage::kNone != coverage, 733 fBlendMode); 734 }(); 735 736 // Skia always saturates after the kPlus blend mode, so it requires shader-based blending when 737 // pixels aren't guaranteed to automatically be normalized (i.e. any floating point config). 738 if ((blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) || 739 (isLCD && (SkBlendMode::kSrcOver != fBlendMode /*|| !color.isOpaque()*/)) || 740 (GrClampType::kAuto != clampType && SkBlendMode::kPlus == fBlendMode)) { 741 return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(fBlendMode, coverage)); 742 } 743 return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage)); 744 } 745 746 static inline GrXPFactory::AnalysisProperties analysis_properties( 747 const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage, 748 const GrCaps& caps, GrClampType clampType, SkBlendMode mode) { 749 using AnalysisProperties = GrXPFactory::AnalysisProperties; 750 AnalysisProperties props = AnalysisProperties::kNone; 751 bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage; 752 bool isLCD = GrProcessorAnalysisCoverage::kLCD == coverage; 753 BlendFormula formula = [&](){ 754 if (isLCD) { 755 return gLCDBlendTable[(int)mode]; 756 } 757 return get_blend_formula(color.isOpaque(), hasCoverage, mode); 758 }(); 759 760 if (formula.canTweakAlphaForCoverage() && !isLCD) { 761 props |= AnalysisProperties::kCompatibleWithCoverageAsAlpha; 762 } 763 764 if (isLCD) { 765 // See comment in MakeSrcOverXferProcessor about color.isOpaque here 766 if (SkBlendMode::kSrcOver == mode && color.isConstant() && /*color.isOpaque() &&*/ 767 !caps.shaderCaps()->dualSourceBlendingSupport() && 768 !caps.shaderCaps()->dstReadInShaderSupport()) { 769 props |= AnalysisProperties::kIgnoresInputColor; 770 } else { 771 // For LCD blending, if the color is not opaque we must read the dst in shader even if 772 // we have dual source blending. The opaqueness check must be done after blending so for 773 // simplicity we only allow src-over to not take the dst read path (though src, src-in, 774 // and DstATop would also work). We also fall into the dst read case for src-over if we 775 // do not have dual source blending. 776 if (SkBlendMode::kSrcOver != mode || 777 /*!color.isOpaque() ||*/ // See comment in MakeSrcOverXferProcessor about isOpaque. 778 (formula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport())) { 779 props |= AnalysisProperties::kReadsDstInShader; 780 } 781 } 782 } else { 783 // With dual-source blending we never need the destination color in the shader. 784 if (!caps.shaderCaps()->dualSourceBlendingSupport()) { 785 if (formula.hasSecondaryOutput()) { 786 props |= AnalysisProperties::kReadsDstInShader; 787 } 788 } 789 } 790 791 if (GrClampType::kAuto != clampType && SkBlendMode::kPlus == mode) { 792 props |= AnalysisProperties::kReadsDstInShader; 793 } 794 795 if (!formula.modifiesDst() || !formula.usesInputColor()) { 796 props |= AnalysisProperties::kIgnoresInputColor; 797 } 798 if (formula.unaffectedByDst() || (formula.unaffectedByDstIfOpaque() && color.isOpaque() && 799 !hasCoverage)) { 800 props |= AnalysisProperties::kUnaffectedByDstValue; 801 } 802 return props; 803 } 804 805 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties( 806 const GrProcessorAnalysisColor& color, 807 const GrProcessorAnalysisCoverage& coverage, 808 const GrCaps& caps, 809 GrClampType clampType) const { 810 return analysis_properties(color, coverage, caps, clampType, fBlendMode); 811 } 812 813 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); 814 815 #if GR_TEST_UTILS 816 const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) { 817 SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode)); 818 return GrPorterDuffXPFactory::Get(mode); 819 } 820 #endif 821 822 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp, 823 int* outPrimary, 824 int* outSecondary) { 825 if (!!strcmp(xp->name(), "Porter Duff")) { 826 *outPrimary = *outSecondary = -1; 827 return; 828 } 829 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula(); 830 *outPrimary = blendFormula.primaryOutput(); 831 *outSecondary = blendFormula.secondaryOutput(); 832 } 833 834 //////////////////////////////////////////////////////////////////////////////////////////////// 835 // SrcOver Global functions 836 //////////////////////////////////////////////////////////////////////////////////////////////// 837 const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() { 838 static BlendFormula gSrcOverBlendFormula = 839 MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff); 840 static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula, 841 GrProcessorAnalysisCoverage::kSingleChannel); 842 return gSrcOverXP; 843 } 844 845 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor( 846 const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage, 847 const GrCaps& caps) { 848 // We want to not make an xfer processor if possible. Thus for the simple case where we are not 849 // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from 850 // the general case where we convert a src-over blend that has solid coverage and an opaque 851 // color to src-mode, which allows disabling of blending. 852 if (coverage != GrProcessorAnalysisCoverage::kLCD) { 853 if (color.isOpaque() && coverage == GrProcessorAnalysisCoverage::kNone && 854 caps.shouldCollapseSrcOverToSrcWhenAble()) { 855 BlendFormula blendFormula = get_blend_formula(true, false, SkBlendMode::kSrc); 856 return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage)); 857 } 858 // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP". 859 // We don't simply return the address of that XP here because our caller would have to unref 860 // it and since it is a global object and GrProgramElement's ref-cnting system is not thread 861 // safe. 862 return nullptr; 863 } 864 865 // Currently up the stack Skia is requiring that the dst is opaque or that the client has said 866 // the opaqueness doesn't matter. Thus for src-over we don't need to worry about the src color 867 // being opaque or not. This allows us to use faster code paths as well as avoid various bugs 868 // that occur with dst reads in the shader blending. For now we disable the check for 869 // opaqueness, but in the future we should pass down the knowledge about dst opaqueness and make 870 // the correct decision here. 871 // 872 // This also fixes a chrome bug on macs where we are getting random fuzziness when doing 873 // blending in the shader for non opaque sources. 874 if (color.isConstant() && /*color.isOpaque() &&*/ 875 !caps.shaderCaps()->dualSourceBlendingSupport() && 876 !caps.shaderCaps()->dstReadInShaderSupport()) { 877 // If we don't have dual source blending or in shader dst reads, we fall 878 // back to this trick for rendering SrcOver LCD text instead of doing a 879 // dst copy. 880 return PDLCDXferProcessor::Make(SkBlendMode::kSrcOver, color); 881 } 882 883 BlendFormula blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver); 884 // See comment above regarding why the opaque check is commented out here. 885 if (/*!color.isOpaque() ||*/ 886 (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport())) { 887 return sk_sp<GrXferProcessor>(new ShaderPDXferProcessor(SkBlendMode::kSrcOver, coverage)); 888 } 889 return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage)); 890 } 891 892 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) { 893 BlendFormula formula = get_blend_formula(false, false, blendmode); 894 return sk_make_sp<PorterDuffXferProcessor>(formula, GrProcessorAnalysisCoverage::kNone); 895 } 896 897 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties( 898 const GrProcessorAnalysisColor& color, 899 const GrProcessorAnalysisCoverage& coverage, 900 const GrCaps& caps, 901 GrClampType clampType) { 902 return analysis_properties(color, coverage, caps, clampType, SkBlendMode::kSrcOver); 903 } 904