replace 4f procs with pipeline (only called in 2 places by ganesh)

enables lots of code to delete

CQ_INCLUDE_TRYBOTS=skia.primary:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD
Bug: skia:
Change-Id: I13631ead68a9232bd8c13c5ef54727f44def26ca
Reviewed-on: https://skia-review.googlesource.com/19278
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Mike Reed <reed@google.com>
diff --git a/src/core/SkBlendMode.cpp b/src/core/SkBlendMode.cpp
index d7ebfb8..81ba69a 100644
--- a/src/core/SkBlendMode.cpp
+++ b/src/core/SkBlendMode.cpp
@@ -102,3 +102,31 @@
     }
     p->append(stage);
 }
+
+SkPM4f SkBlendMode_Apply(SkBlendMode mode, SkPM4f src, SkPM4f dst) {
+    // special-case simple/common modes...
+    switch (mode) {
+        case SkBlendMode::kClear:   return {{ 0, 0, 0, 0 }};
+        case SkBlendMode::kSrc:     return src;
+        case SkBlendMode::kDst:     return dst;
+        case SkBlendMode::kSrcOver:
+            return SkPM4f::From4f(src.to4f() + dst.to4f() * Sk4f(1 - src.a()));
+        default:
+            break;
+    }
+
+    SkRasterPipeline_<256> p;
+    SkPM4f                 *src_ctx = &src,
+                           *dst_ctx = &dst;
+
+    p.append(SkRasterPipeline::load_f32, &dst_ctx);
+    p.append(SkRasterPipeline::move_src_dst);
+    p.append(SkRasterPipeline::load_f32, &src_ctx);
+    SkBlendMode_AppendStages(mode, &p);
+    if (SkBlendMode_CanOverflow(mode)) {
+        p.append(SkRasterPipeline::clamp_1);
+    }
+    p.append(SkRasterPipeline::store_f32, &dst_ctx);
+    p.run(0, 0, 1);
+    return dst;
+}
diff --git a/src/core/SkBlendModePriv.h b/src/core/SkBlendModePriv.h
index c965fe2..406076b 100644
--- a/src/core/SkBlendModePriv.h
+++ b/src/core/SkBlendModePriv.h
@@ -9,7 +9,9 @@
 #define SkBlendModePriv_DEFINED
 
 #include "SkBlendMode.h"
-#include "SkRasterPipeline.h"
+#include "SkPM4f.h"
+
+class SkRasterPipeline;
 
 bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode);
 bool SkBlendMode_CanOverflow(SkBlendMode);
@@ -37,4 +39,6 @@
 
 bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst);
 
+SkPM4f SkBlendMode_Apply(SkBlendMode, SkPM4f src, SkPM4f dst);
+
 #endif
diff --git a/src/core/SkOpts.h b/src/core/SkOpts.h
index 31153f9..4c744e8 100644
--- a/src/core/SkOpts.h
+++ b/src/core/SkOpts.h
@@ -24,7 +24,7 @@
     // Declare function pointers here...
 
     // May return nullptr if we haven't specialized the given Mode.
