aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/Sk4fBench.cpp (renamed from bench/PMFloatBench.cpp)48
-rw-r--r--src/core/SkPMFloat.h69
-rw-r--r--src/core/SkXfermode.cpp1
-rw-r--r--src/effects/SkColorMatrixFilter.cpp44
-rw-r--r--src/opts/SkXfermode_opts.h66
-rw-r--r--tests/PMFloatTest.cpp38
6 files changed, 83 insertions, 183 deletions
diff --git a/bench/PMFloatBench.cpp b/bench/Sk4fBench.cpp
index 540fdb7815..53978637f1 100644
--- a/bench/PMFloatBench.cpp
+++ b/bench/Sk4fBench.cpp
@@ -6,7 +6,8 @@
*/
#include "Benchmark.h"
-#include "SkPMFloat.h"
+#include "SkColor.h"
+#include "SkNx.h"
// Used to prevent the compiler from optimizing away the whole loop.
volatile uint32_t blackhole = 0;
@@ -19,11 +20,10 @@ static uint32_t lcg_rand(uint32_t* seed) {
return *seed;
}
-// I'm having better luck getting these to constant-propagate away as template parameters.
-struct PMFloatRoundtripBench : public Benchmark {
- PMFloatRoundtripBench() {}
+struct Sk4fBytesRoundtripBench : public Benchmark {
+ Sk4fBytesRoundtripBench() {}
- const char* onGetName() override { return "SkPMFloat_roundtrip"; }
+ const char* onGetName() override { return "Sk4f_roundtrip"; }
bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
void onDraw(const int loops, SkCanvas* canvas) override {
@@ -31,32 +31,25 @@ struct PMFloatRoundtripBench : public Benchmark {
uint32_t junk = 0;
uint32_t seed = 0;
for (int i = 0; i < loops; i++) {
- SkPMColor color;
- #ifdef SK_DEBUG
- // Our SkASSERTs will remind us that it's technically required that we premultiply.
- color = SkPreMultiplyColor(lcg_rand(&seed));
- #else
- // But it's a lot faster not to, and this code won't really mind the non-PM colors.
- color = lcg_rand(&seed);
- #endif
-
- auto f = SkPMFloat::FromPMColor(color);
- SkPMColor back = f.round();
+ uint32_t color = lcg_rand(&seed),
+ back;
+ auto f = Sk4f::FromBytes((const uint8_t*)&color);
+ f.toBytes((uint8_t*)&back);
junk ^= back;
}
blackhole ^= junk;
}
};
-DEF_BENCH(return new PMFloatRoundtripBench;)
+DEF_BENCH(return new Sk4fBytesRoundtripBench;)
-struct PMFloatGradientBench : public Benchmark {
- const char* onGetName() override { return "PMFloat_gradient"; }
+struct Sk4fGradientBench : public Benchmark {
+ const char* onGetName() override { return "Sk4f_gradient"; }
bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
SkPMColor fDevice[100];
void onDraw(const int loops, SkCanvas*) override {
- Sk4f c0 = SkPMFloat::FromARGB(1, 1, 0, 0),
- c1 = SkPMFloat::FromARGB(1, 0, 0, 1),
+ Sk4f c0(0,0,255,255),
+ c1(255,0,0,255),
dc = c1 - c0,
fx(0.1f),
dx(0.002f),
@@ -64,15 +57,15 @@ struct PMFloatGradientBench : public Benchmark {
dcdx4(dcdx+dcdx+dcdx+dcdx);
for (int n = 0; n < loops; n++) {
- Sk4f a = c0 + dc*fx,
+ Sk4f a = c0 + dc*fx + Sk4f(0.5f), // add an extra 0.5f to get rounding for free.
b = a + dcdx,
c = b + dcdx,
d = c + dcdx;
for (size_t i = 0; i < SK_ARRAY_COUNT(fDevice); i += 4) {
- fDevice[i+0] = SkPMFloat(a).round();
- fDevice[i+1] = SkPMFloat(b).round();
- fDevice[i+2] = SkPMFloat(c).round();
- fDevice[i+3] = SkPMFloat(d).round();
+ a.toBytes((uint8_t*)(fDevice+i+0));
+ b.toBytes((uint8_t*)(fDevice+i+1));
+ c.toBytes((uint8_t*)(fDevice+i+2));
+ d.toBytes((uint8_t*)(fDevice+i+3));
a = a + dcdx4;
b = b + dcdx4;
c = c + dcdx4;
@@ -81,5 +74,4 @@ struct PMFloatGradientBench : public Benchmark {
}
}
};
-
-DEF_BENCH(return new PMFloatGradientBench;)
+DEF_BENCH(return new Sk4fGradientBench;)
diff --git a/src/core/SkPMFloat.h b/src/core/SkPMFloat.h
deleted file mode 100644
index 4a2235dd75..0000000000
--- a/src/core/SkPMFloat.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkPM_DEFINED
-#define SkPM_DEFINED
-
-#include "SkTypes.h"
-#include "SkColor.h"
-#include "SkColorPriv.h"
-#include "SkNx.h"
-
-// This file may be included multiple times by .cpp files with different flags, leading
-// to different definitions. Usually that doesn't matter because it's all inlined, but
-// in Debug modes the compilers may not inline everything. So wrap everything in an
-// anonymous namespace to give each includer their own silo of this code (or the linker
-// will probably pick one randomly for us, which is rarely correct).
-namespace {
-
-// A pre-multiplied color storing each component in the same order as SkPMColor,
-// but as a float in the range [0, 1].
-class SkPMFloat : public Sk4f {
-public:
- static SkPMFloat FromPMColor(SkPMColor c) { return SkPMFloat(c); }
- static SkPMFloat FromARGB(float a, float r, float g, float b) { return SkPMFloat(a,r,g,b); }
- static SkPMFloat FromOpaqueColor(SkColor c); // Requires c's alpha == 0xFF.
-
- Sk4f alphas() const { return Sk4f(this->a()); }
-
- // Uninitialized.
- SkPMFloat() {}
- explicit SkPMFloat(SkPMColor c) { *this = Sk4f::FromBytes((uint8_t*)&c) * Sk4f(1.0f/255); }
- SkPMFloat(float a, float r, float g, float b)
- #ifdef SK_PMCOLOR_IS_RGBA
- : INHERITED(r,g,b,a) {}
- #else
- : INHERITED(b,g,r,a) {}
- #endif
-
- SkPMFloat(const Sk4f& fs) : INHERITED(fs) {}
-
- float a() const { return this->kth<SK_A32_SHIFT / 8>(); }
- float r() const { return this->kth<SK_R32_SHIFT / 8>(); }
- float g() const { return this->kth<SK_G32_SHIFT / 8>(); }
- float b() const { return this->kth<SK_B32_SHIFT / 8>(); }
-
- SkPMColor round() const {
- SkPMColor c;
- (*this * Sk4f(255) + Sk4f(0.5f)).toBytes((uint8_t*)&c);
- return c;
- }
-
- bool isValid() const {
- return this->a() >= 0 && this->a() <= 1
- && this->r() >= 0 && this->r() <= this->a()
- && this->g() >= 0 && this->g() <= this->a()
- && this->b() >= 0 && this->b() <= this->a();
- }
-
-private:
- typedef Sk4f INHERITED;
-};
-
-} // namespace
-
-#endif//SkPM_DEFINED
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 1d409866bb..18ab9b6a0a 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -12,7 +12,6 @@
#include "SkLazyPtr.h"
#include "SkMathPriv.h"
#include "SkOpts.h"
-#include "SkPMFloat.h"
#include "SkReadBuffer.h"
#include "SkString.h"
#include "SkWriteBuffer.h"
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index 92b26ebdf9..d7f0a74295 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -8,7 +8,7 @@
#include "SkColorMatrixFilter.h"
#include "SkColorMatrix.h"
#include "SkColorPriv.h"
-#include "SkPMFloat.h"
+#include "SkNx.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"
#include "SkUnPreMultiply.h"
@@ -239,25 +239,27 @@ uint32_t SkColorMatrixFilter::getFlags() const {
return this->INHERITED::getFlags() | fFlags;
}
-static Sk4f premul(const Sk4f& x) {
- float scale = SkPMFloat(x).a();
- Sk4f pm = x * SkPMFloat(1, scale, scale, scale);
+static Sk4f scale_rgb(float scale) {
+ static_assert(SK_A32_SHIFT == 24, "Alpha is lane 3");
+ return Sk4f(scale, scale, scale, 1);
+}
-#ifdef SK_DEBUG
- SkPMFloat pmf(pm);
- SkASSERT(pmf.isValid());
-#endif
+static Sk4f premul(const Sk4f& x) {
+ return x * scale_rgb(x.kth<SK_A32_SHIFT/8>());
+}
- return pm;
+static Sk4f unpremul(const Sk4f& x) {
+ return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>()); // TODO: fast/approx invert?
}
-static Sk4f unpremul(const SkPMFloat& pm) {
- float scale = 1 / pm.a(); // candidate for fast/approx invert?
- return pm * SkPMFloat(1, scale, scale, scale);
+static Sk4f clamp_0_1(const Sk4f& x) {
+ return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0));
}
-static Sk4f clamp_0_1(const Sk4f& value) {
- return Sk4f::Max(Sk4f::Min(value, Sk4f(1)), Sk4f(0));
+static SkPMColor round(const Sk4f& x) {
+ SkPMColor c;
+ (x * Sk4f(255) + Sk4f(0.5f)).toBytes((uint8_t*)&c);
+ return c;
}
void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
@@ -285,7 +287,7 @@ void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor
const Sk4f c4 = Sk4f::Load(fTranspose + 16)*Sk4f(1.0f/255);
// todo: we could cache this in the constructor...
- SkPMColor matrix_translate_pmcolor = SkPMFloat(premul(clamp_0_1(c4))).round();
+ SkPMColor matrix_translate_pmcolor = round(premul(clamp_0_1(c4)));
for (int i = 0; i < count; i++) {
const SkPMColor src_c = src[i];
@@ -294,22 +296,22 @@ void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor
continue;
}
- SkPMFloat srcf(src_c);
+ Sk4f srcf = Sk4f::FromBytes((const uint8_t*)&src_c) * Sk4f(1.0f/255);
if (0xFF != SkGetPackedA32(src_c)) {
srcf = unpremul(srcf);
}
- Sk4f r4 = Sk4f(srcf.r());
- Sk4f g4 = Sk4f(srcf.g());
- Sk4f b4 = Sk4f(srcf.b());
- Sk4f a4 = Sk4f(srcf.a());
+ Sk4f r4 = Sk4f(srcf.kth<SK_R32_SHIFT/8>());
+ Sk4f g4 = Sk4f(srcf.kth<SK_G32_SHIFT/8>());
+ Sk4f b4 = Sk4f(srcf.kth<SK_B32_SHIFT/8>());
+ Sk4f a4 = Sk4f(srcf.kth<SK_A32_SHIFT/8>());
// apply matrix
Sk4f dst4 = c0 * r4 + c1 * g4 + c2 * b4 + c3 * a4 + c4;
// clamp, re-premul, and write
- dst[i] = SkPMFloat(premul(clamp_0_1(dst4))).round();
+ dst[i] = round(premul(clamp_0_1(dst4)));
}
} else {
const State& state = fState;
diff --git a/src/opts/SkXfermode_opts.h b/src/opts/SkXfermode_opts.h
index 7005d593af..50bef6ac46 100644
--- a/src/opts/SkXfermode_opts.h
+++ b/src/opts/SkXfermode_opts.h
@@ -9,7 +9,7 @@
#define Sk4pxXfermode_DEFINED
#include "Sk4px.h"
-#include "SkPMFloat.h"
+#include "SkNx.h"
#include "SkXfermode_proccoeff.h"
namespace {
@@ -110,11 +110,19 @@ XFERMODE(Lighten) {
#undef XFERMODE
// Some xfermodes use math like divide or sqrt that's best done in floats 1 pixel at a time.
-#define XFERMODE(Name) static SkPMFloat SK_VECTORCALL Name(SkPMFloat d, SkPMFloat s)
+#define XFERMODE(Name) static Sk4f SK_VECTORCALL Name(Sk4f d, Sk4f s)
+
+static inline Sk4f a_rgb(const Sk4f& a, const Sk4f& rgb) {
+ static_assert(SK_A32_SHIFT == 24, "");
+ return a * Sk4f(0,0,0,1) + rgb * Sk4f(1,1,1,0);
+}
+static inline Sk4f alphas(const Sk4f& f) {
+ return Sk4f(f.kth<SK_A32_SHIFT/8>());
+}
XFERMODE(ColorDodge) {
- auto sa = s.alphas(),
- da = d.alphas(),
+ auto sa = alphas(s),
+ da = alphas(d),
isa = Sk4f(1)-sa,
ida = Sk4f(1)-da;
@@ -126,11 +134,11 @@ XFERMODE(ColorDodge) {
auto colors = (d == Sk4f(0)).thenElse(dstover,
(s == sa).thenElse(srcover,
otherwise));
- return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1);
+ return a_rgb(srcover, colors);
}
XFERMODE(ColorBurn) {
- auto sa = s.alphas(),
- da = d.alphas(),
+ auto sa = alphas(s),
+ da = alphas(d),
isa = Sk4f(1)-sa,
ida = Sk4f(1)-da;
@@ -142,11 +150,11 @@ XFERMODE(ColorBurn) {
auto colors = (d == da).thenElse(dstover,
(s == Sk4f(0)).thenElse(srcover,
otherwise));
- return srcover * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1);
+ return a_rgb(srcover, colors);
}
XFERMODE(SoftLight) {
- auto sa = s.alphas(),
- da = d.alphas(),
+ auto sa = alphas(s),
+ da = alphas(d),
isa = Sk4f(1)-sa,
ida = Sk4f(1)-da;
@@ -167,7 +175,7 @@ XFERMODE(SoftLight) {
auto alpha = s + d*isa;
auto colors = s*ida + d*isa + (s2 <= sa).thenElse(darkSrc, liteSrc); // Case 1 or 2/3?
- return alpha * SkPMFloat(1,0,0,0) + colors * SkPMFloat(0,1,1,1);
+ return a_rgb(alpha, colors);
}
#undef XFERMODE
@@ -232,10 +240,10 @@ private:
typedef SkProcCoeffXfermode INHERITED;
};
-class SkPMFloatXfermode : public SkProcCoeffXfermode {
+class Sk4fXfermode : public SkProcCoeffXfermode {
public:
- typedef SkPMFloat (SK_VECTORCALL *ProcF)(SkPMFloat, SkPMFloat);
- SkPMFloatXfermode(const ProcCoeff& rec, SkXfermode::Mode mode, ProcF procf)
+ typedef Sk4f (SK_VECTORCALL *ProcF)(Sk4f, Sk4f);
+ Sk4fXfermode(const ProcCoeff& rec, SkXfermode::Mode mode, ProcF procf)
: INHERITED(rec, mode)
, fProcF(procf) {}
@@ -256,18 +264,26 @@ public:
}
private:
+ static Sk4f Load(SkPMColor c) {
+ return Sk4f::FromBytes((uint8_t*)&c) * Sk4f(1.0f/255);
+ }
+ static SkPMColor Round(const Sk4f& f) {
+ SkPMColor c;
+ (f * Sk4f(255) + Sk4f(0.5f)).toBytes((uint8_t*)&c);
+ return c;
+ }
inline SkPMColor xfer32(SkPMColor dst, SkPMColor src) const {
- return fProcF(SkPMFloat(dst), SkPMFloat(src)).round();
+ return Round(fProcF(Load(dst), Load(src)));
}
inline SkPMColor xfer32(SkPMColor dst, SkPMColor src, SkAlpha aa) const {
- SkPMFloat s(src),
- d(dst),
- b(fProcF(d,s));
+ Sk4f s(Load(src)),
+ d(Load(dst)),
+ b(fProcF(d,s));
// We do aa in full float precision before going back down to bytes, because we can!
- SkPMFloat a = Sk4f(aa) * Sk4f(1.0f/255);
+ Sk4f a = Sk4f(aa) * Sk4f(1.0f/255);
b = b*a + d*(Sk4f(1)-a);
- return b.round();
+ return Round(b);
}
ProcF fProcF;
@@ -280,9 +296,8 @@ namespace SK_OPTS_NS {
static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode) {
switch (mode) {
-#define CASE(Mode) \
- case SkXfermode::k##Mode##_Mode: \
- return new Sk4pxXfermode(rec, mode, &Mode, &xfer_aa<Mode>)
+#define CASE(Mode) \
+ case SkXfermode::k##Mode##_Mode: return new Sk4pxXfermode(rec, mode, &Mode, &xfer_aa<Mode>)
CASE(Clear);
CASE(Src);
CASE(Dst);
@@ -307,9 +322,8 @@ static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode)
CASE(Lighten);
#undef CASE
-#define CASE(Mode) \
- case SkXfermode::k##Mode##_Mode: \
- return new SkPMFloatXfermode(rec, mode, &Mode)
+#define CASE(Mode) \
+ case SkXfermode::k##Mode##_Mode: return new Sk4fXfermode(rec, mode, &Mode)
CASE(ColorDodge);
CASE(ColorBurn);
CASE(SoftLight);
diff --git a/tests/PMFloatTest.cpp b/tests/PMFloatTest.cpp
deleted file mode 100644
index b7b39411d1..0000000000
--- a/tests/PMFloatTest.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkPMFloat.h"
-#include "Test.h"
-
-DEF_TEST(SkPMFloat, r) {
- // Test SkPMColor <-> SkPMFloat
- SkPMColor c = SkPreMultiplyColor(0xFFCC9933);
- SkPMFloat pmf(c);
- REPORTER_ASSERT(r, SkScalarNearlyEqual(255.0f, 255*pmf.a()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual(204.0f, 255*pmf.r()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual(153.0f, 255*pmf.g()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual( 51.0f, 255*pmf.b()));
- REPORTER_ASSERT(r, c == pmf.round());
-
- // Test rounding.
- pmf = SkPMFloat(254.5f/255, 203.5f/255, 153.1f/255, 50.8f/255);
- REPORTER_ASSERT(r, c == pmf.round());
-
- SkPMFloat clamped(SkPMFloat(510.0f/255, 153.0f/255, 1.0f/255, -0.2f/255).round());
- REPORTER_ASSERT(r, SkScalarNearlyEqual(255.0f, 255*clamped.a()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual(153.0f, 255*clamped.r()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual( 1.0f, 255*clamped.g()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual( 0.0f, 255*clamped.b()));
-
- // Test SkPMFloat <-> Sk4f conversion.
- Sk4f fs = clamped;
- SkPMFloat scaled = fs * Sk4f(0.25f);
- REPORTER_ASSERT(r, SkScalarNearlyEqual(63.75f, 255*scaled.a()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual(38.25f, 255*scaled.r()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual( 0.25f, 255*scaled.g()));
- REPORTER_ASSERT(r, SkScalarNearlyEqual( 0.00f, 255*scaled.b()));
-}