Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2017 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 "SkBlendModePriv.h"
      9 #include "SkCoverageModePriv.h"
     10 #include "SkRasterPipeline.h"
     11 #include "../jumper/SkJumper.h"
     12 
     13 bool SkBlendMode_ShouldPreScaleCoverage(SkBlendMode mode, bool rgb_coverage) {
     14     // The most important things we do here are:
     15     //   1) never pre-scale with rgb coverage if the blend mode involves a source-alpha term;
     16     //   2) always pre-scale Plus.
     17     //
     18     // When we pre-scale with rgb coverage, we scale each of source r,g,b, with a distinct value,
     19     // and source alpha with one of those three values.  This process destructively updates the
     20     // source-alpha term, so we can't evaluate blend modes that need its original value.
     21     //
     22     // Plus always requires pre-scaling as a specific quirk of its implementation in
     23     // SkRasterPipeline.  This lets us put the clamp inside the blend mode itself rather
     24     // than as a separate stage that'd come after the lerp.
     25     //
     26     // This function is a finer-grained breakdown of SkBlendMode_SupportsCoverageAsAlpha().
     27     switch (mode) {
     28         case SkBlendMode::kDst:        // d              --> no sa term, ok!
     29         case SkBlendMode::kDstOver:    // d + s*inv(da)  --> no sa term, ok!
     30         case SkBlendMode::kPlus:       // clamp(s+d)     --> no sa term, ok!
     31             return true;
     32 
     33         case SkBlendMode::kDstOut:     // d * inv(sa)
     34         case SkBlendMode::kSrcATop:    // s*da + d*inv(sa)
     35         case SkBlendMode::kSrcOver:    // s + d*inv(sa)
     36         case SkBlendMode::kXor:        // s*inv(da) + d*inv(sa)
     37             return !rgb_coverage;
     38 
     39         default: break;
     40     }
     41     return false;
     42 }
     43 
     44 // Users of this function may want to switch to the rgb-coverage aware version above.
     45 bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) {
     46     return SkBlendMode_ShouldPreScaleCoverage(mode, false);
     47 }
     48 
     49 struct CoeffRec {
     50     SkBlendModeCoeff    fSrc;
     51     SkBlendModeCoeff    fDst;
     52 };
     53 
     54 const CoeffRec gCoeffs[] = {
     55     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kZero },
     56     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kZero },
     57     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kOne  },
     58     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISA  },
     59     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kOne  },
     60     { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kZero },
     61     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSA   },
     62     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kZero },
     63     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kISA  },
     64     { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kISA  },
     65     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kSA   },
     66     { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kISA  },
     67 
     68     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kOne  },
     69     { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSC   },
     70     { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISC  },    // screen
     71 };
     72 
     73 bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst) {
     74     if (mode > SkBlendMode::kScreen) {
     75         return false;
     76     }
     77     if (src) {
     78         *src = gCoeffs[static_cast<int>(mode)].fSrc;
     79     }
     80     if (dst) {
     81         *dst = gCoeffs[static_cast<int>(mode)].fDst;
     82     }
     83     return true;
     84 }
     85 
     86 void SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) {
     87     auto stage = SkRasterPipeline::srcover;
     88     switch (mode) {
     89         case SkBlendMode::kClear:    stage = SkRasterPipeline::clear; break;
     90         case SkBlendMode::kSrc:      return;  // This stage is a no-op.
     91         case SkBlendMode::kDst:      stage = SkRasterPipeline::move_dst_src; break;
     92         case SkBlendMode::kSrcOver:  stage = SkRasterPipeline::srcover; break;
     93         case SkBlendMode::kDstOver:  stage = SkRasterPipeline::dstover; break;
     94         case SkBlendMode::kSrcIn:    stage = SkRasterPipeline::srcin; break;
     95         case SkBlendMode::kDstIn:    stage = SkRasterPipeline::dstin; break;
     96         case SkBlendMode::kSrcOut:   stage = SkRasterPipeline::srcout; break;
     97         case SkBlendMode::kDstOut:   stage = SkRasterPipeline::dstout; break;
     98         case SkBlendMode::kSrcATop:  stage = SkRasterPipeline::srcatop; break;
     99         case SkBlendMode::kDstATop:  stage = SkRasterPipeline::dstatop; break;
    100         case SkBlendMode::kXor:      stage = SkRasterPipeline::xor_; break;
    101         case SkBlendMode::kPlus:     stage = SkRasterPipeline::plus_; break;
    102         case SkBlendMode::kModulate: stage = SkRasterPipeline::modulate; break;
    103 
    104         case SkBlendMode::kScreen:     stage = SkRasterPipeline::screen; break;
    105         case SkBlendMode::kOverlay:    stage = SkRasterPipeline::overlay; break;
    106         case SkBlendMode::kDarken:     stage = SkRasterPipeline::darken; break;
    107         case SkBlendMode::kLighten:    stage = SkRasterPipeline::lighten; break;
    108         case SkBlendMode::kColorDodge: stage = SkRasterPipeline::colordodge; break;
    109         case SkBlendMode::kColorBurn:  stage = SkRasterPipeline::colorburn; break;
    110         case SkBlendMode::kHardLight:  stage = SkRasterPipeline::hardlight; break;
    111         case SkBlendMode::kSoftLight:  stage = SkRasterPipeline::softlight; break;
    112         case SkBlendMode::kDifference: stage = SkRasterPipeline::difference; break;
    113         case SkBlendMode::kExclusion:  stage = SkRasterPipeline::exclusion; break;
    114         case SkBlendMode::kMultiply:   stage = SkRasterPipeline::multiply; break;
    115 
    116         case SkBlendMode::kHue:        stage = SkRasterPipeline::hue; break;
    117         case SkBlendMode::kSaturation: stage = SkRasterPipeline::saturation; break;
    118         case SkBlendMode::kColor:      stage = SkRasterPipeline::color; break;
    119         case SkBlendMode::kLuminosity: stage = SkRasterPipeline::luminosity; break;
    120     }
    121     p->append(stage);
    122 }
    123 
    124 SkPM4f SkBlendMode_Apply(SkBlendMode mode, const SkPM4f& src, const SkPM4f& dst) {
    125     // special-case simple/common modes...
    126     switch (mode) {
    127         case SkBlendMode::kClear:   return {{ 0, 0, 0, 0 }};
    128         case SkBlendMode::kSrc:     return src;
    129         case SkBlendMode::kDst:     return dst;
    130         case SkBlendMode::kSrcOver:
    131             return SkPM4f::From4f(src.to4f() + dst.to4f() * Sk4f(1 - src.a()));
    132         default:
    133             break;
    134     }
    135 
    136     SkRasterPipeline_<256> p;
    137     SkPM4f                 src_storage = src,
    138                            dst_storage = dst,
    139                            res_storage;
    140     SkJumper_MemoryCtx src_ctx = { &src_storage, 0 },
    141                        dst_ctx = { &dst_storage, 0 },
    142                        res_ctx = { &res_storage, 0 };
    143 
    144     p.append(SkRasterPipeline::load_f32, &dst_ctx);
    145     p.append(SkRasterPipeline::move_src_dst);
    146     p.append(SkRasterPipeline::load_f32, &src_ctx);
    147     SkBlendMode_AppendStages(mode, &p);
    148     p.append(SkRasterPipeline::store_f32, &res_ctx);
    149     p.run(0,0, 1,1);
    150     return res_storage;
    151 }
    152 
    153 ///////////////////////////////////////////////////////////////////////////////////////////////////
    154 
    155 const SkBlendMode gUncorrelatedCoverageToBlend[] = {
    156     SkBlendMode::kSrcOver,  // or DstOver
    157     SkBlendMode::kSrcIn,    // or kDstIn
    158     SkBlendMode::kSrcOut,
    159     SkBlendMode::kDstOut,
    160     SkBlendMode::kXor,
    161 };
    162 
    163 SkBlendMode SkUncorrelatedCoverageModeToBlendMode(SkCoverageMode cm) {
    164     unsigned index = static_cast<unsigned>(cm);
    165     SkASSERT(index < SK_ARRAY_COUNT(gUncorrelatedCoverageToBlend));
    166     return gUncorrelatedCoverageToBlend[index];
    167 }
    168