aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkXfermode.cpp
diff options
context:
space:
mode:
authorGravatar Mike Klein <mtklein@chromium.org>2016-10-04 14:03:27 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-10-04 18:33:52 +0000
commit9161ef012fb22d1b76122cb95dbfddb72f02ef02 (patch)
treeef8bc78b52f1f17431003ac1f7300b15d96ebb2d /src/core/SkXfermode.cpp
parent38911a7cb53474575e1cd1cb545902b50ee00889 (diff)
Make all SkRasterPipeline stages stock stages in SkOpts.
If we want to support VEX-encoded instructions (AVX, F16C, etc.) without a ridiculous slowdown, we need to make sure we're running either all VEX-encoded instructions or all non-VEX-encoded instructions. That means we cannot mix arbitrary user-defined SkRasterPipeline::Fn (never VEX) with those living in SkOpts (maybe VEX)... it's SkOpts or bust. This ports the existing user-defined SkRasterPipeline::Fn use cases over to use stock stages from SkOpts. I rewrote the unit test to use stock stages, and moved the SkXfermode implementations to SkOpts. The code deleted for SkArithmeticMode_scalar should already be dead. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2940 CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot Change-Id: I94dbe766b2d65bfec6e544d260f71d721f0f5cb0 Reviewed-on: https://skia-review.googlesource.com/2940 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Mike Reed <reed@google.com>
Diffstat (limited to 'src/core/SkXfermode.cpp')
-rw-r--r--src/core/SkXfermode.cpp135
1 files changed, 27 insertions, 108 deletions
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 2717fab7e9..58c557805b 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -1433,117 +1433,36 @@ SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
-static Sk4f inv(const Sk4f& x) { return 1.0f - x; }
-
-// Most of these modes apply the same logic kernel to each channel.
-template <Sk4f kernel(const Sk4f& s, const Sk4f& sa, const Sk4f& d, const Sk4f& da)>
-static void SK_VECTORCALL rgba(SkRasterPipeline::Stage* st, size_t x, size_t tail,
- Sk4f r, Sk4f g, Sk4f b, Sk4f a,
- Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
- r = kernel(r,a,dr,da);
- g = kernel(g,a,dg,da);
- b = kernel(b,a,db,da);
- a = kernel(a,a,da,da);
- st->next(x,tail, r,g,b,a, dr,dg,db,da);
-}
-
-#define KERNEL(name) static Sk4f name(const Sk4f& s, const Sk4f& sa, const Sk4f& d, const Sk4f& da)
-KERNEL(clear) { return 0.0f; }
-KERNEL(dst) { return d; }
-KERNEL(dstover) { return d + inv(da)*s; }
-
-KERNEL(srcin) { return s * da; }
-KERNEL(srcout) { return s * inv(da); }
-KERNEL(srcatop) { return s*da + d*inv(sa); }
-KERNEL(dstin) { return srcin (d,da,s,sa); }
-KERNEL(dstout) { return srcout (d,da,s,sa); }
-KERNEL(dstatop) { return srcatop(d,da,s,sa); }
-
-KERNEL(modulate) { return s*d; }
-KERNEL(multiply) { return s*inv(da) + d*inv(sa) + s*d; }
-KERNEL(plus_) { return s + d; }
-KERNEL(screen) { return s + d - s*d; }
-KERNEL(xor_) { return s*inv(da) + d*inv(sa); }
-
-// Most of the rest apply the same logic to each color channel, and srcover's logic to alpha.
-// (darken and lighten can actually go either way, but they're a little faster this way.)
-template <Sk4f kernel(const Sk4f& s, const Sk4f& sa, const Sk4f& d, const Sk4f& da)>
-static void SK_VECTORCALL rgb_srcover(SkRasterPipeline::Stage* st, size_t x, size_t tail,
- Sk4f r, Sk4f g, Sk4f b, Sk4f a,
- Sk4f dr, Sk4f dg, Sk4f db, Sk4f da) {
- r = kernel(r,a,dr,da);
- g = kernel(g,a,dg,da);
- b = kernel(b,a,db,da);
- a = a + da*inv(a);
- st->next(x,tail, r,g,b,a, dr,dg,db,da);
-}
-
-KERNEL(colorburn) {
- return (d == da ).thenElse(d + s*inv(da),
- (s == 0.0f).thenElse(s + d*inv(sa),
- sa*(da - Sk4f::Min(da, (da-d)*sa/s)) + s*inv(da) + d*inv(sa)));
-}
-KERNEL(colordodge) {
- return (d == 0.0f).thenElse(d + s*inv(da),
- (s == sa ).thenElse(s + d*inv(sa),
- sa*Sk4f::Min(da, (d*sa)/(sa - s)) + s*inv(da) + d*inv(sa)));
-}
-KERNEL(darken) { return s + d - Sk4f::Max(s*da, d*sa); }
-KERNEL(difference) { return s + d - 2.0f*Sk4f::Min(s*da,d*sa); }
-KERNEL(exclusion) { return s + d - 2.0f*s*d; }
-KERNEL(hardlight) {
- return s*inv(da) + d*inv(sa)
- + (2.0f*s <= sa).thenElse(2.0f*s*d, sa*da - 2.0f*(da-d)*(sa-s));
-}
-KERNEL(lighten) { return s + d - Sk4f::Min(s*da, d*sa); }
-KERNEL(overlay) { return hardlight(d,da,s,sa); }
-KERNEL(softlight) {
- Sk4f m = (da > 0.0f).thenElse(d / da, 0.0f),
- s2 = 2.0f*s,
- m4 = 4.0f*m;
-
- // The logic forks three ways:
- // 1. dark src?
- // 2. light src, dark dst?
- // 3. light src, light dst?
- Sk4f darkSrc = d*(sa + (s2 - sa)*(1.0f - m)), // Used in case 1.
- darkDst = (m4*m4 + m4)*(m - 1.0f) + 7.0f*m, // Used in case 2.
- liteDst = m.rsqrt().invert() - m, // Used in case 3.
- liteSrc = d*sa + da*(s2 - sa) * (4.0f*d <= da).thenElse(darkDst, liteDst); // 2 or 3?
- return s*inv(da) + d*inv(sa) + (s2 <= sa).thenElse(darkSrc, liteSrc); // 1 or (2 or 3)?
-}
-#undef KERNEL
bool SkProcCoeffXfermode::onAppendStages(SkRasterPipeline* p) const {
switch (fMode) {
- case kSrcOver_Mode: SkASSERT(false); return false; // Well how did we get here?
-
- case kSrc_Mode: /*This stage is a no-op.*/ return true;
- case kDst_Mode: p->append(rgba<dst>); return true;
- case kSrcATop_Mode: p->append(rgba<srcatop>); return true;
- case kDstATop_Mode: p->append(rgba<dstatop>); return true;
- case kSrcIn_Mode: p->append(rgba<srcin>); return true;
- case kDstIn_Mode: p->append(rgba<dstin>); return true;
- case kSrcOut_Mode: p->append(rgba<srcout>); return true;
- case kDstOut_Mode: p->append(rgba<dstout>); return true;
- case kDstOver_Mode: p->append(rgba<dstover>); return true;
-
- case kClear_Mode: p->append(rgba<clear>); return true;
- case kModulate_Mode: p->append(rgba<modulate>); return true;
- case kMultiply_Mode: p->append(rgba<multiply>); return true;
- case kPlus_Mode: p->append(rgba<plus_>); return true;
- case kScreen_Mode: p->append(rgba<screen>); return true;
- case kXor_Mode: p->append(rgba<xor_>); return true;
-
- case kColorBurn_Mode: p->append(rgb_srcover<colorburn>); return true;
- case kColorDodge_Mode: p->append(rgb_srcover<colordodge>); return true;
- case kDarken_Mode: p->append(rgb_srcover<darken>); return true;
- case kDifference_Mode: p->append(rgb_srcover<difference>); return true;
- case kExclusion_Mode: p->append(rgb_srcover<exclusion>); return true;
- case kHardLight_Mode: p->append(rgb_srcover<hardlight>); return true;
- case kLighten_Mode: p->append(rgb_srcover<lighten>); return true;
- case kOverlay_Mode: p->append(rgb_srcover<overlay>); return true;
- case kSoftLight_Mode: p->append(rgb_srcover<softlight>); return true;
+ case kSrc_Mode: /*This stage is a no-op.*/ return true;
+ case kDst_Mode: p->append(SkRasterPipeline::dst); return true;
+ case kSrcATop_Mode: p->append(SkRasterPipeline::srcatop); return true;
+ case kDstATop_Mode: p->append(SkRasterPipeline::dstatop); return true;
+ case kSrcIn_Mode: p->append(SkRasterPipeline::srcin); return true;
+ case kDstIn_Mode: p->append(SkRasterPipeline::dstin); return true;
+ case kSrcOut_Mode: p->append(SkRasterPipeline::srcout); return true;
+ case kDstOut_Mode: p->append(SkRasterPipeline::dstout); return true;
+ case kSrcOver_Mode: p->append(SkRasterPipeline::srcover); return true;
+ case kDstOver_Mode: p->append(SkRasterPipeline::dstover); return true;
+
+ case kClear_Mode: p->append(SkRasterPipeline::clear); return true;
+ case kModulate_Mode: p->append(SkRasterPipeline::modulate); return true;
+ case kMultiply_Mode: p->append(SkRasterPipeline::multiply); return true;
+ case kPlus_Mode: p->append(SkRasterPipeline::plus_); return true;
+ case kScreen_Mode: p->append(SkRasterPipeline::screen); return true;
+ case kXor_Mode: p->append(SkRasterPipeline::xor_); return true;
+
+ case kColorBurn_Mode: p->append(SkRasterPipeline::colorburn); return true;
+ case kColorDodge_Mode: p->append(SkRasterPipeline::colordodge); return true;
+ case kDarken_Mode: p->append(SkRasterPipeline::darken); return true;
+ case kDifference_Mode: p->append(SkRasterPipeline::difference); return true;
+ case kExclusion_Mode: p->append(SkRasterPipeline::exclusion); return true;
+ case kHardLight_Mode: p->append(SkRasterPipeline::hardlight); return true;
+ case kLighten_Mode: p->append(SkRasterPipeline::lighten); return true;
+ case kOverlay_Mode: p->append(SkRasterPipeline::overlay); return true;
+ case kSoftLight_Mode: p->append(SkRasterPipeline::softlight); return true;
// TODO
case kColor_Mode: return false;