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