1 /* 2 * Copyright 2015 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 "GrXfermodeFragmentProcessor.h" 9 10 #include "GrConstColorProcessor.h" 11 #include "GrFragmentProcessor.h" 12 #include "glsl/GrGLSLFragmentProcessor.h" 13 #include "glsl/GrGLSLBlend.h" 14 #include "glsl/GrGLSLFragmentShaderBuilder.h" 15 #include "SkGr.h" 16 #include "SkXfermodePriv.h" 17 18 // Some of the cpu implementations of blend modes differ too much from the GPU enough that 19 // we can't use the cpu implementation to implement constantOutputForConstantInput. 20 static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) { 21 // The non-seperable modes differ too much. So does SoftLight. ColorBurn differs too much on our 22 // test iOS device (but we just disable it across the aboard since it may happen on untested 23 // GPUs). 24 return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight && 25 mode != SkBlendMode::kColorBurn; 26 } 27 28 ////////////////////////////////////////////////////////////////////////////// 29 30 class ComposeTwoFragmentProcessor : public GrFragmentProcessor { 31 public: 32 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src, 33 std::unique_ptr<GrFragmentProcessor> dst, 34 SkBlendMode mode) { 35 return std::unique_ptr<GrFragmentProcessor>( 36 new ComposeTwoFragmentProcessor(std::move(src), std::move(dst), mode)); 37 } 38 39 const char* name() const override { return "ComposeTwo"; } 40 41 SkString dumpInfo() const override { 42 SkString str; 43 44 str.appendf("Mode: %s", SkBlendMode_Name(fMode)); 45 46 for (int i = 0; i < this->numChildProcessors(); ++i) { 47 str.appendf(" [%s %s]", 48 this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str()); 49 } 50 return str; 51 } 52 53 std::unique_ptr<GrFragmentProcessor> clone() const override; 54 55 SkBlendMode getMode() const { return fMode; } 56 57 private: 58 ComposeTwoFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src, 59 std::unique_ptr<GrFragmentProcessor> dst, 60 SkBlendMode mode) 61 : INHERITED(kComposeTwoFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode)) 62 , fMode(mode) { 63 SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src)); 64 SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst)); 65 SkASSERT(0 == shaderAChildIndex); 66 SkASSERT(1 == shaderBChildIndex); 67 } 68 69 static OptimizationFlags OptFlags(const GrFragmentProcessor* src, 70 const GrFragmentProcessor* dst, SkBlendMode mode) { 71 OptimizationFlags flags; 72 switch (mode) { 73 case SkBlendMode::kClear: 74 case SkBlendMode::kSrc: 75 case SkBlendMode::kDst: 76 SK_ABORT("Should never create clear, src, or dst compose two FP."); 77 flags = kNone_OptimizationFlags; 78 break; 79 80 // Produces opaque if both src and dst are opaque. 81 case SkBlendMode::kSrcIn: 82 case SkBlendMode::kDstIn: 83 case SkBlendMode::kModulate: 84 flags = src->preservesOpaqueInput() && dst->preservesOpaqueInput() 85 ? kPreservesOpaqueInput_OptimizationFlag 86 : kNone_OptimizationFlags; 87 break; 88 89 // Produces zero when both are opaque, indeterminate if one is opaque. 90 case SkBlendMode::kSrcOut: 91 case SkBlendMode::kDstOut: 92 case SkBlendMode::kXor: 93 flags = kNone_OptimizationFlags; 94 break; 95 96 // Is opaque if the dst is opaque. 97 case SkBlendMode::kSrcATop: 98 flags = dst->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag 99 : kNone_OptimizationFlags; 100 break; 101 102 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque. 103 case SkBlendMode::kDstATop: 104 case SkBlendMode::kScreen: 105 flags = src->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag 106 : kNone_OptimizationFlags; 107 break; 108 109 // These modes are all opaque if either src or dst is opaque. All the advanced modes 110 // compute alpha as src-over. 111 case SkBlendMode::kSrcOver: 112 case SkBlendMode::kDstOver: 113 case SkBlendMode::kPlus: 114 case SkBlendMode::kOverlay: 115 case SkBlendMode::kDarken: 116 case SkBlendMode::kLighten: 117 case SkBlendMode::kColorDodge: 118 case SkBlendMode::kColorBurn: 119 case SkBlendMode::kHardLight: 120 case SkBlendMode::kSoftLight: 121 case SkBlendMode::kDifference: 122 case SkBlendMode::kExclusion: 123 case SkBlendMode::kMultiply: 124 case SkBlendMode::kHue: 125 case SkBlendMode::kSaturation: 126 case SkBlendMode::kColor: 127 case SkBlendMode::kLuminosity: 128 flags = src->preservesOpaqueInput() || dst->preservesOpaqueInput() 129 ? kPreservesOpaqueInput_OptimizationFlag 130 : kNone_OptimizationFlags; 131 break; 132 } 133 if (does_cpu_blend_impl_match_gpu(mode) && src->hasConstantOutputForConstantInput() && 134 dst->hasConstantOutputForConstantInput()) { 135 flags |= kConstantOutputForConstantInput_OptimizationFlag; 136 } 137 return flags; 138 } 139 140 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { 141 b->add32((int)fMode); 142 } 143 144 bool onIsEqual(const GrFragmentProcessor& other) const override { 145 const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>(); 146 return fMode == cs.fMode; 147 } 148 149 GrColor4f constantOutputForConstantInput(GrColor4f input) const override { 150 float alpha = input.fRGBA[3]; 151 input = input.opaque(); 152 GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input); 153 GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input); 154 SkPM4f src = GrColor4fToSkPM4f(srcColor); 155 SkPM4f dst = GrColor4fToSkPM4f(dstColor); 156 SkPM4f res = SkBlendMode_Apply(fMode, src, dst); 157 return SkPM4fToGrColor4f(res).mulByScalar(alpha); 158 } 159 160 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 161 162 SkBlendMode fMode; 163 164 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 165 166 typedef GrFragmentProcessor INHERITED; 167 }; 168 169 ///////////////////////////////////////////////////////////////////// 170 171 class GLComposeTwoFragmentProcessor : public GrGLSLFragmentProcessor { 172 public: 173 void emitCode(EmitArgs&) override; 174 175 private: 176 typedef GrGLSLFragmentProcessor INHERITED; 177 }; 178 179 ///////////////////////////////////////////////////////////////////// 180 181 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor); 182 183 #if GR_TEST_UTILS 184 std::unique_ptr<GrFragmentProcessor> ComposeTwoFragmentProcessor::TestCreate( 185 GrProcessorTestData* d) { 186 // Create two random frag procs. 187 std::unique_ptr<GrFragmentProcessor> fpA(GrProcessorUnitTest::MakeChildFP(d)); 188 std::unique_ptr<GrFragmentProcessor> fpB(GrProcessorUnitTest::MakeChildFP(d)); 189 190 SkBlendMode mode; 191 do { 192 mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode)); 193 } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode); 194 return std::unique_ptr<GrFragmentProcessor>( 195 new ComposeTwoFragmentProcessor(std::move(fpA), std::move(fpB), mode)); 196 } 197 #endif 198 199 std::unique_ptr<GrFragmentProcessor> ComposeTwoFragmentProcessor::clone() const { 200 auto src = this->childProcessor(0).clone(); 201 auto dst = this->childProcessor(1).clone(); 202 return std::unique_ptr<GrFragmentProcessor>( 203 new ComposeTwoFragmentProcessor(std::move(src), std::move(dst), fMode)); 204 } 205 206 GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{ 207 return new GLComposeTwoFragmentProcessor; 208 } 209 210 ///////////////////////////////////////////////////////////////////// 211 212 void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) { 213 214 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 215 const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>(); 216 217 const char* inputColor = nullptr; 218 if (args.fInputColor) { 219 inputColor = "inputColor"; 220 fragBuilder->codeAppendf("half4 inputColor = half4(%s.rgb, 1.0);", args.fInputColor); 221 } 222 223 // declare outputColor and emit the code for each of the two children 224 SkString srcColor("xfer_src"); 225 this->emitChild(0, inputColor, &srcColor, args); 226 227 SkString dstColor("xfer_dst"); 228 this->emitChild(1, inputColor, &dstColor, args); 229 230 // emit blend code 231 SkBlendMode mode = cs.getMode(); 232 fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode)); 233 GrGLSLBlend::AppendMode(fragBuilder, 234 srcColor.c_str(), 235 dstColor.c_str(), 236 args.fOutputColor, 237 mode); 238 239 // re-multiply the output color by the input color's alpha 240 if (args.fInputColor) { 241 fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor); 242 } 243 } 244 245 std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoProcessors( 246 std::unique_ptr<GrFragmentProcessor> src, 247 std::unique_ptr<GrFragmentProcessor> dst, 248 SkBlendMode mode) { 249 switch (mode) { 250 case SkBlendMode::kClear: 251 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), 252 GrConstColorProcessor::InputMode::kIgnore); 253 case SkBlendMode::kSrc: 254 return src; 255 case SkBlendMode::kDst: 256 return dst; 257 default: 258 return ComposeTwoFragmentProcessor::Make(std::move(src), std::move(dst), mode); 259 } 260 } 261 262 ////////////////////////////////////////////////////////////////////////////// 263 264 class ComposeOneFragmentProcessor : public GrFragmentProcessor { 265 public: 266 enum Child { 267 kDst_Child, 268 kSrc_Child, 269 }; 270 271 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp, 272 SkBlendMode mode, Child child) { 273 if (!fp) { 274 return nullptr; 275 } 276 return std::unique_ptr<GrFragmentProcessor>( 277 new ComposeOneFragmentProcessor(std::move(fp), mode, child)); 278 } 279 280 const char* name() const override { return "ComposeOne"; } 281 282 SkString dumpInfo() const override { 283 SkString str; 284 285 str.appendf("Mode: %s, Child: %s", 286 SkBlendMode_Name(fMode), kDst_Child == fChild ? "Dst" : "Src"); 287 288 for (int i = 0; i < this->numChildProcessors(); ++i) { 289 str.appendf(" [%s %s]", 290 this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str()); 291 } 292 return str; 293 } 294 295 std::unique_ptr<GrFragmentProcessor> clone() const override; 296 297 SkBlendMode mode() const { return fMode; } 298 299 Child child() const { return fChild; } 300 301 private: 302 OptimizationFlags OptFlags(const GrFragmentProcessor* fp, SkBlendMode mode, Child child) { 303 OptimizationFlags flags; 304 switch (mode) { 305 case SkBlendMode::kClear: 306 SK_ABORT("Should never create clear compose one FP."); 307 flags = kNone_OptimizationFlags; 308 break; 309 310 case SkBlendMode::kSrc: 311 SkASSERT(child == kSrc_Child); 312 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag 313 : kNone_OptimizationFlags; 314 break; 315 316 case SkBlendMode::kDst: 317 SkASSERT(child == kDst_Child); 318 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag 319 : kNone_OptimizationFlags; 320 break; 321 322 // Produces opaque if both src and dst are opaque. These also will modulate the child's 323 // output by either the input color or alpha. However, if the child is not compatible 324 // with the coverage as alpha then it may produce a color that is not valid premul. 325 case SkBlendMode::kSrcIn: 326 case SkBlendMode::kDstIn: 327 case SkBlendMode::kModulate: 328 if (fp->compatibleWithCoverageAsAlpha()) { 329 if (fp->preservesOpaqueInput()) { 330 flags = kPreservesOpaqueInput_OptimizationFlag | 331 kCompatibleWithCoverageAsAlpha_OptimizationFlag; 332 } else { 333 flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag; 334 } 335 } else { 336 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag 337 : kNone_OptimizationFlags; 338 } 339 break; 340 341 // Produces zero when both are opaque, indeterminate if one is opaque. 342 case SkBlendMode::kSrcOut: 343 case SkBlendMode::kDstOut: 344 case SkBlendMode::kXor: 345 flags = kNone_OptimizationFlags; 346 break; 347 348 // Is opaque if the dst is opaque. 349 case SkBlendMode::kSrcATop: 350 if (child == kDst_Child) { 351 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag 352 : kNone_OptimizationFlags; 353 } else { 354 flags = kPreservesOpaqueInput_OptimizationFlag; 355 } 356 break; 357 358 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque. 359 case SkBlendMode::kDstATop: 360 case SkBlendMode::kScreen: 361 if (child == kSrc_Child) { 362 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag 363 : kNone_OptimizationFlags; 364 } else { 365 flags = kPreservesOpaqueInput_OptimizationFlag; 366 } 367 break; 368 369 // These modes are all opaque if either src or dst is opaque. All the advanced modes 370 // compute alpha as src-over. 371 case SkBlendMode::kSrcOver: 372 case SkBlendMode::kDstOver: 373 case SkBlendMode::kPlus: 374 case SkBlendMode::kOverlay: 375 case SkBlendMode::kDarken: 376 case SkBlendMode::kLighten: 377 case SkBlendMode::kColorDodge: 378 case SkBlendMode::kColorBurn: 379 case SkBlendMode::kHardLight: 380 case SkBlendMode::kSoftLight: 381 case SkBlendMode::kDifference: 382 case SkBlendMode::kExclusion: 383 case SkBlendMode::kMultiply: 384 case SkBlendMode::kHue: 385 case SkBlendMode::kSaturation: 386 case SkBlendMode::kColor: 387 case SkBlendMode::kLuminosity: 388 flags = kPreservesOpaqueInput_OptimizationFlag; 389 break; 390 } 391 if (does_cpu_blend_impl_match_gpu(mode) && fp->hasConstantOutputForConstantInput()) { 392 flags |= kConstantOutputForConstantInput_OptimizationFlag; 393 } 394 return flags; 395 } 396 397 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { 398 GR_STATIC_ASSERT(((int)SkBlendMode::kLastMode & SK_MaxU16) == (int)SkBlendMode::kLastMode); 399 b->add32((int)fMode | (fChild << 16)); 400 } 401 402 bool onIsEqual(const GrFragmentProcessor& that) const override { 403 return fMode == that.cast<ComposeOneFragmentProcessor>().fMode; 404 } 405 406 GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override { 407 GrColor4f childColor = 408 ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite()); 409 SkPM4f src, dst; 410 if (kSrc_Child == fChild) { 411 src = GrColor4fToSkPM4f(childColor); 412 dst = GrColor4fToSkPM4f(inputColor); 413 } else { 414 src = GrColor4fToSkPM4f(inputColor); 415 dst = GrColor4fToSkPM4f(childColor); 416 } 417 SkPM4f res = SkBlendMode_Apply(fMode, src, dst); 418 return SkPM4fToGrColor4f(res); 419 } 420 421 private: 422 ComposeOneFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, SkBlendMode mode, 423 Child child) 424 : INHERITED(kComposeOneFragmentProcessor_ClassID, OptFlags(fp.get(), mode, child)) 425 , fMode(mode) 426 , fChild(child) { 427 SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp)); 428 SkASSERT(0 == dstIndex); 429 } 430 431 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 432 433 SkBlendMode fMode; 434 Child fChild; 435 436 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 437 438 typedef GrFragmentProcessor INHERITED; 439 }; 440 441 ////////////////////////////////////////////////////////////////////////////// 442 443 class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor { 444 public: 445 void emitCode(EmitArgs& args) override { 446 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 447 SkBlendMode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode(); 448 ComposeOneFragmentProcessor::Child child = 449 args.fFp.cast<ComposeOneFragmentProcessor>().child(); 450 SkString childColor("child"); 451 this->emitChild(0, &childColor, args); 452 453 const char* inputColor = args.fInputColor; 454 // We don't try to optimize for this case at all 455 if (!inputColor) { 456 fragBuilder->codeAppendf("const half4 ones = half4(1);"); 457 inputColor = "ones"; 458 } 459 460 // emit blend code 461 fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode)); 462 const char* childStr = childColor.c_str(); 463 if (ComposeOneFragmentProcessor::kDst_Child == child) { 464 GrGLSLBlend::AppendMode(fragBuilder, inputColor, childStr, args.fOutputColor, mode); 465 } else { 466 GrGLSLBlend::AppendMode(fragBuilder, childStr, inputColor, args.fOutputColor, mode); 467 } 468 } 469 470 private: 471 typedef GrGLSLFragmentProcessor INHERITED; 472 }; 473 474 ///////////////////////////////////////////////////////////////////// 475 476 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor); 477 478 #if GR_TEST_UTILS 479 std::unique_ptr<GrFragmentProcessor> ComposeOneFragmentProcessor::TestCreate( 480 GrProcessorTestData* d) { 481 // Create one random frag procs. 482 // For now, we'll prevent either children from being a shader with children to prevent the 483 // possibility of an arbitrarily large tree of procs. 484 std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d)); 485 SkBlendMode mode; 486 ComposeOneFragmentProcessor::Child child; 487 do { 488 mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode)); 489 child = d->fRandom->nextBool() ? kDst_Child : kSrc_Child; 490 } while (SkBlendMode::kClear == mode || (SkBlendMode::kDst == mode && child == kSrc_Child) || 491 (SkBlendMode::kSrc == mode && child == kDst_Child)); 492 return std::unique_ptr<GrFragmentProcessor>( 493 new ComposeOneFragmentProcessor(std::move(dst), mode, child)); 494 } 495 #endif 496 497 GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const { 498 return new GLComposeOneFragmentProcessor; 499 } 500 501 std::unique_ptr<GrFragmentProcessor> ComposeOneFragmentProcessor::clone() const { 502 return std::unique_ptr<GrFragmentProcessor>( 503 new ComposeOneFragmentProcessor(this->childProcessor(0).clone(), fMode, fChild)); 504 } 505 506 ////////////////////////////////////////////////////////////////////////////// 507 508 // It may seems as though when the input FP is the dst and the mode is kDst (or same for src/kSrc) 509 // that these factories could simply return the input FP. However, that doesn't have quite 510 // the same effect as the returned compose FP will replace the FP's input with solid white and 511 // ignore the original input. This could be implemented as: 512 // RunInSeries(ConstColor(GrColor_WHITE, kIgnoreInput), inputFP). 513 514 std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstProcessor( 515 std::unique_ptr<GrFragmentProcessor> dst, SkBlendMode mode) { 516 switch (mode) { 517 case SkBlendMode::kClear: 518 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), 519 GrConstColorProcessor::InputMode::kIgnore); 520 case SkBlendMode::kSrc: 521 return nullptr; 522 default: 523 return ComposeOneFragmentProcessor::Make(std::move(dst), mode, 524 ComposeOneFragmentProcessor::kDst_Child); 525 } 526 } 527 528 std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcProcessor( 529 std::unique_ptr<GrFragmentProcessor> src, SkBlendMode mode) { 530 switch (mode) { 531 case SkBlendMode::kClear: 532 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(), 533 GrConstColorProcessor::InputMode::kIgnore); 534 case SkBlendMode::kDst: 535 return nullptr; 536 default: 537 return ComposeOneFragmentProcessor::Make(std::move(src), mode, 538 ComposeOneFragmentProcessor::kSrc_Child); 539 } 540 } 541