-    extern SkXfermode* (*create_xfermode)(const ProcCoeff&, SkBlendMode);
+    extern SkXfermode* (*create_xfermode)(SkXfermodeProc, SkBlendMode);
 
     typedef void (*BoxBlur)(const SkPMColor*, int, const SkIRect& srcBounds, SkPMColor*, int, int, int, int, int);
     extern BoxBlur box_blur_xx, box_blur_xy, box_blur_yx;
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 02abe55..e6c10e7 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -56,308 +56,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-#include "SkNx.h"
-
-static Sk4f     alpha(const Sk4f& color) { return Sk4f(color[3]); }
-static Sk4f inv_alpha(const Sk4f& color) { return Sk4f(1 - color[3]); }
-static Sk4f     pin_1(const Sk4f& value) { return Sk4f::Min(value, Sk4f(1)); }
-
-static Sk4f color_alpha(const Sk4f& color, float newAlpha) {
-    return Sk4f(color[0], color[1], color[2], newAlpha);
-}
-static Sk4f color_alpha(const Sk4f& color, const Sk4f& newAlpha) {
-    return color_alpha(color, newAlpha[3]);
-}
-
-static Sk4f set_argb(float a, float r, float g, float b) {
-    if (0 == SkPM4f::R) {
-        return Sk4f(r, g, b, a);
-    } else {
-        return Sk4f(b, g, r, a);
-    }
-}
-
-static Sk4f    clear_4f(const Sk4f& s, const Sk4f& d) { return Sk4f(0); }
-static Sk4f      src_4f(const Sk4f& s, const Sk4f& d) { return s; }
-static Sk4f      dst_4f(const Sk4f& s, const Sk4f& d) { return d; }
-static Sk4f  srcover_4f(const Sk4f& s, const Sk4f& d) { return s + inv_alpha(s) * d; }
-static Sk4f  dstover_4f(const Sk4f& s, const Sk4f& d) { return d + inv_alpha(d) * s; }
-static Sk4f    srcin_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d); }
-static Sk4f    dstin_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s); }
-static Sk4f   srcout_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d); }
-static Sk4f   dstout_4f(const Sk4f& s, const Sk4f& d) { return d * inv_alpha(s); }
-static Sk4f  srcatop_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d) + d * inv_alpha(s); }
-static Sk4f  dstatop_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s) + s * inv_alpha(d); }
-static Sk4f      xor_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d) + d * inv_alpha(s);}
-static Sk4f     plus_4f(const Sk4f& s, const Sk4f& d) { return pin_1(s + d); }
-static Sk4f modulate_4f(const Sk4f& s, const Sk4f& d) { return s * d; }
-static Sk4f   screen_4f(const Sk4f& s, const Sk4f& d) { return s + d - s * d; }
-
-static Sk4f multiply_4f(const Sk4f& s, const Sk4f& d) {
-    return s * inv_alpha(d) + d * inv_alpha(s) + s * d;
-}
-
-static Sk4f overlay_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f sa = alpha(s);
-    Sk4f da = alpha(d);
-    Sk4f two = Sk4f(2);
-    Sk4f rc = (two * d <= da).thenElse(two * s * d,
-                                       sa * da - two * (da - d) * (sa - s));
-    return pin_1(s + d - s * da + color_alpha(rc - d * sa, 0));
-}
-
-static Sk4f hardlight_4f(const Sk4f& s, const Sk4f& d) {
-    return overlay_4f(d, s);
-}
-
-static Sk4f darken_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f sa = alpha(s);
-    Sk4f da = alpha(d);
-    return s + d - Sk4f::Max(s * da, d * sa);
-}
-
-static Sk4f lighten_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f sa = alpha(s);
-    Sk4f da = alpha(d);
-    return s + d - Sk4f::Min(s * da, d * sa);
-}
-
-static Sk4f colordodge_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f sa = alpha(s);
-    Sk4f da = alpha(d);
-    Sk4f isa = Sk4f(1) - sa;
-    Sk4f ida = Sk4f(1) - da;
-
-    Sk4f srcover = s + d * isa;
-    Sk4f dstover = d + s * ida;
-    Sk4f otherwise = sa * Sk4f::Min(da, (d * sa) / (sa - s)) + s * ida + d * isa;
-
-    // Order matters here, preferring d==0 over s==sa.
-    auto colors = (d == Sk4f(0)).thenElse(dstover,
-                                          (s == sa).thenElse(srcover,
-                                                             otherwise));
-    return color_alpha(colors, srcover);
-}
-
-static Sk4f colorburn_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f sa  = alpha(s);
-    Sk4f da  = alpha(d);
-    Sk4f isa = Sk4f(1) - sa;
-    Sk4f ida = Sk4f(1) - da;
-
-    Sk4f srcover = s + d * isa;
-    Sk4f dstover = d + s * ida;
-    Sk4f otherwise = sa * (da - Sk4f::Min(da, (da - d) * sa / s)) + s * ida + d * isa;
-
-    // Order matters here, preferring d==da over s==0.
-    auto colors = (d == da).thenElse(dstover,
-                                     (s == Sk4f(0)).thenElse(srcover,
-                                                             otherwise));
-    return color_alpha(colors, srcover);
-}
-
-static Sk4f softlight_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f sa  = alpha(s);
-    Sk4f da  = alpha(d);
-    Sk4f isa = Sk4f(1) - sa;
-    Sk4f ida = Sk4f(1) - da;
-
-    // Some common terms.
-    Sk4f m  = (da > Sk4f(0)).thenElse(d / da, Sk4f(0));
-    Sk4f s2 = Sk4f(2) * s;
-    Sk4f m4 = Sk4f(4) * 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) * (Sk4f(1) - m));            // Used in case 1.
-    Sk4f darkDst = (m4 * m4 + m4) * (m - Sk4f(1)) + Sk4f(7) * m;    // Used in case 2.
-    Sk4f liteDst = m.sqrt() - m;                                    // Used in case 3.
-    Sk4f liteSrc = d * sa + da * (s2 - sa) * (Sk4f(4) * d <= da).thenElse(darkDst,
-                                                                          liteDst); // Case 2 or 3?
-
-    return color_alpha(s * ida + d * isa + (s2 <= sa).thenElse(darkSrc, liteSrc), // Case 1 or 2/3?
-                       s + d * isa);
-}
-
-static Sk4f difference_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f min = Sk4f::Min(s * alpha(d), d * alpha(s));
-    return s + d - min - color_alpha(min, 0);
-}
-
-static Sk4f exclusion_4f(const Sk4f& s, const Sk4f& d) {
-    Sk4f product = s * d;
-    return s + d - product - color_alpha(product, 0);
-}
-
-////////////////////////////////////////////////////
-
-// The CSS compositing spec introduces the following formulas:
-// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
-// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
-// while PDF and CG uses the one from Rec. Rec. 601
-// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
-static inline float Lum(float r, float g, float b) {
-    return r * 0.2126f + g * 0.7152f + b * 0.0722f;
-}
-
-static inline float max(float a, float b, float c) {
-    return SkTMax(a, SkTMax(b, c));
-}
-
-static inline float min(float a, float b, float c) {
-    return SkTMin(a, SkTMin(b, c));
-}
-
-static inline float Sat(float r, float g, float b) {
-    return max(r, g, b) - min(r, g, b);
-}
-
-static inline void setSaturationComponents(float* Cmin, float* Cmid, float* Cmax, float s) {
-    if(*Cmax > *Cmin) {
-        *Cmid = (*Cmid - *Cmin) * s / (*Cmax - *Cmin);
-        *Cmax = s;
-    } else {
-        *Cmax = 0;
-        *Cmid = 0;
-    }
-    *Cmin = 0;
-}
-
-static inline void SetSat(float* r, float* g, float* b, float s) {
-    if(*r <= *g) {
-        if(*g <= *b) {
-            setSaturationComponents(r, g, b, s);
-        } else if(*r <= *b) {
-            setSaturationComponents(r, b, g, s);
-        } else {
-            setSaturationComponents(b, r, g, s);
-        }
-    } else if(*r <= *b) {
-        setSaturationComponents(g, r, b, s);
-    } else if(*g <= *b) {
-        setSaturationComponents(g, b, r, s);
-    } else {
-        setSaturationComponents(b, g, r, s);
-    }
-}
-
-static inline void clipColor(float* r, float* g, float* b, float a) {
-    float L = Lum(*r, *g, *b);
-    float n = min(*r, *g, *b);
-    float x = max(*r, *g, *b);
-    float denom;
-    if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
-        float scale = L / denom;
-        *r = L + (*r - L) * scale;
-        *g = L + (*g - L) * scale;
-        *b = L + (*b - L) * scale;
-    }
-
-    if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
-        float scale = (a - L) / denom;
-        *r = L + (*r - L) * scale;
-        *g = L + (*g - L) * scale;
-        *b = L + (*b - L) * scale;
-    }
-}
-
-static inline void SetLum(float* r, float* g, float* b, float a, float l) {
-    float d = l - Lum(*r, *g, *b);
-    *r += d;
-    *g += d;
-    *b += d;
-    clipColor(r, g, b, a);
-}
-
-static Sk4f hue_4f(const Sk4f& s, const Sk4f& d) {
-    float sa = s[SkPM4f::A];
-    float sr = s[SkPM4f::R];
-    float sg = s[SkPM4f::G];
-    float sb = s[SkPM4f::B];
-
-    float da = d[SkPM4f::A];
-    float dr = d[SkPM4f::R];
-    float dg = d[SkPM4f::G];
-    float db = d[SkPM4f::B];
-
-    float Sr = sr;
-    float Sg = sg;
-    float Sb = sb;
-    SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
-    SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
-
-    return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
-                       sa + da - sa * da);
-}
-
-static Sk4f saturation_4f(const Sk4f& s, const Sk4f& d) {
-    float sa = s[SkPM4f::A];
-    float sr = s[SkPM4f::R];
-    float sg = s[SkPM4f::G];
-    float sb = s[SkPM4f::B];
-
-    float da = d[SkPM4f::A];
-    float dr = d[SkPM4f::R];
-    float dg = d[SkPM4f::G];
-    float db = d[SkPM4f::B];
-
-    float Dr = dr;
-    float Dg = dg;
-    float Db = db;
-    SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
-    SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
-
-    return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
-                       sa + da - sa * da);
-}
-
-static Sk4f color_4f(const Sk4f& s, const Sk4f& d) {
-    float sa = s[SkPM4f::A];
-    float sr = s[SkPM4f::R];
-    float sg = s[SkPM4f::G];
-    float sb = s[SkPM4f::B];
-
-    float da = d[SkPM4f::A];
-    float dr = d[SkPM4f::R];
-    float dg = d[SkPM4f::G];
-    float db = d[SkPM4f::B];
-
-    float Sr = sr;
-    float Sg = sg;
-    float Sb = sb;
-    SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
-
-    Sk4f res = color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
-                           sa + da - sa * da);
-    // Can return tiny negative values ...
-    return Sk4f::Max(res, Sk4f(0));
-}
-
-static Sk4f luminosity_4f(const Sk4f& s, const Sk4f& d) {
-    float sa = s[SkPM4f::A];
-    float sr = s[SkPM4f::R];
-    float sg = s[SkPM4f::G];
-    float sb = s[SkPM4f::B];
-
-    float da = d[SkPM4f::A];
-    float dr = d[SkPM4f::R];
-    float dg = d[SkPM4f::G];
-    float db = d[SkPM4f::B];
-
-    float Dr = dr;
-    float Dg = dg;
-    float Db = db;
-    SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
-
-    Sk4f res = color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
-                           sa + da - sa * da);
-    // Can return tiny negative values ...
-    return Sk4f::Max(res, Sk4f(0));
-}
-
-///////////////////////////////////////////////////////////////////////////////
 
 //  kClear_Mode,    //!< [0, 0]
 static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
