From dc6c9bf91c158e89cd9d5ef19dfbf1da98c598a6 Mon Sep 17 00:00:00 2001 From: fmalita Date: Mon, 21 Mar 2016 13:16:51 -0700 Subject: Refactor 4f gradients using trait templates Some 4f gradient housekeeping. 1) replace specialization tuples with an enum covering all dest types (L32, S32, F16, F32) 2) group various template helpers into dest trait classes, specialized for each dest type (2a - conflate current dst_swizzle and scale_for_dest ops into one load op) R=reed@google.com,mtklein@google.com,herb@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1816883002 Review URL: https://codereview.chromium.org/1816883002 --- src/effects/gradients/Sk4fGradientBase.cpp | 32 ++-- src/effects/gradients/Sk4fGradientBase.h | 12 +- src/effects/gradients/Sk4fGradientPriv.h | 230 ++++++++++++++++----------- src/effects/gradients/Sk4fLinearGradient.cpp | 146 +++++------------ src/effects/gradients/Sk4fLinearGradient.h | 12 +- 5 files changed, 211 insertions(+), 221 deletions(-) (limited to 'src') diff --git a/src/effects/gradients/Sk4fGradientBase.cpp b/src/effects/gradients/Sk4fGradientBase.cpp index 43910108ff..e09ba77a04 100644 --- a/src/effects/gradients/Sk4fGradientBase.cpp +++ b/src/effects/gradients/Sk4fGradientBase.cpp @@ -276,56 +276,56 @@ GradientShaderBase4fContext::addMirrorIntervals(const SkGradientShaderBase& shad void SkGradientShaderBase:: GradientShaderBase4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { if (fColorsArePremul) { - this->shadePremulSpan(x, y, dst, count); + this->shadePremulSpan(x, y, dst, count); } else { - this->shadePremulSpan(x, y, dst, count); + this->shadePremulSpan(x, y, dst, count); } } void SkGradientShaderBase:: GradientShaderBase4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { if (fColorsArePremul) { - this->shadePremulSpan(x, y, dst, count); + this->shadePremulSpan(x, y, dst, count); } else { - this->shadePremulSpan(x, y, dst, count); + this->shadePremulSpan(x, y, dst, count); } } -template +template void SkGradientShaderBase:: GradientShaderBase4fContext::shadePremulSpan(int x, int y, - DstType dst[], + typename DstTraits::Type dst[], int count) const { const SkGradientShaderBase& shader = static_cast(fShader); switch (shader.fTileMode) { case kClamp_TileMode: - this->shadeSpanInternalshadeSpanInternal(x, y, dst, count); break; case kRepeat_TileMode: - this->shadeSpanInternalshadeSpanInternal(x, y, dst, count); break; case kMirror_TileMode: - this->shadeSpanInternalshadeSpanInternal(x, y, dst, count); break; } } -template +template void SkGradientShaderBase:: GradientShaderBase4fContext::shadeSpanInternal(int x, int y, - DstType dst[], + typename DstTraits::Type dst[], int count) const { static const int kBufSize = 128; SkScalar ts[kBufSize]; - TSampler sampler(*this); + TSampler sampler(*this); SkASSERT(count > 0); do { @@ -333,14 +333,14 @@ GradientShaderBase4fContext::shadeSpanInternal(int x, int y, this->mapTs(x, y, ts, n); for (int i = 0; i < n; ++i) { const Sk4f c = sampler.sample(ts[i]); - store(c, dst++); + DstTraits::store(c, dst++); } x += n; count -= n; } while (count > 0); } -template +template class SkGradientShaderBase::GradientShaderBase4fContext::TSampler { public: TSampler(const GradientShaderBase4fContext& ctx) @@ -423,8 +423,8 @@ private: } void loadIntervalData(const Interval* i) { - fCc = scale_for_dest(dst_swizzle(i->fC0)); - fDc = scale_for_dest(dst_swizzle(i->fDc)); + fCc = DstTraits::load(i->fC0); + fDc = DstTraits::load(i->fDc); } const Interval* fFirstInterval; diff --git a/src/effects/gradients/Sk4fGradientBase.h b/src/effects/gradients/Sk4fGradientBase.h index 03f7e6ef26..ddd0b2bc46 100644 --- a/src/effects/gradients/Sk4fGradientBase.h +++ b/src/effects/gradients/Sk4fGradientBase.h @@ -59,14 +59,16 @@ private: void addMirrorIntervals(const SkGradientShaderBase&, const Sk4f& componentScale, bool reverse); - template + template class TSampler; - template - void shadePremulSpan(int x, int y, DstType[], int count) const; + template + void shadePremulSpan(int x, int y, typename DstTraits::Type[], + int count) const; - template - void shadeSpanInternal(int x, int y, DstType[], int count) const; + template + void shadeSpanInternal(int x, int y, typename DstTraits::Type[], + int count) const; }; #endif // Sk4fGradientBase_DEFINED diff --git a/src/effects/gradients/Sk4fGradientPriv.h b/src/effects/gradients/Sk4fGradientPriv.h index e9bc268b89..4f71d3f14d 100644 --- a/src/effects/gradients/Sk4fGradientPriv.h +++ b/src/effects/gradients/Sk4fGradientPriv.h @@ -14,6 +14,7 @@ #include "SkNx.h" #include "SkPM4f.h" #include "SkPM4fPriv.h" +#include "SkUtils.h" // Templates shared by various 4f gradient flavors. @@ -21,11 +22,12 @@ namespace { enum class ApplyPremul { True, False }; -inline Sk4f premul_4f(const Sk4f& c) { - const float alpha = c[SkPM4f::A]; - // FIXME: portable swizzle? - return c * Sk4f(alpha, alpha, alpha, 1); -} +enum class DstType { + L32, // Linear 32bit. Used for both shader/blitter paths. + S32, // SRGB 32bit. Used for the blitter path only. + F16, // Linear half-float. Used for blitters only. + F32, // Linear float. Used for shaders only. +}; template inline SkPMColor trunc_from_4f_255(const Sk4f& c) { @@ -38,106 +40,156 @@ inline SkPMColor trunc_from_4f_255(const Sk4f& c) { return pmc; } -template -void store(const Sk4f& color, DstType* dst); +template +struct PremulTraits; -template<> -inline void store - (const Sk4f& c, SkPM4f* dst) { - c.store(dst); -} +template <> +struct PremulTraits { + static Sk4f apply(const Sk4f& c) { return c; } +}; -template<> -inline void store - (const Sk4f& c, SkPM4f* dst) { - premul_4f(c).store(dst); -} +template <> +struct PremulTraits { + static Sk4f apply(const Sk4f& c) { + const float alpha = c[SkPM4f::A]; + // FIXME: portable swizzle? + return c * Sk4f(alpha, alpha, alpha, 1); + } +}; + +// Struct encapsulating various dest-dependent ops: +// +// - load() Load a SkPM4f value into Sk4f. Normally called once per interval +// advance. Also applies a scale and swizzle suitable for DstType. +// +// - store() Store one Sk4f to dest. Optionally handles premul, color space +// conversion, etc. +// +// - store(count) Store the Sk4f value repeatedly to dest, count times. +// +// - store4x() Store 4 Sk4f values to dest (opportunistic optimization). +// +template +struct DstTraits; -template<> -inline void store - (const Sk4f& c, SkPMColor* dst) { - *dst = trunc_from_4f_255(c); -} +template +struct DstTraits { + using Type = SkPMColor; -template<> -inline void store - (const Sk4f& c, SkPMColor* dst) { - *dst = trunc_from_4f_255(c); -} + // For L32, we prescale the values by 255 to save a per-pixel multiplication. + static Sk4f load(const SkPM4f& c) { + return c.to4f_pmorder() * Sk4f(255); + } -template<> -inline void store - (const Sk4f& c, SkPMColor* dst) { - // FIXME: this assumes opaque colors. Handle unpremultiplication. - *dst = Sk4f_toS32(c); -} + static void store(const Sk4f& c, Type* dst) { + *dst = trunc_from_4f_255(c); + } -template<> -inline void store - (const Sk4f& c, SkPMColor* dst) { - *dst = Sk4f_toS32(premul_4f(c)); -} + static void store(const Sk4f& c, Type* dst, int n) { + sk_memset32(dst, trunc_from_4f_255(c), n); + } -template<> -inline void store - (const Sk4f& c, uint64_t* dst) { - *dst = SkFloatToHalf_01(c); -} + static void store4x(const Sk4f& c0, const Sk4f& c1, + const Sk4f& c2, const Sk4f& c3, + Type* dst) { + if (premul == ApplyPremul::False) { + Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); + } else { + store(c0, dst + 0); + store(c1, dst + 1); + store(c2, dst + 2); + store(c3, dst + 3); + } + } +}; -template<> -inline void store - (const Sk4f& c, uint64_t* dst) { - *dst = SkFloatToHalf_01(premul_4f(c)); -} +template +struct DstTraits { + using PM = PremulTraits; + using Type = SkPMColor; + + // TODO: prescale by something like (255^2, 255^2, 255^2, 255) and use + // linear_to_srgb to save a mult in store? + static Sk4f load(const SkPM4f& c) { + return c.to4f_pmorder(); + } -template -inline void store4x(const Sk4f& c0, - const Sk4f& c1, - const Sk4f& c2, - const Sk4f& c3, - DstType* dst) { - store(c0, dst++); - store(c1, dst++); - store(c2, dst++); - store(c3, dst++); -} + static void store(const Sk4f& c, Type* dst) { + // FIXME: this assumes opaque colors. Handle unpremultiplication. + *dst = Sk4f_toS32(PM::apply(c)); + } -template<> -inline void store4x - (const Sk4f& c0, const Sk4f& c1, - const Sk4f& c2, const Sk4f& c3, - SkPMColor* dst) { - Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); -} + static void store(const Sk4f& c, Type* dst, int n) { + sk_memset32(dst, Sk4f_toS32(PM::apply(c)), n); + } -template -Sk4f scale_for_dest(const Sk4f& c) { - return c; -} + static void store4x(const Sk4f& c0, const Sk4f& c1, + const Sk4f& c2, const Sk4f& c3, + Type* dst) { + store(c0, dst + 0); + store(c1, dst + 1); + store(c2, dst + 2); + store(c3, dst + 3); + } +}; -template<> -inline Sk4f scale_for_dest(const Sk4f& c) { - return c * 255; -} +template +struct DstTraits { + using PM = PremulTraits; + using Type = uint64_t; -template -Sk4f dst_swizzle(const SkPM4f&); + static Sk4f load(const SkPM4f& c) { + return c.to4f(); + } -template<> -inline Sk4f dst_swizzle(const SkPM4f& c) { - return c.to4f(); -} + static void store(const Sk4f& c, Type* dst) { + *dst = SkFloatToHalf_01(PM::apply(c)); + } -template<> -inline Sk4f dst_swizzle(const SkPM4f& c) { - return c.to4f_pmorder(); -} + static void store(const Sk4f& c, Type* dst, int n) { + sk_memset64(dst, SkFloatToHalf_01(PM::apply(c)), n); + } -template<> -inline Sk4f dst_swizzle(const SkPM4f& c) { - return c.to4f(); -} + static void store4x(const Sk4f& c0, const Sk4f& c1, + const Sk4f& c2, const Sk4f& c3, + Type* dst) { + store(c0, dst + 0); + store(c1, dst + 1); + store(c2, dst + 2); + store(c3, dst + 3); + } +}; -} +template +struct DstTraits { + using PM = PremulTraits; + using Type = SkPM4f; + + static Sk4f load(const SkPM4f& c) { + return c.to4f(); + } + + static void store(const Sk4f& c, Type* dst) { + PM::apply(c).store(dst->fVec); + } + + static void store(const Sk4f& c, Type* dst, int n) { + const Sk4f pmc = PM::apply(c); + for (int i = 0; i < n; ++i) { + pmc.store(dst[i].fVec); + } + } + + static void store4x(const Sk4f& c0, const Sk4f& c1, + const Sk4f& c2, const Sk4f& c3, + Type* dst) { + store(c0, dst + 0); + store(c1, dst + 1); + store(c2, dst + 2); + store(c3, dst + 3); + } +}; + +} // anonymous namespace #endif // Sk4fGradientPriv_DEFINED diff --git a/src/effects/gradients/Sk4fLinearGradient.cpp b/src/effects/gradients/Sk4fLinearGradient.cpp index 84b266accd..f4bb4a7d18 100644 --- a/src/effects/gradients/Sk4fLinearGradient.cpp +++ b/src/effects/gradients/Sk4fLinearGradient.cpp @@ -6,68 +6,12 @@ */ #include "Sk4fLinearGradient.h" -#include "SkUtils.h" #include "SkXfermode.h" namespace { -template -void fill(const Sk4f& c, DstType* dst, int n); - -template<> -void fill - (const Sk4f& c, SkPM4f* dst, int n) { - while (n > 0) { - c.store(dst++); - n--; - } -} - -template<> -void fill - (const Sk4f& c, SkPM4f* dst, int n) { - fill(premul_4f(c), dst, n); -} - -template<> -void fill - (const Sk4f& c, SkPMColor* dst, int n) { - sk_memset32(dst, trunc_from_4f_255(c), n); -} - -template<> -void fill - (const Sk4f& c, SkPMColor* dst, int n) { - sk_memset32(dst, trunc_from_4f_255(c), n); -} - -template<> -void fill - (const Sk4f& c, SkPMColor* dst, int n) { - // FIXME: this assumes opaque colors. Handle unpremultiplication. - sk_memset32(dst, Sk4f_toS32(c), n); -} - -template<> -void fill - (const Sk4f& c, SkPMColor* dst, int n) { - sk_memset32(dst, Sk4f_toS32(premul_4f(c)), n); -} - -template<> -void fill - (const Sk4f& c, uint64_t* dst, int n) { - sk_memset64(dst, SkFloatToHalf_01(c), n); -} - -template<> -void fill - (const Sk4f& c, uint64_t* dst, int n) { - sk_memset64(dst, SkFloatToHalf_01(premul_4f(c)), n); -} - -template -void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { +template +void ramp(const Sk4f& c, const Sk4f& dc, typename DstTraits::Type dst[], int n) { SkASSERT(n > 0); const Sk4f dc2 = dc + dc; @@ -79,7 +23,7 @@ void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { Sk4f c3 = c1 + dc2; while (n >= 4) { - store4x(c0, c1, c2, c3, dst); + DstTraits::store4x(c0, c1, c2, c3, dst); dst += 4; c0 = c0 + dc4; @@ -89,12 +33,12 @@ void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { n -= 4; } if (n & 2) { - store(c0, dst++); - store(c1, dst++); + DstTraits::store(c0, dst++); + DstTraits::store(c1, dst++); c0 = c0 + dc2; } if (n & 1) { - store(c0, dst); + DstTraits::store(c0, dst); } } @@ -193,12 +137,10 @@ LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { // TODO: plumb dithering SkASSERT(count > 0); if (fColorsArePremul) { - this->shadePremulSpanshadePremulSpan(x, y, dst, count); } else { - this->shadePremulSpanshadePremulSpan(x, y, dst, count); } } @@ -213,50 +155,44 @@ LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { // TONOTDO: plumb dithering SkASSERT(count > 0); if (fColorsArePremul) { - this->shadePremulSpanshadePremulSpan(x, y, dst, count); } else { - this->shadePremulSpanshadePremulSpan(x, y, dst, count); } } -template +template void SkLinearGradient:: LinearGradient4fContext::shadePremulSpan(int x, int y, - DstType dst[], + typename DstTraits::Type dst[], int count) const { const SkLinearGradient& shader = static_cast(fShader); switch (shader.fTileMode) { case kClamp_TileMode: - this->shadeSpanInternalshadeSpanInternal(x, y, dst, count); break; case kRepeat_TileMode: - this->shadeSpanInternalshadeSpanInternal(x, y, dst, count); break; case kMirror_TileMode: - this->shadeSpanInternalshadeSpanInternal(x, y, dst, count); break; } } -template +template void SkLinearGradient:: LinearGradient4fContext::shadeSpanInternal(int x, int y, - DstType dst[], + typename DstTraits::Type dst[], int count) const { SkPoint pt; fDstToPosProc(fDstToPos, @@ -265,12 +201,12 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, &pt); const SkScalar fx = pinFx(pt.x()); const SkScalar dx = fDstToPos.getScaleX(); - LinearIntervalProcessor proc(fIntervals.begin(), - fIntervals.end() - 1, - this->findInterval(fx), - fx, - dx, - SkScalarNearlyZero(dx * count)); + LinearIntervalProcessor proc(fIntervals.begin(), + fIntervals.end() - 1, + this->findInterval(fx), + fx, + dx, + SkScalarNearlyZero(dx * count)); while (count > 0) { // What we really want here is SkTPin(advance, 1, count) // but that's a significant perf hit for >> stops; investigate. @@ -285,12 +221,12 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, || (n == count && proc.currentRampIsZero())); if (proc.currentRampIsZero()) { - fill(proc.currentColor(), - dst, n); + DstTraits::store(proc.currentColor(), + dst, n); } else { - ramp(proc.currentColor(), - proc.currentColorGrad(), - dst, n); + ramp(proc.currentColor(), + proc.currentColorGrad(), + dst, n); } proc.advance(SkIntToScalar(n)); @@ -299,7 +235,7 @@ LinearGradient4fContext::shadeSpanInternal(int x, int y, } } -template +template class SkLinearGradient:: LinearGradient4fContext::LinearIntervalProcessor { public: @@ -346,12 +282,11 @@ public: private: void compute_interval_props(SkScalar t) { - fDc = dst_swizzle(fInterval->fDc); - fCc = dst_swizzle(fInterval->fC0); - fCc = fCc + fDc * Sk4f(t); - fCc = scale_for_dest(fCc); - fDcDx = scale_for_dest(fDc * Sk4f(fDx)); - fZeroRamp = fIsVertical || fInterval->isZeroRamp(); + const Sk4f dC = DstTraits::load(fInterval->fDc); + fCc = DstTraits::load(fInterval->fC0); + fCc = fCc + dC * Sk4f(t); + fDcDx = dC * fDx; + fZeroRamp = fIsVertical || fInterval->isZeroRamp(); } const Interval* next_interval(const Interval* i) const { @@ -384,7 +319,6 @@ private: } // Current interval properties. - Sk4f fDc; // local color gradient (dc/dt) Sk4f fDcDx; // dst color gradient (dc/dx) Sk4f fCc; // current color, interpolated in dst SkScalar fAdvX; // remaining interval advance in dst @@ -476,18 +410,18 @@ LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixm if (dst.info().isLinear()) { if (ctx->fColorsArePremul) { - ctx->shadePremulSpan( + ctx->shadePremulSpan( x, y, dst.writable_addr32(x, y), count); } else { - ctx->shadePremulSpan( + ctx->shadePremulSpan( x, y, dst.writable_addr32(x, y), count); } } else { if (ctx->fColorsArePremul) { - ctx->shadePremulSpan( + ctx->shadePremulSpan( x, y, dst.writable_addr32(x, y), count); } else { - ctx->shadePremulSpan( + ctx->shadePremulSpan( x, y, dst.writable_addr32(x, y), count); } } @@ -501,10 +435,10 @@ LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixm static_cast(state->fCtx); if (ctx->fColorsArePremul) { - ctx->shadePremulSpan( + ctx->shadePremulSpan( x, y, dst.writable_addr64(x, y), count); } else { - ctx->shadePremulSpan( + ctx->shadePremulSpan( x, y, dst.writable_addr64(x, y), count); } } diff --git a/src/effects/gradients/Sk4fLinearGradient.h b/src/effects/gradients/Sk4fLinearGradient.h index 30292c361f..dc7a179583 100644 --- a/src/effects/gradients/Sk4fLinearGradient.h +++ b/src/effects/gradients/Sk4fLinearGradient.h @@ -27,14 +27,16 @@ protected: private: using INHERITED = GradientShaderBase4fContext; - template + template class LinearIntervalProcessor; - template - void shadePremulSpan(int x, int y, DstType[], int count) const; + template + void shadePremulSpan(int x, int y, typename DstTraits::Type[], + int count) const; - template - void shadeSpanInternal(int x, int y, DstType[], int count) const; + template + void shadeSpanInternal(int x, int y, typename DstTraits::Type[], + int count) const; const Interval* findInterval(SkScalar fx) const; -- cgit v1.2.3