Index: src/core/SkSpriteBlitterU64.cpp |
diff --git a/src/core/SkSpriteBlitterU64.cpp b/src/core/SkSpriteBlitterU64.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5c6647dc019e67be65d8d3cd05530bcd93e1c834 |
--- /dev/null |
+++ b/src/core/SkSpriteBlitterU64.cpp |
@@ -0,0 +1,168 @@ |
+ |
+/* |
+ * Copyright 2006 The Android Open Source Project |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
herb_g
2016/02/19 21:36:46
I think this should be:
/*
* Copyright 2016 Googl
reed1
2016/02/20 19:37:17
Done.
|
+ */ |
+ |
+ |
+#include "SkSpriteBlitter.h" |
+#include "SkColorFilter.h" |
+#include "SkHalf.h" |
+#include "SkNx.h" |
+#include "SkPM4f.h" |
+#include "SkPM4fPriv.h" |
+#include "SkTemplates.h" |
+#include "SkUtils.h" |
+#include "SkXfermode.h" |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+typedef void (*SkLoadSpanProc)(const SkPixmap&, int x, int y, SkPM4f span[], int count); |
+ |
+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); |
f(malita)
2016/02/19 20:38:43
Is there a benefit to loading Sk4f(1/255) outside
mtklein
2016/02/19 20:41:17
It's very hoistable. I'd only move it out of the
|
+ } |
+} |
+ |
+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); |
+ } |
+} |
+ |
+static SkLoadSpanProc choose_loadspanproc(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; |
+ } |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+typedef void (*SkFilterSpanProc)(const SkPaint& paint, SkPM4f span[], int count); |
+ |
+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); |
+} |
+ |
+static SkFilterSpanProc choose_filterspanproc(const SkPaint& paint) { |
+ if (paint.getColorFilter()) { |
+ return 0xFF == paint.getAlpha() ? colorfilter_filterspan : colorfilter_alpha_filterspan; |
+ } else { |
+ return 0xFF == paint.getAlpha() ? noop_filterspan : alpha_filterspan; |
+ } |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////////////////////////// |
+ |
+static SkXfermode::Mode get_mode(const SkXfermode* xfer) { |
+ SkXfermode::Mode mode; |
+ if (!SkXfermode::AsMode(xfer, &mode)) { |
+ mode = SkXfermode::kSrcOver_Mode; |
+ } |
+ return mode; |
+} |
+ |
+class Sprite_D64 : public SkSpriteBlitter { |
+public: |
+ Sprite_D64(const SkPixmap& src, const SkPaint& paint) : INHERITED(src) { |
+ fLoader = choose_loadspanproc(src.info()); |
+ fFilter = choose_filterspanproc(paint); |
+ fState = { paint.getXfermode(), SkXfermode::kDstIsFloat16_U64Flag }; |
+ fXfer = SkXfermode::GetU64ProcN(get_mode(fState.fXfer), fState.fFlags); |
+ fBuffer = new SkPM4f[src.width()]; |
+ } |
+ |
+ ~Sprite_D64() { |
+ delete[] fBuffer; |
+ } |
+ |
+ 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); |
+ } |
+ } |
+ |
+protected: |
+ SkLoadSpanProc fLoader; |
+ SkFilterSpanProc fFilter; |
+ SkXfermode::U64State fState; |
+ SkXfermode::U64ProcN fXfer; |
+ SkPM4f* fBuffer; |
f(malita)
2016/02/19 20:38:43
SkAutoTMalloc?
|
+ |
+private: |
+ typedef SkSpriteBlitter INHERITED; |
+}; |
+ |
+ |
+SkSpriteBlitter* SkSpriteBlitter::ChooseD64(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_D64>(source, paint); |
+ default: |
+ return nullptr; |
+ } |
+} |