@@ -924,71 +622,39 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-static SkPM4f as_pm4f(const Sk4f& x) {
-    SkPM4f pm4;
-    x.store(pm4.fVec);
-    return pm4;
-}
+const SkXfermodeProc gProcs[] = {
+    clear_modeproc,
+    src_modeproc,
+    dst_modeproc,
+    srcover_modeproc,
+    dstover_modeproc,
+    srcin_modeproc,
+    dstin_modeproc,
+    srcout_modeproc,
+    dstout_modeproc,
+    srcatop_modeproc,
+    dstatop_modeproc,
+    xor_modeproc,
 
-static Sk4f as_4f(const SkPM4f& pm4) {
-    return Sk4f::Load(pm4.fVec);
-}
-
-static void assert_unit(const SkPM4f& r) {
-#ifdef SK_DEBUG
-    const float eps = 0.00001f;
-    const float min = 0 - eps;
-    const float max = 1 + eps;
-    for (int i = 0; i < 4; ++i) {
-        SkASSERT(r.fVec[i] >= min && r.fVec[i] <= max);
-    }
-#endif
-}
-
-template <Sk4f (blend)(const Sk4f&, const Sk4f&)> SkPM4f proc_4f(const SkPM4f& s, const SkPM4f& d) {
-    assert_unit(s);
-    assert_unit(d);
-    SkPM4f r = as_pm4f(blend(as_4f(s), as_4f(d)));
-    // Turn this assert off for now because srgb conversions may end up in rgb > a
-    // assert_unit(r);
-    return r;
-}
-
-const ProcCoeff gProcCoeffs[] = {
-    { clear_modeproc,       proc_4f<clear_4f>       },
-    { src_modeproc,         proc_4f<src_4f>         },
-    { dst_modeproc,         proc_4f<dst_4f>         },
-    { srcover_modeproc,     proc_4f<srcover_4f>     },
-    { dstover_modeproc,     proc_4f<dstover_4f>     },
-    { srcin_modeproc,       proc_4f<srcin_4f>       },
-    { dstin_modeproc,       proc_4f<dstin_4f>       },
-    { srcout_modeproc,      proc_4f<srcout_4f>      },
-    { dstout_modeproc,      proc_4f<dstout_4f>      },
-    { srcatop_modeproc,     proc_4f<srcatop_4f>     },
-    { dstatop_modeproc,     proc_4f<dstatop_4f>     },
-    { xor_modeproc,         proc_4f<xor_4f>         },
-
-    { plus_modeproc,        proc_4f<plus_4f>        },
-    { modulate_modeproc,    proc_4f<modulate_4f>    },
-    { screen_modeproc,      proc_4f<screen_4f>      },
-    { overlay_modeproc,     proc_4f<overlay_4f>     },
-    { darken_modeproc,      proc_4f<darken_4f>      },
-    { lighten_modeproc,     proc_4f<lighten_4f>     },
-    { colordodge_modeproc,  proc_4f<colordodge_4f>  },
-    { colorburn_modeproc,   proc_4f<colorburn_4f>   },
-    { hardlight_modeproc,   proc_4f<hardlight_4f>   },
-    { softlight_modeproc,   proc_4f<softlight_4f>   },
-    { difference_modeproc,  proc_4f<difference_4f>  },
-    { exclusion_modeproc,   proc_4f<exclusion_4f>   },
-    { multiply_modeproc,    proc_4f<multiply_4f>    },
-    { hue_modeproc,         proc_4f<hue_4f>         },
-    { saturation_modeproc,  proc_4f<saturation_4f>  },
-    { color_modeproc,       proc_4f<color_4f>       },
-    { luminosity_modeproc,  proc_4f<luminosity_4f>  },
+    plus_modeproc,
+    modulate_modeproc,
+    screen_modeproc,
+    overlay_modeproc,
+    darken_modeproc,
+    lighten_modeproc,
+    colordodge_modeproc,
+    colorburn_modeproc,
+    hardlight_modeproc,
+    softlight_modeproc,
+    difference_modeproc,
+    exclusion_modeproc,
+    multiply_modeproc,
+    hue_modeproc,
+    saturation_modeproc,
+    color_modeproc,
+    luminosity_modeproc,
 };
 
-///////////////////////////////////////////////////////////////////////////////
-
 bool SkXfermode::asMode(SkBlendMode* mode) const {
     return false;
 }
@@ -1015,7 +681,7 @@
 
 sk_sp<SkFlattenable> SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) {
     uint32_t mode32 = buffer.read32();
-    if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) {
+    if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcs))) {
         return nullptr;
     }
     return SkXfermode::Make((SkBlendMode)mode32);
