aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar reed <reed@google.com>2016-02-22 06:42:31 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-22 06:42:31 -0800
commit129ed1cd6d792f3f6cf563aefa9756fc6308289d (patch)
tree262b64d17622d8ff3a4af19bc60337b5a4b76a08 /src
parent653db51b440491b0fb1908bf5a43dcc89c90044d (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.h2
-rw-r--r--src/core/SkBlitter.cpp6
-rw-r--r--src/core/SkBlitter_PM4f.cpp2
-rw-r--r--src/core/SkBlitter_Sprite.cpp9
-rw-r--r--src/core/SkCanvas.cpp48
-rw-r--r--src/core/SkSpanProcs.cpp95
-rw-r--r--src/core/SkSpanProcs.h24
-rw-r--r--src/core/SkSpriteBlitter.h4
-rw-r--r--src/core/SkSpriteBlitter4f.cpp137
-rw-r--r--src/core/SkSpriteBlitter_ARGB32.cpp6
-rw-r--r--src/core/SkXfermode.cpp11
-rw-r--r--src/core/SkXfermode4f.cpp113
-rw-r--r--src/core/SkXfermodeU64.cpp67
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) {