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