aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-06-20 06:07:45 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-06-20 06:07:45 -0700
commitd2809573deb7b99e764f7f71fe34a5b5322df0b2 (patch)
treea51709dd5e37fe8816a1e14e24d4eff9a839f5e9 /src
parent452ba88066b51931696fc3d0a2a1c0f8809a4143 (diff)
Support sRGB dsts in opt code
201295.jpg on HP z620 (300x280) QCMS Xform 0.418 ms Skia NEW Xform 0.378 ms Vs QCMS 1.11x BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2078623002 CQ_EXTRA_TRYBOTS=client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot Review-Url: https://codereview.chromium.org/2078623002
Diffstat (limited to 'src')
-rw-r--r--src/core/SkColorSpaceXform.cpp60
-rw-r--r--src/core/SkColorSpaceXform.h18
-rw-r--r--src/core/SkOpts.cpp4
-rw-r--r--src/core/SkOpts.h4
-rw-r--r--src/opts/SkColorXform_opts.h44
-rw-r--r--src/opts/SkNx_sse.h4
-rw-r--r--src/opts/SkOpts_sse41.cpp2
7 files changed, 101 insertions, 35 deletions
diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp
index 4c67e8d3f0..f42811a549 100644
--- a/src/core/SkColorSpaceXform.cpp
+++ b/src/core/SkColorSpaceXform.cpp
@@ -37,15 +37,35 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa
return nullptr;
}
- if (SkColorSpace::k2Dot2Curve_GammaNamed == dstSpace->gammaNamed() &&
- 0.0f == srcToDst.getFloat(3, 0) &&
+ if (0.0f == srcToDst.getFloat(3, 0) &&
0.0f == srcToDst.getFloat(3, 1) &&
0.0f == srcToDst.getFloat(3, 2))
{
- if (SkColorSpace::kSRGB_GammaNamed == srcSpace->gammaNamed()) {
- return std::unique_ptr<SkColorSpaceXform>(new SkSRGBTo2Dot2Xform(srcToDst));
- } else if (SkColorSpace::k2Dot2Curve_GammaNamed == srcSpace->gammaNamed()) {
- return std::unique_ptr<SkColorSpaceXform>(new Sk2Dot2To2Dot2Xform(srcToDst));
+ switch (srcSpace->gammaNamed()) {
+ case SkColorSpace::kSRGB_GammaNamed:
+ if (SkColorSpace::kSRGB_GammaNamed == dstSpace->gammaNamed()) {
+ return std::unique_ptr<SkColorSpaceXform>(
+ new SkFastXform<SkColorSpace::kSRGB_GammaNamed,
+ SkColorSpace::kSRGB_GammaNamed>(srcToDst));
+ } else if (SkColorSpace::k2Dot2Curve_GammaNamed == dstSpace->gammaNamed()) {
+ return std::unique_ptr<SkColorSpaceXform>(
+ new SkFastXform<SkColorSpace::kSRGB_GammaNamed,
+ SkColorSpace::k2Dot2Curve_GammaNamed>(srcToDst));
+ }
+ break;
+ case SkColorSpace::k2Dot2Curve_GammaNamed:
+ if (SkColorSpace::kSRGB_GammaNamed == dstSpace->gammaNamed()) {
+ return std::unique_ptr<SkColorSpaceXform>(
+ new SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed,
+ SkColorSpace::kSRGB_GammaNamed>(srcToDst));
+ } else if (SkColorSpace::k2Dot2Curve_GammaNamed == dstSpace->gammaNamed()) {
+ return std::unique_ptr<SkColorSpaceXform>(
+ new SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed,
+ SkColorSpace::k2Dot2Curve_GammaNamed>(srcToDst));
+ }
+ break;
+ default:
+ break;
}
}
@@ -90,23 +110,37 @@ static void build_src_to_dst(float srcToDstArray[12], const SkMatrix44& srcToDst
#endif
}
-SkSRGBTo2Dot2Xform::SkSRGBTo2Dot2Xform(const SkMatrix44& srcToDst)
+template <SkColorSpace::GammaNamed Src, SkColorSpace::GammaNamed Dst>
+SkFastXform<Src, Dst>::SkFastXform(const SkMatrix44& srcToDst)
{
build_src_to_dst(fSrcToDst, srcToDst);
}
-void SkSRGBTo2Dot2Xform::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const {
- SkOpts::color_xform_RGB1_srgb_to_2dot2(dst, src, len, fSrcToDst);
+template <>
+void SkFastXform<SkColorSpace::kSRGB_GammaNamed, SkColorSpace::kSRGB_GammaNamed>
+::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const
+{
+ SkOpts::color_xform_RGB1_srgb_to_srgb(dst, src, len, fSrcToDst);
}
-///////////////////////////////////////////////////////////////////////////////////////////////////
+template <>
+void SkFastXform<SkColorSpace::kSRGB_GammaNamed, SkColorSpace::k2Dot2Curve_GammaNamed>
+::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const
+{
+ SkOpts::color_xform_RGB1_srgb_to_2dot2(dst, src, len, fSrcToDst);
+}
-Sk2Dot2To2Dot2Xform::Sk2Dot2To2Dot2Xform(const SkMatrix44& srcToDst)
+template <>
+void SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed, SkColorSpace::kSRGB_GammaNamed>
+::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const
{
- build_src_to_dst(fSrcToDst, srcToDst);
+ SkOpts::color_xform_RGB1_2dot2_to_srgb(dst, src, len, fSrcToDst);
}
-void Sk2Dot2To2Dot2Xform::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const {
+template <>
+void SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed, SkColorSpace::k2Dot2Curve_GammaNamed>
+::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const
+{
SkOpts::color_xform_RGB1_2dot2_to_2dot2(dst, src, len, fSrcToDst);
}
diff --git a/src/core/SkColorSpaceXform.h b/src/core/SkColorSpaceXform.h
index 1ea608094f..e6abdbb992 100644
--- a/src/core/SkColorSpaceXform.h
+++ b/src/core/SkColorSpaceXform.h
@@ -34,26 +34,14 @@ public:
virtual ~SkColorSpaceXform() {}
};
-class SkSRGBTo2Dot2Xform : public SkColorSpaceXform {
+template <SkColorSpace::GammaNamed Src, SkColorSpace::GammaNamed Dst>
+class SkFastXform : public SkColorSpaceXform {
public:
void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override;
private:
- SkSRGBTo2Dot2Xform(const SkMatrix44& srcToDst);
-
- float fSrcToDst[12];
-
- friend class SkColorSpaceXform;
-};
-
-class Sk2Dot2To2Dot2Xform : public SkColorSpaceXform {
-public:
-
- void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override;
-
-private:
- Sk2Dot2To2Dot2Xform(const SkMatrix44& srcToDst);
+ SkFastXform(const SkMatrix44& srcToDst);
float fSrcToDst[12];
diff --git a/src/core/SkOpts.cpp b/src/core/SkOpts.cpp
index b4145acb7a..a2de1f59d2 100644
--- a/src/core/SkOpts.cpp
+++ b/src/core/SkOpts.cpp
@@ -81,6 +81,10 @@ namespace SkOpts {
sk_default::color_xform_RGB1_srgb_to_2dot2;
decltype(color_xform_RGB1_2dot2_to_2dot2) color_xform_RGB1_2dot2_to_2dot2 =
sk_default::color_xform_RGB1_2dot2_to_2dot2;
+ decltype(color_xform_RGB1_srgb_to_srgb) color_xform_RGB1_srgb_to_srgb =
+ sk_default::color_xform_RGB1_srgb_to_srgb;
+ decltype(color_xform_RGB1_2dot2_to_srgb) color_xform_RGB1_2dot2_to_srgb =
+ sk_default::color_xform_RGB1_2dot2_to_srgb;
// Each Init_foo() is defined in src/opts/SkOpts_foo.cpp.
void Init_ssse3();
diff --git a/src/core/SkOpts.h b/src/core/SkOpts.h
index 1c33529d52..186fa73d4c 100644
--- a/src/core/SkOpts.h
+++ b/src/core/SkOpts.h
@@ -74,6 +74,10 @@ namespace SkOpts {
const float srcToDstMatrix[16]);
extern void (*color_xform_RGB1_2dot2_to_2dot2)(uint32_t* dst, const uint32_t* src, int len,
const float srcToDstMatrix[16]);
+ extern void (*color_xform_RGB1_srgb_to_srgb) (uint32_t* dst, const uint32_t* src, int len,
+ const float srcToDstMatrix[16]);
+ extern void (*color_xform_RGB1_2dot2_to_srgb)(uint32_t* dst, const uint32_t* src, int len,
+ const float srcToDstMatrix[16]);
}
#endif//SkOpts_DEFINED
diff --git a/src/opts/SkColorXform_opts.h b/src/opts/SkColorXform_opts.h
index 5af5c2aed7..2c14c80283 100644
--- a/src/opts/SkColorXform_opts.h
+++ b/src/opts/SkColorXform_opts.h
@@ -157,13 +157,33 @@ static Sk4f linear_to_2dot2(const Sk4f& x) {
return 255.0f * x2.invert() * x32 * x64.invert();
}
+static Sk4f linear_to_srgb(const Sk4f& x) {
+ // Approximation of the sRGB gamma curve (within 1 when scaled to 8-bit pixels).
+ // For 0.00000f <= x < 0.00349f, 12.92 * x
+ // For 0.00349f <= x <= 1.00000f, 0.679*(x.^0.5) + 0.423*x.^(0.25) - 0.101
+ // Note that 0.00349 was selected because it is a point where both functions produce the
+ // same pixel value when rounded.
+ auto rsqrt = x.rsqrt(),
+ sqrt = rsqrt.invert(),
+ ftrt = rsqrt.rsqrt();
+
+ auto hi = (-0.101115084998961f * 255.0f) +
+ (+0.678513029959381f * 255.0f) * sqrt +
+ (+0.422602055039580f * 255.0f) * ftrt;
+
+ auto lo = (12.92f * 255.0f) * x;
+
+ auto mask = (x < 0.00349f);
+ return mask.thenElse(lo, hi);
+}
+
static Sk4f clamp_0_to_255(const Sk4f& x) {
// The order of the arguments is important here. We want to make sure that NaN
// clamps to zero. Note that max(NaN, 0) = 0, while max(0, NaN) = NaN.
return Sk4f::Min(Sk4f::Max(x, 0.0f), 255.0f);
}
-template <const float (&linear_from_curve)[256]>
+template <const float (&linear_from_curve)[256], Sk4f (*linear_to_curve)(const Sk4f&)>
static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len,
const float matrix[16]) {
// Load transformation matrix.
@@ -192,9 +212,9 @@ static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len,
dstBlues = rXgXbX[2]*reds + rYgYbY[2]*greens + rZgZbZ[2]*blues;
// Convert to dst gamma.
- dstReds = linear_to_2dot2(dstReds);
- dstGreens = linear_to_2dot2(dstGreens);
- dstBlues = linear_to_2dot2(dstBlues);
+ dstReds = linear_to_curve(dstReds);
+ dstGreens = linear_to_curve(dstGreens);
+ dstBlues = linear_to_curve(dstBlues);
// Clamp floats to byte range.
dstReds = clamp_0_to_255(dstReds);
@@ -223,7 +243,7 @@ static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len,
auto dstPixel = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
// Convert to dst gamma.
- dstPixel = linear_to_2dot2(dstPixel);
+ dstPixel = linear_to_curve(dstPixel);
// Clamp floats to byte range.
dstPixel = clamp_0_to_255(dstPixel);
@@ -242,12 +262,22 @@ static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len,
static void color_xform_RGB1_srgb_to_2dot2(uint32_t* dst, const uint32_t* src, int len,
const float matrix[16]) {
- color_xform_RGB1<linear_from_srgb>(dst, src, len, matrix);
+ color_xform_RGB1<linear_from_srgb, linear_to_2dot2>(dst, src, len, matrix);
}
static void color_xform_RGB1_2dot2_to_2dot2(uint32_t* dst, const uint32_t* src, int len,
const float matrix[16]) {
- color_xform_RGB1<linear_from_2dot2>(dst, src, len, matrix);
+ color_xform_RGB1<linear_from_2dot2, linear_to_2dot2>(dst, src, len, matrix);
+}
+
+static void color_xform_RGB1_srgb_to_srgb(uint32_t* dst, const uint32_t* src, int len,
+ const float matrix[16]) {
+ color_xform_RGB1<linear_from_srgb, linear_to_srgb>(dst, src, len, matrix);
+}
+
+static void color_xform_RGB1_2dot2_to_srgb(uint32_t* dst, const uint32_t* src, int len,
+ const float matrix[16]) {
+ color_xform_RGB1<linear_from_2dot2, linear_to_srgb>(dst, src, len, matrix);
}
} // namespace SK_OPTS_NS
diff --git a/src/opts/SkNx_sse.h b/src/opts/SkNx_sse.h
index bdc6d77ce7..9751c4db91 100644
--- a/src/opts/SkNx_sse.h
+++ b/src/opts/SkNx_sse.h
@@ -124,8 +124,12 @@ public:
bool anyTrue() const { return 0x0000 != _mm_movemask_epi8(_mm_castps_si128(fVec)); }
SkNx thenElse(const SkNx& t, const SkNx& e) const {
+#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41
+ return _mm_blendv_ps(e.fVec, t.fVec, fVec);
+#else
return _mm_or_ps(_mm_and_ps (fVec, t.fVec),
_mm_andnot_ps(fVec, e.fVec));
+#endif
}
__m128 fVec;
diff --git a/src/opts/SkOpts_sse41.cpp b/src/opts/SkOpts_sse41.cpp
index 416157125f..4489242de7 100644
--- a/src/opts/SkOpts_sse41.cpp
+++ b/src/opts/SkOpts_sse41.cpp
@@ -23,5 +23,7 @@ namespace SkOpts {
color_xform_RGB1_srgb_to_2dot2 = sk_sse41::color_xform_RGB1_srgb_to_2dot2;
color_xform_RGB1_2dot2_to_2dot2 = sk_sse41::color_xform_RGB1_2dot2_to_2dot2;
+ color_xform_RGB1_srgb_to_srgb = sk_sse41::color_xform_RGB1_srgb_to_srgb;
+ color_xform_RGB1_2dot2_to_srgb = sk_sse41::color_xform_RGB1_2dot2_to_srgb;
}
}