@@ -1115,17 +781,17 @@
     }
 
     const int COUNT_BLENDMODES = (int)SkBlendMode::kLastMode + 1;
-    SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == COUNT_BLENDMODES);
+    SkASSERT(SK_ARRAY_COUNT(gProcs) == COUNT_BLENDMODES);
 
     static SkOnce        once[COUNT_BLENDMODES];
     static SkXfermode* cached[COUNT_BLENDMODES];
 
     once[(int)mode]([mode] {
-        ProcCoeff rec = gProcCoeffs[(int)mode];
-        if (auto xfermode = SkOpts::create_xfermode(rec, mode)) {
+        SkXfermodeProc proc = gProcs[(int)mode];
+        if (auto xfermode = SkOpts::create_xfermode(proc, mode)) {
             cached[(int)mode] = xfermode;
         } else {
-            cached[(int)mode] = new SkProcCoeffXfermode(rec, mode);
+            cached[(int)mode] = new SkProcCoeffXfermode(proc, mode);
         }
     });
     return sk_ref_sp(cached[(int)mode]);
@@ -1134,15 +800,7 @@
 SkXfermodeProc SkXfermode::GetProc(SkBlendMode mode) {
     SkXfermodeProc  proc = nullptr;
     if ((unsigned)mode <= (unsigned)SkBlendMode::kLastMode) {
-        proc = gProcCoeffs[(unsigned)mode].fProc;
-    }
-    return proc;
-}
-
-SkXfermodeProc4f SkXfermode::GetProc4f(SkBlendMode mode) {
-    SkXfermodeProc4f  proc = nullptr;
-    if ((unsigned)mode <= (unsigned)SkBlendMode::kLastMode) {
-        proc = gProcCoeffs[(unsigned)mode].fProc4f;
+        proc = gProcs[(unsigned)mode];
     }
     return proc;
 }
diff --git a/src/core/SkXfermodePriv.h b/src/core/SkXfermodePriv.h
index 51e08be..c150666 100644
--- a/src/core/SkXfermodePriv.h
+++ b/src/core/SkXfermodePriv.h
@@ -72,7 +72,6 @@
     }
 
     static SkXfermodeProc GetProc(SkBlendMode);
