diff options
author | 2016-06-16 10:50:55 -0700 | |
---|---|---|
committer | 2016-06-16 10:50:55 -0700 | |
commit | dea0340cadb759932e53416a657f5ea75fee8b5f (patch) | |
tree | f3c7e4c1873771ee818e0a1c86515a3ea5250d75 /src/core | |
parent | bd770d619553a88eeaa64ff29082f62db5c9b4d2 (diff) |
Implement fast, correct gamma conversion for color xforms
201295.jpg on HP z620
(300x280, most common form of sRGB profile)
QCMS Xform 0.495 ms
Skia Old Xform 0.235 ms
Skia NEW Xform 0.423 ms
Vs Old Code 0.56x
Vs QCMS 1.17x
So to summarize, we are now much slower than before,
but still a bit faster than QCMS. And now we are also
far more accurate than QCMS :).
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2060823003
CQ_EXTRA_TRYBOTS=client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot
Review-Url: https://codereview.chromium.org/2060823003
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkColorSpaceXform.cpp | 92 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform.h | 29 | ||||
-rw-r--r-- | src/core/SkOpts.cpp | 6 | ||||
-rw-r--r-- | src/core/SkOpts.h | 9 |
4 files changed, 93 insertions, 43 deletions
diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp index e142011305..4c67e8d3f0 100644 --- a/src/core/SkColorSpaceXform.cpp +++ b/src/core/SkColorSpaceXform.cpp @@ -37,10 +37,16 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa return nullptr; } - if (SkColorSpace::k2Dot2Curve_GammaNamed == srcSpace->gammaNamed() && - SkColorSpace::k2Dot2Curve_GammaNamed == dstSpace->gammaNamed()) + if (SkColorSpace::k2Dot2Curve_GammaNamed == dstSpace->gammaNamed() && + 0.0f == srcToDst.getFloat(3, 0) && + 0.0f == srcToDst.getFloat(3, 1) && + 0.0f == srcToDst.getFloat(3, 2)) { - return std::unique_ptr<SkColorSpaceXform>(new Sk2Dot2Xform(srcToDst)); + 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)); + } } return std::unique_ptr<SkColorSpaceXform>( @@ -49,33 +55,59 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa /////////////////////////////////////////////////////////////////////////////////////////////////// -Sk2Dot2Xform::Sk2Dot2Xform(const SkMatrix44& srcToDst) -{ - // Build row major 4x4 matrix: +static void build_src_to_dst(float srcToDstArray[12], const SkMatrix44& srcToDstMatrix) { + // Build the following row major matrix: // rX gX bX 0 // rY gY bY 0 // rZ gZ bZ 0 - // rQ gQ bQ 0 - fSrcToDst[0] = srcToDst.getFloat(0, 0); - fSrcToDst[1] = srcToDst.getFloat(0, 1); - fSrcToDst[2] = srcToDst.getFloat(0, 2); - fSrcToDst[3] = 0.0f; - fSrcToDst[4] = srcToDst.getFloat(1, 0); - fSrcToDst[5] = srcToDst.getFloat(1, 1); - fSrcToDst[6] = srcToDst.getFloat(1, 2); - fSrcToDst[7] = 0.0f; - fSrcToDst[8] = srcToDst.getFloat(2, 0); - fSrcToDst[9] = srcToDst.getFloat(2, 1); - fSrcToDst[10] = srcToDst.getFloat(2, 2); - fSrcToDst[11] = 0.0f; - fSrcToDst[12] = srcToDst.getFloat(3, 0); - fSrcToDst[13] = srcToDst.getFloat(3, 1); - fSrcToDst[14] = srcToDst.getFloat(3, 2); - fSrcToDst[15] = 0.0f; + // Swap R and B if necessary to make sure that we output SkPMColor order. +#ifdef SK_PMCOLOR_IS_BGRA + srcToDstArray[0] = srcToDstMatrix.getFloat(0, 2); + srcToDstArray[1] = srcToDstMatrix.getFloat(0, 1); + srcToDstArray[2] = srcToDstMatrix.getFloat(0, 0); + srcToDstArray[3] = 0.0f; + srcToDstArray[4] = srcToDstMatrix.getFloat(1, 2); + srcToDstArray[5] = srcToDstMatrix.getFloat(1, 1); + srcToDstArray[6] = srcToDstMatrix.getFloat(1, 0); + srcToDstArray[7] = 0.0f; + srcToDstArray[8] = srcToDstMatrix.getFloat(2, 2); + srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); + srcToDstArray[10] = srcToDstMatrix.getFloat(2, 0); + srcToDstArray[11] = 0.0f; +#else + srcToDstArray[0] = srcToDstMatrix.getFloat(0, 0); + srcToDstArray[1] = srcToDstMatrix.getFloat(0, 1); + srcToDstArray[2] = srcToDstMatrix.getFloat(0, 2); + srcToDstArray[3] = 0.0f; + srcToDstArray[4] = srcToDstMatrix.getFloat(1, 0); + srcToDstArray[5] = srcToDstMatrix.getFloat(1, 1); + srcToDstArray[6] = srcToDstMatrix.getFloat(1, 2); + srcToDstArray[7] = 0.0f; + srcToDstArray[8] = srcToDstMatrix.getFloat(2, 0); + srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); + srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); + srcToDstArray[11] = 0.0f; +#endif +} + +SkSRGBTo2Dot2Xform::SkSRGBTo2Dot2Xform(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); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +Sk2Dot2To2Dot2Xform::Sk2Dot2To2Dot2Xform(const SkMatrix44& srcToDst) +{ + build_src_to_dst(fSrcToDst, srcToDst); } -void Sk2Dot2Xform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const { - SkOpts::color_xform_2Dot2_RGBA_to_8888(dst, src, len, fSrcToDst); +void Sk2Dot2To2Dot2Xform::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); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -86,13 +118,15 @@ static inline float byte_to_float(uint8_t v) { // Expand range from 0-1 to 0-255, then convert. static inline uint8_t clamp_normalized_float_to_byte(float v) { + // The ordering of the logic is a little strange here in order + // to make sure we convert NaNs to 0. v = v * 255.0f; if (v >= 254.5f) { return 255; - } else if (v < 0.5f) { - return 0; - } else { + } else if (v >= 0.5f) { return (uint8_t) (v + 0.5f); + } else { + return 0; } } @@ -142,7 +176,7 @@ SkDefaultXform::SkDefaultXform(const sk_sp<SkGammas>& srcGammas, const SkMatrix4 , fDstGammas(dstGammas) {} -void SkDefaultXform::xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const { +void SkDefaultXform::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const { while (len-- > 0) { // Convert to linear. // FIXME (msarett): diff --git a/src/core/SkColorSpaceXform.h b/src/core/SkColorSpaceXform.h index 3472643519..1ea608094f 100644 --- a/src/core/SkColorSpaceXform.h +++ b/src/core/SkColorSpaceXform.h @@ -26,23 +26,36 @@ public: /** * Apply the color conversion to a src buffer, storing the output in the dst buffer. - * The src is stored in RGBA_8888 and the dst is stored in 8888 platform format. - * The output is not premultiplied. + * The src is opaque and stored in RGBA_8888, and the dst is also opaque and stored + * in 8888 platform format. */ - virtual void xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const = 0; + virtual void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const = 0; virtual ~SkColorSpaceXform() {} }; -class Sk2Dot2Xform : public SkColorSpaceXform { +class SkSRGBTo2Dot2Xform : public SkColorSpaceXform { public: - void xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override; + void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override; private: - Sk2Dot2Xform(const SkMatrix44& srcToDst); + SkSRGBTo2Dot2Xform(const SkMatrix44& srcToDst); - float fSrcToDst[16]; + 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); + + float fSrcToDst[12]; friend class SkColorSpaceXform; }; @@ -53,7 +66,7 @@ private: class SkDefaultXform : public SkColorSpaceXform { public: - void xform_RGBA_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override; + void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override; private: SkDefaultXform(const sk_sp<SkGammas>& srcGammas, const SkMatrix44& srcToDst, diff --git a/src/core/SkOpts.cpp b/src/core/SkOpts.cpp index 8dec3fad0f..b4145acb7a 100644 --- a/src/core/SkOpts.cpp +++ b/src/core/SkOpts.cpp @@ -77,8 +77,10 @@ namespace SkOpts { decltype(srcover_srgb_srgb) srcover_srgb_srgb = sk_default::srcover_srgb_srgb; - decltype(color_xform_2Dot2_RGBA_to_8888) color_xform_2Dot2_RGBA_to_8888 = - sk_default::color_xform_2Dot2_RGBA_to_8888; + decltype(color_xform_RGB1_srgb_to_2dot2) color_xform_RGB1_srgb_to_2dot2 = + 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; // 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 0711471fb4..1c33529d52 100644 --- a/src/core/SkOpts.h +++ b/src/core/SkOpts.h @@ -69,10 +69,11 @@ namespace SkOpts { // If nsrc < ndst, we loop over src to create a pattern. extern void (*srcover_srgb_srgb)(uint32_t* dst, const uint32_t* src, int ndst, int nsrc); - // Color xform RGBA input into SkPMColor ordered 8888 pixels. Does not premultiply, and - // assumes src and dst gamma curves are both 2.2f exponentials. - extern void (*color_xform_2Dot2_RGBA_to_8888)(uint32_t* dst, const uint32_t* src, int len, - const float srcToDstMatrix[16]); + // Color xform RGB1 pixels. Does not change byte ordering. + extern void (*color_xform_RGB1_srgb_to_2dot2) (uint32_t* dst, const uint32_t* src, int len, + 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]); } #endif//SkOpts_DEFINED |