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