1 /* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef Sk4fGradientPriv_DEFINED 9 #define Sk4fGradientPriv_DEFINED 10 11 #include "SkColor.h" 12 #include "SkHalf.h" 13 #include "SkImageInfo.h" 14 #include "SkNx.h" 15 #include "SkPM4f.h" 16 #include "SkPM4fPriv.h" 17 #include "SkUtils.h" 18 19 // Templates shared by various 4f gradient flavors. 20 21 namespace { 22 23 enum class ApplyPremul { True, False }; 24 25 template <ApplyPremul> 26 struct PremulTraits; 27 28 template <> 29 struct PremulTraits<ApplyPremul::False> { 30 static Sk4f apply(const Sk4f& c) { return c; } 31 }; 32 33 template <> 34 struct PremulTraits<ApplyPremul::True> { 35 static Sk4f apply(const Sk4f& c) { 36 const float alpha = c[SkPM4f::A]; 37 // FIXME: portable swizzle? 38 return c * Sk4f(alpha, alpha, alpha, 1); 39 } 40 }; 41 42 // Struct encapsulating various dest-dependent ops: 43 // 44 // - load() Load a SkPM4f value into Sk4f. Normally called once per interval 45 // advance. Also applies a scale and swizzle suitable for DstType. 46 // 47 // - store() Store one Sk4f to dest. Optionally handles premul, color space 48 // conversion, etc. 49 // 50 // - store(count) Store the Sk4f value repeatedly to dest, count times. 51 // 52 // - store4x() Store 4 Sk4f values to dest (opportunistic optimization). 53 // 54 template <typename dst, ApplyPremul premul> 55 struct DstTraits; 56 57 template <ApplyPremul premul> 58 struct DstTraits<SkPMColor, premul> { 59 using PM = PremulTraits<premul>; 60 61 // For L32, prescaling by 255 saves a per-pixel multiplication when premul is not needed. 62 static Sk4f load(const SkPM4f& c) { 63 return premul == ApplyPremul::False 64 ? c.to4f_pmorder() * Sk4f(255) 65 : c.to4f_pmorder(); 66 } 67 68 static void store(const Sk4f& c, SkPMColor* dst, const Sk4f& bias) { 69 if (premul == ApplyPremul::False) { 70 // c is pre-scaled by 255 and pre-biased, just store. 71 SkNx_cast<uint8_t>(c).store(dst); 72 } else { 73 *dst = Sk4f_toL32(PM::apply(c) + bias); 74 } 75 } 76 77 static void store(const Sk4f& c, SkPMColor* dst, int n) { 78 SkPMColor pmc; 79 store(c, &pmc, Sk4f(0)); 80 sk_memset32(dst, pmc, n); 81 } 82 83 static void store4x(const Sk4f& c0, const Sk4f& c1, 84 const Sk4f& c2, const Sk4f& c3, 85 SkPMColor* dst, 86 const Sk4f& bias0, 87 const Sk4f& bias1) { 88 if (premul == ApplyPremul::False) { 89 // colors are pre-scaled and pre-biased. 90 Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); 91 } else { 92 store(c0, dst + 0, bias0); 93 store(c1, dst + 1, bias1); 94 store(c2, dst + 2, bias0); 95 store(c3, dst + 3, bias1); 96 } 97 } 98 99 static Sk4f pre_lerp_bias(const Sk4f& bias) { 100 // We can apply the bias before interpolation when the colors are premultiplied. 101 return premul == ApplyPremul::False ? bias : 0; 102 } 103 }; 104 105 template <ApplyPremul premul> 106 struct DstTraits<SkPM4f, premul> { 107 using PM = PremulTraits<premul>; 108 109 static Sk4f load(const SkPM4f& c) { 110 return c.to4f(); 111 } 112 113 static void store(const Sk4f& c, SkPM4f* dst, const Sk4f& /*bias*/) { 114 PM::apply(c).store(dst->fVec); 115 } 116 117 static void store(const Sk4f& c, SkPM4f* dst, int n) { 118 const Sk4f pmc = PM::apply(c); 119 for (int i = 0; i < n; ++i) { 120 pmc.store(dst[i].fVec); 121 } 122 } 123 124 static void store4x(const Sk4f& c0, const Sk4f& c1, 125 const Sk4f& c2, const Sk4f& c3, 126 SkPM4f* dst, 127 const Sk4f& bias0, const Sk4f& bias1) { 128 store(c0, dst + 0, bias0); 129 store(c1, dst + 1, bias1); 130 store(c2, dst + 2, bias0); 131 store(c3, dst + 3, bias1); 132 } 133 134 static Sk4f pre_lerp_bias(const Sk4f& /*bias*/) { 135 // For 4f dests we never bias. 136 return 0; 137 } 138 }; 139 140 } // anonymous namespace 141 142 #endif // Sk4fGradientPriv_DEFINED 143