diff options
author | reed <reed@google.com> | 2016-02-22 06:42:31 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-22 06:42:31 -0800 |
commit | 129ed1cd6d792f3f6cf563aefa9756fc6308289d (patch) | |
tree | 262b64d17622d8ff3a4af19bc60337b5a4b76a08 /src | |
parent | 653db51b440491b0fb1908bf5a43dcc89c90044d (diff) |
lots of sRGB and F16 blits
- generalize F16 xfermode procs
- spriteblits for F16 and sRGB
- saveLayer now respects colortype and profiletype
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1686013002
Review URL: https://codereview.chromium.org/1685203002
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkBitmapProcShader.h | 2 | ||||
-rw-r--r-- | src/core/SkBlitter.cpp | 6 | ||||
-rw-r--r-- | src/core/SkBlitter_PM4f.cpp | 2 | ||||
-rw-r--r-- | src/core/SkBlitter_Sprite.cpp | 9 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 48 | ||||
-rw-r--r-- | src/core/SkSpanProcs.cpp | 95 | ||||
-rw-r--r-- | src/core/SkSpanProcs.h | 24 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter.h | 4 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter4f.cpp | 137 | ||||
-rw-r--r-- | src/core/SkSpriteBlitter_ARGB32.cpp | 6 | ||||
-rw-r--r-- | src/core/SkXfermode.cpp | 11 | ||||
-rw-r--r-- | src/core/SkXfermode4f.cpp | 113 | ||||
-rw-r--r-- | src/core/SkXfermodeU64.cpp | 67 |
13 files changed, 435 insertions, 89 deletions
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h index 0346eff0e2..2134927c4c 100644 --- a/src/core/SkBitmapProcShader.h +++ b/src/core/SkBitmapProcShader.h @@ -75,7 +75,7 @@ private: // an Sk3DBlitter in SkDraw.cpp // Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not // yet found a situation where the size below isn't big enough. -typedef SkSmallAllocator<3, 1160> SkTBlitterAllocator; +typedef SkSmallAllocator<3, 1280> SkTBlitterAllocator; // If alloc is non-nullptr, it will be used to allocate the returned SkShader, and MUST outlive // the SkShader. diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index a3dbe5e80f..41d6071d6e 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -938,11 +938,13 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, break; default: - SkDEBUGFAIL("unsupported device config"); - blitter = allocator->createT<SkNullBlitter>(); break; } + if (!blitter) { + blitter = allocator->createT<SkNullBlitter>(); + } + if (shader3D) { SkBlitter* innerBlitter = blitter; // innerBlitter was allocated by allocator, which will delete it. diff --git a/src/core/SkBlitter_PM4f.cpp b/src/core/SkBlitter_PM4f.cpp index 3c13baa4c9..24fc4a39dd 100644 --- a/src/core/SkBlitter_PM4f.cpp +++ b/src/core/SkBlitter_PM4f.cpp @@ -356,7 +356,7 @@ struct State64 : SkXfermode::U64State { } SkXfermode::Mode mode; - if (SkXfermode::AsMode(fXfer, &mode)) { + if (!SkXfermode::AsMode(fXfer, &mode)) { mode = SkXfermode::kSrcOver_Mode; } fProc1 = SkXfermode::GetU64Proc1(mode, fFlags); diff --git a/src/core/SkBlitter_Sprite.cpp b/src/core/SkBlitter_Sprite.cpp index 605fa43bf6..27cbd61768 100644 --- a/src/core/SkBlitter_Sprite.cpp +++ b/src/core/SkBlitter_Sprite.cpp @@ -60,7 +60,14 @@ SkBlitter* SkBlitter::ChooseSprite(const SkPixmap& dst, const SkPaint& paint, blitter = SkSpriteBlitter::ChooseD16(source, paint, allocator); break; case kN32_SkColorType: - blitter = SkSpriteBlitter::ChooseD32(source, paint, allocator); + if (dst.info().isSRGB()) { + blitter = SkSpriteBlitter::ChooseS32(source, paint, allocator); + } else { + blitter = SkSpriteBlitter::ChooseL32(source, paint, allocator); + } + break; + case kRGBA_F16_SkColorType: + blitter = SkSpriteBlitter::ChooseF16(source, paint, allocator); break; default: blitter = nullptr; diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 653f4b117f..f0476cd183 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1167,6 +1167,22 @@ static void draw_filter_into_device(SkBaseDevice* src, const SkImageFilter* filt c.drawBitmap(srcBM, x, y, &p); } +static SkImageInfo make_layer_info(const SkImageInfo& prev, int w, int h, bool isOpaque, + const SkPaint* paint) { + // need to force L32 for now if we have an image filter. Once filters support other colortypes + // e.g. sRGB or F16, we can remove this check + const bool hasImageFilter = paint && paint->getImageFilter(); + + SkAlphaType alphaType = isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; + if ((prev.bytesPerPixel() < 4) || hasImageFilter) { + // force to L32 + return SkImageInfo::MakeN32(w, h, alphaType); + } else { + // keep the same characteristics as the prev + return SkImageInfo::Make(w, h, prev.colorType(), alphaType, prev.profileType()); + } +} + void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy strategy) { const SkRect* bounds = rec.fBounds; const SkPaint* paint = rec.fPaint; @@ -1202,8 +1218,6 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra geo = kUnknown_SkPixelGeometry; } } - SkImageInfo info = SkImageInfo::MakeN32(ir.width(), ir.height(), - isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); SkBaseDevice* device = this->getTopDevice(); if (nullptr == device) { @@ -1211,6 +1225,9 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra return; } + SkImageInfo info = make_layer_info(device->imageInfo(), ir.width(), ir.height(), isOpaque, + paint); + bool forceSpriteOnRestore = false; { const bool preserveLCDText = kOpaque_SkAlphaType == info.alphaType() || @@ -2200,8 +2217,20 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S paint = lazy.init(); } - const bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), - *paint); + bool drawAsSprite = this->canDrawBitmapAsSprite(x, y, image->width(), image->height(), + *paint); + if (drawAsSprite && paint->getImageFilter()) { + SkBitmap bitmap; + if (!as_IB(image)->asBitmapForImageFilters(&bitmap)) { + drawAsSprite = false; + } else{ + // Until imagefilters are updated, they cannot handle any src type but N32... + if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) { + drawAsSprite = false; + } + } + } + LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, &bounds) while (iter.next()) { @@ -2277,8 +2306,15 @@ void SkCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y, cons bounds = &storage; } - const bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), - bitmap.height(), *paint); + bool drawAsSprite = bounds && this->canDrawBitmapAsSprite(x, y, bitmap.width(), bitmap.height(), + *paint); + if (drawAsSprite && paint->getImageFilter()) { + // Until imagefilters are updated, they cannot handle any src type but N32... + if (bitmap.info().colorType() != kN32_SkColorType || bitmap.info().isSRGB()) { + drawAsSprite = false; + } + } + LOOPER_BEGIN_DRAWBITMAP(*paint, drawAsSprite, bounds) while (iter.next()) { diff --git a/src/core/SkSpanProcs.cpp b/src/core/SkSpanProcs.cpp new file mode 100644 index 0000000000..efbce9704a --- /dev/null +++ b/src/core/SkSpanProcs.cpp @@ -0,0 +1,95 @@ +/* + * 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 "SkColorFilter.h" +#include "SkHalf.h" +#include "SkNx.h" +#include "SkPaint.h" +#include "SkPixmap.h" +#include "SkPM4f.h" +#include "SkPM4fPriv.h" +#include "SkSpanProcs.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static void load_l32(const SkPixmap& src, int x, int y, SkPM4f span[], int count) { + SkASSERT(count > 0); + const uint32_t* addr = src.addr32(x, y); + SkASSERT(src.addr32(x + count - 1, y)); + + for (int i = 0; i < count; ++i) { + (SkNx_cast<float>(Sk4b::Load(&addr[i])) * Sk4f(1.0f/255)).store(span[i].fVec); + } +} + +static void load_s32(const SkPixmap& src, int x, int y, SkPM4f span[], int count) { + SkASSERT(count > 0); + const uint32_t* addr = src.addr32(x, y); + SkASSERT(src.addr32(x + count - 1, y)); + + for (int i = 0; i < count; ++i) { + srgb_to_linear(SkNx_cast<float>(Sk4b::Load(&addr[i])) * Sk4f(1.0f/255)).store(span[i].fVec); + } +} + +static void load_f16(const SkPixmap& src, int x, int y, SkPM4f span[], int count) { + SkASSERT(count > 0); + const uint64_t* addr = src.addr64(x, y); + SkASSERT(src.addr64(x + count - 1, y)); + + for (int i = 0; i < count; ++i) { + SkHalfToFloat_01(addr[i]).store(span[i].fVec); + } +} + +SkLoadSpanProc SkLoadSpanProc_Choose(const SkImageInfo& info) { + switch (info.colorType()) { + case kN32_SkColorType: + return info.isSRGB() ? load_s32 : load_l32; + case kRGBA_F16_SkColorType: + return load_f16; + default: + return nullptr; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static void noop_filterspan(const SkPaint& paint, SkPM4f[], int) { + SkASSERT(!paint.getColorFilter()); + SkASSERT(0xFF == paint.getAlpha()); +} + +static void alpha_filterspan(const SkPaint& paint, SkPM4f span[], int count) { + SkASSERT(!paint.getColorFilter()); + SkASSERT(0xFF != paint.getAlpha()); + const Sk4f scale = Sk4f(paint.getAlpha() * (1.0f/255)); + for (int i = 0; i < count; ++i) { + (Sk4f::Load(span[i].fVec) * scale).store(span[i].fVec); + } +} + +static void colorfilter_filterspan(const SkPaint& paint, SkPM4f span[], int count) { + SkASSERT(paint.getColorFilter()); + SkASSERT(0xFF == paint.getAlpha()); + paint.getColorFilter()->filterSpan4f(span, count, span); +} + +static void colorfilter_alpha_filterspan(const SkPaint& paint, SkPM4f span[], int count) { + SkASSERT(paint.getColorFilter()); + SkASSERT(0xFF != paint.getAlpha()); + alpha_filterspan(paint, span, count); + paint.getColorFilter()->filterSpan4f(span, count, span); +} + +SkFilterSpanProc SkFilterSpanProc_Choose(const SkPaint& paint) { + if (paint.getColorFilter()) { + return 0xFF == paint.getAlpha() ? colorfilter_filterspan : colorfilter_alpha_filterspan; + } else { + return 0xFF == paint.getAlpha() ? noop_filterspan : alpha_filterspan; + } +} diff --git a/src/core/SkSpanProcs.h b/src/core/SkSpanProcs.h new file mode 100644 index 0000000000..891f4e2d82 --- /dev/null +++ b/src/core/SkSpanProcs.h @@ -0,0 +1,24 @@ +/* + * 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 SkSpanProcs_DEFINED +#define SkSpanProcs_DEFINED + +#include "SkPM4f.h" + +struct SkImageInfo; +class SkPaint; +class SkPixmap; +struct SkPM4f; + +typedef void (*SkLoadSpanProc)(const SkPixmap&, int x, int y, SkPM4f span[], int count); +typedef void (*SkFilterSpanProc)(const SkPaint& paint, SkPM4f span[], int count); + +SkLoadSpanProc SkLoadSpanProc_Choose(const SkImageInfo&); +SkFilterSpanProc SkFilterSpanProc_Choose(const SkPaint&); + +#endif diff --git a/src/core/SkSpriteBlitter.h b/src/core/SkSpriteBlitter.h index 536c8926d4..62c50c8b35 100644 --- a/src/core/SkSpriteBlitter.h +++ b/src/core/SkSpriteBlitter.h @@ -29,7 +29,9 @@ public: #endif static SkSpriteBlitter* ChooseD16(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); - static SkSpriteBlitter* ChooseD32(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); + static SkSpriteBlitter* ChooseL32(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); + static SkSpriteBlitter* ChooseS32(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); + static SkSpriteBlitter* ChooseF16(const SkPixmap& source, const SkPaint&, SkTBlitterAllocator*); protected: SkPixmap fDst; diff --git a/src/core/SkSpriteBlitter4f.cpp b/src/core/SkSpriteBlitter4f.cpp new file mode 100644 index 0000000000..fc4b480951 --- /dev/null +++ b/src/core/SkSpriteBlitter4f.cpp @@ -0,0 +1,137 @@ +/* + * 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 "SkSpriteBlitter.h" +#include "SkSpanProcs.h" +#include "SkTemplates.h" +#include "SkXfermode.h" + +class Sprite_4f : public SkSpriteBlitter { +public: + Sprite_4f(const SkPixmap& src, const SkPaint& paint) : INHERITED(src) { + fLoader = SkLoadSpanProc_Choose(src.info()); + fFilter = SkFilterSpanProc_Choose(paint); + fBuffer.reset(src.width()); + } + +protected: + SkLoadSpanProc fLoader; + SkFilterSpanProc fFilter; + SkAutoTMalloc<SkPM4f> fBuffer; + +private: + typedef SkSpriteBlitter INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static SkXfermode::Mode get_mode(const SkXfermode* xfer) { + SkXfermode::Mode mode; + if (!SkXfermode::AsMode(xfer, &mode)) { + mode = SkXfermode::kSrcOver_Mode; + } + return mode; +} + +class Sprite_F16 : public Sprite_4f { +public: + Sprite_F16(const SkPixmap& src, const SkPaint& paint) : INHERITED(src, paint) { + fState = { paint.getXfermode(), SkXfermode::kDstIsFloat16_U64Flag }; + if (src.isOpaque()) { + fState.fFlags |= SkXfermode::kSrcIsOpaque_U64Flag; + } + fXfer = SkXfermode::GetU64ProcN(get_mode(fState.fXfer), fState.fFlags); + } + + void blitRect(int x, int y, int width, int height) override { + SkASSERT(width > 0 && height > 0); + uint64_t* SK_RESTRICT dst = fDst.writable_addr64(x, y); + size_t dstRB = fDst.rowBytes(); + + for (int bottom = y + height; y < bottom; ++y) { + fLoader(fSource, x - fLeft, y - fTop, fBuffer, width); + fFilter(*fPaint, fBuffer, width); + fXfer(fState, dst, fBuffer, width, nullptr); + dst = (uint64_t* SK_RESTRICT)((char*)dst + dstRB); + } + } + +private: + SkXfermode::U64State fState; + SkXfermode::U64ProcN fXfer; + + typedef Sprite_4f INHERITED; +}; + + +SkSpriteBlitter* SkSpriteBlitter::ChooseF16(const SkPixmap& source, const SkPaint& paint, + SkTBlitterAllocator* allocator) { + SkASSERT(allocator != nullptr); + + if (paint.getMaskFilter() != nullptr) { + return nullptr; + } + + switch (source.colorType()) { + case kN32_SkColorType: + case kRGBA_F16_SkColorType: + return allocator->createT<Sprite_F16>(source, paint); + default: + return nullptr; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class Sprite_sRGB : public Sprite_4f { +public: + Sprite_sRGB(const SkPixmap& src, const SkPaint& paint) : INHERITED(src, paint) { + fState = { paint.getXfermode(), SkXfermode::kDstIsSRGB_PM4fFlag }; + if (src.isOpaque()) { + fState.fFlags |= SkXfermode::kSrcIsOpaque_PM4fFlag; + } + fXfer = SkXfermode::GetPM4fProcN(get_mode(fState.fXfer), fState.fFlags); + } + + void blitRect(int x, int y, int width, int height) override { + SkASSERT(width > 0 && height > 0); + uint32_t* SK_RESTRICT dst = fDst.writable_addr32(x, y); + size_t dstRB = fDst.rowBytes(); + + for (int bottom = y + height; y < bottom; ++y) { + fLoader(fSource, x - fLeft, y - fTop, fBuffer, width); + fFilter(*fPaint, fBuffer, width); + fXfer(fState, dst, fBuffer, width, nullptr); + dst = (uint32_t* SK_RESTRICT)((char*)dst + dstRB); + } + } + +protected: + SkXfermode::PM4fState fState; + SkXfermode::PM4fProcN fXfer; + +private: + typedef Sprite_4f INHERITED; +}; + + +SkSpriteBlitter* SkSpriteBlitter::ChooseS32(const SkPixmap& source, const SkPaint& paint, + SkTBlitterAllocator* allocator) { + SkASSERT(allocator != nullptr); + + if (paint.getMaskFilter() != nullptr) { + return nullptr; + } + + switch (source.colorType()) { + case kN32_SkColorType: + case kRGBA_F16_SkColorType: + return allocator->createT<Sprite_sRGB>(source, paint); + default: + return nullptr; + } +} diff --git a/src/core/SkSpriteBlitter_ARGB32.cpp b/src/core/SkSpriteBlitter_ARGB32.cpp index 9c47844082..93885996ea 100644 --- a/src/core/SkSpriteBlitter_ARGB32.cpp +++ b/src/core/SkSpriteBlitter_ARGB32.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #include "SkSpriteBlitter.h" #include "SkBlitRow.h" #include "SkColorFilter.h" @@ -256,8 +254,8 @@ public: /////////////////////////////////////////////////////////////////////////////// -SkSpriteBlitter* SkSpriteBlitter::ChooseD32(const SkPixmap& source, const SkPaint& paint, - SkTBlitterAllocator* allocator) { +SkSpriteBlitter* SkSpriteBlitter::ChooseL32(const SkPixmap& source, const SkPaint& paint, + SkTBlitterAllocator* allocator) { SkASSERT(allocator != nullptr); if (paint.getMaskFilter() != nullptr) { diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 7f89327703..7002e9a533 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -95,7 +95,7 @@ static Sk4f overlay_4f(const Sk4f& s, const Sk4f& d) { Sk4f two = Sk4f(2); Sk4f rc = (two * d <= da).thenElse(two * s * d, sa * da - two * (da - d) * (sa - s)); - return s + d - s * da + color_alpha(rc - d * sa, 0); + return pin_1(s + d - s * da + color_alpha(rc - d * sa, 0)); } static Sk4f hardlight_4f(const Sk4f& s, const Sk4f& d) { @@ -1343,6 +1343,15 @@ SkXfermodeProc4f SkXfermode::GetProc4f(Mode mode) { return proc; } +static SkPM4f missing_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return src; +} + +SkXfermodeProc4f SkXfermode::getProc4f() const { + Mode mode; + return this->asMode(&mode) ? GetProc4f(mode) : missing_proc4f; +} + bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) { SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); diff --git a/src/core/SkXfermode4f.cpp b/src/core/SkXfermode4f.cpp index 1f6c6747bb..8aa2ce26a4 100644 --- a/src/core/SkXfermode4f.cpp +++ b/src/core/SkXfermode4f.cpp @@ -45,76 +45,53 @@ static Sk4f linear_unit_to_srgb_255f(const Sk4f& l4) { /////////////////////////////////////////////////////////////////////////////////////////////////// -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; +template <DstType D> void general_1(const SkXfermode::PM4fState& state, uint32_t dst[], + const SkPM4f& src, int count, const SkAlpha aa[]) { + SkXfermodeProc4f proc = state.fXfer->getProc4f(); + SkPM4f d; + if (aa) { + for (int i = 0; i < count; ++i) { + Sk4f d4 = load_dst<D>(dst[i]); + d4.store(d.fVec); + Sk4f r4 = Sk4f::Load(proc(src, d).fVec); + dst[i] = store_dst<D>(lerp(r4, d4, aa[i])); + } + } else { + for (int i = 0; i < count; ++i) { + load_dst<D>(dst[i]).store(d.fVec); + Sk4f r4 = Sk4f::Load(proc(src, d).fVec); + dst[i] = store_dst<D>(r4); } - 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; +template <DstType D> void general_n(const SkXfermode::PM4fState& state, uint32_t dst[], + const SkPM4f src[], int count, const SkAlpha aa[]) { + SkXfermodeProc4f proc = state.fXfer->getProc4f(); + SkPM4f d; + if (aa) { + for (int i = 0; i < count; ++i) { + Sk4f d4 = load_dst<D>(dst[i]); + d4.store(d.fVec); + Sk4f r4 = Sk4f::Load(proc(src[i], d).fVec); + dst[i] = store_dst<D>(lerp(r4, d4, aa[i])); + } + } else { + for (int i = 0; i < count; ++i) { + load_dst<D>(dst[i]).store(d.fVec); + Sk4f r4 = Sk4f::Load(proc(src[i], d).fVec); + dst[i] = store_dst<D>(r4); } - count -= n; } } +const XferProcPair gProcs_General[] = { + { general_1<kLinear_Dst>, general_n<kLinear_Dst> }, // linear alpha + { general_1<kLinear_Dst>, general_n<kLinear_Dst> }, // linear opaque + { general_1<kSRGB_Dst>, general_n<kSRGB_Dst> }, // srgb alpha + { general_1<kSRGB_Dst>, general_n<kSRGB_Dst> }, // srgb opaque +}; + /////////////////////////////////////////////////////////////////////////////////////////////////// static void clear_linear_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f[], @@ -402,7 +379,7 @@ static XferProcPair find_procs(SkXfermode::Mode mode, uint32_t flags) { default: break; } - return { xfer_pm4_proc_1, xfer_pm4_proc_n }; + return gProcs_General[flags]; } SkXfermode::PM4fProc1 SkXfermode::GetPM4fProc1(Mode mode, uint32_t flags) { @@ -414,13 +391,19 @@ SkXfermode::PM4fProcN SkXfermode::GetPM4fProcN(Mode mode, uint32_t flags) { } SkXfermode::PM4fProc1 SkXfermode::getPM4fProc1(uint32_t flags) const { + SkASSERT(0 == (flags & ~3)); + flags &= 3; + Mode mode; - return this->asMode(&mode) ? GetPM4fProc1(mode, flags) : xfer_pm4_proc_1; + return this->asMode(&mode) ? GetPM4fProc1(mode, flags) : gProcs_General[flags].fP1; } SkXfermode::PM4fProcN SkXfermode::getPM4fProcN(uint32_t flags) const { + SkASSERT(0 == (flags & ~3)); + flags &= 3; + Mode mode; - return this->asMode(&mode) ? GetPM4fProcN(mode, flags) : xfer_pm4_proc_n; + return this->asMode(&mode) ? GetPM4fProcN(mode, flags) : gProcs_General[flags].fPN; } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkXfermodeU64.cpp b/src/core/SkXfermodeU64.cpp index 5b26228170..5d260c1713 100644 --- a/src/core/SkXfermodeU64.cpp +++ b/src/core/SkXfermodeU64.cpp @@ -30,10 +30,14 @@ static Sk4f lerp_by_coverage(const Sk4f& src, const Sk4f& dst, uint8_t srcCovera return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f)); } -template <DstType D> Sk4f unit_to_dst_bias(const Sk4f& x4) { +template <DstType D> Sk4f unit_to_bias(const Sk4f& x4) { return (D == kU16_Dst) ? x4 * Sk4f(65535) : x4; } +template <DstType D> Sk4f bias_to_unit(const Sk4f& x4) { + return (D == kU16_Dst) ? x4 * Sk4f(1.0f/65535) : x4; +} + // returns value already biased by 65535 static Sk4f load_from_u16(uint64_t value) { return SkNx_cast<float>(Sk4h::Load(&value)); @@ -68,9 +72,58 @@ static inline Sk4f pm_to_rgba_order(const Sk4f& x) { /////////////////////////////////////////////////////////////////////////////////////////////////// +template <DstType D> void xfer_u64_1(const SkXfermode::U64State& state, uint64_t dst[], + const SkPM4f& src, int count, const SkAlpha aa[]) { + SkXfermodeProc4f proc = state.fXfer->getProc4f(); + SkPM4f d; + if (aa) { + for (int i = 0; i < count; ++i) { + Sk4f d4 = bias_to_unit<D>(load_from_dst<D>(dst[i])); + d4.store(d.fVec); + Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(src, d).fVec)); + dst[i] = store_to_dst<D>(lerp_by_coverage(r4, d4, aa[i])); + } + } else { + for (int i = 0; i < count; ++i) { + bias_to_unit<D>(load_from_dst<D>(dst[i])).store(d.fVec); + Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(src, d).fVec)); + dst[i] = store_to_dst<D>(r4); + } + } +} + +template <DstType D> void xfer_u64_n(const SkXfermode::U64State& state, uint64_t dst[], + const SkPM4f src[], int count, const SkAlpha aa[]) { + SkXfermodeProc4f proc = state.fXfer->getProc4f(); + SkPM4f d; + if (aa) { + for (int i = 0; i < count; ++i) { + Sk4f d4 = bias_to_unit<D>(load_from_dst<D>(dst[i])); + d4.store(d.fVec); + Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(src[i], d).fVec)); + dst[i] = store_to_dst<D>(lerp_by_coverage(r4, d4, aa[i])); + } + } else { + for (int i = 0; i < count; ++i) { + bias_to_unit<D>(load_from_dst<D>(dst[i])).store(d.fVec); + Sk4f r4 = unit_to_bias<D>(Sk4f::Load(proc(src[i], d).fVec)); + dst[i] = store_to_dst<D>(r4); + } + } +} + +const U64ProcPair gU64Procs_General[] = { + { xfer_u64_1<kU16_Dst>, xfer_u64_n<kU16_Dst> }, // U16 alpha + { xfer_u64_1<kU16_Dst>, xfer_u64_n<kU16_Dst> }, // U16 opaque + { xfer_u64_1<kF16_Dst>, xfer_u64_n<kF16_Dst> }, // F16 alpha + { xfer_u64_1<kF16_Dst>, xfer_u64_n<kF16_Dst> }, // F16 opaque +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// + template <DstType D> void src_1(const SkXfermode::U64State& state, uint64_t dst[], const SkPM4f& src, int count, const SkAlpha aa[]) { - const Sk4f s4 = pm_to_rgba_order(unit_to_dst_bias<D>(Sk4f::Load(src.fVec))); + const Sk4f s4 = pm_to_rgba_order(unit_to_bias<D>(Sk4f::Load(src.fVec))); if (aa) { for (int i = 0; i < count; ++i) { const Sk4f d4 = load_from_dst<D>(dst[i]); @@ -85,13 +138,13 @@ template <DstType D> void src_n(const SkXfermode::U64State& state, uint64_t dst[ const SkPM4f src[], int count, const SkAlpha aa[]) { if (aa) { for (int i = 0; i < count; ++i) { - const Sk4f s4 = pm_to_rgba_order(unit_to_dst_bias<D>(Sk4f::Load(src[i].fVec))); + const Sk4f s4 = pm_to_rgba_order(unit_to_bias<D>(Sk4f::Load(src[i].fVec))); const Sk4f d4 = load_from_dst<D>(dst[i]); dst[i] = store_to_dst<D>(lerp_by_coverage(s4, d4, aa[i])); } } else { for (int i = 0; i < count; ++i) { - const Sk4f s4 = pm_to_rgba_order(unit_to_dst_bias<D>(Sk4f::Load(src[i].fVec))); + const Sk4f s4 = pm_to_rgba_order(unit_to_bias<D>(Sk4f::Load(src[i].fVec))); dst[i] = store_to_dst<D>(s4); } } @@ -110,7 +163,7 @@ template <DstType D> void srcover_1(const SkXfermode::U64State& state, uint64_t const SkPM4f& src, int count, const SkAlpha aa[]) { const Sk4f s4 = pm_to_rgba_order(Sk4f::Load(src.fVec)); const Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); - const Sk4f s4bias = unit_to_dst_bias<D>(s4); + const Sk4f s4bias = unit_to_bias<D>(s4); for (int i = 0; i < count; ++i) { const Sk4f d4bias = load_from_dst<D>(dst[i]); const Sk4f r4bias = s4bias + d4bias * dst_scale; @@ -127,7 +180,7 @@ template <DstType D> void srcover_n(const SkXfermode::U64State& state, uint64_t for (int i = 0; i < count; ++i) { const Sk4f s4 = pm_to_rgba_order(Sk4f::Load(src[i].fVec)); const Sk4f dst_scale = Sk4f(1 - get_alpha(s4)); - const Sk4f s4bias = unit_to_dst_bias<D>(s4); + const Sk4f s4bias = unit_to_bias<D>(s4); const Sk4f d4bias = load_from_dst<D>(dst[i]); const Sk4f r4bias = s4bias + d4bias * dst_scale; if (aa) { @@ -157,7 +210,7 @@ static U64ProcPair find_procs(SkXfermode::Mode mode, uint32_t flags) { default: break; } - return { nullptr, nullptr }; + return gU64Procs_General[flags]; } SkXfermode::U64Proc1 SkXfermode::GetU64Proc1(Mode mode, uint32_t flags) { |