diff options
-rw-r--r-- | src/core/SkColorSpaceXformPriv.h | 6 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform_A2B.cpp | 169 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform_A2B.h | 27 | ||||
-rw-r--r-- | src/core/SkRasterPipeline.h | 3 | ||||
-rw-r--r-- | src/opts/SkRasterPipeline_opts.h | 50 |
5 files changed, 118 insertions, 137 deletions
diff --git a/src/core/SkColorSpaceXformPriv.h b/src/core/SkColorSpaceXformPriv.h index c2418a93b6..03be68ab4c 100644 --- a/src/core/SkColorSpaceXformPriv.h +++ b/src/core/SkColorSpaceXformPriv.h @@ -12,13 +12,11 @@ #include "SkHalf.h" #include "SkSRGB.h" -#define AI SK_ALWAYS_INLINE - #define SkCSXformPrintfDefined 0 #define SkCSXformPrintf(...) // Interpolating lookup in a variably sized table. -static AI float interp_lut(float input, const float* table, int tableSize) { +static inline float interp_lut(float input, const float* table, int tableSize) { float index = input * (tableSize - 1); float diff = index - sk_float_floor2int(index); return table[(int) sk_float_floor2int(index)] * (1.0f - diff) + @@ -28,7 +26,7 @@ static AI float interp_lut(float input, const float* table, int tableSize) { // Inverse table lookup. Ex: what index corresponds to the input value? This will // have strange results when the table is non-increasing. But any sane gamma // function will be increasing. -static float inverse_interp_lut(float input, const float* table, int tableSize) { +static inline float inverse_interp_lut(float input, const float* table, int tableSize) { if (input <= table[0]) { return table[0]; } else if (input >= table[tableSize - 1]) { diff --git a/src/core/SkColorSpaceXform_A2B.cpp b/src/core/SkColorSpaceXform_A2B.cpp index e54cb27840..ead48f33fd 100644 --- a/src/core/SkColorSpaceXform_A2B.cpp +++ b/src/core/SkColorSpaceXform_A2B.cpp @@ -21,52 +21,6 @@ #define AI SK_ALWAYS_INLINE -namespace { - -class ApplyParametric { -public: - ApplyParametric(const SkColorSpaceTransferFn& fn) - : fFn(fn) - {} - - float operator()(float x) const { - float y; - if (x >= fFn.fD) { - y = ::powf(fFn.fA * x + fFn.fB, fFn.fG) + fFn.fC; - } else { - y = fFn.fE * x + fFn.fF; - } - if (y >= 1.f) { - return 1.f; - } else if (y >= 0.f) { - return y; - } - return 0.f; - } - -private: - SkColorSpaceTransferFn fFn; -}; - -class ApplyTable { -public: - ApplyTable(const float* table, int size) - : fTable(table) - , fSize(size) - {} - - float operator()(float x) const { - return interp_lut(x, fTable, fSize); - } - -private: - const float* fTable; - int fSize; -}; - -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// bool SkColorSpaceXform_A2B::onApply(ColorFormat dstFormat, void* dst, ColorFormat srcFormat, const void* src, int count, SkAlphaType alphaType) const { SkRasterPipeline pipeline; @@ -226,34 +180,43 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, if (kLinear_SkGammaNamed != e.gammaNamed()) { SkCSXformPrintf("Gamma stage added: %s\n", debugGammaNamed[(int)e.gammaNamed()]); - addGamma(ApplyParametric(gammanamed_to_parametric(e.gammaNamed())), - kRGB_Channels); + SkColorSpaceTransferFn fn = gammanamed_to_parametric(e.gammaNamed()); + this->addTransferFn(fn, kRGB_Channels); + + fElementsPipeline.append(SkRasterPipeline::clamp_0); + fElementsPipeline.append(SkRasterPipeline::clamp_1); } break; case SkColorSpace_A2B::Element::Type::kGammas: { - const SkGammas& gammas = e.gammas(); - SkCSXformPrintf("Gamma stage added:"); - for (int channel = 0; channel < 3; ++channel) { - SkCSXformPrintf(" %s", debugGammas[(int)gammas.type(channel)]); - } - SkCSXformPrintf("\n"); - bool gammaNeedsRef = false; - for (int channel = 0; channel < 3; ++channel) { - if (SkGammas::Type::kTable_Type == gammas.type(channel)) { - addGamma(ApplyTable(gammas.table(channel), - gammas.data(channel).fTable.fSize), - static_cast<Channels>(channel)); - gammaNeedsRef = true; - } else { - addGamma(ApplyParametric(gamma_to_parametric(gammas, channel)), - static_cast<Channels>(channel)); - } - } - if (gammaNeedsRef) { - fGammaRefs.push_back(sk_ref_sp(&gammas)); + const SkGammas& gammas = e.gammas(); + SkCSXformPrintf("Gamma stage added:"); + for (int channel = 0; channel < 3; ++channel) { + SkCSXformPrintf(" %s", debugGammas[(int)gammas.type(channel)]); + } + SkCSXformPrintf("\n"); + bool gammaNeedsRef = false; + for (int channel = 0; channel < 3; ++channel) { + if (SkGammas::Type::kTable_Type == gammas.type(channel)) { + SkTableTransferFn table = { + gammas.table(channel), + gammas.data(channel).fTable.fSize, + }; + + this->addTableFn(table, static_cast<Channels>(channel)); + gammaNeedsRef = true; + } else { + SkColorSpaceTransferFn fn = gamma_to_parametric(gammas, channel); + this->addTransferFn(fn, static_cast<Channels>(channel)); } } + if (gammaNeedsRef) { + fGammaRefs.push_back(sk_ref_sp(&gammas)); + } + + fElementsPipeline.append(SkRasterPipeline::clamp_0); + fElementsPipeline.append(SkRasterPipeline::clamp_1); break; + } case SkColorSpace_A2B::Element::Type::kCLUT: SkCSXformPrintf("CLUT stage added [%d][%d][%d]\n", e.colorLUT().fGridPoints[0], e.colorLUT().fGridPoints[1], e.colorLUT().fGridPoints[2]); @@ -283,42 +246,74 @@ SkColorSpaceXform_A2B::SkColorSpaceXform_A2B(SkColorSpace_A2B* srcSpace, if (kNonStandard_SkGammaNamed != dstSpace->gammaNamed()) { if (!fLinearDstGamma) { - addGamma(ApplyParametric( - invert_parametric(gammanamed_to_parametric(dstSpace->gammaNamed()))), - kRGB_Channels); + SkColorSpaceTransferFn fn = + invert_parametric(gammanamed_to_parametric(dstSpace->gammaNamed())); + this->addTransferFn(fn, kRGB_Channels); + fElementsPipeline.append(SkRasterPipeline::clamp_0); + fElementsPipeline.append(SkRasterPipeline::clamp_1); } } else { for (int channel = 0; channel < 3; ++channel) { const SkGammas& gammas = *dstSpace->gammas(); if (SkGammas::Type::kTable_Type == gammas.type(channel)) { - fGammaTables.push_front(build_inverse_table(gammas.table(channel), - gammas.data(channel).fTable.fSize)); - addGamma(ApplyTable(fGammaTables.front().data(), fGammaTables.front().size()), - static_cast<Channels>(channel)); + std::vector<float> storage = build_inverse_table(gammas.table(channel), + gammas.data(channel).fTable.fSize); + SkTableTransferFn table = { + storage.data(), + (int) storage.size(), + }; + fTableStorage.push_front(std::move(storage)); + + this->addTableFn(table, static_cast<Channels>(channel)); } else { - addGamma(ApplyParametric(invert_parametric(gamma_to_parametric(gammas, channel))), - static_cast<Channels>(channel)); + SkColorSpaceTransferFn fn = invert_parametric(gamma_to_parametric(gammas, channel)); + this->addTransferFn(fn, static_cast<Channels>(channel)); } } + + fElementsPipeline.append(SkRasterPipeline::clamp_0); + fElementsPipeline.append(SkRasterPipeline::clamp_1); + } +} + +void SkColorSpaceXform_A2B::addTransferFn(const SkColorSpaceTransferFn& fn, Channels channels) { + fTransferFns.push_front(fn); + switch (channels) { + case kRGB_Channels: + fElementsPipeline.append(SkRasterPipeline::parametric_r, &fTransferFns.front()); + fElementsPipeline.append(SkRasterPipeline::parametric_g, &fTransferFns.front()); + fElementsPipeline.append(SkRasterPipeline::parametric_b, &fTransferFns.front()); + break; + case kR_Channels: + fElementsPipeline.append(SkRasterPipeline::parametric_r, &fTransferFns.front()); + break; + case kG_Channels: + fElementsPipeline.append(SkRasterPipeline::parametric_g, &fTransferFns.front()); + break; + case kB_Channels: + fElementsPipeline.append(SkRasterPipeline::parametric_b, &fTransferFns.front()); + break; + default: + SkASSERT(false); } } -void SkColorSpaceXform_A2B::addGamma(std::function<float(float)> fn, Channels channels) { - fGammaFunctions.push_front(std::move(fn)); +void SkColorSpaceXform_A2B::addTableFn(const SkTableTransferFn& fn, Channels channels) { + fTableTransferFns.push_front(fn); switch (channels) { case kRGB_Channels: - fElementsPipeline.append(SkRasterPipeline::fn_1_r, &fGammaFunctions.front()); - fElementsPipeline.append(SkRasterPipeline::fn_1_g, &fGammaFunctions.front()); - fElementsPipeline.append(SkRasterPipeline::fn_1_b, &fGammaFunctions.front()); + fElementsPipeline.append(SkRasterPipeline::table_r, &fTableTransferFns.front()); + fElementsPipeline.append(SkRasterPipeline::table_g, &fTableTransferFns.front()); + fElementsPipeline.append(SkRasterPipeline::table_b, &fTableTransferFns.front()); break; case kR_Channels: - fElementsPipeline.append(SkRasterPipeline::fn_1_r, &fGammaFunctions.front()); + fElementsPipeline.append(SkRasterPipeline::table_r, &fTableTransferFns.front()); break; case kG_Channels: - fElementsPipeline.append(SkRasterPipeline::fn_1_g, &fGammaFunctions.front()); + fElementsPipeline.append(SkRasterPipeline::table_g, &fTableTransferFns.front()); break; case kB_Channels: - fElementsPipeline.append(SkRasterPipeline::fn_1_b, &fGammaFunctions.front()); + fElementsPipeline.append(SkRasterPipeline::table_b, &fTableTransferFns.front()); break; default: SkASSERT(false); @@ -346,7 +341,5 @@ void SkColorSpaceXform_A2B::addMatrix(const SkMatrix44& matrix) { SkASSERT(matrix.get(3, 3) == 1.f); fElementsPipeline.append(SkRasterPipeline::matrix_3x4, m.data()); fElementsPipeline.append(SkRasterPipeline::clamp_0); - fElementsPipeline.append(SkRasterPipeline::clamp_a); + fElementsPipeline.append(SkRasterPipeline::clamp_1); } - - diff --git a/src/core/SkColorSpaceXform_A2B.h b/src/core/SkColorSpaceXform_A2B.h index 681261ad20..6beda285e1 100644 --- a/src/core/SkColorSpaceXform_A2B.h +++ b/src/core/SkColorSpaceXform_A2B.h @@ -19,6 +19,10 @@ class SkColorSpace_A2B; class SkColorSpace_XYZ; +struct SkTableTransferFn { + const float* fData; + int fSize; +}; class SkColorSpaceXform_A2B : public SkColorSpaceXform_Base { public: @@ -34,19 +38,26 @@ private: kG_Channels = 1, kB_Channels = 2 }; - void addGamma(std::function<float(float)> fn, Channels channels); + + + + void addTransferFn(const SkColorSpaceTransferFn& fn, Channels channels); + void addTableFn(const SkTableTransferFn& table, Channels channels); void addMatrix(const SkMatrix44& matrix); - SkRasterPipeline fElementsPipeline; - bool fLinearDstGamma; + SkRasterPipeline fElementsPipeline; + bool fLinearDstGamma; + // storage used by the pipeline - std::forward_list<std::function<float(float)>> fGammaFunctions; - std::forward_list<std::vector<float>> fMatrices; - std::forward_list<std::vector<float>> fGammaTables; - std::vector<sk_sp<const SkColorLookUpTable>> fCLUTs; + std::forward_list<SkColorSpaceTransferFn> fTransferFns; + std::forward_list<SkTableTransferFn> fTableTransferFns; + std::forward_list<std::vector<float>> fMatrices; + std::vector<sk_sp<const SkColorLookUpTable>> fCLUTs; + // these are here to maintain ownership of tables used in the pipeline - std::vector<sk_sp<const SkGammas>> fGammaRefs; + std::forward_list<std::vector<float>> fTableStorage; + std::vector<sk_sp<const SkGammas>> fGammaRefs; friend class SkColorSpaceXform; }; diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h index 484f28365a..b361ab6896 100644 --- a/src/core/SkRasterPipeline.h +++ b/src/core/SkRasterPipeline.h @@ -57,7 +57,7 @@ #define SK_RASTER_PIPELINE_STAGES(M) \ M(trace) M(registers) \ M(move_src_dst) M(swap_src_dst) \ - M(clamp_0) M(clamp_a) M(unpremul) M(premul) \ + M(clamp_0) M(clamp_a) M(clamp_1) M(unpremul) M(premul) \ M(constant_color) M(store_f32) \ M(load_s_565) M(load_d_565) M(store_565) \ M(load_s_srgb) M(load_d_srgb) M(store_srgb) \ @@ -72,7 +72,6 @@ M(colorburn) M(colordodge) M(darken) M(difference) \ M(exclusion) M(hardlight) M(lighten) M(overlay) M(softlight) \ M(luminance_to_alpha) M(matrix_3x4) M(matrix_4x5) \ - M(fn_1_r) M(fn_1_g) M(fn_1_b) \ M(parametric_r) M(parametric_g) M(parametric_b) \ M(table_r) M(table_g) M(table_b) \ M(color_lookup_table) M(lab_to_xyz) M(swap_rb) diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h index 087a63025f..f1aa250d21 100644 --- a/src/opts/SkRasterPipeline_opts.h +++ b/src/opts/SkRasterPipeline_opts.h @@ -10,6 +10,8 @@ #include "SkColorPriv.h" #include "SkColorLookUpTable.h" +#include "SkColorSpaceXform_A2B.h" +#include "SkColorSpaceXformPriv.h" #include "SkHalf.h" #include "SkPM4f.h" #include "SkPM4fPriv.h" @@ -232,6 +234,13 @@ STAGE(clamp_a, true) { b = SkNf::Min(b, a); } +STAGE(clamp_1, true) { + a = SkNf::Min(a, 1.0f); + r = SkNf::Min(r, 1.0f); + g = SkNf::Min(g, 1.0f); + b = SkNf::Min(b, 1.0f); +} + STAGE(unpremul, true) { r *= a.invert(); g *= a.invert(); @@ -585,51 +594,22 @@ STAGE(parametric_b, true) { b = parametric(b, *(const SkColorSpaceTransferFn*)ctx); } -SI SkNf table(const SkNf& v, const float t[1024]) { - SkNi ix = SkNx_cast<int>(SkNf::Max(0, SkNf::Min(v, 1)) * 1023 + 0.5); - - float result[N]; // TODO: vgatherdps? +SI SkNf table(const SkNf& v, const SkTableTransferFn& table) { + float result[N]; for (int i = 0; i < N; i++) { - result[i] = t[ix[i]]; + result[i] = interp_lut(v[i], table.fData, table.fSize); } return SkNf::Load(result); } STAGE(table_r, true) { - r = table(r, (const float*)ctx); + r = table(r, *(const SkTableTransferFn*)ctx); } STAGE(table_g, true) { - g = table(g, (const float*)ctx); + g = table(g, *(const SkTableTransferFn*)ctx); } STAGE(table_b, true) { - b = table(b, (const float*)ctx); -} - -STAGE(fn_1_r, true) { - auto fn = (const std::function<float(float)>*)ctx; - float result[N]; - for (int i = 0; i < N; ++i) { - result[i] = (*fn)(r[i]); - } - r = SkNf::Load(result); -} - -STAGE(fn_1_g, true) { - auto fn = (const std::function<float(float)>*)ctx; - float result[N]; - for (int i = 0; i < N; ++i) { - result[i] = (*fn)(g[i]); - } - g = SkNf::Load(result); -} - -STAGE(fn_1_b, true) { - auto fn = (const std::function<float(float)>*)ctx; - float result[N]; - for (int i = 0; i < N; ++i) { - result[i] = (*fn)(b[i]); - } - b = SkNf::Load(result); + b = table(b, *(const SkTableTransferFn*)ctx); } STAGE(color_lookup_table, true) { |