| Index: src/core/SkXfermode.cpp
|
| diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
|
| index 7165e99161bd2bc69e4aff56e536a1c5f9e5d336..2aaef70fb97c809296dd70fcca264fe4eac8151d 100644
|
| --- a/src/core/SkXfermode.cpp
|
| +++ b/src/core/SkXfermode.cpp
|
| @@ -12,32 +12,20 @@
|
| #include "SkColorPriv.h"
|
| #include "SkLazyPtr.h"
|
| #include "SkMathPriv.h"
|
| +#include "SkPMFloat.h"
|
| #include "SkReadBuffer.h"
|
| #include "SkString.h"
|
| #include "SkUtilsArm.h"
|
| #include "SkWriteBuffer.h"
|
|
|
| +#define SK_SUPPORT_LEGACY_SCALAR_XFERMODES
|
| +
|
| #if !SK_ARM_NEON_IS_NONE
|
| #include "SkXfermode_opts_arm_neon.h"
|
| #endif
|
|
|
| #define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
|
|
|
| -#if 0
|
| -// idea for higher precision blends in xfer procs (and slightly faster)
|
| -// see DstATop as a probable caller
|
| -static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
|
| - SkASSERT(a <= 255);
|
| - SkASSERT(b <= 255);
|
| - SkASSERT(c <= 255);
|
| - SkASSERT(d <= 255);
|
| - unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
|
| - unsigned result = (prod + (prod >> 8)) >> 8;
|
| - SkASSERT(result <= 255);
|
| - return result;
|
| -}
|
| -#endif
|
| -
|
| static inline unsigned saturated_add(unsigned a, unsigned b) {
|
| SkASSERT(a <= 255);
|
| SkASSERT(b <= 255);
|
| @@ -1186,6 +1174,175 @@ void SkDstInXfermode::toString(SkString* str) const {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +/* These modes can merge coverage into src-alpha
|
| + *
|
| +{ dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
|
| +{ srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
|
| +{ dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
|
| +{ dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
|
| +{ srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
|
| +{ xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
|
| +{ plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
|
| +{ screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
|
| +*/
|
| +
|
| +#ifndef SK_SUPPORT_LEGACY_SCALAR_XFERMODES
|
| +static const float gInv255 = 0.0039215683f; // (1.0f / 255) - ULP == SkBits2Float(0x3B808080)
|
| +
|
| +static Sk4f ramp(const Sk4f& v0, const Sk4f& v1, const Sk4f& t) {
|
| + return v0 + (v1 - v0) * t;
|
| +}
|
| +
|
| +static Sk4f clamp_255(const Sk4f& value) {
|
| + return Sk4f::Min(value, Sk4f(255));
|
| +}
|
| +
|
| +/**
|
| + * Some modes can, due to very slight numerical error, generate "invalid" pmcolors...
|
| + *
|
| + * e.g.
|
| + * alpha = 100.9999
|
| + * red = 101
|
| + *
|
| + * or
|
| + * alpha = 255.0001
|
| + *
|
| + * If we know we're going to write-out the values as bytes, we can relax these somewhat,
|
| + * since we only really need to enforce that the bytes are valid premul...
|
| + *
|
| + * To that end, this method asserts that the resulting pmcolor will be valid, but does not call
|
| + * SkPMFloat::isValid(), as that would fire sometimes, but not result in a bad pixel.
|
| + */
|
| +static inline SkPMFloat check_as_pmfloat(const Sk4f& value) {
|
| + SkPMFloat pm = value;
|
| +#ifdef SK_DEBUG
|
| + (void)pm.get();
|
| +#endif
|
| + return pm;
|
| +}
|
| +
|
| +// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
|
| +struct SrcATop4f {
|
| + static SkPMFloat Xfer(const SkPMFloat& src, const SkPMFloat& dst) {
|
| + const Sk4f inv255(gInv255);
|
| + Sk4f s4 = src;
|
| + Sk4f d4 = dst;
|
| + return check_as_pmfloat(d4 + (s4 * Sk4f(dst.a()) - d4 * Sk4f(src.a())) * inv255);
|
| + }
|
| + static const bool kFoldCoverageIntoSrcAlpha = true;
|
| + static const SkXfermode::Mode kMode = SkXfermode::kSrcATop_Mode;
|
| +};
|
| +
|
| +// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
|
| +struct DstATop4f {
|
| + static SkPMFloat Xfer(const SkPMFloat& src, const SkPMFloat& dst) {
|
| + const Sk4f inv255(gInv255);
|
| + Sk4f s4 = src;
|
| + Sk4f d4 = dst;
|
| + return check_as_pmfloat(s4 + (d4 * Sk4f(src.a()) - s4 * Sk4f(dst.a())) * inv255);
|
| + }
|
| + static const bool kFoldCoverageIntoSrcAlpha = false;
|
| + static const SkXfermode::Mode kMode = SkXfermode::kDstATop_Mode;
|
| +};
|
| +
|
| +// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
|
| +struct Xor4f {
|
| + static SkPMFloat Xfer(const SkPMFloat& src, const SkPMFloat& dst) {
|
| + const Sk4f inv255(gInv255);
|
| + Sk4f s4 = src;
|
| + Sk4f d4 = dst;
|
| + return check_as_pmfloat(s4 + d4 - (s4 * Sk4f(dst.a()) + d4 * Sk4f(src.a())) * inv255);
|
| + }
|
| + static const bool kFoldCoverageIntoSrcAlpha = true;
|
| + static const SkXfermode::Mode kMode = SkXfermode::kXor_Mode;
|
| +};
|
| +
|
| +// kPlus_Mode [Sa + Da, Sc + Dc]
|
| +struct Plus4f {
|
| + static SkPMFloat Xfer(const SkPMFloat& src, const SkPMFloat& dst) {
|
| + Sk4f s4 = src;
|
| + Sk4f d4 = dst;
|
| + return check_as_pmfloat(clamp_255(s4 + d4));
|
| + }
|
| + static const bool kFoldCoverageIntoSrcAlpha = true;
|
| + static const SkXfermode::Mode kMode = SkXfermode::kPlus_Mode;
|
| +};
|
| +
|
| +// kModulate_Mode [Sa * Da, Sc * Dc]
|
| +struct Modulate4f {
|
| + static SkPMFloat Xfer(const SkPMFloat& src, const SkPMFloat& dst) {
|
| + const Sk4f inv255(gInv255);
|
| + Sk4f s4 = src;
|
| + Sk4f d4 = dst;
|
| + return check_as_pmfloat(s4 * d4 * inv255);
|
| + }
|
| + static const bool kFoldCoverageIntoSrcAlpha = false;
|
| + static const SkXfermode::Mode kMode = SkXfermode::kModulate_Mode;
|
| +};
|
| +
|
| +// kScreen_Mode [S + D - S * D]
|
| +struct Screen4f {
|
| + static SkPMFloat Xfer(const SkPMFloat& src, const SkPMFloat& dst) {
|
| + const Sk4f inv255(gInv255);
|
| + Sk4f s4 = src;
|
| + Sk4f d4 = dst;
|
| + return check_as_pmfloat(check_as_pmfloat(s4 + d4 - s4 * d4 * inv255));
|
| + }
|
| + static const bool kFoldCoverageIntoSrcAlpha = true;
|
| + static const SkXfermode::Mode kMode = SkXfermode::kScreen_Mode;
|
| +};
|
| +
|
| +template <typename ProcType>
|
| +class SkT4fXfermode : public SkProcCoeffXfermode {
|
| +public:
|
| + static SkXfermode* Create(const ProcCoeff& rec) {
|
| + return SkNEW_ARGS(SkT4fXfermode, (rec));
|
| + }
|
| +
|
| + void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override {
|
| + if (NULL == aa) {
|
| + while (n & 3) {
|
| + *dst = ProcType::Xfer(SkPMFloat(*src++), SkPMFloat(*dst)).get();
|
| + dst++;
|
| + n -= 1;
|
| + }
|
| + n >>= 2;
|
| + for (int i = 0; i < n; ++i) {
|
| + SkPMFloat s0, s1, s2, s3;
|
| + SkPMFloat::From4PMColors(src, &s0, &s1, &s2, &s3);
|
| + SkPMFloat d0, d1, d2, d3;
|
| + SkPMFloat::From4PMColors(dst, &d0, &d1, &d2, &d3);
|
| + SkPMFloat::To4PMColors(ProcType::Xfer(s0, d0), ProcType::Xfer(s1, d1),
|
| + ProcType::Xfer(s2, d2), ProcType::Xfer(s3, d3), dst);
|
| + src += 4;
|
| + dst += 4;
|
| + }
|
| + } else {
|
| + for (int i = 0; i < n; ++i) {
|
| + const Sk4f aa4 = Sk4f(aa[i] * gInv255);
|
| + SkPMFloat dstF(dst[i]);
|
| + SkPMFloat srcF(src[i]);
|
| + Sk4f res;
|
| + if (ProcType::kFoldCoverageIntoSrcAlpha) {
|
| + Sk4f src4 = srcF;
|
| + res = ProcType::Xfer(src4 * aa4, dstF);
|
| + } else {
|
| + res = ramp(dstF, ProcType::Xfer(srcF, dstF), aa4);
|
| + }
|
| + dst[i] = SkPMFloat(res).get();
|
| + }
|
| + }
|
| + }
|
| +
|
| +private:
|
| + SkT4fXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, ProcType::kMode) {}
|
| +
|
| + typedef SkProcCoeffXfermode INHERITED;
|
| +};
|
| +#endif
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| class SkDstOutXfermode : public SkProcCoeffXfermode {
|
| public:
|
| static SkDstOutXfermode* Create(const ProcCoeff& rec) {
|
| @@ -1245,6 +1402,35 @@ SkXfermode* create_mode(int iMode) {
|
| }
|
|
|
| SkXfermode* xfer = NULL;
|
| +
|
| +#ifndef SK_SUPPORT_LEGACY_SCALAR_XFERMODES
|
| + switch (mode) {
|
| + case SkXfermode::kSrcATop_Mode:
|
| + xfer = SkT4fXfermode<SrcATop4f>::Create(rec);
|
| + break;
|
| + case SkXfermode::kDstATop_Mode:
|
| + xfer = SkT4fXfermode<DstATop4f>::Create(rec);
|
| + break;
|
| + case SkXfermode::kXor_Mode:
|
| + xfer = SkT4fXfermode<Xor4f>::Create(rec);
|
| + break;
|
| + case SkXfermode::kPlus_Mode:
|
| + xfer = SkT4fXfermode<Plus4f>::Create(rec);
|
| + break;
|
| + case SkXfermode::kModulate_Mode:
|
| + xfer = SkT4fXfermode<Modulate4f>::Create(rec);
|
| + break;
|
| + case SkXfermode::kScreen_Mode:
|
| + xfer = SkT4fXfermode<Screen4f>::Create(rec);
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + if (xfer) {
|
| + return xfer;
|
| + }
|
| +#endif
|
| +
|
| // check if we have a platform optim for that
|
| SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
|
| if (xfm != NULL) {
|
|
|