diff options
-rw-r--r-- | bench/ColorCodecBench.cpp | 4 | ||||
-rw-r--r-- | dm/DM.cpp | 15 | ||||
-rw-r--r-- | dm/DMSrcSink.cpp | 48 | ||||
-rw-r--r-- | dm/DMSrcSink.h | 3 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform.cpp | 42 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform.h | 19 | ||||
-rw-r--r-- | src/core/SkOpts.cpp | 1 | ||||
-rw-r--r-- | src/core/SkOpts.h | 5 | ||||
-rw-r--r-- | src/opts/SkColorXform_opts.h | 106 | ||||
-rw-r--r-- | src/opts/SkOpts_sse41.cpp | 1 | ||||
-rw-r--r-- | tests/ColorSpaceXformTest.cpp | 2 | ||||
-rw-r--r-- | tools/viewer/ImageSlide.cpp | 2 |
12 files changed, 165 insertions, 83 deletions
diff --git a/bench/ColorCodecBench.cpp b/bench/ColorCodecBench.cpp index 9dde5da813..edad759860 100644 --- a/bench/ColorCodecBench.cpp +++ b/bench/ColorCodecBench.cpp @@ -61,7 +61,7 @@ void ColorCodecBench::decodeAndXform() { codec->getScanlines(fSrc.get(), 1, 0); SkASSERT(1 == rows); - xform->xform_RGB1_8888((uint32_t*) dst, (uint32_t*) fSrc.get(), fInfo.width()); + xform->applyTo8888((SkPMColor*) dst, (uint32_t*) fSrc.get(), fInfo.width()); dst = SkTAddOffset<void>(dst, fInfo.minRowBytes()); } } @@ -116,7 +116,7 @@ void ColorCodecBench::xformOnly() { void* src = fSrc.get(); for (int y = 0; y < fInfo.height(); y++) { // Transform in place - xform->xform_RGB1_8888((uint32_t*) dst, (uint32_t*) src, fInfo.width()); + xform->applyTo8888((SkPMColor*) dst, (uint32_t*) src, fInfo.width()); dst = SkTAddOffset<void>(dst, fInfo.minRowBytes()); src = SkTAddOffset<void>(src, fInfo.minRowBytes()); } @@ -740,17 +740,22 @@ static bool gather_srcs() { } for (auto colorImage : colorImages) { - ColorCodecSrc* src = new ColorCodecSrc(colorImage, ColorCodecSrc::kBaseline_Mode); + ColorCodecSrc* src = new ColorCodecSrc(colorImage, ColorCodecSrc::kBaseline_Mode, + kN32_SkColorType); push_src("image", "color_codec_baseline", src); - src = new ColorCodecSrc(colorImage, ColorCodecSrc::kDst_HPZR30w_Mode); + src = new ColorCodecSrc(colorImage, ColorCodecSrc::kDst_HPZR30w_Mode, kN32_SkColorType); push_src("image", "color_codec_HPZR30w", src); + // TODO (msarett): + // Should we test this Dst in F16 mode (even though the Dst gamma is 2.2 instead of sRGB)? - src = new ColorCodecSrc(colorImage, ColorCodecSrc::kDst_sRGB_Mode); - push_src("image", "color_codec_sRGB", src); + src = new ColorCodecSrc(colorImage, ColorCodecSrc::kDst_sRGB_Mode, kN32_SkColorType); + push_src("image", "color_codec_sRGB_kN32", src); + src = new ColorCodecSrc(colorImage, ColorCodecSrc::kDst_sRGB_Mode, kRGBA_F16_SkColorType); + push_src("image", "color_codec_sRGB_kF16", src); #if defined(SK_TEST_QCMS) - src = new ColorCodecSrc(colorImage, ColorCodecSrc::kQCMS_HPZR30w_Mode); + src = new ColorCodecSrc(colorImage, ColorCodecSrc::kQCMS_HPZR30w_Mode, kN32_SkColorType); push_src("image", "color_codec_QCMS_HPZR30w", src); #endif } diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp index 78fa140b31..932d80f570 100644 --- a/dm/DMSrcSink.cpp +++ b/dm/DMSrcSink.cpp @@ -837,9 +837,10 @@ Name ImageGenSrc::name() const { /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -ColorCodecSrc::ColorCodecSrc(Path path, Mode mode) +ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType) : fPath(path) , fMode(mode) + , fColorType(colorType) {} bool ColorCodecSrc::veto(SinkFlags flags) const { @@ -852,6 +853,10 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { return Error::Nonfatal("No need to test color correction to 565 backend."); } + if (nullptr == canvas->imageInfo().colorSpace() && kRGBA_F16_SkColorType == fColorType) { + return Error::Nonfatal("F16 does not draw in legacy mode."); + } + SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); if (!encoded) { return SkStringPrintf("Couldn't read %s.", fPath.c_str()); @@ -862,7 +867,7 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); } - SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); + SkImageInfo info = codec->getInfo().makeColorType(fColorType); SkBitmap bitmap; if (!bitmap.tryAllocPixels(info)) { return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), @@ -870,11 +875,16 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { } SkImageInfo decodeInfo = info; - if (kBaseline_Mode != fMode) { + size_t srcRowBytes = sizeof(SkPMColor) * info.width(); + SkAutoMalloc src(srcRowBytes * info.height()); + void* srcPixels = src.get(); + if (kBaseline_Mode == fMode) { + srcPixels = bitmap.getPixels(); + } else { decodeInfo = decodeInfo.makeColorType(kRGBA_8888_SkColorType); } - SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes()); + SkCodec::Result r = codec->getPixels(decodeInfo, srcPixels, srcRowBytes); if (SkCodec::kSuccess != r) { return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r); } @@ -903,10 +913,24 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { return "Unimplemented color conversion."; } - uint32_t* row = (uint32_t*) bitmap.getPixels(); - for (int y = 0; y < info.height(); y++) { - xform->xform_RGB1_8888(row, row, info.width()); - row = SkTAddOffset<uint32_t>(row, bitmap.rowBytes()); + if (kN32_SkColorType == fColorType) { + uint32_t* srcRow = (uint32_t*) srcPixels; + uint32_t* dstRow = (uint32_t*) bitmap.getPixels(); + for (int y = 0; y < info.height(); y++) { + xform->applyTo8888(dstRow, srcRow, info.width()); + srcRow = SkTAddOffset<uint32_t>(srcRow, srcRowBytes); + dstRow = SkTAddOffset<uint32_t>(dstRow, bitmap.rowBytes()); + } + } else { + SkASSERT(kRGBA_F16_SkColorType == fColorType); + + uint32_t* srcRow = (uint32_t*) srcPixels; + uint64_t* dstRow = (uint64_t*) bitmap.getPixels(); + for (int y = 0; y < info.height(); y++) { + xform->applyToF16(dstRow, srcRow, info.width()); + srcRow = SkTAddOffset<uint32_t>(srcRow, srcRowBytes); + dstRow = SkTAddOffset<uint64_t>(dstRow, bitmap.rowBytes()); + } } canvas->drawBitmap(bitmap, 0, 0); @@ -943,10 +967,12 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { #endif // Perform color correction. - uint32_t* row = (uint32_t*) bitmap.getPixels(); + uint32_t* srcRow = (uint32_t*) srcPixels; + uint32_t* dstRow = (uint32_t*) bitmap.getPixels(); for (int y = 0; y < info.height(); y++) { - qcms_transform_data_type(transform, row, row, info.width(), outType); - row = SkTAddOffset<uint32_t>(row, bitmap.rowBytes()); + qcms_transform_data_type(transform, srcRow, dstRow, info.width(), outType); + srcRow = SkTAddOffset<uint32_t>(srcRow, srcRowBytes); + dstRow = SkTAddOffset<uint32_t>(dstRow, bitmap.rowBytes()); } canvas->drawBitmap(bitmap, 0, 0); diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h index 50a3b5a41a..b05fdb0439 100644 --- a/dm/DMSrcSink.h +++ b/dm/DMSrcSink.h @@ -225,7 +225,7 @@ public: #endif }; - ColorCodecSrc(Path, Mode); + ColorCodecSrc(Path, Mode, SkColorType); Error draw(SkCanvas*) const override; SkISize size() const override; @@ -234,6 +234,7 @@ public: private: Path fPath; Mode fMode; + SkColorType fColorType; }; class SKPSrc : public Src { diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp index 634fcb6325..8b23d18e1a 100644 --- a/src/core/SkColorSpaceXform.cpp +++ b/src/core/SkColorSpaceXform.cpp @@ -394,26 +394,13 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(const sk_sp<SkColorSpa /////////////////////////////////////////////////////////////////////////////////////////////////// +// TODO (msarett): +// Once SkFastXform supports translation, delete this function and use asRowMajorf(). 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 - // 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); @@ -426,7 +413,6 @@ static void build_src_to_dst(float srcToDstArray[12], const SkMatrix44& srcToDst srcToDstArray[9] = srcToDstMatrix.getFloat(2, 1); srcToDstArray[10] = srcToDstMatrix.getFloat(2, 2); srcToDstArray[11] = 0.0f; -#endif } template <SkColorSpace::GammaNamed Dst> @@ -506,6 +492,9 @@ SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri } // Build tables to transform linear to dst gamma. + // FIXME (msarett): + // Should we spend all of this time bulding the dst gamma tables when the client only + // wants to convert to F16? switch (dstSpace->gammaNamed()) { case SkColorSpace::kSRGB_GammaNamed: case SkColorSpace::k2Dot2Curve_GammaNamed: @@ -579,25 +568,32 @@ SkFastXform<Dst>::SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatri template <> void SkFastXform<SkColorSpace::kSRGB_GammaNamed> -::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const +::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const { SkOpts::color_xform_RGB1_to_srgb(dst, src, len, fSrcGammaTables, fSrcToDst); } template <> void SkFastXform<SkColorSpace::k2Dot2Curve_GammaNamed> -::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const +::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const { SkOpts::color_xform_RGB1_to_2dot2(dst, src, len, fSrcGammaTables, fSrcToDst); } template <> void SkFastXform<SkColorSpace::kNonStandard_GammaNamed> -::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const +::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const { SkOpts::color_xform_RGB1_to_table(dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables); } +template <SkColorSpace::GammaNamed T> +void SkFastXform<T> +::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const +{ + SkOpts::color_xform_RGB1_to_linear(dst, src, len, fSrcGammaTables, fSrcToDst); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// SkDefaultXform::SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst, @@ -857,7 +853,7 @@ static void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable* } } -void SkDefaultXform::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const { +void SkDefaultXform::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const { while (len-- > 0) { uint8_t r = (*src >> 0) & 0xFF, g = (*src >> 8) & 0xFF, @@ -912,3 +908,9 @@ void SkDefaultXform::xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_ src++; } } + +void SkDefaultXform::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const { + // FIXME (msarett): + // Planning to delete SkDefaultXform. Not going to bother to implement this. + memset(dst, 0, len * sizeof(RGBAF16)); +} diff --git a/src/core/SkColorSpaceXform.h b/src/core/SkColorSpaceXform.h index e09a7252ba..16b8cfaa33 100644 --- a/src/core/SkColorSpaceXform.h +++ b/src/core/SkColorSpaceXform.h @@ -14,6 +14,9 @@ class SkColorSpaceXform : SkNoncopyable { public: + typedef uint32_t RGBA32; + typedef uint64_t RGBAF16; + /** * Create an object to handle color space conversions. * @@ -26,10 +29,11 @@ public: /** * Apply the color conversion to a src buffer, storing the output in the dst buffer. - * The src is opaque and stored in RGBA_8888, and the dst is also opaque and stored - * in 8888 platform format. + * The src is stored as RGBA (8888) and is treated as opaque. + * TODO (msarett): Support non-opaque srcs. */ - virtual void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const = 0; + virtual void applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const = 0; + virtual void applyToF16(RGBAF16* dst, const RGBA32* src, int len) const = 0; virtual ~SkColorSpaceXform() {} }; @@ -38,7 +42,8 @@ template <SkColorSpace::GammaNamed Dst> class SkFastXform : public SkColorSpaceXform { public: - void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override; + void applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const override; + void applyToF16(RGBAF16* dst, const RGBA32* src, int len) const override; private: SkFastXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst, @@ -62,10 +67,14 @@ private: /** * Works for any valid src and dst profiles. */ +// TODO (msarett): +// Merge with SkFastXform and delete this. SkFastXform can almost do everything that +// this does. class SkDefaultXform : public SkColorSpaceXform { public: - void xform_RGB1_8888(uint32_t* dst, const uint32_t* src, uint32_t len) const override; + void applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const override; + void applyToF16(RGBAF16* dst, const RGBA32* src, int len) const override; private: SkDefaultXform(const sk_sp<SkColorSpace>& srcSpace, const SkMatrix44& srcToDst, diff --git a/src/core/SkOpts.cpp b/src/core/SkOpts.cpp index bc9ec536ac..c577bf9603 100644 --- a/src/core/SkOpts.cpp +++ b/src/core/SkOpts.cpp @@ -75,6 +75,7 @@ namespace SkOpts { DEFINE_DEFAULT(color_xform_RGB1_to_2dot2); DEFINE_DEFAULT(color_xform_RGB1_to_srgb); DEFINE_DEFAULT(color_xform_RGB1_to_table); + DEFINE_DEFAULT(color_xform_RGB1_to_linear); #undef DEFINE_DEFAULT // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp. diff --git a/src/core/SkOpts.h b/src/core/SkOpts.h index 2bf4bdabde..7acceef6a6 100644 --- a/src/core/SkOpts.h +++ b/src/core/SkOpts.h @@ -66,7 +66,7 @@ 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 RGB1 pixels into SkPMColor order. + // Color xform RGB1 pixels. extern void (*color_xform_RGB1_to_2dot2) (uint32_t* dst, const uint32_t* src, int len, const float* const srcTables[3], const float srcToDstMatrix[12]); @@ -77,6 +77,9 @@ namespace SkOpts { const float* const srcTables[3], const float srcToDstMatrix[12], const uint8_t* const dstTables[3]); + extern void (*color_xform_RGB1_to_linear)(uint64_t* dst, const uint32_t* src, int len, + const float* const srcTables[3], + const float srcToDstMatrix[12]); } diff --git a/src/opts/SkColorXform_opts.h b/src/opts/SkColorXform_opts.h index 72ef35381e..e7a2b45946 100644 --- a/src/opts/SkColorXform_opts.h +++ b/src/opts/SkColorXform_opts.h @@ -10,7 +10,9 @@ #include "SkNx.h" #include "SkColorPriv.h" +#include "SkHalf.h" #include "SkSRGB.h" +#include "SkTemplates.h" namespace SK_OPTS_NS { @@ -31,13 +33,17 @@ static Sk4f clamp_0_to_255(const Sk4f& x) { } enum DstGamma { + // 8888 kSRGB_DstGamma, k2Dot2_DstGamma, kTable_DstGamma, + + // F16 + kLinear_DstGamma, }; template <DstGamma kDstGamma> -static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len, +static void color_xform_RGB1(void* dst, const uint32_t* src, int len, const float* const srcTables[3], const float matrix[16], const uint8_t* const dstTables[3]) { Sk4f rXgXbX = Sk4f::Load(matrix + 0), @@ -84,12 +90,14 @@ static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len, dstGreens = clamp_0_to_255(dstGreens); dstBlues = clamp_0_to_255(dstBlues); - auto rgba = (Sk4f_round(dstReds) ) - | (Sk4f_round(dstGreens) << 8) - | (Sk4f_round(dstBlues) << 16) - | (Sk4i{ 0xFF << 24}); - rgba.store(dst); - } else { + auto rgba = (Sk4f_round(dstReds) << SK_R32_SHIFT) + | (Sk4f_round(dstGreens) << SK_G32_SHIFT) + | (Sk4f_round(dstBlues) << SK_B32_SHIFT) + | (Sk4i{ 0xFF << SK_A32_SHIFT}); + rgba.store((uint32_t*) dst); + + dst = SkTAddOffset<void>(dst, 4 * sizeof(uint32_t)); + } else if (kTable_DstGamma == kDstGamma) { Sk4f scaledReds = Sk4f::Min(Sk4f::Max(1023.0f * dstReds, 0.0f), 1023.0f); Sk4f scaledGreens = Sk4f::Min(Sk4f::Max(1023.0f * dstGreens, 0.0f), 1023.0f); Sk4f scaledBlues = Sk4f::Min(Sk4f::Max(1023.0f * dstBlues, 0.0f), 1023.0f); @@ -98,25 +106,38 @@ static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len, Sk4i indicesGreens = Sk4f_round(scaledGreens); Sk4i indicesBlues = Sk4f_round(scaledBlues); - dst[0] = dstTables[0][indicesReds [0]] - | dstTables[1][indicesGreens[0]] << 8 - | dstTables[2][indicesBlues [0]] << 16 - | 0xFF << 24; - dst[1] = dstTables[0][indicesReds [1]] - | dstTables[1][indicesGreens[1]] << 8 - | dstTables[2][indicesBlues [1]] << 16 - | 0xFF << 24; - dst[2] = dstTables[0][indicesReds [2]] - | dstTables[1][indicesGreens[2]] << 8 - | dstTables[2][indicesBlues [2]] << 16 - | 0xFF << 24; - dst[3] = dstTables[0][indicesReds [3]] - | dstTables[1][indicesGreens[3]] << 8 - | dstTables[2][indicesBlues [3]] << 16 - | 0xFF << 24; + uint32_t* dst32 = (uint32_t*) dst; + dst32[0] = dstTables[0][indicesReds [0]] << SK_R32_SHIFT + | dstTables[1][indicesGreens[0]] << SK_G32_SHIFT + | dstTables[2][indicesBlues [0]] << SK_B32_SHIFT + | 0xFF << SK_A32_SHIFT; + dst32[1] = dstTables[0][indicesReds [1]] << SK_R32_SHIFT + | dstTables[1][indicesGreens[1]] << SK_G32_SHIFT + | dstTables[2][indicesBlues [1]] << SK_B32_SHIFT + | 0xFF << SK_A32_SHIFT; + dst32[2] = dstTables[0][indicesReds [2]] << SK_R32_SHIFT + | dstTables[1][indicesGreens[2]] << SK_G32_SHIFT + | dstTables[2][indicesBlues [2]] << SK_B32_SHIFT + | 0xFF << SK_A32_SHIFT; + dst32[3] = dstTables[0][indicesReds [3]] << SK_R32_SHIFT + | dstTables[1][indicesGreens[3]] << SK_G32_SHIFT + | dstTables[2][indicesBlues [3]] << SK_B32_SHIFT + | 0xFF << SK_A32_SHIFT; + + dst = SkTAddOffset<void>(dst, 4 * sizeof(uint32_t)); + } else { + // FIXME (msarett): + // Can we do better here? Should we store half floats as planar? + // Should we write Intel/Arm specific code? Should we add a transpose + // function to SkNx? Should we rewrite the algorithm to be interleaved? + uint64_t* dst64 = (uint64_t*) dst; + dst64[0] = SkFloatToHalf_finite(Sk4f(dstReds[0], dstGreens[0], dstBlues[0], 1.0f)); + dst64[1] = SkFloatToHalf_finite(Sk4f(dstReds[1], dstGreens[1], dstBlues[1], 1.0f)); + dst64[2] = SkFloatToHalf_finite(Sk4f(dstReds[2], dstGreens[2], dstBlues[2], 1.0f)); + dst64[3] = SkFloatToHalf_finite(Sk4f(dstReds[3], dstGreens[3], dstBlues[3], 1.0f)); + + dst = SkTAddOffset<void>(dst, 4 * sizeof(uint64_t)); } - - dst += 4; }; load_next_4(); @@ -137,7 +158,6 @@ static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len, g = Sk4f{srcTables[1][(*src >> 8) & 0xFF]}, b = Sk4f{srcTables[2][(*src >> 16) & 0xFF]}; - // Apply transformation matrix to dst gamut. auto dstPixel = rXgXbX*r + rYgYbY*g + rZgZbZ*b; if (kSRGB_DstGamma == kDstGamma || k2Dot2_DstGamma == kDstGamma) { @@ -151,40 +171,54 @@ static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len, uint32_t rgba; SkNx_cast<uint8_t>(Sk4f_round(dstPixel)).store(&rgba); rgba |= 0xFF000000; - *dst = rgba; - } else { + *((uint32_t*) dst) = SkSwizzle_RGBA_to_PMColor(rgba); + dst = SkTAddOffset<void>(dst, sizeof(uint32_t)); + } else if (kTable_DstGamma == kDstGamma) { Sk4f scaledPixel = Sk4f::Min(Sk4f::Max(1023.0f * dstPixel, 0.0f), 1023.0f); Sk4i indices = Sk4f_round(scaledPixel); - *dst = dstTables[0][indices[0]] - | dstTables[1][indices[1]] << 8 - | dstTables[2][indices[2]] << 16 - | 0xFF << 24; + *((uint32_t*) dst) = dstTables[0][indices[0]] << SK_R32_SHIFT + | dstTables[1][indices[1]] << SK_G32_SHIFT + | dstTables[2][indices[2]] << SK_B32_SHIFT + | 0xFF << SK_A32_SHIFT; + + dst = SkTAddOffset<void>(dst, sizeof(uint32_t)); + } else { + uint64_t rgba = SkFloatToHalf_finite(dstPixel); + + // Set alpha to 1.0 + rgba |= 0x3C00000000000000; + *((uint64_t*) dst) = rgba; + dst = SkTAddOffset<void>(dst, sizeof(uint64_t)); } - dst += 1; src += 1; len -= 1; } } static void color_xform_RGB1_to_2dot2(uint32_t* dst, const uint32_t* src, int len, - const float* const srcTables[3], const float matrix[16]) { + const float* const srcTables[3], const float matrix[12]) { color_xform_RGB1<k2Dot2_DstGamma>(dst, src, len, srcTables, matrix, nullptr); } static void color_xform_RGB1_to_srgb(uint32_t* dst, const uint32_t* src, int len, - const float* const srcTables[3], const float matrix[16]) { + const float* const srcTables[3], const float matrix[12]) { color_xform_RGB1<kSRGB_DstGamma>(dst, src, len, srcTables, matrix, nullptr); } static void color_xform_RGB1_to_table(uint32_t* dst, const uint32_t* src, int len, - const float* const srcTables[3], const float matrix[16], + const float* const srcTables[3], const float matrix[12], const uint8_t* const dstTables[3]) { color_xform_RGB1<kTable_DstGamma>(dst, src, len, srcTables, matrix, dstTables); } +static void color_xform_RGB1_to_linear(uint64_t* dst, const uint32_t* src, int len, + const float* const srcTables[3], const float matrix[12]) { + color_xform_RGB1<kLinear_DstGamma>(dst, src, len, srcTables, matrix, nullptr); +} + } // namespace SK_OPTS_NS #endif // SkColorXform_opts_DEFINED diff --git a/src/opts/SkOpts_sse41.cpp b/src/opts/SkOpts_sse41.cpp index 56ac386333..e1e024d948 100644 --- a/src/opts/SkOpts_sse41.cpp +++ b/src/opts/SkOpts_sse41.cpp @@ -24,5 +24,6 @@ namespace SkOpts { color_xform_RGB1_to_2dot2 = sse41::color_xform_RGB1_to_2dot2; color_xform_RGB1_to_srgb = sse41::color_xform_RGB1_to_srgb; color_xform_RGB1_to_table = sse41::color_xform_RGB1_to_table; + color_xform_RGB1_to_linear = sse41::color_xform_RGB1_to_linear; } } diff --git a/tests/ColorSpaceXformTest.cpp b/tests/ColorSpaceXformTest.cpp index b5df1e1e72..2b5db2bbe4 100644 --- a/tests/ColorSpaceXformTest.cpp +++ b/tests/ColorSpaceXformTest.cpp @@ -45,7 +45,7 @@ static void test_xform(skiatest::Reporter* r, const sk_sp<SkGammas>& gammas) { // Create and perform xform std::unique_ptr<SkColorSpaceXform> xform = ColorSpaceXformTest::CreateDefaultXform(gammas, srcToDst, gammas); - xform->xform_RGB1_8888(dstPixels, srcPixels, width); + xform->applyTo8888(dstPixels, srcPixels, width); // Since the matrix is the identity, and the gamma curves match, the pixels // should be unchanged. diff --git a/tools/viewer/ImageSlide.cpp b/tools/viewer/ImageSlide.cpp index 0eb3b0a6ce..3ba6b58460 100644 --- a/tools/viewer/ImageSlide.cpp +++ b/tools/viewer/ImageSlide.cpp @@ -47,7 +47,7 @@ void ImageSlide::load(SkScalar, SkScalar) { fOriginalBitmap.deepCopyTo(&fXformedBitmap); uint32_t* row = (uint32_t*) fXformedBitmap.getPixels(); for (int y = 0; y < fXformedBitmap.height(); y++) { - xform->xform_RGB1_8888(row, row, fXformedBitmap.width()); + xform->applyTo8888(row, row, fXformedBitmap.width()); row = SkTAddOffset<uint32_t>(row, fXformedBitmap.rowBytes()); } fXformedBitmap.notifyPixelsChanged(); // This is needed for the deepCopy |