float components in xfermodes
authorreed <reed@google.com>
Sun, 31 Jan 2016 02:52:31 +0000 (18:52 -0800)
committerCommit bot <commit-bot@chromium.org>
Sun, 31 Jan 2016 02:52:31 +0000 (18:52 -0800)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1623483002

TBR=mtklein

Review URL: https://codereview.chromium.org/1634273002

16 files changed:
bench/Xfer4fBench.cpp
gm/color4f.cpp [new file with mode: 0644]
gm/xfer4f.cpp
gyp/core.gypi
include/core/SkColor.h
include/core/SkXfermode.h
src/core/SkBlitter.cpp
src/core/SkBlitter_PM4f.cpp [new file with mode: 0644]
src/core/SkColor.cpp
src/core/SkCoreBlitters.h
src/core/SkPM4fPriv.h
src/core/SkXfer4f.cpp [deleted file]
src/core/SkXfer4f.h [deleted file]
src/core/SkXfermode.cpp
src/core/SkXfermode4f.cpp [new file with mode: 0644]
src/effects/SkColorMatrixFilter.cpp

index 2c28169..751f0df 100644 (file)
@@ -8,24 +8,25 @@
 
 #include "Benchmark.h"
 #include "SkString.h"
-#include "SkXfer4f.h"
+#include "SkXfermode.h"
 
 #define INNER_LOOPS 100
 
 // Benchmark that draws non-AA rects or AA text with an SkXfermode::Mode.
 class Xfer4fBench : public Benchmark {
 public:
-    Xfer4fBench(SkXfermode::Mode mode, const char name[], bool doN, uint32_t flags) : fDoN(doN) {
-        fProc1 = SkPM4fXfer1ProcFactory(mode, flags);
-        fProcN = SkPM4fXferNProcFactory(mode, flags);
+    Xfer4fBench(SkXfermode::Mode mode, const char name[], bool doN, uint32_t flags)
+        : fDoN(doN)
+        , fFlags(flags)
+    {
+        fProc1 = SkXfermode::GetPM4fProc1(mode, flags);
+        fProcN = SkXfermode::GetPM4fProcN(mode, flags);
         fName.printf("xfer4f_%s_%c_%s_%s", name, fDoN ? 'N' : '1',
-                     (flags & kSrcIsOpaque_SkXfer4fFlag) ? "opaque" : "alpha",
-                     (flags & kDstIsSRGB_SkXfer4fFlag) ? "srgb" : "linear");
+                     (flags & SkXfermode::kSrcIsOpaque_PM4fFlag) ? "opaque" : "alpha",
+                     (flags & SkXfermode::kDstIsSRGB_PM4fFlag) ? "srgb" : "linear");
 
-        SkPM4f c;
-        c.fVec[0] = 1; c.fVec[1] = 1; c.fVec[2] = 1; c.fVec[3] = 1;
         for (int i = 0; i < N; ++i) {
-            fSrc[i] = c;
+            fSrc[i] = {{ 1, 1, 1, 1 }};
             fDst[i] = 0;
         }
     }
@@ -36,22 +37,24 @@ protected:
     const char* onGetName() override { return fName.c_str(); }
 
     void onDraw(int loops, SkCanvas*) override {
-        for (int i = 0; i < loops; ++i) {
-            for (int j = 0; j < INNER_LOOPS; ++j) {
-                if (fDoN) {
-                    fProcN(fDst, fSrc, N);
-                } else {
-                    fProc1(fDst, fSrc[0], N);
-                }
+        const SkXfermode::PM4fState state{ nullptr, fFlags };
+        const uint8_t* aa = nullptr;
+
+        for (int i = 0; i < loops * INNER_LOOPS; ++i) {
+            if (fDoN) {
+                fProcN(state, fDst, fSrc, N, aa);
+            } else {
+                fProc1(state, fDst, fSrc[0], N, aa);
             }
         }
     }
 
 private:
     SkString        fName;
-    SkPM4fXfer1Proc fProc1;
-    SkPM4fXferNProc fProcN;
+    SkXfermode::PM4fProc1 fProc1;
+    SkXfermode::PM4fProcN fProcN;
     bool            fDoN;
+    uint32_t        fFlags;
 
     enum {
         N = 1000,
@@ -62,12 +65,17 @@ private:
     typedef Benchmark INHERITED;
 };
 
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, kDstIsSRGB_SkXfer4fFlag); )
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, 0); )
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, kDstIsSRGB_SkXfer4fFlag | kSrcIsOpaque_SkXfer4fFlag); )
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, kSrcIsOpaque_SkXfer4fFlag); )
+#define F00 0
+#define F01 (SkXfermode::kSrcIsOpaque_PM4fFlag)
+#define F10 (SkXfermode::kDstIsSRGB_PM4fFlag)
+#define F11 (SkXfermode::kSrcIsOpaque_PM4fFlag | SkXfermode::kDstIsSRGB_PM4fFlag)
+
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, F10); )
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, F00); )
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, F11); )
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", false, F01); )
 
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  kDstIsSRGB_SkXfer4fFlag); )
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  0); )
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  kDstIsSRGB_SkXfer4fFlag | kSrcIsOpaque_SkXfer4fFlag); )
-DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  kSrcIsOpaque_SkXfer4fFlag); )
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  F10); )
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  F00); )
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  F11); )
+DEF_BENCH( return new Xfer4fBench(SkXfermode::kSrcOver_Mode, "srcover", true,  F01); )
diff --git a/gm/color4f.cpp b/gm/color4f.cpp
new file mode 100644 (file)
index 0000000..98ce082
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkSurface.h"
+
+#include "SkColorMatrixFilter.h"
+#include "SkGradientShader.h"
+
+static SkShader* make_opaque_color() {
+    return SkShader::CreateColorShader(0xFFFF0000);
+}
+
+static SkShader* make_alpha_color() {
+    return SkShader::CreateColorShader(0x80FF0000);
+}
+
+static SkColorFilter* make_cf_null() {
+    return nullptr;
+}
+
+static SkColorFilter* make_cf0() {
+    SkColorMatrix cm;
+    cm.setSaturation(0.75f);
+    return SkColorMatrixFilter::Create(cm);
+}
+
+static void draw_into_canvas(SkCanvas* canvas) {
+    const SkRect r = SkRect::MakeWH(100, 100);
+    SkShader* (*shaders[])() { make_opaque_color, make_alpha_color };
+    SkColorFilter* (*filters[])() { make_cf_null, make_cf0 };
+    
+    SkPaint paint;
+    for (auto shProc : shaders) {
+        paint.setShader(shProc())->unref();
+        for (auto cfProc : filters) {
+            SkSafeUnref(paint.setColorFilter(cfProc()));
+            canvas->drawRect(r, paint);
+            canvas->translate(120, 0);
+        }
+    }
+}
+
+DEF_SIMPLE_GM(color4f, canvas, 510, 250) {
+    canvas->translate(20, 20);
+
+    SkPaint bg;
+    // need the target to be opaque, so we can draw it to the screen
+    // even if it holds sRGB values.
+    bg.setColor(0xFFFFFFFF);
+
+    SkColorProfileType const profiles[] { kLinear_SkColorProfileType, kSRGB_SkColorProfileType };
+    for (auto profile : profiles) {
+        const SkImageInfo info = SkImageInfo::Make(500, 100, kN32_SkColorType, kPremul_SkAlphaType,
+                                                   profile);
+        SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
+        surface->getCanvas()->drawPaint(bg);
+        draw_into_canvas(surface->getCanvas());
+        surface->draw(canvas, 0, 0, nullptr);
+        canvas->translate(0, 120);
+    }
+}
index 1951fdb..b74b6e0 100644 (file)
@@ -8,7 +8,7 @@
 #include "gm.h"
 #include "SkCanvas.h"
 #include "SkImageInfo.h"
