• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/SkBlendModePriv.h"
9 
10 #include "src/base/SkVx.h"
11 #include "src/core/SkRasterPipeline.h"
12 
SkBlendMode_ShouldPreScaleCoverage(SkBlendMode mode,bool rgb_coverage)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.
SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode)45 bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode mode) {
46     return SkBlendMode_ShouldPreScaleCoverage(mode, false);
47 }
48 
SkBlendMode_AsCoeff(SkBlendMode mode,SkBlendModeCoeff * src,SkBlendModeCoeff * dst)49 bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst) {
50     struct CoeffRec {
51         SkBlendModeCoeff    fSrc;
52         SkBlendModeCoeff    fDst;
53     };
54 
55     static constexpr CoeffRec kCoeffs[] = {
56         // For Porter-Duff blend functions, color = src * src coeff + dst * dst coeff
57         // src coeff                  dst coeff                     blend func
58         // ----------------------     -----------------------       ----------
59         { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kZero }, // clear
60         { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kZero }, // src
61         { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kOne  }, // dst
62         { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISA  }, // src-over
63         { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kOne  }, // dst-over
64         { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kZero }, // src-in
65         { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSA   }, // dst-in
66         { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kZero }, // src-out
67         { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kISA  }, // dst-out
68         { SkBlendModeCoeff::kDA,      SkBlendModeCoeff::kISA  }, // src-atop
69         { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kSA   }, // dst-atop
70         { SkBlendModeCoeff::kIDA,     SkBlendModeCoeff::kISA  }, // xor
71 
72         { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kOne  }, // plus
73         { SkBlendModeCoeff::kZero,    SkBlendModeCoeff::kSC   }, // modulate
74         { SkBlendModeCoeff::kOne,     SkBlendModeCoeff::kISC  }, // screen
75     };
76 
77     if (mode > SkBlendMode::kScreen) {
78         return false;
79     }
80     if (src) {
81         *src = kCoeffs[static_cast<int>(mode)].fSrc;
82     }
83     if (dst) {
84         *dst = kCoeffs[static_cast<int>(mode)].fDst;
85     }
86     return true;
87 }
88 
SkBlendMode_AppendStages(SkBlendMode mode,SkRasterPipeline * p)89 void SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) {
90     auto stage = SkRasterPipelineOp::srcover;
91     switch (mode) {
92         case SkBlendMode::kClear:    stage = SkRasterPipelineOp::clear; break;
93         case SkBlendMode::kSrc:      return;  // This stage is a no-op.
94         case SkBlendMode::kDst:      stage = SkRasterPipelineOp::move_dst_src; break;
95         case SkBlendMode::kSrcOver:  stage = SkRasterPipelineOp::srcover; break;
96         case SkBlendMode::kDstOver:  stage = SkRasterPipelineOp::dstover; break;
97         case SkBlendMode::kSrcIn:    stage = SkRasterPipelineOp::srcin; break;
98         case SkBlendMode::kDstIn:    stage = SkRasterPipelineOp::dstin; break;
99         case SkBlendMode::kSrcOut:   stage = SkRasterPipelineOp::srcout; break;
100         case SkBlendMode::kDstOut:   stage = SkRasterPipelineOp::dstout; break;
101         case SkBlendMode::kSrcATop:  stage = SkRasterPipelineOp::srcatop; break;
102         case SkBlendMode::kDstATop:  stage = SkRasterPipelineOp::dstatop; break;
103         case SkBlendMode::kXor:      stage = SkRasterPipelineOp::xor_; break;
104         case SkBlendMode::kPlus:     stage = SkRasterPipelineOp::plus_; break;
105         case SkBlendMode::kModulate: stage = SkRasterPipelineOp::modulate; break;
106 
107         case SkBlendMode::kScreen:     stage = SkRasterPipelineOp::screen; break;
108         case SkBlendMode::kOverlay:    stage = SkRasterPipelineOp::overlay; break;
109         case SkBlendMode::kDarken:     stage = SkRasterPipelineOp::darken; break;
110         case SkBlendMode::kLighten:    stage = SkRasterPipelineOp::lighten; break;
111         case SkBlendMode::kColorDodge: stage = SkRasterPipelineOp::colordodge; break;
112         case SkBlendMode::kColorBurn:  stage = SkRasterPipelineOp::colorburn; break;
113         case SkBlendMode::kHardLight:  stage = SkRasterPipelineOp::hardlight; break;
114         case SkBlendMode::kSoftLight:  stage = SkRasterPipelineOp::softlight; break;
115         case SkBlendMode::kDifference: stage = SkRasterPipelineOp::difference; break;
116         case SkBlendMode::kExclusion:  stage = SkRasterPipelineOp::exclusion; break;
117         case SkBlendMode::kMultiply:   stage = SkRasterPipelineOp::multiply; break;
118 
119         case SkBlendMode::kHue:        stage = SkRasterPipelineOp::hue; break;
120         case SkBlendMode::kSaturation: stage = SkRasterPipelineOp::saturation; break;
121         case SkBlendMode::kColor:      stage = SkRasterPipelineOp::color; break;
122         case SkBlendMode::kLuminosity: stage = SkRasterPipelineOp::luminosity; break;
123     }
124     p->append(stage);
125 }
126 
SkBlendMode_Apply(SkBlendMode mode,const SkPMColor4f & src,const SkPMColor4f & dst)127 SkPMColor4f SkBlendMode_Apply(SkBlendMode mode, const SkPMColor4f& src, const SkPMColor4f& dst) {
128     // special-case simple/common modes...
129     switch (mode) {
130         case SkBlendMode::kClear:   return SK_PMColor4fTRANSPARENT;
131         case SkBlendMode::kSrc:     return src;
132         case SkBlendMode::kDst:     return dst;
133         case SkBlendMode::kSrcOver: {
134             SkPMColor4f r;
135             (skvx::float4::Load(src.vec()) + skvx::float4::Load(dst.vec()) * (1-src.fA)).store(&r);
136             return r;
137         }
138         default:
139             break;
140     }
141 
142     SkRasterPipeline_<256> p;
143     SkPMColor4f            src_storage = src,
144                            dst_storage = dst,
145                            res_storage;
146     SkRasterPipeline_MemoryCtx src_ctx = { &src_storage, 0 },
147                                dst_ctx = { &dst_storage, 0 },
148                                res_ctx = { &res_storage, 0 };
149 
150     p.append(SkRasterPipelineOp::load_f32, &dst_ctx);
151     p.append(SkRasterPipelineOp::move_src_dst);
152     p.append(SkRasterPipelineOp::load_f32, &src_ctx);
153     SkBlendMode_AppendStages(mode, &p);
154     p.append(SkRasterPipelineOp::store_f32, &res_ctx);
155     p.run(0,0, 1,1);
156     return res_storage;
157 }
158