1 /* 2 * Copyright 2013 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 SkBitmapFilter_DEFINED 9 #define SkBitmapFilter_DEFINED 10 11 #include "SkFixed.h" 12 #include "SkMath.h" 13 #include "SkScalar.h" 14 15 #include "SkNx.h" 16 17 // size of the precomputed bitmap filter tables for high quality filtering. 18 // Used to precompute the shape of the filter kernel. 19 // Table size chosen from experiments to see where I could start to see a difference. 20 21 #define SKBITMAP_FILTER_TABLE_SIZE 128 22 23 class SkBitmapFilter { 24 public: SkBitmapFilter(float width)25 SkBitmapFilter(float width) : fWidth(width), fInvWidth(1.f/width) { 26 fPrecomputed = false; 27 fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1); 28 } ~SkBitmapFilter()29 virtual ~SkBitmapFilter() {} 30 lookupScalar(float x)31 SkScalar lookupScalar(float x) const { 32 if (!fPrecomputed) { 33 precomputeTable(); 34 } 35 int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); 36 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); 37 return fFilterTableScalar[filter_idx]; 38 } 39 width()40 float width() const { return fWidth; } invWidth()41 float invWidth() const { return fInvWidth; } 42 virtual float evaluate(float x) const = 0; 43 evaluate_n(float val,float diff,int count,float * output)44 virtual float evaluate_n(float val, float diff, int count, float* output) const { 45 float sum = 0; 46 for (int index = 0; index < count; index++) { 47 float filterValue = evaluate(val); 48 *output++ = filterValue; 49 sum += filterValue; 50 val += diff; 51 } 52 return sum; 53 } 54 55 protected: 56 float fWidth; 57 float fInvWidth; 58 float fLookupMultiplier; 59 60 mutable bool fPrecomputed; 61 mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE]; 62 63 private: precomputeTable()64 void precomputeTable() const { 65 fPrecomputed = true; 66 SkScalar *ftpScalar = fFilterTableScalar; 67 for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) { 68 float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_SIZE; 69 float filter_value = evaluate(fx); 70 *ftpScalar++ = filter_value; 71 } 72 } 73 }; 74 75 class SkMitchellFilter final : public SkBitmapFilter { 76 public: SkMitchellFilter()77 SkMitchellFilter() 78 : INHERITED(2) 79 , fB(1.f / 3.f) 80 , fC(1.f / 3.f) 81 , fA1(-fB - 6*fC) 82 , fB1(6*fB + 30*fC) 83 , fC1(-12*fB - 48*fC) 84 , fD1(8*fB + 24*fC) 85 , fA2(12 - 9*fB - 6*fC) 86 , fB2(-18 + 12*fB + 6*fC) 87 , fD2(6 - 2*fB) 88 {} 89 evaluate(float x)90 float evaluate(float x) const override { 91 x = fabsf(x); 92 if (x > 2.f) { 93 return 0; 94 } else if (x > 1.f) { 95 return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f); 96 } else { 97 return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f); 98 } 99 } 100 evalcore_n(const Sk4f & val)101 Sk4f evalcore_n(const Sk4f& val) const { 102 Sk4f x = val.abs(); 103 Sk4f over2 = x > Sk4f(2); 104 Sk4f over1 = x > Sk4f(1); 105 Sk4f poly1 = (((Sk4f(fA1) * x + Sk4f(fB1)) * x + Sk4f(fC1)) * x + Sk4f(fD1)) 106 * Sk4f(1.f/6.f); 107 Sk4f poly0 = ((Sk4f(fA2) * x + Sk4f(fB2)) * x*x + Sk4f(fD2)) * Sk4f(1.f/6.f); 108 return over2.thenElse(Sk4f(0), over1.thenElse(poly1, poly0)); 109 } 110 evaluate_n(float val,float diff,int count,float * output)111 float evaluate_n(float val, float diff, int count, float* output) const override { 112 Sk4f sum(0); 113 while (count >= 4) { 114 float v0 = val; 115 float v1 = val += diff; 116 float v2 = val += diff; 117 float v3 = val += diff; 118 val += diff; 119 Sk4f filterValue = evalcore_n(Sk4f(v0, v1, v2, v3)); 120 filterValue.store(output); 121 output += 4; 122 sum = sum + filterValue; 123 count -= 4; 124 } 125 float sums[4]; 126 sum.store(sums); 127 float result = sums[0] + sums[1] + sums[2] + sums[3]; 128 result += INHERITED::evaluate_n(val, diff, count, output); 129 return result; 130 } 131 132 protected: 133 float fB, fC; 134 float fA1, fB1, fC1, fD1; 135 float fA2, fB2, fD2; 136 private: 137 typedef SkBitmapFilter INHERITED; 138 }; 139 140 class SkGaussianFilter final : public SkBitmapFilter { 141 float fAlpha, fExpWidth; 142 143 public: 144 SkGaussianFilter(float a, float width = 2) SkBitmapFilter(width)145 : SkBitmapFilter(width) 146 , fAlpha(a) 147 , fExpWidth(expf(-a * width * width)) 148 {} 149 evaluate(float x)150 float evaluate(float x) const override { 151 return SkTMax(0.f, float(expf(-fAlpha*x*x) - fExpWidth)); 152 } 153 }; 154 155 class SkTriangleFilter final : public SkBitmapFilter { 156 public: SkBitmapFilter(width)157 SkTriangleFilter(float width = 1) : SkBitmapFilter(width) {} 158 evaluate(float x)159 float evaluate(float x) const override { 160 return SkTMax(0.f, fWidth - fabsf(x)); 161 } 162 }; 163 164 class SkBoxFilter final : public SkBitmapFilter { 165 public: SkBitmapFilter(width)166 SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {} 167 evaluate(float x)168 float evaluate(float x) const override { 169 return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f; 170 } 171 }; 172 173 class SkHammingFilter final : public SkBitmapFilter { 174 public: SkBitmapFilter(width)175 SkHammingFilter(float width = 1) : SkBitmapFilter(width) {} 176 evaluate(float x)177 float evaluate(float x) const override { 178 if (x <= -fWidth || x >= fWidth) { 179 return 0.0f; // Outside of the window. 180 } 181 if (x > -FLT_EPSILON && x < FLT_EPSILON) { 182 return 1.0f; // Special case the sinc discontinuity at the origin. 183 } 184 const float xpi = x * static_cast<float>(SK_ScalarPI); 185 186 return ((sk_float_sin(xpi) / xpi) * // sinc(x) 187 (0.54f + 0.46f * sk_float_cos(xpi / fWidth))); // hamming(x) 188 } 189 }; 190 191 class SkLanczosFilter final : public SkBitmapFilter { 192 public: SkBitmapFilter(width)193 SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {} 194 evaluate(float x)195 float evaluate(float x) const override { 196 if (x <= -fWidth || x >= fWidth) { 197 return 0.0f; // Outside of the window. 198 } 199 if (x > -FLT_EPSILON && x < FLT_EPSILON) { 200 return 1.0f; // Special case the discontinuity at the origin. 201 } 202 float xpi = x * static_cast<float>(SK_ScalarPI); 203 return (sk_float_sin(xpi) / xpi) * // sinc(x) 204 sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth) 205 } 206 }; 207 208 209 #endif 210