From: reed Date: Sun, 31 Jan 2016 02:52:31 +0000 (-0800) Subject: float components in xfermodes X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~129^2~2321 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=395eabeb0e72334c45324874c6e009b54634df21;p=platform%2Fupstream%2FlibSkiaSharp.git float components in xfermodes 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 --- diff --git a/bench/Xfer4fBench.cpp b/bench/Xfer4fBench.cpp index 2c28169..751f0df 100644 --- a/bench/Xfer4fBench.cpp +++ b/bench/Xfer4fBench.cpp @@ -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 index 0000000..98ce082 --- /dev/null +++ b/gm/color4f.cpp @@ -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 surface(SkSurface::NewRaster(info)); + surface->getCanvas()->drawPaint(bg); + draw_into_canvas(surface->getCanvas()); + surface->draw(canvas, 0, 0, nullptr); + canvas->translate(0, 120); + } +} diff --git a/gm/xfer4f.cpp b/gm/xfer4f.cpp index 1951fdb..b74b6e0 100644 --- a/gm/xfer4f.cpp +++ b/gm/xfer4f.cpp @@ -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); diff --git a/gyp/core.gypi b/gyp/core.gypi index b5405a4..b80f43a 100644 --- a/gyp/core.gypi +++ b/gyp/core.gypi @@ -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', @@ -293,8 +294,8 @@ '<(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', diff --git a/include/core/SkColor.h b/include/core/SkColor.h index 099771a..461a538 100644 --- a/include/core/SkColor.h +++ b/include/core/SkColor.h @@ -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 }; /* diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 261f580..890a0b9 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -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 diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index b73be40..eec3152 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -19,6 +19,15 @@ #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( - device, *paint, shaderContext); + if (shaderContext->supports4f() && ALLOW_SRGB) { + blitter = allocator->createT( + device, *paint, shaderContext); + } else { + blitter = allocator->createT( + device, *paint, shaderContext); + } } else if (paint->getColor() == SK_ColorBLACK) { blitter = allocator->createT(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 index 0000000..bd8ae49 --- /dev/null +++ b/src/core/SkBlitter_PM4f.cpp @@ -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(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); + } +} diff --git a/src/core/SkColor.cpp b/src/core/SkColor.cpp index 9deac7a..cf6e0b2 100644 --- a/src/core/SkColor.cpp +++ b/src/core/SkColor.cpp @@ -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 diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h index b327039..d2559f5 100644 --- a/src/core/SkCoreBlitters.h +++ b/src/core/SkCoreBlitters.h @@ -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. diff --git a/src/core/SkPM4fPriv.h b/src/core/SkPM4fPriv.h index a4cec5c..81aff70 100644 --- a/src/core/SkPM4fPriv.h +++ b/src/core/SkPM4fPriv.h @@ -27,12 +27,12 @@ static inline Sk4f to_4f(uint32_t b4) { return SkNx_cast(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(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(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 index b177e49..0000000 --- a/src/core/SkXfer4f.cpp +++ /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 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 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 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()); - - 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 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, SRC_pm4np }, // linear [alpha ignored] - { SRC_pm41p, SRC_pm4np }, // linear [opaque ignored] - { SRC_pm41p, SRC_pm4np }, // srgb [alpha ignored] - { SRC_pm41p, SRC_pm4np }, // 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, SRCOVER_pm4np }, // linear alpha - { SRC_pm41p, SRC_pm4np }, // linear opaque - { SRCOVER_pm41p, SRCOVER_pm4np }, // srgb alpha - { SRC_pm41p, SRC_pm4np }, // 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 index fd6657f..0000000 --- a/src/core/SkXfer4f.h +++ /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 diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index c3a40dc..f6d83fa 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -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 index 0000000..0485a5e --- /dev/null +++ b/src/core/SkXfermode4f.cpp @@ -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 Sk4f load_dst(SkPMColor dstC) { + return (D == kSRGB_Dst) ? Sk4f_fromS32(dstC) : Sk4f_fromL32(dstC); +} + +template 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(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 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(dst[i]); + r4 = lerp(r4, d4, a); + } + dst[i] = store_dst(r4); + } +} + +template 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(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(dst[i]); + dst[i] = store_dst(lerp(r4, d4, a)); + } else { + dst[i] = r32; + } + } + } else { + sk_memset32(dst, r32, count); + } +} + +const XferProcPair gProcs_Src[] = { + { src_1, src_n }, // linear [alpha] + { src_1, src_n }, // linear [opaque] + { src_1, src_n }, // srgb [alpha] + { src_1, src_n }, // 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 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(dst[i]); + if (a != 0xFF) { + s4 = scale_by_coverage(s4, a); + } + Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); + dst[i] = store_dst(r4); + } + } else { + for (int i = 0; i < count; ++i) { + Sk4f s4 = Sk4f::Load(src[i].fVec); + Sk4f d4 = load_dst(dst[i]); + Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); + dst[i] = store_dst(r4); + } + } +} + +template 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(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(r4); + } + } else { + for (int i = 0; i < count; ++i) { + Sk4f d4 = load_dst(dst[i]); + Sk4f r4 = s4 + d4 * scale; + dst[i] = store_dst(r4); + } + } +} + +const XferProcPair gProcs_SrcOver[] = { + { srcover_1, srcover_n }, // linear alpha + { src_1, src_n }, // linear opaque [ we are src-mode ] + { srcover_1, srcover_n }, // srgb alpha + { src_1, src_n }, // 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; +} diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp index 980412b..4bc07b3 100644 --- a/src/effects/SkColorMatrixFilter.cpp +++ b/src/effects/SkColorMatrixFilter.cpp @@ -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()); + return x * scale_rgb(x.kth()); } static Sk4f unpremul(const Sk4f& x) { - return x * scale_rgb(1 / x.kth()); // TODO: fast/approx invert? + return x * scale_rgb(1 / x.kth()); // 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(); + float srcA = srcf.kth(); if (0 == srcA) { dst[i] = matrix_translate_pmcolor;