OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkBitmapFilter_DEFINED | 8 #ifndef SkBitmapFilter_DEFINED |
9 #define SkBitmapFilter_DEFINED | 9 #define SkBitmapFilter_DEFINED |
10 | 10 |
11 #include "SkFixed.h" | 11 #include "SkFixed.h" |
12 #include "SkMath.h" | 12 #include "SkMath.h" |
13 #include "SkScalar.h" | 13 #include "SkScalar.h" |
14 | 14 |
15 #ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER | 15 #ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER |
16 #include "SkNx.h" | 16 #include "SkNx.h" |
17 #endif | 17 #endif |
18 | 18 |
19 // size of the precomputed bitmap filter tables for high quality filtering. | 19 // size of the precomputed bitmap filter tables for high quality filtering. |
20 // Used to precompute the shape of the filter kernel. | 20 // Used to precompute the shape of the filter kernel. |
21 // Table size chosen from experiments to see where I could start to see a differ
ence. | 21 // Table size chosen from experiments to see where I could start to see a differ
ence. |
22 | 22 |
23 #define SKBITMAP_FILTER_TABLE_SIZE 128 | 23 #define SKBITMAP_FILTER_TABLE_SIZE 128 |
24 | 24 |
25 class SkBitmapFilter { | 25 class SkBitmapFilter { |
26 public: | 26 public: |
27 SkBitmapFilter(float width) | 27 SkBitmapFilter(float width) : fWidth(width), fInvWidth(1.f/width) { |
28 : fWidth(width), fInvWidth(1.f/width) { | 28 fPrecomputed = false; |
29 fPrecomputed = false; | 29 fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1); |
30 fLookupMultiplier = this->invWidth() * (SKBITMAP_FILTER_TABLE_SIZE-1); | 30 } |
31 } | 31 virtual ~SkBitmapFilter() {} |
32 | 32 |
33 SkFixed lookup(float x) const { | 33 SkFixed lookup(float x) const { |
34 if (!fPrecomputed) { | 34 if (!fPrecomputed) { |
35 precomputeTable(); | 35 precomputeTable(); |
36 } | 36 } |
37 int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); | 37 int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); |
38 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); | 38 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); |
39 return fFilterTable[filter_idx]; | 39 return fFilterTable[filter_idx]; |
40 } | 40 } |
41 | 41 |
42 SkScalar lookupScalar(float x) const { | 42 SkScalar lookupScalar(float x) const { |
43 if (!fPrecomputed) { | 43 if (!fPrecomputed) { |
44 precomputeTable(); | 44 precomputeTable(); |
45 } | 45 } |
46 int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); | 46 int filter_idx = int(sk_float_abs(x * fLookupMultiplier)); |
47 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); | 47 SkASSERT(filter_idx < SKBITMAP_FILTER_TABLE_SIZE); |
48 return fFilterTableScalar[filter_idx]; | 48 return fFilterTableScalar[filter_idx]; |
49 } | 49 } |
50 | 50 |
51 float width() const { return fWidth; } | 51 float width() const { return fWidth; } |
52 float invWidth() const { return fInvWidth; } | 52 float invWidth() const { return fInvWidth; } |
53 virtual float evaluate(float x) const = 0; | 53 virtual float evaluate(float x) const = 0; |
54 | 54 |
55 #ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER | 55 #ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER |
56 virtual float evaluate_n(float val, float diff, int count, float* output)
const { | 56 virtual float evaluate_n(float val, float diff, int count, float* output) co
nst { |
57 float sum = 0; | 57 float sum = 0; |
58 for (int index = 0; index < count; index++) { | 58 for (int index = 0; index < count; index++) { |
59 float filterValue = evaluate(val); | 59 float filterValue = evaluate(val); |
60 *output++ = filterValue; | 60 *output++ = filterValue; |
61 sum += filterValue; | 61 sum += filterValue; |
62 val += diff; | 62 val += diff; |
63 } | 63 } |
64 return sum; | 64 return sum; |
65 } | 65 } |
66 #endif | 66 #endif |
67 | 67 |
68 virtual ~SkBitmapFilter() {} | 68 static SkBitmapFilter* Allocate(); |
69 | 69 |
70 static SkBitmapFilter* Allocate(); | 70 protected: |
71 protected: | 71 float fWidth; |
72 float fWidth; | 72 float fInvWidth; |
73 float fInvWidth; | 73 float fLookupMultiplier; |
74 | 74 |
75 float fLookupMultiplier; | 75 mutable bool fPrecomputed; |
| 76 mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE]; |
| 77 mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE]; |
76 | 78 |
77 mutable bool fPrecomputed; | 79 private: |
78 mutable SkFixed fFilterTable[SKBITMAP_FILTER_TABLE_SIZE]; | 80 void precomputeTable() const { |
79 mutable SkScalar fFilterTableScalar[SKBITMAP_FILTER_TABLE_SIZE]; | 81 fPrecomputed = true; |
80 private: | 82 SkFixed *ftp = fFilterTable; |
81 void precomputeTable() const { | 83 SkScalar *ftpScalar = fFilterTableScalar; |
82 fPrecomputed = true; | 84 for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) { |
83 SkFixed *ftp = fFilterTable; | 85 float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABLE_
SIZE; |
84 SkScalar *ftpScalar = fFilterTableScalar; | 86 float filter_value = evaluate(fx); |
85 for (int x = 0; x < SKBITMAP_FILTER_TABLE_SIZE; ++x) { | 87 *ftpScalar++ = filter_value; |
86 float fx = ((float)x + .5f) * this->width() / SKBITMAP_FILTER_TABL
E_SIZE; | 88 *ftp++ = SkFloatToFixed(filter_value); |
87 float filter_value = evaluate(fx); | 89 } |
88 *ftpScalar++ = filter_value; | 90 } |
89 *ftp++ = SkFloatToFixed(filter_value); | |
90 } | |
91 } | |
92 }; | 91 }; |
93 | 92 |
94 class SkMitchellFilter : public SkBitmapFilter { | 93 class SkMitchellFilter final : public SkBitmapFilter { |
95 public: | 94 public: |
96 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER | 95 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER |
97 SkMitchellFilter() | 96 SkMitchellFilter() : INHERITED(2), B(1.f / 3), C(1.f / 3) {} |
98 : INHERITED(2), B(1.f / 3), C(1.f / 3) { | |
99 } | |
100 #else | 97 #else |
101 SkMitchellFilter() | 98 SkMitchellFilter() |
102 : INHERITED(2) | 99 : INHERITED(2) |
103 , fB(1.f / 3.f) | 100 , fB(1.f / 3.f) |
104 , fC(1.f / 3.f) | 101 , fC(1.f / 3.f) |
105 , fA1(-fB - 6*fC) | 102 , fA1(-fB - 6*fC) |
106 , fB1(6*fB + 30*fC) | 103 , fB1(6*fB + 30*fC) |
107 , fC1(-12*fB - 48*fC) | 104 , fC1(-12*fB - 48*fC) |
108 , fD1(8*fB + 24*fC) | 105 , fD1(8*fB + 24*fC) |
109 , fA2(12 - 9*fB - 6*fC) | 106 , fA2(12 - 9*fB - 6*fC) |
110 , fB2(-18 + 12*fB + 6*fC) | 107 , fB2(-18 + 12*fB + 6*fC) |
111 , fD2(6 - 2*fB) { | 108 , fD2(6 - 2*fB) |
112 } | 109 {} |
113 #endif | 110 #endif |
114 | 111 |
115 float evaluate(float x) const override { | 112 float evaluate(float x) const override { |
116 x = fabsf(x); | 113 x = fabsf(x); |
117 if (x > 2.f) { | 114 if (x > 2.f) { |
118 return 0; | 115 return 0; |
119 } else if (x > 1.f) { | 116 } else if (x > 1.f) { |
120 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER | 117 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER |
121 return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x + | 118 return ((-B - 6*C) * x*x*x + (6*B + 30*C) * x*x + |
122 (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f); | 119 (-12*B - 48*C) * x + (8*B + 24*C)) * (1.f/6.f); |
123 #else | 120 #else |
124 return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f); | 121 return (((fA1 * x + fB1) * x + fC1) * x + fD1) * (1.f/6.f); |
125 #endif | 122 #endif |
126 } else { | 123 } else { |
127 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER | 124 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER |
128 return ((12 - 9*B - 6*C) * x*x*x + | 125 return ((12 - 9*B - 6*C) * x*x*x + |
129 (-18 + 12*B + 6*C) * x*x + | 126 (-18 + 12*B + 6*C) * x*x + |
130 (6 - 2*B)) * (1.f/6.f); | 127 (6 - 2*B)) * (1.f/6.f); |
131 #else | 128 #else |
132 return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f); | 129 return ((fA2 * x + fB2) * x*x + fD2) * (1.f/6.f); |
133 #endif | 130 #endif |
134 } | 131 } |
135 } | 132 } |
136 | 133 |
137 #ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER | 134 #ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER |
138 // TODO : native Sk4f abs | 135 // TODO : native Sk4f abs |
139 static Sk4f abs(const Sk4f& x) { | 136 static Sk4f abs(const Sk4f& x) { |
140 Sk4f neg = x < Sk4f(0); | 137 Sk4f neg = x < Sk4f(0); |
141 return neg.thenElse(Sk4f(0) - x, x); | 138 return neg.thenElse(Sk4f(0) - x, x); |
142 } | 139 } |
143 | 140 |
144 Sk4f evalcore_n(const Sk4f& val) const { | 141 Sk4f evalcore_n(const Sk4f& val) const { |
145 Sk4f x = abs(val); | 142 Sk4f x = abs(val); |
146 Sk4f over2 = x > Sk4f(2); | 143 Sk4f over2 = x > Sk4f(2); |
147 Sk4f over1 = x > Sk4f(1); | 144 Sk4f over1 = x > Sk4f(1); |
148 Sk4f poly1 = (((Sk4f(fA1) * x + Sk4f(fB1)) * x + Sk4f(fC1)) * x + Sk4f
(fD1)) | 145 Sk4f poly1 = (((Sk4f(fA1) * x + Sk4f(fB1)) * x + Sk4f(fC1)) * x + Sk4f(f
D1)) |
149 * Sk4f(1.f/6.f); | 146 * Sk4f(1.f/6.f); |
150 Sk4f poly0 = ((Sk4f(fA2) * x + Sk4f(fB2)) * x*x + Sk4f(fD2)) * Sk4f(1.
f/6.f); | 147 Sk4f poly0 = ((Sk4f(fA2) * x + Sk4f(fB2)) * x*x + Sk4f(fD2)) * Sk4f(1.f/
6.f); |
151 return over2.thenElse(Sk4f(0), over1.thenElse(poly1, poly0)); | 148 return over2.thenElse(Sk4f(0), over1.thenElse(poly1, poly0)); |
152 } | 149 } |
153 | 150 |
154 float evaluate_n(float val, float diff, int count, float* output) const ov
erride { | 151 float evaluate_n(float val, float diff, int count, float* output) const over
ride { |
155 Sk4f sum(0); | 152 Sk4f sum(0); |
156 while (count >= 4) { | 153 while (count >= 4) { |
157 float v0 = val; | 154 float v0 = val; |
158 float v1 = val += diff; | 155 float v1 = val += diff; |
159 float v2 = val += diff; | 156 float v2 = val += diff; |
160 float v3 = val += diff; | 157 float v3 = val += diff; |
161 val += diff; | 158 val += diff; |
162 Sk4f filterValue = evalcore_n(Sk4f(v0, v1, v2, v3)); | 159 Sk4f filterValue = evalcore_n(Sk4f(v0, v1, v2, v3)); |
163 filterValue.store(output); | 160 filterValue.store(output); |
164 output += 4; | 161 output += 4; |
165 sum = sum + filterValue; | 162 sum = sum + filterValue; |
166 count -= 4; | 163 count -= 4; |
167 } | 164 } |
168 float sums[4]; | 165 float sums[4]; |
169 sum.store(sums); | 166 sum.store(sums); |
170 float result = sums[0] + sums[1] + sums[2] + sums[3]; | 167 float result = sums[0] + sums[1] + sums[2] + sums[3]; |
171 result += INHERITED::evaluate_n(val, diff, count, output); | 168 result += INHERITED::evaluate_n(val, diff, count, output); |
172 return result; | 169 return result; |
173 } | 170 } |
174 #endif | 171 #endif |
175 | 172 |
176 protected: | 173 protected: |
177 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER | 174 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER |
178 float B, C; | 175 float B, C; |
179 #else | 176 #else |
180 float fB, fC; | 177 float fB, fC; |
181 float fA1, fB1, fC1, fD1; | 178 float fA1, fB1, fC1, fD1; |
182 float fA2, fB2, fD2; | 179 float fA2, fB2, fD2; |
183 #endif | 180 #endif |
184 private: | 181 private: |
185 typedef SkBitmapFilter INHERITED; | 182 typedef SkBitmapFilter INHERITED; |
186 }; | 183 }; |
187 | 184 |
188 class SkGaussianFilter: public SkBitmapFilter { | 185 class SkGaussianFilter final : public SkBitmapFilter { |
189 public: | 186 float fAlpha, fExpWidth; |
190 SkGaussianFilter(float a, float width=2.0f) | |
191 : SkBitmapFilter(width), alpha(a), expWidth(expf(-alpha * width * width))
{ | |
192 } | |
193 | 187 |
194 float evaluate(float x) const override { | 188 public: |
195 return SkTMax(0.f, float(expf(-alpha*x*x) - expWidth)); | 189 SkGaussianFilter(float a, float width = 2) |
196 } | 190 : SkBitmapFilter(width) |
197 protected: | 191 , fAlpha(a) |
198 float alpha, expWidth; | 192 , fExpWidth(expf(-a * width * width)) |
| 193 {} |
| 194 |
| 195 float evaluate(float x) const override { |
| 196 return SkTMax(0.f, float(expf(-fAlpha*x*x) - fExpWidth)); |
| 197 } |
199 }; | 198 }; |
200 | 199 |
201 class SkTriangleFilter: public SkBitmapFilter { | 200 class SkTriangleFilter final : public SkBitmapFilter { |
202 public: | 201 public: |
203 SkTriangleFilter(float width=1) | 202 SkTriangleFilter(float width = 1) : SkBitmapFilter(width) {} |
204 : SkBitmapFilter(width) { | |
205 } | |
206 | 203 |
207 float evaluate(float x) const override { | 204 float evaluate(float x) const override { |
208 return SkTMax(0.f, fWidth - fabsf(x)); | 205 return SkTMax(0.f, fWidth - fabsf(x)); |
209 } | 206 } |
210 protected: | |
211 }; | 207 }; |
212 | 208 |
213 class SkBoxFilter: public SkBitmapFilter { | 209 class SkBoxFilter final : public SkBitmapFilter { |
214 public: | 210 public: |
215 SkBoxFilter(float width=0.5f) | 211 SkBoxFilter(float width = 0.5f) : SkBitmapFilter(width) {} |
216 : SkBitmapFilter(width) { | |
217 } | |
218 | 212 |
219 float evaluate(float x) const override { | 213 float evaluate(float x) const override { |
220 return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f; | 214 return (x >= -fWidth && x < fWidth) ? 1.0f : 0.0f; |
221 } | 215 } |
222 protected: | |
223 }; | 216 }; |
224 | 217 |
225 class SkHammingFilter: public SkBitmapFilter { | 218 class SkHammingFilter final : public SkBitmapFilter { |
226 public: | 219 public: |
227 SkHammingFilter(float width=1.f) | 220 SkHammingFilter(float width = 1) : SkBitmapFilter(width) {} |
228 : SkBitmapFilter(width) { | 221 |
229 } | |
230 float evaluate(float x) const override { | 222 float evaluate(float x) const override { |
231 if (x <= -fWidth || x >= fWidth) { | 223 if (x <= -fWidth || x >= fWidth) { |
232 return 0.0f; // Outside of the window. | 224 return 0.0f; // Outside of the window. |
233 } | 225 } |
234 if (x > -FLT_EPSILON && x < FLT_EPSILON) { | 226 if (x > -FLT_EPSILON && x < FLT_EPSILON) { |
235 return 1.0f; // Special case the sinc discontinuity at the origin. | 227 return 1.0f; // Special case the sinc discontinuity at the origin. |
236 } | 228 } |
237 const float xpi = x * static_cast<float>(SK_ScalarPI); | 229 const float xpi = x * static_cast<float>(SK_ScalarPI); |
238 | 230 |
239 return ((sk_float_sin(xpi) / xpi) * // sinc(x) | 231 return ((sk_float_sin(xpi) / xpi) * // sinc(x) |
240 (0.54f + 0.46f * sk_float_cos(xpi / fWidth))); // hamming(x) | 232 (0.54f + 0.46f * sk_float_cos(xpi / fWidth))); // hamming(x) |
241 } | 233 } |
242 }; | 234 }; |
243 | 235 |
244 class SkLanczosFilter: public SkBitmapFilter { | 236 class SkLanczosFilter final : public SkBitmapFilter { |
245 public: | 237 public: |
246 SkLanczosFilter(float width=3.f) | 238 SkLanczosFilter(float width = 3.f) : SkBitmapFilter(width) {} |
247 : SkBitmapFilter(width) { | |
248 } | |
249 | 239 |
250 float evaluate(float x) const override { | 240 float evaluate(float x) const override { |
251 if (x <= -fWidth || x >= fWidth) { | 241 if (x <= -fWidth || x >= fWidth) { |
252 return 0.0f; // Outside of the window. | 242 return 0.0f; // Outside of the window. |
253 } | 243 } |
254 if (x > -FLT_EPSILON && x < FLT_EPSILON) { | 244 if (x > -FLT_EPSILON && x < FLT_EPSILON) { |
255 return 1.0f; // Special case the discontinuity at the origin. | 245 return 1.0f; // Special case the discontinuity at the origin. |
256 } | 246 } |
257 float xpi = x * static_cast<float>(SK_ScalarPI); | 247 float xpi = x * static_cast<float>(SK_ScalarPI); |
258 return (sk_float_sin(xpi) / xpi) * // sinc(x) | 248 return (sk_float_sin(xpi) / xpi) * // sinc(x) |
259 sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth
) | 249 sk_float_sin(xpi / fWidth) / (xpi / fWidth); // sinc(x/fWidth) |
260 } | 250 } |
261 }; | 251 }; |
262 | 252 |
263 | 253 |
264 #endif | 254 #endif |
OLD | NEW |