diff options
author | 2016-12-01 14:46:12 -0500 | |
---|---|---|
committer | 2016-12-01 20:59:36 +0000 | |
commit | f6878baba8c7cd347e185361bac2eabaef863bfa (patch) | |
tree | 84eda725488255eb431c7efca5d078353a476d91 /src/core | |
parent | dd56632ae39331138442d1d0469f05988bda91d7 (diff) |
Reland "Add RasterPipeline implementation for SkColorSpaceXform"
This is initially turned on for Linux debug builds,
which allows us to start testing.
Chrome for Android is a really good candidate for
this (will appreciate the code size savings), but
I'd first like to run some tests to understand the
performance/size tradeoffs a little better.
BUG:660416
CQ_INCLUDE_TRYBOTS=skia.primary:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD
Change-Id: Ifc80e663767df6bb767abb8b12b1ec5cec644ec5
Reviewed-on: https://skia-review.googlesource.com/5452
Reviewed-by: Matt Sarett <msarett@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkColorSpaceXform.cpp | 192 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform_Base.h | 41 | ||||
-rw-r--r-- | src/core/SkRasterPipeline.h | 2 |
3 files changed, 235 insertions, 0 deletions
diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp index 450a643cfc..39398532e1 100644 --- a/src/core/SkColorSpaceXform.cpp +++ b/src/core/SkColorSpaceXform.cpp @@ -15,8 +15,15 @@ #include "SkColorSpaceXformPriv.h" #include "SkHalf.h" #include "SkOpts.h" +#include "SkRasterPipeline.h" #include "SkSRGB.h" +#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_UNIX) +static constexpr bool kUseRasterPipeline = true; +#else +static constexpr bool kUseRasterPipeline = false; +#endif + static constexpr float sk_linear_from_2dot2[256] = { 0.000000000000000000f, 0.000005077051900662f, 0.000023328004666099f, 0.000056921765712193f, 0.000107187362341244f, 0.000175123977503027f, 0.000261543754548491f, 0.000367136269815943f, @@ -350,6 +357,27 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace } } + if (kUseRasterPipeline) { + SrcGamma srcGamma = srcSpaceXYZ->gammaIsLinear() ? kLinear_SrcGamma : kTable_SrcGamma; + DstGamma dstGamma; + switch (dstSpaceXYZ->gammaNamed()) { + case kSRGB_SkGammaNamed: + dstGamma = kSRGB_DstGamma; + break; + case k2Dot2Curve_SkGammaNamed: + dstGamma = k2Dot2_DstGamma; + break; + case kLinear_SkGammaNamed: + dstGamma = kLinear_DstGamma; + break; + default: + dstGamma = kTable_DstGamma; + break; + } + return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Pipeline( + srcSpaceXYZ, srcToDst, dstSpaceXYZ, csm, srcGamma, dstGamma)); + } + switch (csm) { case kNone_ColorSpaceMatch: switch (dstSpaceXYZ->gammaNamed()) { @@ -1264,8 +1292,172 @@ bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat /////////////////////////////////////////////////////////////////////////////////////////////////// +SkColorSpaceXform_Pipeline::SkColorSpaceXform_Pipeline(SkColorSpace_XYZ* srcSpace, + const SkMatrix44& srcToDst, + SkColorSpace_XYZ* dstSpace, + ColorSpaceMatch csm, + SrcGamma srcGamma, + DstGamma dstGamma) + : fCSM(csm) + , fSrcGamma(srcGamma) + , fDstGamma(dstGamma) +{ + fSrcToDst[ 0] = srcToDst.get(0, 0); + fSrcToDst[ 1] = srcToDst.get(1, 0); + fSrcToDst[ 2] = srcToDst.get(2, 0); + fSrcToDst[ 3] = srcToDst.get(0, 1); + fSrcToDst[ 4] = srcToDst.get(1, 1); + fSrcToDst[ 5] = srcToDst.get(2, 1); + fSrcToDst[ 6] = srcToDst.get(0, 2); + fSrcToDst[ 7] = srcToDst.get(1, 2); + fSrcToDst[ 8] = srcToDst.get(2, 2); + fSrcToDst[ 9] = srcToDst.get(0, 3); + fSrcToDst[10] = srcToDst.get(1, 3); + fSrcToDst[11] = srcToDst.get(2, 3); + + const int numSrcTables = num_tables(srcSpace); + const size_t srcEntries = numSrcTables * 256; + const bool srcGammasAreMatching = (1 >= numSrcTables); + fSrcStorage.reset(srcEntries); + build_gamma_tables(fSrcGammaTables, fSrcStorage.get(), 256, srcSpace, kToLinear, + srcGammasAreMatching); + + const int numDstTables = num_tables(dstSpace); + dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables); +} + +bool SkColorSpaceXform_Pipeline::onApply(ColorFormat dstColorFormat, void* dst, + ColorFormat srcColorFormat, const void* src, int len, + SkAlphaType alphaType) const { + if (kFull_ColorSpaceMatch == fCSM) { + if (kPremul_SkAlphaType != alphaType) { + if ((kRGBA_8888_ColorFormat == dstColorFormat && + kRGBA_8888_ColorFormat == srcColorFormat) || + (kBGRA_8888_ColorFormat == dstColorFormat && + kBGRA_8888_ColorFormat == srcColorFormat)) + { + memcpy(dst, src, len * sizeof(uint32_t)); + return true; + } + + if ((kRGBA_8888_ColorFormat == dstColorFormat && + kBGRA_8888_ColorFormat == srcColorFormat) || + (kBGRA_8888_ColorFormat == dstColorFormat && + kRGBA_8888_ColorFormat == srcColorFormat)) + { + SkOpts::RGBA_to_BGRA((uint32_t*) dst, src, len); + return true; + } + } + } + + if (kRGBA_F16_ColorFormat == srcColorFormat || kRGBA_F32_ColorFormat == srcColorFormat) { + return false; + } + + SkRasterPipeline pipeline; + + LoadTablesContext loadTables; + if (kLinear_SrcGamma == fSrcGamma) { + pipeline.append(SkRasterPipeline::load_8888, &src); + if (kBGRA_8888_ColorFormat == srcColorFormat) { + pipeline.append(SkRasterPipeline::swap_rb); + } + } else { + loadTables.fSrc = (const uint32_t*) src; + loadTables.fG = fSrcGammaTables[1]; + if (kRGBA_8888_ColorFormat == srcColorFormat) { + loadTables.fR = fSrcGammaTables[0]; + loadTables.fB = fSrcGammaTables[2]; + pipeline.append(SkRasterPipeline::load_tables, &loadTables); + } else { + loadTables.fR = fSrcGammaTables[2]; + loadTables.fB = fSrcGammaTables[0]; + pipeline.append(SkRasterPipeline::load_tables, &loadTables); + pipeline.append(SkRasterPipeline::swap_rb); + } + } + + if (kNone_ColorSpaceMatch == fCSM) { + pipeline.append(SkRasterPipeline::matrix_3x4, fSrcToDst); + } + + if (kRGBA_8888_ColorFormat == dstColorFormat || kBGRA_8888_ColorFormat == dstColorFormat) { + pipeline.append(SkRasterPipeline::clamp_0); + pipeline.append(SkRasterPipeline::clamp_1); + } + + if (kPremul_SkAlphaType == alphaType) { + pipeline.append(SkRasterPipeline::premul); + } + + StoreTablesContext storeTables; + switch (fDstGamma) { + case kSRGB_DstGamma: + pipeline.append(SkRasterPipeline::to_srgb); + break; + case k2Dot2_DstGamma: + pipeline.append(SkRasterPipeline::to_2dot2); + break; + default: + break; + } + + switch (dstColorFormat) { + case kRGBA_8888_ColorFormat: + if (kTable_DstGamma == fDstGamma) { + storeTables.fDst = (uint32_t*) dst; + storeTables.fR = fDstGammaTables[0]; + storeTables.fG = fDstGammaTables[1]; + storeTables.fB = fDstGammaTables[2]; + storeTables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize; + pipeline.append(SkRasterPipeline::store_tables, &storeTables); + } else { + pipeline.append(SkRasterPipeline::store_8888, &dst); + } + break; + case kBGRA_8888_ColorFormat: + if (kTable_DstGamma == fDstGamma) { + storeTables.fDst = (uint32_t*) dst; + storeTables.fR = fDstGammaTables[2]; + storeTables.fG = fDstGammaTables[1]; + storeTables.fB = fDstGammaTables[0]; + storeTables.fCount = SkColorSpaceXform_Base::kDstGammaTableSize; + pipeline.append(SkRasterPipeline::swap_rb); + pipeline.append(SkRasterPipeline::store_tables, &storeTables); + } else { + pipeline.append(SkRasterPipeline::swap_rb); + pipeline.append(SkRasterPipeline::store_8888, &dst); + } + break; + case kRGBA_F16_ColorFormat: + if (kLinear_DstGamma != fDstGamma) { + return false; + } + pipeline.append(SkRasterPipeline::store_f16, &dst); + break; + case kRGBA_F32_ColorFormat: + if (kLinear_DstGamma != fDstGamma) { + return false; + } + pipeline.append(SkRasterPipeline::store_f32, &dst); + break; + } + + pipeline.run(0, 0, len); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) { + if (kUseRasterPipeline) { + return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_Pipeline( + space, SkMatrix::I(), space, kNone_ColorSpaceMatch, kTable_SrcGamma, + kTable_DstGamma)); + } else { return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ <kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch> (space, SkMatrix::I(), space)); + } } diff --git a/src/core/SkColorSpaceXform_Base.h b/src/core/SkColorSpaceXform_Base.h index a648677609..3d17f67866 100644 --- a/src/core/SkColorSpaceXform_Base.h +++ b/src/core/SkColorSpaceXform_Base.h @@ -71,6 +71,47 @@ private: friend std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space); }; +struct LoadTablesContext { + const uint32_t* fSrc; + const float* fR; + const float* fG; + const float* fB; +}; + +struct StoreTablesContext { + uint32_t* fDst; + const uint8_t* fR; + const uint8_t* fG; + const uint8_t* fB; + int fCount; +}; + +class SkColorSpaceXform_Pipeline : public SkColorSpaceXform_Base { +protected: + virtual bool onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, + int count, SkAlphaType alphaType) const; + +private: + SkColorSpaceXform_Pipeline(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst, + SkColorSpace_XYZ* dstSpace, ColorSpaceMatch csm, SrcGamma srcGamma, + DstGamma dstGamma); + + // Contain pointers into storage or pointers into precomputed tables. + const float* fSrcGammaTables[3]; + SkAutoTMalloc<float> fSrcStorage; + const uint8_t* fDstGammaTables[3]; + sk_sp<SkData> fDstStorage; + + float fSrcToDst[12]; + + ColorSpaceMatch fCSM; + SrcGamma fSrcGamma; + DstGamma fDstGamma; + + friend class SkColorSpaceXform; + friend std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space); +}; + // For testing. Bypasses opts for when src and dst color spaces are equal. std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space); diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h index 7338c4d001..8762386f58 100644 --- a/src/core/SkRasterPipeline.h +++ b/src/core/SkRasterPipeline.h @@ -61,10 +61,12 @@ M(unpremul) M(premul) \ M(set_rgb) \ M(from_srgb) M(from_srgb_d) M(to_srgb) \ + M(to_2dot2) \ M(constant_color) M(store_f32) \ M(load_565) M(load_565_d) M(store_565) \ M(load_f16) M(load_f16_d) M(store_f16) \ M(load_8888) M(load_8888_d) M(store_8888) \ + M(load_tables) M(store_tables) \ M(scale_u8) M(scale_1_float) \ M(lerp_u8) M(lerp_565) M(lerp_1_float) \ M(dstatop) M(dstin) M(dstout) M(dstover) \ |