Home | History | Annotate | Download | only in effects
      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