-    static SkXfermodeProc4f GetProc4f(SkBlendMode);
 
     enum SrcColorOpacity {
         // The src color is known to be opaque (alpha == 255)
diff --git a/src/core/SkXfermode_proccoeff.h b/src/core/SkXfermode_proccoeff.h
index fdc36c6..5bcd3a0 100644
--- a/src/core/SkXfermode_proccoeff.h
+++ b/src/core/SkXfermode_proccoeff.h
@@ -10,18 +10,13 @@
 
 #include "SkXfermodePriv.h"
 
-struct ProcCoeff {
-    SkXfermodeProc      fProc;
-    SkXfermodeProc4f    fProc4f;
-};
-
 #define CANNOT_USE_COEFF    SkXfermode::Coeff(-1)
 
 class SK_API SkProcCoeffXfermode : public SkXfermode {
 public:
-    SkProcCoeffXfermode(const ProcCoeff& rec, SkBlendMode mode) {
+    SkProcCoeffXfermode(SkXfermodeProc proc, SkBlendMode mode) {
         fMode = mode;
-        fProc = rec.fProc;
+        fProc = proc;
     }
 
     void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index 3228d15..dd37611 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -327,10 +327,9 @@
         // It would be awesome to use SkXfermode::Create here but it knows better
         // than us and won't return a kSrcOver_Mode SkXfermode. That means we
         // have to get one the hard way.
-        struct ProcCoeff rec;
-        rec.fProc = SkXfermode::GetProc(SkBlendMode::kSrcOver);
+        SkXfermodeProc proc = SkXfermode::GetProc(SkBlendMode::kSrcOver);
 
-        srcover.reset(new SkProcCoeffXfermode(rec, SkBlendMode::kSrcOver));
+        srcover.reset(new SkProcCoeffXfermode(proc, SkBlendMode::kSrcOver));
         xfer = srcover.get();
 
     }
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
index 8779c55..f034938 100644
--- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
@@ -143,8 +143,8 @@
         GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input);
         SkPM4f src = GrColor4fToSkPM4f(srcColor);
         SkPM4f dst = GrColor4fToSkPM4f(dstColor);
-        auto proc = SkXfermode::GetProc4f(fMode);
-        return SkPM4fToGrColor4f(proc(src, dst)).mulByScalar(alpha);
+        SkPM4f res = SkBlendMode_Apply(fMode, src, dst);
+        return SkPM4fToGrColor4f(res).mulByScalar(alpha);
     }
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
@@ -391,8 +391,8 @@
             src = GrColor4fToSkPM4f(inputColor);
             dst = GrColor4fToSkPM4f(childColor);
         }
