extend modecolorfilter to 4f

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1670063002

Review URL: https://codereview.chromium.org/1670063002
This commit is contained in:
reed 2016-02-08 12:56:56 -08:00 committed by Commit bot
parent 21eaf3b00a
commit 3125565804
8 changed files with 196 additions and 39 deletions

View File

@ -45,10 +45,14 @@ static SkColorFilter* make_cf1() {
return SkColorFilter::CreateComposeFilter(a, b);
}
static SkColorFilter* make_cf2() {
return SkColorFilter::CreateModeFilter(0x8044CC88, SkXfermode::kSrcATop_Mode);
}
static void draw_into_canvas(SkCanvas* canvas) {
const SkRect r = SkRect::MakeWH(100, 100);
const SkRect r = SkRect::MakeWH(50, 100);
SkShader* (*shaders[])() { make_opaque_color, make_alpha_color };
SkColorFilter* (*filters[])() { make_cf_null, make_cf0, make_cf1 };
SkColorFilter* (*filters[])() { make_cf_null, make_cf0, make_cf1, make_cf2 };
SkPaint paint;
for (auto shProc : shaders) {
@ -56,13 +60,13 @@ static void draw_into_canvas(SkCanvas* canvas) {
for (auto cfProc : filters) {
SkSafeUnref(paint.setColorFilter(cfProc()));
canvas->drawRect(r, paint);
canvas->translate(120, 0);
canvas->translate(60, 0);
}
}
}
DEF_SIMPLE_GM(color4f, canvas, 620, 260) {
canvas->translate(20, 20);
DEF_SIMPLE_GM(color4f, canvas, 1024, 260) {
canvas->translate(10, 10);
SkPaint bg;
// need the target to be opaque, so we can draw it to the screen
@ -71,7 +75,7 @@ DEF_SIMPLE_GM(color4f, canvas, 620, 260) {
SkColorProfileType const profiles[] { kLinear_SkColorProfileType, kSRGB_SkColorProfileType };
for (auto profile : profiles) {
const SkImageInfo info = SkImageInfo::Make(600, 100, kN32_SkColorType, kPremul_SkAlphaType,
const SkImageInfo info = SkImageInfo::Make(1024, 100, kN32_SkColorType, kPremul_SkAlphaType,
profile);
SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
surface->getCanvas()->drawPaint(bg);

View File

@ -192,6 +192,8 @@ struct SkPM4f {
#endif
};
typedef SkPM4f (*SkXfermodeProc4f)(const SkPM4f& src, const SkPM4f& dst);
/*
* The float values are 0...1 unpremultiplied
*/

View File

@ -144,6 +144,7 @@ public:
porter-duff transfer mode.
*/
static SkXfermodeProc GetProc(Mode mode);
static SkXfermodeProc4f GetProc4f(Mode);
/**
* If the specified mode can be represented by a pair of Coeff, then return
@ -241,6 +242,7 @@ public:
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;

View File

@ -37,20 +37,30 @@ bool SkModeColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) cons
}
uint32_t SkModeColorFilter::getFlags() const {
uint32_t flags = kSupports4f_Flag;
switch (fMode) {
case SkXfermode::kDst_Mode: //!< [Da, Dc]
case SkXfermode::kSrcATop_Mode: //!< [Da, Sc * Da + (1 - Sa) * Dc]
return kAlphaUnchanged_Flag;
flags |= kAlphaUnchanged_Flag;
default:
break;
}
return 0;
return flags;
}
void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const {
SkPMColor color = fPMColor;
SkXfermodeProc proc = fProc;
for (int i = 0; i < count; i++) {
result[i] = proc(color, shader[i]);
}
}
void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const {
SkPM4f color = SkPM4f::FromPMColor(fPMColor);
SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode);
for (int i = 0; i < count; i++) {
result[i] = proc(color, shader[i]);
}

View File

@ -24,6 +24,7 @@ public:
bool asColorMode(SkColor*, SkXfermode::Mode*) const override;
uint32_t getFlags() const override;
void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override;
void filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const override;
#ifndef SK_IGNORE_TO_STRING
void toString(SkString* str) const override;

View File

@ -47,6 +47,54 @@ static inline int clamp_div255round(int prod) {
}
///////////////////////////////////////////////////////////////////////////////
#include "SkNx.h"
static Sk4f alpha(const Sk4f& color) { return Sk4f(color.kth<3>()); }
static Sk4f inv_alpha(const Sk4f& color) { return Sk4f(1 - color.kth<3>()); }
static Sk4f pin_1(const Sk4f& value) { return Sk4f::Min(value, Sk4f(1)); }
static Sk4f clear_4f(const Sk4f& s, const Sk4f& d) { return Sk4f(0); }
static Sk4f src_4f(const Sk4f& s, const Sk4f& d) { return s; }
static Sk4f dst_4f(const Sk4f& s, const Sk4f& d) { return d; }
static Sk4f srcover_4f(const Sk4f& s, const Sk4f& d) { return s + inv_alpha(s) * d; }
static Sk4f dstover_4f(const Sk4f& s, const Sk4f& d) { return d + inv_alpha(d) * s; }
static Sk4f srcin_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d); }
static Sk4f dstin_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s); }
static Sk4f srcout_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d); }
static Sk4f dstout_4f(const Sk4f& s, const Sk4f& d) { return d * inv_alpha(s); }
static Sk4f srcatop_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d) + d * inv_alpha(s); }
static Sk4f dstatop_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s) + s * inv_alpha(d); }
static Sk4f xor_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d) + d * inv_alpha(s);}
static Sk4f plus_4f(const Sk4f& s, const Sk4f& d) { return pin_1(s + d); }
static Sk4f modulate_4f(const Sk4f& s, const Sk4f& d) { return s * d; }
static Sk4f screen_4f(const Sk4f& s, const Sk4f& d) { return s + d - s * d; }
static Sk4f multiply_4f(const Sk4f& s, const Sk4f& d) {
return s * inv_alpha(d) + d * inv_alpha(s) + s * d;
}
///////////////////////////////////////////////////////////////////////////////
static SkPM4f as_pm4f(const Sk4f& x) {
SkPM4f pm4;
x.store(pm4.fVec);
return pm4;
}
static Sk4f as_4f(const SkPM4f& pm4) {
return Sk4f::Load(pm4.fVec);
}
template <Sk4f (blend)(const Sk4f&, const Sk4f&)>
SkPM4f proc_4f(const SkPM4f& src, const SkPM4f& dst) {
return as_pm4f(blend(as_4f(src), as_4f(dst)));
}
///////////////////////////////////////////////////////////////////////////////
static SkPM4f not_implemented_yet_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return {{ 0.5f, 1.0f, 0.25f, 0.5f }};
}
// kClear_Mode, //!< [0, 0]
static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
@ -219,6 +267,9 @@ static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f overlay_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kDarken_Mode
static inline int darken_byte(int sc, int dc, int sa, int da) {
@ -241,6 +292,9 @@ static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f darken_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kLighten_Mode
static inline int lighten_byte(int sc, int dc, int sa, int da) {
@ -263,6 +317,9 @@ static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f lighten_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kColorDodge_Mode
static inline int colordodge_byte(int sc, int dc, int sa, int da) {
@ -287,6 +344,9 @@ static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f colordodge_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kColorBurn_Mode
static inline int colorburn_byte(int sc, int dc, int sa, int da) {
@ -311,6 +371,9 @@ static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f colorburn_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kHardLight_Mode
static inline int hardlight_byte(int sc, int dc, int sa, int da) {
@ -331,6 +394,9 @@ static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f hardlight_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// returns 255 * sqrt(n/255)
static U8CPU sqrt_unit_byte(U8CPU n) {
@ -361,6 +427,9 @@ static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f softlight_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kDifference_Mode
static inline int difference_byte(int sc, int dc, int sa, int da) {
@ -376,6 +445,9 @@ static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f difference_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kExclusion_Mode
static inline int exclusion_byte(int sc, int dc, int, int) {
@ -395,6 +467,9 @@ static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f exclusion_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// The CSS compositing spec introduces the following formulas:
// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
@ -510,6 +585,9 @@ static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f hue_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kSaturation_Mode
// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
@ -544,6 +622,9 @@ static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f saturation_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kColor_Mode
// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
@ -577,6 +658,9 @@ static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f color_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
// kLuminosity_Mode
// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
@ -610,38 +694,41 @@ static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
return SkPackARGB32(a, r, g, b);
}
static SkPM4f luminosity_proc4f(const SkPM4f& src, const SkPM4f& dst) {
return not_implemented_yet_proc4f(src, dst);
}
const ProcCoeff gProcCoeffs[] = {
{ clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
{ src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
{ dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
{ srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
{ dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
{ srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
{ dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
{ srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
{ dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
{ srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
{ dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
{ xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
{ clear_modeproc, proc_4f<clear_4f>, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff },
{ src_modeproc, proc_4f<src_4f>, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff },
{ dst_modeproc, proc_4f<dst_4f>, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff },
{ srcover_modeproc, proc_4f<srcover_4f>, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff },
{ dstover_modeproc, proc_4f<dstover_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff },
{ srcin_modeproc, proc_4f<srcin_4f>, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff },
{ dstin_modeproc, proc_4f<dstin_4f>, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff },
{ srcout_modeproc, proc_4f<srcout_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff },
{ dstout_modeproc, proc_4f<dstout_4f>, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff },
{ srcatop_modeproc, proc_4f<srcatop_4f>, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff },
{ dstatop_modeproc, proc_4f<dstatop_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff },
{ xor_modeproc, proc_4f<xor_4f>, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff },
{ plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
{ modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
{ screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
{ overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ plus_modeproc, proc_4f<plus_4f>, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
{ modulate_modeproc, proc_4f<modulate_4f>, SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
{ screen_modeproc, proc_4f<screen_4f>, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
{ overlay_modeproc, overlay_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ darken_modeproc, darken_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ lighten_modeproc, lighten_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colordodge_modeproc, colordodge_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ colorburn_modeproc, colorburn_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hardlight_modeproc, hardlight_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ softlight_modeproc, softlight_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ difference_modeproc, difference_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ exclusion_modeproc, exclusion_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ multiply_modeproc, proc_4f<multiply_4f>, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ hue_modeproc, hue_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ saturation_modeproc, saturation_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ color_modeproc, color_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ luminosity_modeproc, luminosity_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
};
///////////////////////////////////////////////////////////////////////////////
@ -1006,6 +1093,14 @@ SkXfermodeProc SkXfermode::GetProc(Mode mode) {
return proc;
}
SkXfermodeProc4f SkXfermode::GetProc4f(Mode mode) {
SkXfermodeProc4f proc = nullptr;
if ((unsigned)mode < kModeCount) {
proc = gProcCoeffs[mode].fProc4f;
}
return proc;
}
bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);

View File

@ -14,6 +14,7 @@
struct ProcCoeff {
SkXfermodeProc fProc;
SkXfermodeProc4f fProc4f;
SkXfermode::Coeff fSC;
SkXfermode::Coeff fDC;
};

View File

@ -168,9 +168,9 @@ DEF_TEST(Color4f_colorfilter, reporter) {
SkColorFilter* (*fFact)();
bool fSupports4f;
} recs[] = {
{ make_mode_cf, false },
{ make_mode_cf, true },
{ make_mx_cf, true },
{ make_compose_cf, false },
{ make_compose_cf, true },
};
// prepare the src
@ -197,3 +197,45 @@ DEF_TEST(Color4f_colorfilter, reporter) {
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
typedef SkPM4f (*SkXfermodeProc4f)(const SkPM4f& src, const SkPM4f& dst);
static bool compare_procs(SkXfermodeProc proc32, SkXfermodeProc4f proc4f) {
const float kTolerance = 1.0f / 255;
const SkColor colors[] = {
0, 0xFF000000, 0xFFFFFFFF, 0x80FF0000
};
for (auto s32 : colors) {
SkPMColor s_pm32 = SkPreMultiplyColor(s32);
SkPM4f s_pm4f = SkColor4f::FromColor(s32).premul();
for (auto d32 : colors) {
SkPMColor d_pm32 = SkPreMultiplyColor(d32);
SkPM4f d_pm4f = SkColor4f::FromColor(d32).premul();
SkPMColor r32 = proc32(s_pm32, d_pm32);
SkPM4f r4f = proc4f(s_pm4f, d_pm4f);
SkPM4f r32_4f = SkPM4f::FromPMColor(r32);
if (!nearly_equal(r4f, r32_4f, kTolerance)) {
return false;
}
}
}
return true;
}
// Check that our Proc and Proc4f return (nearly) the same results
//
DEF_TEST(Color4f_xfermode_proc4f, reporter) {
// TODO: extend xfermodes so that all cases can be tested.
//
for (int mode = SkXfermode::kClear_Mode; mode <= SkXfermode::kScreen_Mode; ++mode) {
SkXfermodeProc proc32 = SkXfermode::GetProc((SkXfermode::Mode)mode);
SkXfermodeProc4f proc4f = SkXfermode::GetProc4f((SkXfermode::Mode)mode);
REPORTER_ASSERT(reporter, compare_procs(proc32, proc4f));
}
}