-#include "SkXfer4f.h"
+#include "SkXfermode.h"
 
 static void draw_rect(SkCanvas* canvas, const SkRect& r, SkColor c, SkColorProfileType profile) {
     const SkIRect ir = r.round();
@@ -21,26 +21,28 @@ static void draw_rect(SkCanvas* canvas, const SkRect& r, SkColor c, SkColorProfi
 
     uint32_t flags = 0;
     if (SkColorGetA(c) == 0xFF) {
-        flags |= kSrcIsOpaque_SkXfer4fFlag;
+        flags |= SkXfermode::kSrcIsOpaque_PM4fFlag;
     }
     if (kSRGB_SkColorProfileType == profile) {
-        flags |= kDstIsSRGB_SkXfer4fFlag;
+        flags |= SkXfermode::kDstIsSRGB_PM4fFlag;
     }
 
-    const SkPM4f src = SkPM4f::FromPMColor(SkPreMultiplyColor(c));
-    auto proc1 = SkPM4fXfer1ProcFactory(SkXfermode::kSrcOver_Mode, flags);
+    const SkXfermode::PM4fState state { nullptr, flags };
+
+    const SkPM4f src = SkColor4f::FromColor(c).premul();
+    auto proc1 = SkXfermode::GetPM4fProc1(SkXfermode::kSrcOver_Mode, flags);
     for (int y = 0; y < ir.height()/2; ++y) {
-        proc1(pm.writable_addr32(0, y), src, ir.width());
+        proc1(state, pm.writable_addr32(0, y), src, ir.width(), nullptr);
     }
 
     SkPM4f srcRow[1000];
     for (int i = 0; i < ir.width(); ++i) {
         srcRow[i] = src;
     }
-    auto procN = SkPM4fXferNProcFactory(SkXfermode::kSrcOver_Mode, flags);
+    auto procN = SkXfermode::GetPM4fProcN(SkXfermode::kSrcOver_Mode, flags);
     // +1 to skip a row, so we can see the boundary between proc1 and procN
     for (int y = ir.height()/2 + 1; y < ir.height(); ++y) {
-        procN(pm.writable_addr32(0, y), srcRow, ir.width());
+        procN(state, pm.writable_addr32(0, y), srcRow, ir.width(), nullptr);
     }
 
     canvas->drawBitmap(bm, r.left(), r.top(), nullptr);
index b5405a4..b80f43a 100644 (file)
@@ -58,6 +58,7 @@
         '<(skia_src_path)/core/SkBlitter.cpp',
         '<(skia_src_path)/core/SkBlitter_A8.cpp',
         '<(skia_src_path)/core/SkBlitter_ARGB32.cpp',
+        '<(skia_src_path)/core/SkBlitter_PM4f.cpp',
         '<(skia_src_path)/core/SkBlitter_RGB16.cpp',
         '<(skia_src_path)/core/SkBlitter_Sprite.cpp',
         '<(skia_src_path)/core/SkBuffer.cpp',
         '<(skia_src_path)/core/SkVertState.cpp',
         '<(skia_src_path)/core/SkWriteBuffer.cpp',
         '<(skia_src_path)/core/SkWriter32.cpp',
-        '<(skia_src_path)/core/SkXfer4f.cpp',
         '<(skia_src_path)/core/SkXfermode.cpp',
+        '<(skia_src_path)/core/SkXfermode4f.cpp',
         '<(skia_src_path)/core/SkXfermode_proccoeff.h',
         '<(skia_src_path)/core/SkXfermodeInterpretation.cpp',
         '<(skia_src_path)/core/SkXfermodeInterpretation.h',
index 099771a..461a538 100644 (file)
@@ -172,11 +172,15 @@ struct SkPM4f {
     };
     float fVec[4];
 
-    float a() const { return fVec[3]; }
+    float a() const { return fVec[A]; }
 
     static SkPM4f FromPMColor(SkPMColor);
 
-    bool isUnit() const;
+#ifdef SK_DEBUG
+    void assertIsUnit() const;
+#else
+    void assertIsUnit() const {}
+#endif
 };
 
 /*
index 261f580..890a0b9 100644 (file)
@@ -229,6 +229,23 @@ public:
     SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
     SK_DEFINE_FLATTENABLE_TYPE(SkXfermode)
 
+    enum PM4fFlags {
+        kSrcIsOpaque_PM4fFlag  = 1 << 0,
+        kDstIsSRGB_PM4fFlag    = 1 << 1,
+    };
+    struct PM4fState {
+        const SkXfermode* fXfer;
+        uint32_t          fFlags;
+    };
+    typedef void (*PM4fProc1)(const PM4fState&, uint32_t dst[], const SkPM4f& src,
+                              int count, const SkAlpha coverage[]);
+    typedef void (*PM4fProcN)(const PM4fState&, uint32_t dst[], const SkPM4f src[],
+                              int count, const SkAlpha coverage[]);
+    static PM4fProc1 GetPM4fProc1(Mode, uint32_t flags);
+    static PM4fProcN GetPM4fProcN(Mode, uint32_t flags);
+    virtual PM4fProc1 getPM4fProc1(uint32_t flags) const;
+    virtual PM4fProcN getPM4fProcN(uint32_t flags) const;
+
 protected:
     SkXfermode() {}
     /** The default implementation of xfer32/xfer16/xferA8 in turn call this
index b73be40..eec3152 100644 (file)
 #include "SkXfermode.h"
 #include "SkXfermodeInterpretation.h"
 
+// define this for testing srgb blits
+//#define SK_SUPPORT_SRGB_RASTER
+
+#ifdef SK_SUPPORT_SRGB_RASTER
+    #define ALLOW_SRGB  true
+#else
+    #define ALLOW_SRGB  false
+#endif
+
 SkBlitter::~SkBlitter() {}
 
 bool SkBlitter::isNullBlitter() const { return false; }
@@ -905,8 +914,13 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device,
 
         case kN32_SkColorType:
             if (shader) {
-                blitter = allocator->createT<SkARGB32_Shader_Blitter>(
-                        device, *paint, shaderContext);
+                if (shaderContext->supports4f() && ALLOW_SRGB) {
+                    blitter = allocator->createT<SkARGB32_Shader4f_Blitter>(
+                                                                  device, *paint, shaderContext);
+                } else {
+                    blitter = allocator->createT<SkARGB32_Shader_Blitter>(
+                            device, *paint, shaderContext);
+                }
             } else if (paint->getColor() == SK_ColorBLACK) {
                 blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
             } else if (paint->getAlpha() == 0xFF) {
diff --git a/src/core/SkBlitter_PM4f.cpp b/src/core/SkBlitter_PM4f.cpp
new file mode 100644 (file)
index 0000000..bd8ae49
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCoreBlitters.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+#include "SkBlitMask.h"
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+SkARGB32_Shader4f_Blitter::SkARGB32_Shader4f_Blitter(const SkPixmap& device,
+        const SkPaint& paint, SkShader::Context* shaderContext)
+    : INHERITED(device, paint, shaderContext)
+{
+    const uint32_t shaderFlags = shaderContext->getFlags();
+
+    SkASSERT(shaderFlags & SkShader::kSupports4f_Flag);
+
+    fBuffer = (SkPM4f*)sk_malloc_throw(device.width() * (sizeof(SkPM4f)));
+
+    fState.fXfer = SkSafeRef(paint.getXfermode());
+    fState.fFlags = 0;
+    if (shaderFlags & SkShader::kOpaqueAlpha_Flag) {
+        fState.fFlags |= SkXfermode::kSrcIsOpaque_PM4fFlag;
+    }
+    if (device.info().isSRGB()) {
+        fState.fFlags |= SkXfermode::kDstIsSRGB_PM4fFlag;
+    }
+    if (fState.fXfer) {
+        fProc1 = fState.fXfer->getPM4fProc1(fState.fFlags);
+        fProcN = fState.fXfer->getPM4fProcN(fState.fFlags);
+    } else {
+        fProc1 = SkXfermode::GetPM4fProc1(SkXfermode::kSrcOver_Mode, fState.fFlags);
+        fProcN = SkXfermode::GetPM4fProcN(SkXfermode::kSrcOver_Mode, fState.fFlags);
+    }
+
+    fConstInY = SkToBool(shaderFlags & SkShader::kConstInY32_Flag);
+}
+
+SkARGB32_Shader4f_Blitter::~SkARGB32_Shader4f_Blitter() {
+    SkSafeUnref(fState.fXfer);
+    sk_free(fBuffer);
+}
+
+void SkARGB32_Shader4f_Blitter::blitH(int x, int y, int width) {
+    SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
+
+    uint32_t* device = fDevice.writable_addr32(x, y);
+    fShaderContext->shadeSpan4f(x, y, fBuffer, width);
+    fProcN(fState, device, fBuffer, width, nullptr);
+}
+
+void SkARGB32_Shader4f_Blitter::blitRect(int x, int y, int width, int height) {
+    SkASSERT(x >= 0 && y >= 0 &&
+             x + width <= fDevice.width() && y + height <= fDevice.height());
+
+    uint32_t*   device = fDevice.writable_addr32(x, y);
+    size_t      deviceRB = fDevice.rowBytes();
+
+    if (fConstInY) {
+        fShaderContext->shadeSpan4f(x, y, fBuffer, width);
+        do {
+            fProcN(fState, device, fBuffer, width, nullptr);
+            y += 1;
+            device = (uint32_t*)((char*)device + deviceRB);
+        } while (--height > 0);
+    } else {
+        do {
+            fShaderContext->shadeSpan4f(x, y, fBuffer, width);
+            fProcN(fState, device, fBuffer, width, nullptr);
+            y += 1;
+            device = (uint32_t*)((char*)device + deviceRB);
+        } while (--height > 0);
+    }
+}
+
+void SkARGB32_Shader4f_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
+                                        const int16_t runs[]) {
+    uint32_t* device = fDevice.writable_addr32(x, y);
+
+    for (;;) {
+        int count = *runs;
+        if (count <= 0) {
+            break;
+        }
+        int aa = *antialias;
+        if (aa) {
+            fShaderContext->shadeSpan4f(x, y, fBuffer, count);
+            if (aa == 255) {
+                fProcN(fState, device, fBuffer, count, nullptr);
+            } else {
+                // count is almost always 1
+                for (int i = count - 1; i >= 0; --i) {
+                    fProcN(fState, &device[i], &fBuffer[i], 1, antialias);
+                }
+            }
+        }
+        device += count;
+        runs += count;
+        antialias += count;
+        x += count;
+    }
+}
+
+void SkARGB32_Shader4f_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
+    // we only handle kA8
+    if (SkMask::kA8_Format != mask.fFormat) {
+        this->INHERITED::blitMask(mask, clip);
+        return;
+    }
+
+    SkASSERT(mask.fBounds.contains(clip));
+
+    const int x = clip.fLeft;
+    const int width = clip.width();
+    int y = clip.fTop;
+    int height = clip.height();
+
+    char* dstRow = (char*)fDevice.writable_addr32(x, y);
+    const size_t dstRB = fDevice.rowBytes();
+    const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y);
+    const size_t maskRB = mask.fRowBytes;
+
+    do {
+        fShaderContext->shadeSpan4f(x, y, fBuffer, width);
+        fProcN(fState, reinterpret_cast<SkPMColor*>(dstRow), fBuffer, width, maskRow);
+        dstRow += dstRB;
+        maskRow += maskRB;
+        y += 1;
+    } while (--height > 0);
+}
+
+void SkARGB32_Shader4f_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
+    SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height());
+
+    uint32_t*   device = fDevice.writable_addr32(x, y);
+    size_t      deviceRB = fDevice.rowBytes();
+
+    if (fConstInY) {
+        fShaderContext->shadeSpan4f(x, y, fBuffer, 1);
+        do {
+            fProcN(fState, device, fBuffer, 1, &alpha);
+            device = (uint32_t*)((char*)device + deviceRB);
+        } while (--height > 0);
+    } else {
+        do {
+            fShaderContext->shadeSpan4f(x, y, fBuffer, 1);
+            fProcN(fState, device, fBuffer, 1, &alpha);
+            y += 1;
+            device = (uint32_t*)((char*)device + deviceRB);
+        } while (--height > 0);
+    }
+}
index 9deac7a..cf6e0b2 100644 (file)
@@ -142,7 +142,9 @@ SkPM4f SkColor4f::premul() const {
     return pm4;
 }
 
-bool SkPM4f::isUnit() const {
+#ifdef SK_DEBUG
+void SkPM4f::assertIsUnit() const {
     auto c4 = Sk4f::Load(fVec);
-    return (c4 >= Sk4f(0)).allTrue() && (c4 <= Sk4f(1)).allTrue();
+    SkASSERT((c4 >= Sk4f(0)).allTrue() && (c4 <= Sk4f(1)).allTrue());
 }
+#endif
index b327039..d2559f5 100644 (file)
@@ -170,7 +170,7 @@ public:
     void blitRect(int x, int y, int width, int height) override;
     void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
     void blitMask(const SkMask&, const SkIRect&) override;
-
+    
 private:
     SkXfermode*         fXfermode;
     SkPMColor*          fBuffer;
@@ -178,13 +178,37 @@ private:
     SkBlitRow::Proc32   fProc32Blend;
     bool                fShadeDirectlyIntoDevice;
     bool                fConstInY;
-
+    
     // illegal
     SkARGB32_Shader_Blitter& operator=(const SkARGB32_Shader_Blitter&);
-
+    
     typedef SkShaderBlitter INHERITED;
 };
 
+class SkARGB32_Shader4f_Blitter : public SkARGB32_Shader_Blitter {
+public:
+    SkARGB32_Shader4f_Blitter(const SkPixmap& device, const SkPaint& paint,
+                              SkShader::Context* shaderContext);
+    virtual ~SkARGB32_Shader4f_Blitter();
+    void blitH(int x, int y, int width) override;
+    void blitV(int x, int y, int height, SkAlpha alpha) override;
+    void blitRect(int x, int y, int width, int height) override;
+    void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) override;
+    void blitMask(const SkMask&, const SkIRect&) override;
+    
+private:
+    SkXfermode::PM4fState   fState;
+    SkXfermode::PM4fProc1   fProc1;
+    SkXfermode::PM4fProcN   fProcN;
+    SkPM4f*                 fBuffer;
+    bool                    fConstInY;
+    
+    // illegal
+    SkARGB32_Shader4f_Blitter& operator=(const SkARGB32_Shader4f_Blitter&);
+    
+    typedef SkARGB32_Shader_Blitter INHERITED;
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 
 /*  These return the correct subclass of blitter for their device config.
index a4cec5c..81aff70 100644 (file)
@@ -27,12 +27,12 @@ static inline Sk4f to_4f(uint32_t b4) {
     return SkNx_cast<float>(Sk4b::Load((const uint8_t*)&b4));
 }
 
-static inline Sk4f s2l(const Sk4f& s4) {
+static inline Sk4f srgb_to_linear(const Sk4f& s4) {
     return set_alpha(s4 * s4, get_alpha(s4));
 }
 
-static inline Sk4f l2s(const Sk4f& l4) {
-    return set_alpha(l4.rsqrt1() * l4, get_alpha(l4));
+static inline Sk4f linear_to_srgb(const Sk4f& l4) {
+    return set_alpha(l4.sqrt(), get_alpha(l4));
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -42,7 +42,7 @@ static inline Sk4f Sk4f_fromL32(uint32_t src) {
 }
 
 static inline Sk4f Sk4f_fromS32(uint32_t src) {
-    return s2l(to_4f(src) * Sk4f(1.0f/255));
+    return srgb_to_linear(to_4f(src) * Sk4f(1.0f/255));
 }
 
 static inline uint32_t Sk4f_toL32(const Sk4f& x4) {
@@ -50,72 +50,5 @@ static inline uint32_t Sk4f_toL32(const Sk4f& x4) {
 }
 
 static inline uint32_t Sk4f_toS32(const Sk4f& x4) {
-    return to_4b(l2s(x4) * Sk4f(255) + Sk4f(0.5f));
+    return to_4b(linear_to_srgb(x4) * Sk4f(255) + Sk4f(0.5f));
 }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-static Sk4f unit_to_l255_round(const SkPM4f& pm4) {
-    return Sk4f::Load(pm4.fVec) * Sk4f(255) + Sk4f(0.5f);
-}
-
-static Sk4f unit_to_s255_round(const SkPM4f& pm4) {
-    return l2s(Sk4f::Load(pm4.fVec)) * Sk4f(255) + Sk4f(0.5f);
-}
-
-static inline void SkPM4f_l32_src_mode(SkPMColor dst[], const SkPM4f src[], int count) {
-    for (int i = 0; i < (count >> 2); ++i) {
-        SkASSERT(src[0].isUnit());
-        SkASSERT(src[1].isUnit());
-        SkASSERT(src[2].isUnit());
-        SkASSERT(src[3].isUnit());
-        Sk4f_ToBytes((uint8_t*)dst,
-                     unit_to_l255_round(src[0]), unit_to_l255_round(src[1]),
-                     unit_to_l255_round(src[2]), unit_to_l255_round(src[3]));
-        src += 4;
-        dst += 4;
-    }
-    count &= 3;
-    for (int i = 0; i < count; ++i) {
-        SkASSERT(src[i].isUnit());
-        SkNx_cast<uint8_t>(unit_to_l255_round(src[i])).store((uint8_t*)&dst[i]);
-    }
-}
-
-static inline void SkPM4f_l32_srcover_mode(SkPMColor dst[], const SkPM4f src[], int count) {
-    for (int i = 0; i < count; ++i) {
-        SkASSERT(src[i].isUnit());
-        Sk4f s4 = Sk4f::Load(src[i].fVec);
-        Sk4f d4 = Sk4f_fromL32(dst[i]);
-        dst[i] = Sk4f_toL32(s4 + d4 * Sk4f(1 - get_alpha(s4)));
-    }
-}
-
-static inline void SkPM4f_s32_src_mode(SkPMColor dst[], const SkPM4f src[], int count) {
-    for (int i = 0; i < (count >> 2); ++i) {
-        SkASSERT(src[0].isUnit());
-        SkASSERT(src[1].isUnit());
-        SkASSERT(src[2].isUnit());
-        SkASSERT(src[3].isUnit());
-        Sk4f_ToBytes((uint8_t*)dst,
-                     unit_to_s255_round(src[0]), unit_to_s255_round(src[1]),
-                     unit_to_s255_round(src[2]), unit_to_s255_round(src[3]));
-        src += 4;
-        dst += 4;
-    }
-    count &= 3;
-    for (int i = 0; i < count; ++i) {
-        SkASSERT(src[i].isUnit());
-        SkNx_cast<uint8_t>(unit_to_s255_round(src[i])).store((uint8_t*)&dst[i]);
-    }
-}
-
-static inline void SkPM4f_s32_srcover_mode(SkPMColor dst[], const SkPM4f src[], int count) {
-    for (int i = 0; i < count; ++i) {
-        SkASSERT(src[i].isUnit());
-        Sk4f s4 = Sk4f::Load(src[i].fVec);
-        Sk4f d4 = Sk4f_fromS32(dst[i]);
-        dst[i] = Sk4f_toS32(s4 + d4 * Sk4f(1 - get_alpha(s4)));
-    }
-}
-
diff --git a/src/core/SkXfer4f.cpp b/src/core/SkXfer4f.cpp
deleted file mode 100644 (file)
index b177e49..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkXfer4f.h"
-#include "SkPM4fPriv.h"
-#include "SkUtils.h"
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-void CLEAR_pm41p(uint32_t dst[], const SkPM4f& src, int count) {
-    sk_bzero(dst, count * sizeof(uint32_t));
-}
-
-void CLEAR_pm4np(uint32_t dst[], const SkPM4f src[], int count) {
-    sk_bzero(dst, count * sizeof(uint32_t));
-}
-
-//////////
-
-template <bool isSRGB> void SRC_pm41p(uint32_t dst[], const SkPM4f& src, int count) {
-    uint32_t res;
-    if (isSRGB) {
-        res = Sk4f_toS32(Sk4f::Load(src.fVec));
-    } else {
-        res = Sk4f_toL32(Sk4f::Load(src.fVec));
-    }
-    sk_memset32(dst, res, count);
-}
-
-template <bool isSRGB> void SRC_pm4np(uint32_t dst[], const SkPM4f src[], int count) {
-    if (isSRGB) {
-        SkPM4f_s32_src_mode(dst, src, count);
-    } else {
-        SkPM4f_l32_src_mode(dst, src, count);
-    }
-}
-
-//////////
-
-void DST_pm41p(uint32_t dst[], const SkPM4f& src, int count) {}
-void DST_pm4np(uint32_t dst[], const SkPM4f src[], int count) {}
-
-//////////
-
-template <bool isSRGB> void SRCOVER_pm41p(uint32_t dst[], const SkPM4f& src, int count) {
-    SkASSERT(src.isUnit());
-    Sk4f s4 = Sk4f::Load(src.fVec);
-    Sk4f scale(1 - s4.kth<SkPM4f::A>());
-
-    if (!isSRGB) {
-        s4 = s4 * Sk4f(255);
-    }
-
-    for (int i = 0; i < count; ++i) {
-        if (isSRGB) {
-            Sk4f d4 = Sk4f_fromS32(dst[i]);
-            dst[i] = Sk4f_toS32(s4 + d4 * scale);
-        } else {
-            Sk4f d4 = to_4f(dst[i]);
-            dst[i] = to_4b(s4 + d4 * scale + Sk4f(0.5f));
-        }
-    }
-}
-
-template <bool isSRGB> void SRCOVER_pm4np(uint32_t dst[], const SkPM4f src[], int count) {
-    if (isSRGB) {
-        SkPM4f_s32_srcover_mode(dst, src, count);
-    } else {
-        SkPM4f_l32_srcover_mode(dst, src, count);
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-struct Pair {
-    SkPM4fXfer1Proc fProc1;
-    SkPM4fXferNProc fProcN;
-};
-
-const Pair gClearPairs[] = {
-    { CLEAR_pm41p, CLEAR_pm4np },
-    { CLEAR_pm41p, CLEAR_pm4np },
-    { CLEAR_pm41p, CLEAR_pm4np },
-    { CLEAR_pm41p, CLEAR_pm4np },
-};
-
-const Pair gSrcPairs[] = {
-    { SRC_pm41p<false>, SRC_pm4np<false> }, // linear [alpha  ignored]
-    { SRC_pm41p<false>, SRC_pm4np<false> }, // linear [opaque ignored]
-    { SRC_pm41p<true>,  SRC_pm4np<true>  }, // srgb   [alpha  ignored]
-    { SRC_pm41p<true>,  SRC_pm4np<true>  }, // srgb   [opaque ignored]
-};
-
-const Pair gDstPairs[] = {
-    { DST_pm41p, DST_pm4np },
-    { DST_pm41p, DST_pm4np },
-    { DST_pm41p, DST_pm4np },
-    { DST_pm41p, DST_pm4np },
-};
-
-const Pair gSrcOverPairs[] = {
-    { SRCOVER_pm41p<false>,   SRCOVER_pm4np<false>  },  // linear   alpha
-    { SRC_pm41p<false>,       SRC_pm4np<false>      },  // linear   opaque
-    { SRCOVER_pm41p<true>,    SRCOVER_pm4np<true>   },  // srgb     alpha
-    { SRC_pm41p<true>,        SRC_pm4np<true>       },  // srgb     opaque
-};
-
-static const Pair* find_pair(SkXfermode::Mode mode, uint32_t flags) {
-    SkASSERT(0 == (flags & ~3));
-    const Pair* pairs = nullptr;
-
-    switch (mode) {
-        case SkXfermode::kClear_Mode:   pairs = gClearPairs;
-        case SkXfermode::kSrc_Mode:     pairs = gSrcPairs; break;
-        case SkXfermode::kDst_Mode:     pairs = gDstPairs;
-        case SkXfermode::kSrcOver_Mode: pairs = gSrcOverPairs; break;
-        default: return nullptr;
-    }
-    return &pairs[flags & 3];
-}
-
-SkPM4fXfer1Proc SkPM4fXfer1ProcFactory(SkXfermode::Mode mode, uint32_t flags) {
-    const Pair* pair = find_pair(mode, flags);
-    return pair ? pair->fProc1 : nullptr;
-}
-
-SkPM4fXferNProc SkPM4fXferNProcFactory(SkXfermode::Mode mode, uint32_t flags) {
-    const Pair* pair = find_pair(mode, flags);
-    return pair ? pair->fProcN : nullptr;
-}
diff --git a/src/core/SkXfer4f.h b/src/core/SkXfer4f.h
deleted file mode 100644 (file)
index fd6657f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkXfermodePriv_DEFINED
-#define SkXfermodePriv_DEFINED
-
-#include "SkXfermode.h"
-
-enum SkXfef4fFlags {
-    kSrcIsOpaque_SkXfer4fFlag   = 1 << 0,
-    kDstIsSRGB_SkXfer4fFlag     = 1 << 1,
-};
-
-typedef void (*SkPM4fXfer1Proc)(uint32_t dst[], const SkPM4f& src, int count);
-typedef void (*SkPM4fXferNProc)(uint32_t dst[], const SkPM4f src[], int count);
-
-SkPM4fXfer1Proc SkPM4fXfer1ProcFactory(SkXfermode::Mode, uint32_t flags);
-SkPM4fXferNProc SkPM4fXferNProcFactory(SkXfermode::Mode, uint32_t flags);
-
-#endif
index c3a40dc..f6d83fa 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2006 The Android Open Source Project
  *
diff --git a/src/core/SkXfermode4f.cpp b/src/core/SkXfermode4f.cpp
new file mode 100644 (file)
index 0000000..0485a5e
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkPM4fPriv.h"
+#include "SkUtils.h"
+#include "SkXfermode.h"
+
+struct XferProcPair {
+    SkXfermode::PM4fProc1 fP1;
+    SkXfermode::PM4fProcN fPN;
+};
+
+enum DstType {
+    kLinear_Dst,
+    kSRGB_Dst,
+};
+
+static Sk4f scale_by_coverage(const Sk4f& x4, uint8_t coverage) {
+    return x4 * Sk4f(coverage * (1/255.0f));
+}
+
+static Sk4f lerp(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) {
+    return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f));
+}
+
+template <DstType D> Sk4f load_dst(SkPMColor dstC) {
+    return (D == kSRGB_Dst) ? Sk4f_fromS32(dstC) : Sk4f_fromL32(dstC);
+}
+
+template <DstType D> uint32_t store_dst(const Sk4f& x4) {
+    return (D == kSRGB_Dst) ? Sk4f_toS32(x4) : Sk4f_toL32(x4);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static Sk4f scale_255_round(const SkPM4f& pm4) {
+    return Sk4f::Load(pm4.fVec) * Sk4f(255) + Sk4f(0.5f);
+}
+
+static void pm4f_to_linear_32(SkPMColor dst[], const SkPM4f src[], int count) {
+    while (count >= 4) {
+        src[0].assertIsUnit();
+        src[1].assertIsUnit();
+        src[2].assertIsUnit();
+        src[3].assertIsUnit();
+        Sk4f_ToBytes((uint8_t*)dst,
+                     scale_255_round(src[0]), scale_255_round(src[1]),
+                     scale_255_round(src[2]), scale_255_round(src[3]));
+        src += 4;
+        dst += 4;
+        count -= 4;
+    }
+    for (int i = 0; i < count; ++i) {
+        src[i].assertIsUnit();
+        SkNx_cast<uint8_t>(scale_255_round(src[i])).store((uint8_t*)&dst[i]);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// These are our fallback impl for the SkPM4f procs...
+//
+// They just convert the src color(s) into a linear SkPMColor value(s), and then
+// call the existing virtual xfer32. This clear throws away data (converting floats to bytes)
+// in the src, and ignores the sRGB flag, but should draw about the same as if the caller
+// had passed in SkPMColor values directly.
+//
+
+void xfer_pm4_proc_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f& src,
+                     int count, const SkAlpha aa[]) {
+    uint32_t pm;
+    pm4f_to_linear_32(&pm, &src, 1);
+
+    const int N = 128;
+    SkPMColor tmp[N];
+    sk_memset32(tmp, pm, SkMin32(count, N));
+    while (count > 0) {
+        const int n = SkMin32(count, N);
+        state.fXfer->xfer32(dst, tmp, n, aa);
+
+        dst += n;
+        if (aa) {
+            aa += n;
+        }
+        count -= n;
+    }
+}
+
+void xfer_pm4_proc_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f src[],
+                     int count, const SkAlpha aa[]) {
+    const int N = 128;
+    SkPMColor tmp[N];
+    while (count > 0) {
+        const int n = SkMin32(count, N);
+        pm4f_to_linear_32(tmp, src, n);
+        state.fXfer->xfer32(dst, tmp, n, aa);
+
+        src += n;
+        dst += n;
+        if (aa) {
+            aa += n;
+        }
+        count -= n;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static void clear_linear_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f[],
+                           int count, const SkAlpha aa[]) {
+    if (aa) {
+        for (int i = 0; i < count; ++i) {
+            unsigned a = aa[i];
+            if (a) {
+                SkPMColor dstC = dst[i];
+                SkPMColor C = 0;
+                if (0xFF != a) {
+                    C = SkFourByteInterp(C, dstC, a);
+                }
+                dst[i] = C;
+            }
+        }
+    } else {
+        sk_bzero(dst, count * sizeof(SkPMColor));
+    }
+}
+
+static void clear_linear_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f&,
+                           int count, const SkAlpha coverage[]) {
+    clear_linear_n(state, dst, nullptr, count, coverage);
+}
+
+static void clear_srgb_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f[],
+                           int count, const SkAlpha aa[]) {
+    if (aa) {
+        for (int i = 0; i < count; ++i) {
+            unsigned a = aa[i];
+            if (a) {
+                Sk4f d = Sk4f_fromS32(dst[i]) * Sk4f((255 - a) * (1/255.0f));
+                dst[i] = Sk4f_toS32(d);
+            }
+        }
+    } else {
+        sk_bzero(dst, count * sizeof(SkPMColor));
+    }
+}
+
+static void clear_srgb_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f&,
+                           int count, const SkAlpha coverage[]) {
+    clear_srgb_n(state, dst, nullptr, count, coverage);
+}
+
+const XferProcPair gProcs_Clear[] = {
+    { clear_linear_1, clear_linear_n },       // linear   [alpha]
+    { clear_linear_1, clear_linear_n },       // linear   [opaque]
+    { clear_srgb_1,   clear_srgb_n   },       // srgb     [alpha]
+    { clear_srgb_1,   clear_srgb_n   },       // srgb     [opaque]
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <DstType D> void src_n(const SkXfermode::PM4fState& state, uint32_t dst[],
+                                const SkPM4f src[], int count, const SkAlpha aa[]) {
+    for (int i = 0; i < count; ++i) {
+        unsigned a = 0xFF;
+        if (aa) {
+            a = aa[i];
+            if (0 == a) {
+                continue;
+            }
+        }
+        Sk4f r4 = Sk4f::Load(src[i].fVec);   // src always overrides dst
+        if (a != 0xFF) {
+            Sk4f d4 = load_dst<D>(dst[i]);
+            r4 = lerp(r4, d4, a);
+        }
+        dst[i] = store_dst<D>(r4);
+    }
+}
+
+template <DstType D> void src_1(const SkXfermode::PM4fState& state, uint32_t dst[],
+                                const SkPM4f& src, int count, const SkAlpha aa[]) {
+    const Sk4f r4 = Sk4f::Load(src.fVec);   // src always overrides dst
+    const uint32_t r32 = store_dst<D>(r4);
+
+    if (aa) {
+        for (int i = 0; i < count; ++i) {
+            unsigned a = aa[i];
+            if (0 == a) {
+                continue;
+            }
+            if (a != 0xFF) {
+                Sk4f d4 = load_dst<D>(dst[i]);
+                dst[i] = store_dst<D>(lerp(r4, d4, a));
+            } else {
+                dst[i] = r32;
+            }
+        }
+    } else {
+        sk_memset32(dst, r32, count);
+    }
+}
+
+const XferProcPair gProcs_Src[] = {
+    { src_1<kLinear_Dst>, src_n<kLinear_Dst> },       // linear   [alpha]
+    { src_1<kLinear_Dst>, src_n<kLinear_Dst> },       // linear   [opaque]
+    { src_1<kSRGB_Dst>,   src_n<kSRGB_Dst>   },       // srgb     [alpha]
+    { src_1<kSRGB_Dst>,   src_n<kSRGB_Dst>   },       // srgb     [opaque]
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static void dst_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f[],
+                         int count, const SkAlpha aa[]) {}
+
+static void dst_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f&,
+                  int count, const SkAlpha coverage[]) {}
+
+const XferProcPair gProcs_Dst[] = {
+    { dst_1, dst_n },
+    { dst_1, dst_n },
+    { dst_1, dst_n },
+    { dst_1, dst_n },
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+template <DstType D> void srcover_n(const SkXfermode::PM4fState& state, uint32_t dst[],
+                                    const SkPM4f src[], int count, const SkAlpha aa[]) {
+    if (aa) {
+        for (int i = 0; i < count; ++i) {
+            unsigned a = aa[i];
+            if (0 == a) {
+                continue;
+            }
+            Sk4f s4 = Sk4f::Load(src[i].fVec);
+            Sk4f d4 = load_dst<D>(dst[i]);
+            if (a != 0xFF) {
+                s4 = scale_by_coverage(s4, a);
+            }
+            Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
+            dst[i] = store_dst<D>(r4);
+        }
+    } else {
+        for (int i = 0; i < count; ++i) {
+            Sk4f s4 = Sk4f::Load(src[i].fVec);
+            Sk4f d4 = load_dst<D>(dst[i]);
+            Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
+            dst[i] = store_dst<D>(r4);
+        }
+    }
+}
+
+template <DstType D> void srcover_1(const SkXfermode::PM4fState& state, uint32_t dst[],
+                                    const SkPM4f& src, int count, const SkAlpha aa[]) {
+    Sk4f s4 = Sk4f::Load(src.fVec);
+    Sk4f scale = Sk4f(1 - get_alpha(s4));
+
+    if (aa) {
+        for (int i = 0; i < count; ++i) {
+            unsigned a = aa[i];
+            if (0 == a) {
+                continue;
+            }
+            Sk4f d4 = load_dst<D>(dst[i]);
+            Sk4f r4;
+            if (a != 0xFF) {
+                s4 = scale_by_coverage(s4, a);
+                r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
+            } else {
+                r4 = s4 + d4 * scale;
+            }
+            dst[i] = store_dst<D>(r4);
+        }
+    } else {
+        for (int i = 0; i < count; ++i) {
+            Sk4f d4 = load_dst<D>(dst[i]);
+            Sk4f r4 = s4 + d4 * scale;
+            dst[i] = store_dst<D>(r4);
+        }
+    }
+}
+
+const XferProcPair gProcs_SrcOver[] = {
+    { srcover_1<kLinear_Dst>,   srcover_n<kLinear_Dst> },   // linear   alpha
+    { src_1<kLinear_Dst>,       src_n<kLinear_Dst>     },   // linear   opaque [ we are src-mode ]
+    { srcover_1<kSRGB_Dst>,     srcover_n<kSRGB_Dst>   },   // srgb     alpha
+    { src_1<kSRGB_Dst>,         src_n<kSRGB_Dst>       },   // srgb     opaque [ we are src-mode ]
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static XferProcPair find_procs(SkXfermode::Mode mode, uint32_t flags) {
+    SkASSERT(0 == (flags & ~3));
+    flags &= 3;
+
+    switch (mode) {
+        case SkXfermode::kClear_Mode:   return gProcs_Clear[flags];
+        case SkXfermode::kSrc_Mode:     return gProcs_Src[flags];
+        case SkXfermode::kDst_Mode:     return gProcs_Dst[flags];
+        case SkXfermode::kSrcOver_Mode: return gProcs_SrcOver[flags];
+        default:
+            break;
+    }
+    return { xfer_pm4_proc_1, xfer_pm4_proc_n };
+}
+
+SkXfermode::PM4fProc1 SkXfermode::GetPM4fProc1(Mode mode, uint32_t flags) {
+    return find_procs(mode, flags).fP1;
+}
+
+SkXfermode::PM4fProcN SkXfermode::GetPM4fProcN(Mode mode, uint32_t flags) {
+    return find_procs(mode, flags).fPN;
+}
+
+SkXfermode::PM4fProc1 SkXfermode::getPM4fProc1(uint32_t flags) const {
+    Mode mode;
+    return this->asMode(&mode) ? GetPM4fProc1(mode, flags) : xfer_pm4_proc_1;
+}
+
+SkXfermode::PM4fProcN SkXfermode::getPM4fProcN(uint32_t flags) const {
+    Mode mode;
+    return this->asMode(&mode) ? GetPM4fProcN(mode, flags) : xfer_pm4_proc_n;
+}
index 980412b..4bc07b3 100644 (file)
@@ -68,16 +68,16 @@ uint32_t SkColorMatrixFilter::getFlags() const {
 }
 
 static Sk4f scale_rgb(float scale) {
-    static_assert(SK_A32_SHIFT == 24, "Alpha is lane 3");
+    static_assert(SkPM4f::A == 3, "Alpha is lane 3");
     return Sk4f(scale, scale, scale, 1);
 }
 
 static Sk4f premul(const Sk4f& x) {
-    return x * scale_rgb(x.kth<SK_A32_SHIFT/8>());
+    return x * scale_rgb(x.kth<SkPM4f::A>());
 }
 
 static Sk4f unpremul(const Sk4f& x) {
-    return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>());  // TODO: fast/approx invert?
+    return x * scale_rgb(1 / x.kth<SkPM4f::A>());  // TODO: fast/approx invert?
 }
 
 static Sk4f clamp_0_1(const Sk4f& x) {
@@ -105,7 +105,7 @@ void filter_span(const float array[], const T src[], int count, T dst[]) {
 
     for (int i = 0; i < count; i++) {
         Sk4f srcf = Adaptor::To4f(src[i]);
-        float srcA = srcf.kth<SK_A32_SHIFT/8>();
+        float srcA = srcf.kth<SkPM4f::A>();
 
         if (0 == srcA) {
             dst[i] = matrix_translate_pmcolor;