aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkXfermode.h10
-rw-r--r--src/core/SkBlitter_PM4f.cpp73
-rw-r--r--src/core/SkXfermode4f.cpp95
3 files changed, 175 insertions, 3 deletions
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index 21d77f8747..3b0f49d22e 100644
--- a/include/core/SkXfermode.h
+++ b/include/core/SkXfermode.h
@@ -248,6 +248,16 @@ public:
static U64Proc1 GetU64Proc1(Mode, uint32_t flags);
static U64ProcN GetU64ProcN(Mode, uint32_t flags);
+ enum LCDFlags {
+ kSrcIsOpaque_LCDFlag = 1 << 0, // else src(s) may have alpha < 1
+ kSrcIsSingle_LCDFlag = 1 << 1, // else src[count]
+ kDstIsLinearInt_LCDFlag = 1 << 2, // else srgb/half-float
+ };
+ typedef void (*LCD32Proc)(uint32_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]);
+ typedef void (*LCD64Proc)(uint64_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]);
+ static LCD32Proc GetLCD32Proc(uint32_t flags);
+ static LCD64Proc GetLCD64Proc(uint32_t) { return nullptr; }
+
protected:
SkXfermode() {}
/** The default implementation of xfer32/xfer16/xferA8 in turn call this
diff --git a/src/core/SkBlitter_PM4f.cpp b/src/core/SkBlitter_PM4f.cpp
index 01fd704254..cec2361c06 100644
--- a/src/core/SkBlitter_PM4f.cpp
+++ b/src/core/SkBlitter_PM4f.cpp
@@ -80,8 +80,31 @@ public:
}
}
+ void blitLCDMask(const SkMask& mask, const SkIRect& clip) {
+ auto proc = fState.getLCDProc(SkXfermode::kSrcIsSingle_LCDFlag);
+
+ const int x = clip.fLeft;
+ const int width = clip.width();
+ const int y = clip.fTop;
+ const int height = clip.height();
+
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y);
+ const size_t dstRB = fDevice.rowBytes();
+ const uint16_t* maskRow = (const uint16_t*)mask.getAddr(x, y);
+ const size_t maskRB = mask.fRowBytes;
+
+ for (int i = 0; i < height; ++i) {
+ proc(device, &fState.fPM4f, width, maskRow);
+ device = (typename State::DstType*)((char*)device + dstRB);
+ maskRow = (const uint16_t*)((const char*)maskRow + maskRB);
+ }
+ }
+
void blitMask(const SkMask& mask, const SkIRect& clip) override {
- // we only handle kA8
+ if (SkMask::kLCD16_Format == mask.fFormat) {
+ this->blitLCDMask(mask, clip);
+ return;
+ }
if (SkMask::kA8_Format != mask.fFormat) {
this->INHERITED::blitMask(mask, clip);
return;
@@ -190,8 +213,36 @@ public:
}
}
+ void blitLCDMask(const SkMask& mask, const SkIRect& clip) {
+ auto proc = fState.getLCDProc(0);
+
+ const int x = clip.fLeft;
+ const int width = clip.width();
+ int y = clip.fTop;
+
+ typename State::DstType* device = State::WritableAddr(fDevice, x, y);
+ const size_t deviceRB = fDevice.rowBytes();
+ const uint16_t* maskRow = (const uint16_t*)mask.getAddr(x, y);
+ const size_t maskRB = mask.fRowBytes;
+
+ if (fConstInY) {
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
+ }
+ for (; y < clip.fBottom; ++y) {
+ if (!fConstInY) {
+ fShaderContext->shadeSpan4f(x, y, fState.fBuffer, width);
+ }
+ proc(device, fState.fBuffer, width, maskRow);
+ device = (typename State::DstType*)((char*)device + deviceRB);
+ maskRow = (const uint16_t*)((const char*)maskRow + maskRB);
+ }
+ }
+
void blitMask(const SkMask& mask, const SkIRect& clip) override {
- // we only handle kA8
+ if (SkMask::kLCD16_Format == mask.fFormat) {
+ this->blitLCDMask(mask, clip);
+ return;
+ }
if (SkMask::kA8_Format != mask.fFormat) {
this->INHERITED::blitMask(mask, clip);
return;
@@ -271,7 +322,15 @@ struct State32 : SkXfermode::PM4fState {
SkSafeUnref(fXfer);
delete[] fBuffer;
}
-
+
+ SkXfermode::LCD32Proc getLCDProc(uint32_t oneOrManyFlag) const {
+ uint32_t flags = fFlags & 1;
+ if (!(fFlags & SkXfermode::kDstIsSRGB_PM4fFlag)) {
+ flags |= SkXfermode::kDstIsLinearInt_LCDFlag;
+ }
+ return SkXfermode::GetLCD32Proc(flags | oneOrManyFlag);
+ }
+
static DstType* WritableAddr(const SkPixmap& device, int x, int y) {
return device.writable_addr32(x, y);
}
@@ -315,6 +374,14 @@ struct State64 : SkXfermode::U64State {
delete[] fBuffer;
}
+ SkXfermode::LCD64Proc getLCDProc(uint32_t oneOrManyFlag) const {
+ uint32_t flags = fFlags & 1;
+ if (!(fFlags & SkXfermode::kDstIsFloat16_U64Flag)) {
+ flags |= SkXfermode::kDstIsLinearInt_LCDFlag;
+ }
+ return SkXfermode::GetLCD64Proc(flags | oneOrManyFlag);
+ }
+
static DstType* WritableAddr(const SkPixmap& device, int x, int y) {
return device.writable_addr64(x, y);
}
diff --git a/src/core/SkXfermode4f.cpp b/src/core/SkXfermode4f.cpp
index 9aba0da04f..bf30e92ae7 100644
--- a/src/core/SkXfermode4f.cpp
+++ b/src/core/SkXfermode4f.cpp
@@ -422,3 +422,98 @@ SkXfermode::PM4fProcN SkXfermode::getPM4fProcN(uint32_t flags) const {
Mode mode;
return this->asMode(&mode) ? GetPM4fProcN(mode, flags) : xfer_pm4_proc_n;
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#include "SkColorPriv.h"
+
+static Sk4f lcd16_to_unit_4f(uint16_t rgb) {
+ Sk4i rgbi = Sk4i(SkGetPackedR16(rgb), SkGetPackedG16(rgb), SkGetPackedB16(rgb), 0);
+ return SkNx_cast<float>(rgbi) * Sk4f(1.0f/31, 1.0f/63, 1.0f/31, 0);
+}
+
+template <DstType D>
+void src_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
+ const Sk4f s4 = Sk4f::Load(src->fVec);
+
+ if (D == kLinear_Dst) {
+ // operate in bias-255 space for src and dst
+ const Sk4f s4bias = s4 * Sk4f(255);
+ for (int i = 0; i < count; ++i) {
+ uint16_t rgb = lcd[i];
+ if (0 == rgb) {
+ continue;
+ }
+ Sk4f d4bias = to_4f(dst[i]);
+ dst[i] = to_4b(lerp(s4bias, d4bias, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
+ }
+ } else { // kSRGB
+ for (int i = 0; i < count; ++i) {
+ uint16_t rgb = lcd[i];
+ if (0 == rgb) {
+ continue;
+ }
+ Sk4f d4 = load_dst<D>(dst[i]);
+ dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
+ }
+ }
+}
+
+template <DstType D>
+void src_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
+ for (int i = 0; i < count; ++i) {
+ uint16_t rgb = lcd[i];
+ if (0 == rgb) {
+ continue;
+ }
+ Sk4f s4 = Sk4f::Load(src[i].fVec);
+ Sk4f d4 = load_dst<D>(dst[i]);
+ dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
+ }
+}
+
+template <DstType D>
+void srcover_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
+ const Sk4f s4 = Sk4f::Load(src->fVec);
+ Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
+
+ for (int i = 0; i < count; ++i) {
+ uint16_t rgb = lcd[i];
+ if (0 == rgb) {
+ continue;
+ }
+ Sk4f d4 = load_dst<D>(dst[i]);
+ Sk4f r4 = s4 + d4 * dst_scale;
+ r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
+ dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
+ }
+}
+
+template <DstType D>
+void srcover_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
+ for (int i = 0; i < count; ++i) {
+ uint16_t rgb = lcd[i];
+ if (0 == rgb) {
+ continue;
+ }
+ Sk4f s4 = Sk4f::Load(src[i].fVec);
+ Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
+ Sk4f d4 = load_dst<D>(dst[i]);
+ Sk4f r4 = s4 + d4 * dst_scale;
+ r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
+ dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
+ }
+}
+
+SkXfermode::LCD32Proc SkXfermode::GetLCD32Proc(uint32_t flags) {
+ SkASSERT((flags & ~7) == 0);
+ flags &= 7;
+
+ const LCD32Proc procs[] = {
+ srcover_n_lcd<kSRGB_Dst>, src_n_lcd<kSRGB_Dst>,
+ srcover_1_lcd<kSRGB_Dst>, src_1_lcd<kSRGB_Dst>,
+
+ srcover_n_lcd<kLinear_Dst>, src_n_lcd<kLinear_Dst>,
+ srcover_1_lcd<kLinear_Dst>, src_1_lcd<kLinear_Dst>,
+ };
+ return procs[flags];
+}