| Index: src/effects/gradients/Sk4fGradientPriv.h
|
| diff --git a/src/effects/gradients/Sk4fGradientPriv.h b/src/effects/gradients/Sk4fGradientPriv.h
|
| index e9bc268b89cabc180d336e08d7fe0ba50a072503..4f71d3f14df6929d403872c1c22f7a014090ca42 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 <ApplyPremul premul>
|
| 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<typename DstType, SkColorProfileType, ApplyPremul premul>
|
| -void store(const Sk4f& color, DstType* dst);
|
| +template <ApplyPremul>
|
| +struct PremulTraits;
|
|
|
| -template<>
|
| -inline void store<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False>
|
| - (const Sk4f& c, SkPM4f* dst) {
|
| - c.store(dst);
|
| -}
|
| +template <>
|
| +struct PremulTraits<ApplyPremul::False> {
|
| + static Sk4f apply(const Sk4f& c) { return c; }
|
| +};
|
|
|
| -template<>
|
| -inline void store<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::True>
|
| - (const Sk4f& c, SkPM4f* dst) {
|
| - premul_4f(c).store(dst);
|
| -}
|
| +template <>
|
| +struct PremulTraits<ApplyPremul::True> {
|
| + 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 <DstType, ApplyPremul premul = ApplyPremul::False>
|
| +struct DstTraits;
|
|
|
| -template<>
|
| -inline void store<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False>
|
| - (const Sk4f& c, SkPMColor* dst) {
|
| - *dst = trunc_from_4f_255<ApplyPremul::False>(c);
|
| -}
|
| +template <ApplyPremul premul>
|
| +struct DstTraits<DstType::L32, premul> {
|
| + using Type = SkPMColor;
|
|
|
| -template<>
|
| -inline void store<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::True>
|
| - (const Sk4f& c, SkPMColor* dst) {
|
| - *dst = trunc_from_4f_255<ApplyPremul::True>(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<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::False>
|
| - (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<premul>(c);
|
| + }
|
|
|
| -template<>
|
| -inline void store<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::True>
|
| - (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<premul>(c), n);
|
| + }
|
|
|
| -template<>
|
| -inline void store<uint64_t, kLinear_SkColorProfileType, ApplyPremul::False>
|
| - (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<uint64_t, kLinear_SkColorProfileType, ApplyPremul::True>
|
| - (const Sk4f& c, uint64_t* dst) {
|
| - *dst = SkFloatToHalf_01(premul_4f(c));
|
| -}
|
| +template <ApplyPremul premul>
|
| +struct DstTraits<DstType::S32, premul> {
|
| + using PM = PremulTraits<premul>;
|
| + 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<typename DstType, SkColorProfileType profile, ApplyPremul premul>
|
| -inline void store4x(const Sk4f& c0,
|
| - const Sk4f& c1,
|
| - const Sk4f& c2,
|
| - const Sk4f& c3,
|
| - DstType* dst) {
|
| - store<DstType, profile, premul>(c0, dst++);
|
| - store<DstType, profile, premul>(c1, dst++);
|
| - store<DstType, profile, premul>(c2, dst++);
|
| - store<DstType, profile, premul>(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<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False>
|
| - (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<typename DstType, SkColorProfileType>
|
| -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<SkPMColor, kLinear_SkColorProfileType>(const Sk4f& c) {
|
| - return c * 255;
|
| -}
|
| +template <ApplyPremul premul>
|
| +struct DstTraits<DstType::F16, premul> {
|
| + using PM = PremulTraits<premul>;
|
| + using Type = uint64_t;
|
|
|
| -template<typename DstType>
|
| -Sk4f dst_swizzle(const SkPM4f&);
|
| + static Sk4f load(const SkPM4f& c) {
|
| + return c.to4f();
|
| + }
|
|
|
| -template<>
|
| -inline Sk4f dst_swizzle<SkPM4f>(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<SkPMColor>(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<uint64_t>(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 <ApplyPremul premul>
|
| +struct DstTraits<DstType::F32, premul> {
|
| + using PM = PremulTraits<premul>;
|
| + 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
|
|
|