diff options
author | msarett <msarett@google.com> | 2016-09-16 11:45:58 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-09-16 11:45:59 -0700 |
commit | c0444615ed76360f680619ad4d1f92cda6181a50 (patch) | |
tree | 4c534202035fd7094967d435e2d986ef9f6ab7d8 | |
parent | bfef32ff0ac743b10995985b891f5fd09fe918db (diff) |
Support Float32 output from SkColorSpaceXform
* Adds Float32 support to SkColorSpaceXform
* Changes API to allows clients to ask for F32, updates clients to
new API
* Adds Sk4f_load4 and Sk4f_store4 to SkNx
* Make use of new xform in SkGr.cpp
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2339233003
CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot
Committed: https://skia.googlesource.com/skia/+/43d6651111374b5d1e4ddd9030dcf079b448ec47
Review-Url: https://codereview.chromium.org/2339233003
-rw-r--r-- | bench/ColorCodecBench.cpp | 5 | ||||
-rw-r--r-- | gm/colorspacexform.cpp | 88 | ||||
-rw-r--r-- | gyp/bench.gyp | 1 | ||||
-rw-r--r-- | src/codec/SkCodecPriv.h | 18 | ||||
-rw-r--r-- | src/codec/SkJpegCodec.cpp | 3 | ||||
-rw-r--r-- | src/codec/SkPngCodec.cpp | 42 | ||||
-rw-r--r-- | src/codec/SkPngCodec.h | 9 | ||||
-rw-r--r-- | src/codec/SkWebpCodec.cpp | 5 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform.cpp | 62 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform.h | 27 | ||||
-rw-r--r-- | src/core/SkNx.h | 22 | ||||
-rw-r--r-- | src/opts/SkNx_neon.h | 19 | ||||
-rw-r--r-- | src/opts/SkNx_sse.h | 25 | ||||
-rw-r--r-- | tests/ColorSpaceXformTest.cpp | 4 | ||||
-rw-r--r-- | tests/SkNxTest.cpp | 32 |
15 files changed, 313 insertions, 49 deletions
diff --git a/bench/ColorCodecBench.cpp b/bench/ColorCodecBench.cpp index e35aef87c9..faa2a9a118 100644 --- a/bench/ColorCodecBench.cpp +++ b/bench/ColorCodecBench.cpp @@ -8,6 +8,7 @@ #include "ColorCodecBench.h" #include "Resources.h" #include "SkCodec.h" +#include "SkCodecPriv.h" #include "SkColorSpaceXform.h" #include "SkCommandLineFlags.h" @@ -99,8 +100,8 @@ void ColorCodecBench::xformOnly() { void* dst = fDst.get(); void* src = fSrc.get(); for (int y = 0; y < fSrcInfo.height(); y++) { - xform->apply(dst, (uint32_t*) src, fSrcInfo.width(), fDstInfo.colorType(), - fDstInfo.alphaType()); + xform->apply(dst, (uint32_t*) src, fSrcInfo.width(), + select_xform_format(fDstInfo.colorType()), fDstInfo.alphaType()); dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes()); src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes()); } diff --git a/gm/colorspacexform.cpp b/gm/colorspacexform.cpp new file mode 100644 index 0000000000..b3d79c91f0 --- /dev/null +++ b/gm/colorspacexform.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" +#include "SkColor.h" +#include "SkColorSpaceXform.h" +#include "SkRect.h" + +class ColorSpaceXformGM : public skiagm::GM { +public: + ColorSpaceXformGM() {} + +protected: + void onOnceBeforeDraw() override { + SkColor colors[] = { + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorMAGENTA, SK_ColorCYAN, SK_ColorYELLOW, + SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorMAGENTA, + }; + static_assert(kNumColors == SK_ARRAY_COUNT(colors), "Fix number of colors."); + + for (int i = 0; i < kNumColors; i++) { + fSRGBColors[i] = SkColor4f::FromColor(colors[i]); + + // FIXME (msarett): SkColorSpaceXform does not support BGRA. + colors[i] = SkSwizzle_RB(colors[i]); + } + + static constexpr float kWideGamutRGB_toXYZD50[]{ + 0.7161046f, 0.1009296f, 0.1471858f, + 0.2581874f, 0.7249378f, 0.0168748f, + 0.0000000f, 0.0517813f, 0.7734287f, + }; + + SkMatrix44 wideGamut(SkMatrix44::kUninitialized_Constructor); + wideGamut.set3x3RowMajorf(kWideGamutRGB_toXYZD50); + std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New( + SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named), + SkColorSpace::NewRGB(SkColorSpace::kLinear_RenderTargetGamma, wideGamut)); + + xform->apply(fWideGamutColors, colors, kNumColors, + SkColorSpaceXform::kRGBA_F32_ColorFormat, kOpaque_SkAlphaType); + } + + SkString onShortName() override { + return SkString("colorspacexform"); + } + + SkISize onISize() override { + return SkISize::Make(500, 200); + } + + void onDraw(SkCanvas* canvas) override { + auto drawColors = [canvas](SkColor4f* colors) { + SkRect r = SkRect::MakeXYWH(0.0f, 0.0f, 50.0f, 100.0f); + + canvas->save(); + for (int i = 0; i < kNumColors; i++) { + sk_sp<SkColorSpace> space = + SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma(); + sk_sp<SkShader> s = SkShader::MakeColorShader(colors[i], space); + SkPaint paint; + paint.setShader(s); + canvas->drawRect(r, paint); + canvas->translate(50.0f, 0.0f); + } + canvas->restore(); + }; + + // Wide gamut colors should appear darker - we are simulating a more intense display. + drawColors(fSRGBColors); + canvas->translate(0.0f, 100.0f); + drawColors(fWideGamutColors); + } + +private: + static constexpr int kNumColors = 10; + + SkColor4f fSRGBColors[kNumColors]; + SkColor4f fWideGamutColors[kNumColors]; + + typedef skiagm::GM INHERITED; +}; + +DEF_GM(return new ColorSpaceXformGM;) diff --git a/gyp/bench.gyp b/gyp/bench.gyp index 3d5c329ef5..4c2bca2b02 100644 --- a/gyp/bench.gyp +++ b/gyp/bench.gyp @@ -21,6 +21,7 @@ 'gmslides.gypi', ], 'include_dirs' : [ + '../src/codec', '../src/image', ], 'dependencies': [ diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h index 8876b72aa7..830f153cba 100644 --- a/src/codec/SkCodecPriv.h +++ b/src/codec/SkCodecPriv.h @@ -144,6 +144,20 @@ static inline const SkPMColor* get_color_ptr(SkColorTable* colorTable) { return nullptr != colorTable ? colorTable->readColors() : nullptr; } +static inline SkColorSpaceXform::ColorFormat select_xform_format(SkColorType colorType) { + switch (colorType) { + case kRGBA_8888_SkColorType: + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + case kBGRA_8888_SkColorType: + return SkColorSpaceXform::kBGRA_8888_ColorFormat; + case kRGBA_F16_SkColorType: + return SkColorSpaceXform::kRGBA_F16_ColorFormat; + default: + SkASSERT(false); + return SkColorSpaceXform::kRGBA_8888_ColorFormat; + } +} + /* * Given that the encoded image uses a color table, return the fill value */ @@ -162,7 +176,7 @@ static inline uint64_t get_color_table_fill_value(SkColorType colorType, SkAlpha SkASSERT(colorXform); uint64_t dstColor; uint32_t srcColor = colorPtr[fillIndex]; - colorXform->apply(&dstColor, &srcColor, 1, colorType, alphaType); + colorXform->apply(&dstColor, &srcColor, 1, select_xform_format(colorType), alphaType); return dstColor; } default: @@ -343,7 +357,7 @@ static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageIn return !isLegacy && (needsPremul || isF16 || srcDstNotEqual); } -static inline SkAlphaType select_alpha_xform(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) { +static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) { return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType; } diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index d2f7cdb0fa..c865fbccd1 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -517,7 +517,8 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes } if (fColorXform) { - fColorXform->apply(dst, swizzleDst, dstWidth, dstInfo.colorType(), kOpaque_SkAlphaType); + fColorXform->apply(dst, swizzleDst, dstWidth, select_xform_format(dstInfo.colorType()), + kOpaque_SkAlphaType); dst = SkTAddOffset<void>(dst, rowBytes); } diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index 04c8821203..1e633eaaed 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -267,11 +267,12 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) // If we are not decoding to F16, we can color xform now and store the results // in the color table. if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) { - SkColorType xformColorType = is_rgba(dstInfo.colorType()) ? - kRGBA_8888_SkColorType : kBGRA_8888_SkColorType; - SkAlphaType xformAlphaType = select_alpha_xform(dstInfo.alphaType(), + SkColorSpaceXform::ColorFormat xformColorFormat = is_rgba(dstInfo.colorType()) ? + SkColorSpaceXform::kRGBA_8888_ColorFormat : + SkColorSpaceXform::kBGRA_8888_ColorFormat; + SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), this->getInfo().alphaType()); - fColorXform->apply(colorTable, colorTable, numColors, xformColorType, xformAlphaType); + fColorXform->apply(colorTable, colorTable, numColors, xformColorFormat, xformAlphaType); } // Pad the color table with the last color in the table (or black) in the case that @@ -492,17 +493,18 @@ void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) { } void SkPngCodec::applyXformRow(void* dst, const void* src) { - const SkColorType colorType = this->dstInfo().colorType(); switch (fXformMode) { case kSwizzleOnly_XformMode: fSwizzler->swizzle(dst, (const uint8_t*) src); break; case kColorOnly_XformMode: - fColorXform->apply(dst, (const uint32_t*) src, fXformWidth, colorType, fXformAlphaType); + fColorXform->apply(dst, (const uint32_t*) src, fXformWidth, fXformColorFormat, + fXformAlphaType); break; case kSwizzleColor_XformMode: fSwizzler->swizzle(fColorXformSrcRow, (const uint8_t*) src); - fColorXform->apply(dst, fColorXformSrcRow, fXformWidth, colorType, fXformAlphaType); + fColorXform->apply(dst, fColorXformSrcRow, fXformWidth, fXformColorFormat, + fXformAlphaType); break; } } @@ -1137,9 +1139,23 @@ bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& opt return true; } -void SkPngCodec::initializeXformAlphaAndWidth() { - fXformAlphaType = select_alpha_xform(this->dstInfo().alphaType(), this->getInfo().alphaType()); - fXformWidth = this->swizzler() ? this->swizzler()->swizzleWidth() : this->dstInfo().width(); +void SkPngCodec::initializeXformParams() { + switch (fXformMode) { + case kColorOnly_XformMode: + fXformColorFormat = select_xform_format(this->dstInfo().colorType()); + fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(), + this->getInfo().alphaType()); + fXformWidth = this->dstInfo().width(); + break; + case kSwizzleColor_XformMode: + fXformColorFormat = select_xform_format(this->dstInfo().colorType()); + fXformAlphaType = select_xform_alpha(this->dstInfo().alphaType(), + this->getInfo().alphaType()); + fXformWidth = this->swizzler()->swizzleWidth(); + break; + default: + break; + } } static inline bool apply_xform_on_decode(SkColorType dstColorType, SkEncodedInfo::Color srcColor) { @@ -1226,7 +1242,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, } this->allocateStorage(dstInfo); - this->initializeXformAlphaAndWidth(); + this->initializeXformParams(); return this->decodeAllRows(dst, rowBytes, rowsDecoded); } @@ -1261,7 +1277,7 @@ SkCodec::Result SkPngCodec::onStartIncrementalDecode(const SkImageInfo& dstInfo, SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) { // FIXME: Only necessary on the first call. - this->initializeXformAlphaAndWidth(); + this->initializeXformParams(); return this->decode(rowsDecoded); } @@ -1269,7 +1285,7 @@ SkCodec::Result SkPngCodec::onIncrementalDecode(int* rowsDecoded) { uint64_t SkPngCodec::onGetFillValue(const SkImageInfo& dstInfo) const { const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); if (colorPtr) { - SkAlphaType alphaType = select_alpha_xform(dstInfo.alphaType(), + SkAlphaType alphaType = select_xform_alpha(dstInfo.alphaType(), this->getInfo().alphaType()); return get_color_table_fill_value(dstInfo.colorType(), alphaType, colorPtr, 0, fColorXform.get()); diff --git a/src/codec/SkPngCodec.h b/src/codec/SkPngCodec.h index e3059ba0d5..1fc451757e 100644 --- a/src/codec/SkPngCodec.h +++ b/src/codec/SkPngCodec.h @@ -64,7 +64,7 @@ protected: SkSwizzler* swizzler() { return fSwizzler; } // Initialize variables used by applyXformRow. - void initializeXformAlphaAndWidth(); + void initializeXformParams(); /** * Pass available input to libpng to process it. @@ -128,9 +128,10 @@ private: virtual void setRange(int firstRow, int lastRow, void* dst, size_t rowBytes) = 0; virtual Result decode(int* rowsDecoded) = 0; - XformMode fXformMode; - SkAlphaType fXformAlphaType; - int fXformWidth; + XformMode fXformMode; + SkColorSpaceXform::ColorFormat fXformColorFormat; + SkAlphaType fXformAlphaType; + int fXformWidth; #ifdef SK_GOOGLE3_PNG_HACK bool fNeedsToRereadHeader; diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp index e8b27b2178..86bda576e4 100644 --- a/src/codec/SkWebpCodec.cpp +++ b/src/codec/SkWebpCodec.cpp @@ -307,13 +307,14 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, } if (colorXform) { - SkAlphaType xformAlphaType = select_alpha_xform(dstInfo.alphaType(), + SkColorSpaceXform::ColorFormat colorFormat = select_xform_format(dstInfo.colorType()); + SkAlphaType xformAlphaType = select_xform_alpha(dstInfo.alphaType(), this->getInfo().alphaType()); uint32_t* src = (uint32_t*) config.output.u.RGBA.rgba; size_t srcRowBytes = config.output.u.RGBA.stride; for (int y = 0; y < rowsDecoded; y++) { - colorXform->apply(dst, src, dstInfo.width(), dstInfo.colorType(), xformAlphaType); + colorXform->apply(dst, src, dstInfo.width(), colorFormat, xformAlphaType); dst = SkTAddOffset<void>(dst, rowBytes); src = SkTAddOffset<uint32_t>(src, srcRowBytes); } diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp index 599adc90f9..b1dda34817 100644 --- a/src/core/SkColorSpaceXform.cpp +++ b/src/core/SkColorSpaceXform.cpp @@ -908,8 +908,23 @@ static inline void store_f16_1(void* dst, const uint32_t* src, } template <SwapRB kSwapRB> +static inline void store_f32(void* dst, const uint32_t* src, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, + const uint8_t* const[3]) { + Sk4f_store4(dst, dr, dg, db, da); +} + +template <SwapRB kSwapRB> +static inline void store_f32_1(void* dst, const uint32_t* src, + Sk4f& rgba, const Sk4f& a, + const uint8_t* const[3]) { + rgba = Sk4f(rgba[0], rgba[1], rgba[2], a[3]); + rgba.store((float*) dst); +} + +template <SwapRB kSwapRB> static inline void store_f16_opaque(void* dst, const uint32_t* src, - Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f& da, + Sk4f& dr, Sk4f& dg, Sk4f& db, Sk4f&, const uint8_t* const[3]) { Sk4h_store4(dst, SkFloatToHalf_finite_ftz(dr), SkFloatToHalf_finite_ftz(dg), @@ -919,7 +934,7 @@ static inline void store_f16_opaque(void* dst, const uint32_t* src, template <SwapRB kSwapRB> static inline void store_f16_1_opaque(void* dst, const uint32_t* src, - Sk4f& rgba, const Sk4f& a, + Sk4f& rgba, const Sk4f&, const uint8_t* const[3]) { uint64_t tmp; SkFloatToHalf_finite_ftz(rgba).store(&tmp); @@ -1089,6 +1104,7 @@ enum DstFormat { k8888_2Dot2_DstFormat, k8888_Table_DstFormat, kF16_Linear_DstFormat, + kF32_Linear_DstFormat, }; template <SrcFormat kSrc, @@ -1101,9 +1117,12 @@ static void color_xform_RGBA(void* dst, const uint32_t* src, int len, const uint8_t* const dstTables[3]) { LoadFn load; Load1Fn load_1; + static constexpr bool loadAlpha = (kPremul_SkAlphaType == kAlphaType) || + (kF16_Linear_DstFormat == kDst) || + (kF32_Linear_DstFormat == kDst); switch (kSrc) { case kRGBA_8888_Linear_SrcFormat: - if (kPremul_SkAlphaType == kAlphaType || kF16_Linear_DstFormat == kDst) { + if (loadAlpha) { load = load_rgba_linear; load_1 = load_rgba_linear_1; } else { @@ -1112,7 +1131,7 @@ static void color_xform_RGBA(void* dst, const uint32_t* src, int len, } break; case kRGBA_8888_Table_SrcFormat: - if (kPremul_SkAlphaType == kAlphaType || kF16_Linear_DstFormat == kDst) { + if (loadAlpha) { load = load_rgba_from_tables; load_1 = load_rgba_from_tables_1; } else { @@ -1153,6 +1172,11 @@ static void color_xform_RGBA(void* dst, const uint32_t* src, int len, store_f16_1<kSwapRB>; sizeOfDstPixel = 8; break; + case kF32_Linear_DstFormat: + store = store_f32<kSwapRB>; + store_1 = store_f32_1<kSwapRB>; + sizeOfDstPixel = 16; + break; } do_color_xform<kAlphaType, kCSM> @@ -1245,7 +1269,7 @@ static inline void apply_set_src(void* dst, const uint32_t* src, int len, SkAlph template <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM> void SkColorSpaceXform_Base<kSrc, kDst, kCSM> -::apply(void* dst, const uint32_t* src, int len, SkColorType dstColorType, SkAlphaType alphaType) +::apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, SkAlphaType alphaType) const { if (kFull_ColorSpaceMatch == kCSM) { @@ -1255,13 +1279,14 @@ const // linear space. break; default: - switch (dstColorType) { - case kRGBA_8888_SkColorType: + switch (dstColorFormat) { + case kRGBA_8888_ColorFormat: return (void) memcpy(dst, src, len * sizeof(uint32_t)); - case kBGRA_8888_SkColorType: + case kBGRA_8888_ColorFormat: return SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len); - case kRGBA_F16_SkColorType: - // There's still work to do to xform to linear F16. + case kRGBA_F16_ColorFormat: + case kRGBA_F32_ColorFormat: + // There's still work to do to xform to linear floats. break; default: SkASSERT(false); @@ -1283,8 +1308,8 @@ const src = (const uint32_t*) storage.get(); } - switch (dstColorType) { - case kRGBA_8888_SkColorType: + switch (dstColorFormat) { + case kRGBA_8888_ColorFormat: switch (kDst) { case kLinear_DstGamma: return apply_set_src<kSrc, k8888_Linear_DstFormat, kCSM, kNo_SwapRB> @@ -1299,7 +1324,7 @@ const return apply_set_src<kSrc, k8888_Table_DstFormat, kCSM, kNo_SwapRB> (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables); } - case kBGRA_8888_SkColorType: + case kBGRA_8888_ColorFormat: switch (kDst) { case kLinear_DstGamma: return apply_set_src<kSrc, k8888_Linear_DstFormat, kCSM, kYes_SwapRB> @@ -1314,7 +1339,7 @@ const return apply_set_src<kSrc, k8888_Table_DstFormat, kCSM, kYes_SwapRB> (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, fDstGammaTables); } - case kRGBA_F16_SkColorType: + case kRGBA_F16_ColorFormat: switch (kDst) { case kLinear_DstGamma: return apply_set_src<kSrc, kF16_Linear_DstFormat, kCSM, kNo_SwapRB> @@ -1323,6 +1348,15 @@ const SkASSERT(false); return; } + case kRGBA_F32_ColorFormat: + switch (kDst) { + case kLinear_DstGamma: + return apply_set_src<kSrc, kF32_Linear_DstFormat, kCSM, kNo_SwapRB> + (dst, src, len, alphaType, fSrcGammaTables, fSrcToDst, nullptr); + default: + SkASSERT(false); + return; + } default: SkASSERT(false); return; diff --git a/src/core/SkColorSpaceXform.h b/src/core/SkColorSpaceXform.h index c80cd15dca..6c996a9c09 100644 --- a/src/core/SkColorSpaceXform.h +++ b/src/core/SkColorSpaceXform.h @@ -25,20 +25,27 @@ public: static std::unique_ptr<SkColorSpaceXform> New(const sk_sp<SkColorSpace>& srcSpace, const sk_sp<SkColorSpace>& dstSpace); + enum ColorFormat : uint8_t { + kRGBA_8888_ColorFormat, + kBGRA_8888_ColorFormat, + kRGBA_F16_ColorFormat, + kRGBA_F32_ColorFormat, + }; + /** * Apply the color conversion to a |src| buffer, storing the output in the |dst| buffer. * - * @param dst Stored in the format described by |dstColorType| and |dstAlphaType| - * @param src Stored as RGBA_8888, kUnpremul (note kOpaque is a form of kUnpremul) - * @param len Number of pixels in the buffers - * @param dstColorType Describes color type of |dst| - * @param dstAlphaType Describes alpha type of |dst| - * kUnpremul preserves input alpha values - * kPremul performs a premultiplication and also preserves alpha values - * kOpaque optimization hint, |dst| alphas set to 1 + * @param dst Stored in the format described by |dstColorType| and |dstAlphaType| + * @param src Stored as RGBA_8888, kUnpremul (note kOpaque is a form of kUnpremul) + * @param len Number of pixels in the buffers + * @param dstColorFormat Describes color format of |dst| + * @param dstAlphaType Describes alpha type of |dst| + * kUnpremul preserves input alpha values + * kPremul performs a premultiplication and also preserves alpha values + * kOpaque optimization hint, |dst| alphas set to 1 * */ - virtual void apply(void* dst, const uint32_t* src, int len, SkColorType dstColorType, + virtual void apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, SkAlphaType dstAlphaType) const = 0; virtual ~SkColorSpaceXform() {} @@ -66,7 +73,7 @@ template <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM> class SkColorSpaceXform_Base : public SkColorSpaceXform { public: - void apply(void* dst, const uint32_t* src, int len, SkColorType dstColorType, + void apply(void* dst, const uint32_t* src, int len, ColorFormat dstColorFormat, SkAlphaType dstAlphaType) const override; static constexpr int kDstGammaTableSize = 1024; diff --git a/src/core/SkNx.h b/src/core/SkNx.h index 881a475ce0..6bca856d8b 100644 --- a/src/core/SkNx.h +++ b/src/core/SkNx.h @@ -332,6 +332,28 @@ SI void Sk4h_store4(void* dst, const Sk4h& r, const Sk4h& g, const Sk4h& b, cons Sk4h(r[3], g[3], b[3], a[3]).store(dst64 + 3); } +// Load 4 Sk4f and transpose them (512 bits total). +SI void Sk4f_load4(const void* vptr, Sk4f* r, Sk4f* g, Sk4f* b, Sk4f* a) { + const float* ptr = (const float*) vptr; + auto p0 = Sk4f::Load(ptr + 0), + p1 = Sk4f::Load(ptr + 4), + p2 = Sk4f::Load(ptr + 8), + p3 = Sk4f::Load(ptr + 12); + *r = { p0[0], p1[0], p2[0], p3[0] }; + *g = { p0[1], p1[1], p2[1], p3[1] }; + *b = { p0[2], p1[2], p2[2], p3[2] }; + *a = { p0[3], p1[3], p2[3], p3[3] }; +} + +// Transpose 4 Sk4f and store (512 bits total). +SI void Sk4f_store4(void* vdst, const Sk4f& r, const Sk4f& g, const Sk4f& b, const Sk4f& a) { + float* dst = (float*) vdst; + Sk4f(r[0], g[0], b[0], a[0]).store(dst + 0); + Sk4f(r[1], g[1], b[1], a[1]).store(dst + 4); + Sk4f(r[2], g[2], b[2], a[2]).store(dst + 8); + Sk4f(r[3], g[3], b[3], a[3]).store(dst + 12); +} + #endif SI void Sk4f_ToBytes(uint8_t p[16], const Sk4f& a, const Sk4f& b, const Sk4f& c, const Sk4f& d) { diff --git a/src/opts/SkNx_neon.h b/src/opts/SkNx_neon.h index a511243219..f5a0b09785 100644 --- a/src/opts/SkNx_neon.h +++ b/src/opts/SkNx_neon.h @@ -534,4 +534,23 @@ static inline void Sk4h_store4(void* dst, const Sk4h& r, const Sk4h& g, const Sk vst4_u16((uint16_t*) dst, rgba); } +static inline void Sk4f_load4(const void* ptr, Sk4f* r, Sk4f* g, Sk4f* b, Sk4f* a) { + float32x4x4_t rgba = vld4q_f32((const float*) ptr); + *r = rgba.val[0]; + *g = rgba.val[1]; + *b = rgba.val[2]; + *a = rgba.val[3]; +} + +static inline void Sk4f_store4(void* dst, const Sk4f& r, const Sk4f& g, const Sk4f& b, + const Sk4f& a) { + float32x4x4_t rgba = {{ + r.fVec, + g.fVec, + b.fVec, + a.fVec, + }}; + vst4q_f32((float*) dst, rgba); +} + #endif//SkNx_neon_DEFINED diff --git a/src/opts/SkNx_sse.h b/src/opts/SkNx_sse.h index 3e66637df3..25a5cd8f84 100644 --- a/src/opts/SkNx_sse.h +++ b/src/opts/SkNx_sse.h @@ -478,4 +478,29 @@ static inline void Sk4h_store4(void* dst, const Sk4h& r, const Sk4h& g, const Sk _mm_storeu_si128(((__m128i*) dst) + 1, hi); } +static inline void Sk4f_load4(const void* ptr, Sk4f* r, Sk4f* g, Sk4f* b, Sk4f* a) { + __m128 v0 = _mm_loadu_ps(((float*)ptr) + 0), + v1 = _mm_loadu_ps(((float*)ptr) + 4), + v2 = _mm_loadu_ps(((float*)ptr) + 8), + v3 = _mm_loadu_ps(((float*)ptr) + 12); + _MM_TRANSPOSE4_PS(v0, v1, v2, v3); + *r = v0; + *g = v1; + *b = v2; + *a = v3; +} + +static inline void Sk4f_store4(void* dst, const Sk4f& r, const Sk4f& g, const Sk4f& b, + const Sk4f& a) { + __m128 v0 = r.fVec, + v1 = g.fVec, + v2 = b.fVec, + v3 = a.fVec; + _MM_TRANSPOSE4_PS(v0, v1, v2, v3); + _mm_storeu_ps(((float*) dst) + 0, v0); + _mm_storeu_ps(((float*) dst) + 4, v1); + _mm_storeu_ps(((float*) dst) + 8, v2); + _mm_storeu_ps(((float*) dst) + 12, v3); +} + #endif//SkNx_sse_DEFINED diff --git a/tests/ColorSpaceXformTest.cpp b/tests/ColorSpaceXformTest.cpp index 0beb38fb7a..2401af582b 100644 --- a/tests/ColorSpaceXformTest.cpp +++ b/tests/ColorSpaceXformTest.cpp @@ -7,6 +7,7 @@ #include "Resources.h" #include "SkCodec.h" +#include "SkCodecPriv.h" #include "SkColorPriv.h" #include "SkColorSpace.h" #include "SkColorSpace_Base.h" @@ -39,7 +40,8 @@ static void test_identity_xform(skiatest::Reporter* r, const sk_sp<SkGammas>& ga // Create and perform an identity xform. std::unique_ptr<SkColorSpaceXform> xform = ColorSpaceXformTest::CreateIdentityXform(gammas); - xform->apply(dstPixels, srcPixels, width, kN32_SkColorType, kOpaque_SkAlphaType); + xform->apply(dstPixels, srcPixels, width, select_xform_format(kN32_SkColorType), + kOpaque_SkAlphaType); // Since the src->dst matrix is the identity, and the gamma curves match, // the pixels should be unchanged. diff --git a/tests/SkNxTest.cpp b/tests/SkNxTest.cpp index 51d937dd4d..a3aef6bb8e 100644 --- a/tests/SkNxTest.cpp +++ b/tests/SkNxTest.cpp @@ -307,3 +307,35 @@ DEF_TEST(SkNx_int_u16, r) { REPORTER_ASSERT(r, expected == actual); } } + +DEF_TEST(SkNx_4fLoad4Store4, r) { + float src[] = { + 0.0f, 1.0f, 2.0f, 3.0f, + 4.0f, 5.0f, 6.0f, 7.0f, + 8.0f, 9.0f, 10.0f, 11.0f, + 12.0f, 13.0f, 14.0f, 15.0f + }; + + Sk4f a, b, c, d; + Sk4f_load4(src, &a, &b, &c, &d); + REPORTER_ASSERT(r, 0.0f == a[0]); + REPORTER_ASSERT(r, 4.0f == a[1]); + REPORTER_ASSERT(r, 8.0f == a[2]); + REPORTER_ASSERT(r, 12.0f == a[3]); + REPORTER_ASSERT(r, 1.0f == b[0]); + REPORTER_ASSERT(r, 5.0f == b[1]); + REPORTER_ASSERT(r, 9.0f == b[2]); + REPORTER_ASSERT(r, 13.0f == b[3]); + REPORTER_ASSERT(r, 2.0f == c[0]); + REPORTER_ASSERT(r, 6.0f == c[1]); + REPORTER_ASSERT(r, 10.0f == c[2]); + REPORTER_ASSERT(r, 14.0f == c[3]); + REPORTER_ASSERT(r, 3.0f == d[0]); + REPORTER_ASSERT(r, 7.0f == d[1]); + REPORTER_ASSERT(r, 11.0f == d[2]); + REPORTER_ASSERT(r, 15.0f == d[3]); + + float dst[16]; + Sk4f_store4(dst, a, b, c, d); + REPORTER_ASSERT(r, 0 == memcmp(dst, src, 16 * sizeof(float))); +} |