-        auto proc = SkXfermode::GetProc4f(fMode);
-        return SkPM4fToGrColor4f(proc(src, dst));
+        SkPM4f res = SkBlendMode_Apply(fMode, src, dst);
+        return SkPM4fToGrColor4f(res);
     }
 
 private:
diff --git a/src/opts/SkXfermode_opts.h b/src/opts/SkXfermode_opts.h
index e7db073..85715fa 100644
--- a/src/opts/SkXfermode_opts.h
+++ b/src/opts/SkXfermode_opts.h
@@ -217,8 +217,8 @@
 template <typename Xfermode>
 class Sk4pxXfermode : public SkProcCoeffXfermode {
 public:
-    Sk4pxXfermode(const ProcCoeff& rec, SkBlendMode mode)
-        : INHERITED(rec, mode) {}
+    Sk4pxXfermode(SkXfermodeProc proc, SkBlendMode mode)
+        : INHERITED(proc, mode) {}
 
     void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override {
         mark_dst_initialized_if_safe<Xfermode>(dst, dst+n);
@@ -236,8 +236,8 @@
 template <typename Xfermode>
 class Sk4fXfermode : public SkProcCoeffXfermode {
 public:
-    Sk4fXfermode(const ProcCoeff& rec, SkBlendMode mode)
-        : INHERITED(rec, mode) {}
+    Sk4fXfermode(SkXfermodeProc proc, SkBlendMode mode)
+        : INHERITED(proc, mode) {}
 
     void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override {
         for (int i = 0; i < n; i++) {
@@ -274,10 +274,10 @@
 
 namespace SK_OPTS_NS {
 
-static SkXfermode* create_xfermode(const ProcCoeff& rec, SkBlendMode mode) {
+static SkXfermode* create_xfermode(SkXfermodeProc proc, SkBlendMode mode) {
     switch (mode) {
 #define CASE(Xfermode) \
-    case SkBlendMode::k##Xfermode: return new Sk4pxXfermode<Xfermode>(rec, mode)
+    case SkBlendMode::k##Xfermode: return new Sk4pxXfermode<Xfermode>(proc, mode)
         CASE(Clear);
         CASE(Src);
         CASE(Dst);
@@ -303,7 +303,7 @@
     #undef CASE
 
 #define CASE(Xfermode) \
-    case SkBlendMode::k##Xfermode: return new Sk4fXfermode<Xfermode>(rec, mode)
+    case SkBlendMode::k##Xfermode: return new Sk4fXfermode<Xfermode>(proc, mode)
         CASE(ColorDodge);
         CASE(ColorBurn);
         CASE(SoftLight);