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
This commit is contained in:
parent
afd25f703d
commit
395eabeb0e
@ -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", 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", 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, 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); )
|
||||
|
69
gm/color4f.cpp
Normal file
69
gm/color4f.cpp
Normal file
@ -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<SkSurface> surface(SkSurface::NewRaster(info));
|
||||
surface->getCanvas()->drawPaint(bg);
|
||||
draw_into_canvas(surface->getCanvas());
|
||||
surface->draw(canvas, 0, 0, nullptr);
|
||||
canvas->translate(0, 120);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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<SkARGB32_Shader_Blitter>(
|
||||
device, *paint, shaderContext);
|
||||
if (shaderContext->supports4f() && ALLOW_SRGB) {
|
||||
blitter = allocator->createT<SkARGB32_Shader4f_Blitter>(
|
||||
device, *paint, shaderContext);
|
||||
} else {
|
||||
blitter = allocator->createT<SkARGB32_Shader_Blitter>(
|
||||
device, *paint, shaderContext);
|
||||
}
|
||||
} else if (paint->getColor() == SK_ColorBLACK) {
|
||||
blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint);
|
||||
} else if (paint->getAlpha() == 0xFF) {
|
||||
|
159
src/core/SkBlitter_PM4f.cpp
Normal file
159
src/core/SkBlitter_PM4f.cpp
Normal file
@ -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<SkPMColor*>(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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -27,12 +27,12 @@ static inline Sk4f to_4f(uint32_t b4) {
|
||||
return SkNx_cast<float>(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<uint8_t>(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<uint8_t>(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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 <bool isSRGB> 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 <bool isSRGB> 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 <bool isSRGB> 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<SkPM4f::A>());
|
||||
|
||||
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 <bool isSRGB> 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<false>, SRC_pm4np<false> }, // linear [alpha ignored]
|
||||
{ SRC_pm41p<false>, SRC_pm4np<false> }, // linear [opaque ignored]
|
||||
{ SRC_pm41p<true>, SRC_pm4np<true> }, // srgb [alpha ignored]
|
||||
{ SRC_pm41p<true>, SRC_pm4np<true> }, // 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<false>, SRCOVER_pm4np<false> }, // linear alpha
|
||||
{ SRC_pm41p<false>, SRC_pm4np<false> }, // linear opaque
|
||||
{ SRCOVER_pm41p<true>, SRCOVER_pm4np<true> }, // srgb alpha
|
||||
{ SRC_pm41p<true>, SRC_pm4np<true> }, // 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;
|
||||
}
|
@ -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
|
@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright 2006 The Android Open Source Project
|
||||
*
|
||||
|
327
src/core/SkXfermode4f.cpp
Normal file
327
src/core/SkXfermode4f.cpp
Normal file
@ -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 <DstType D> Sk4f load_dst(SkPMColor dstC) {
|
||||
return (D == kSRGB_Dst) ? Sk4f_fromS32(dstC) : Sk4f_fromL32(dstC);
|
||||
}
|
||||
|
||||
template <DstType D> 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<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;
|
||||
}
|
||||
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 <DstType D> 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<D>(dst[i]);
|
||||
r4 = lerp(r4, d4, a);
|
||||
}
|
||||
dst[i] = store_dst<D>(r4);
|
||||
}
|
||||
}
|
||||
|
||||
template <DstType D> 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<D>(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<D>(dst[i]);
|
||||
dst[i] = store_dst<D>(lerp(r4, d4, a));
|
||||
} else {
|
||||
dst[i] = r32;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sk_memset32(dst, r32, count);
|
||||
}
|
||||
}
|
||||
|
||||
const XferProcPair gProcs_Src[] = {
|
||||
{ src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear [alpha]
|
||||
{ src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear [opaque]
|
||||
{ src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // srgb [alpha]
|
||||
{ src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // 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 <DstType D> 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<D>(dst[i]);
|
||||
if (a != 0xFF) {
|
||||
s4 = scale_by_coverage(s4, a);
|
||||
}
|
||||
Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
|
||||
dst[i] = store_dst<D>(r4);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Sk4f s4 = Sk4f::Load(src[i].fVec);
|
||||
Sk4f d4 = load_dst<D>(dst[i]);
|
||||
Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
|
||||
dst[i] = store_dst<D>(r4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <DstType D> 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<D>(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<D>(r4);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
Sk4f d4 = load_dst<D>(dst[i]);
|
||||
Sk4f r4 = s4 + d4 * scale;
|
||||
dst[i] = store_dst<D>(r4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const XferProcPair gProcs_SrcOver[] = {
|
||||
{ srcover_1<kLinear_Dst>, srcover_n<kLinear_Dst> }, // linear alpha
|
||||
{ src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear opaque [ we are src-mode ]
|
||||
{ srcover_1<kSRGB_Dst>, srcover_n<kSRGB_Dst> }, // srgb alpha
|
||||
{ src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // 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;
|
||||
}
|
@ -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<SK_A32_SHIFT/8>());
|
||||
return x * scale_rgb(x.kth<SkPM4f::A>());
|
||||
}
|
||||
|
||||
static Sk4f unpremul(const Sk4f& x) {
|
||||
return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>()); // TODO: fast/approx invert?
|
||||
return x * scale_rgb(1 / x.kth<SkPM4f::A>()); // 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<SK_A32_SHIFT/8>();
|
||||
float srcA = srcf.kth<SkPM4f::A>();
|
||||
|
||||
if (0 == srcA) {
|
||||
dst[i] = matrix_translate_pmcolor;
|
||||
|
Loading…
Reference in New Issue
Block a user