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 #include "SkMipMap.h" | 8 #include "SkMipMap.h" |
9 #include "SkBitmap.h" | 9 #include "SkBitmap.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 #include "SkHalf.h" |
11 #include "SkMath.h" | 12 #include "SkMath.h" |
12 #include "SkNx.h" | 13 #include "SkNx.h" |
13 #include "SkTypes.h" | 14 #include "SkTypes.h" |
14 | 15 |
15 // | 16 // |
16 // ColorTypeFilter is the "Type" we pass to some downsample template functions. | 17 // ColorTypeFilter is the "Type" we pass to some downsample template functions. |
17 // It controls how we expand a pixel into a large type, with space between each
component, | 18 // It controls how we expand a pixel into a large type, with space between each
component, |
18 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates | 19 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates |
19 // in the expanded type. | 20 // in the expanded type. |
20 // | 21 // |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 struct ColorTypeFilter_8 { | 64 struct ColorTypeFilter_8 { |
64 typedef uint8_t Type; | 65 typedef uint8_t Type; |
65 static unsigned Expand(unsigned x) { | 66 static unsigned Expand(unsigned x) { |
66 return x; | 67 return x; |
67 } | 68 } |
68 static uint8_t Compact(unsigned x) { | 69 static uint8_t Compact(unsigned x) { |
69 return (uint8_t)x; | 70 return (uint8_t)x; |
70 } | 71 } |
71 }; | 72 }; |
72 | 73 |
| 74 struct ColorTypeFilter_F16 { |
| 75 typedef uint64_t Type; // SkHalf x4 |
| 76 static Sk4f Expand(uint64_t x) { |
| 77 return SkHalfToFloat_01(x); |
| 78 } |
| 79 static uint64_t Compact(const Sk4f& x) { |
| 80 return SkFloatToHalf_01(x); |
| 81 } |
| 82 }; |
| 83 |
73 template <typename T> T add_121(const T& a, const T& b, const T& c) { | 84 template <typename T> T add_121(const T& a, const T& b, const T& c) { |
74 return a + b + b + c; | 85 return a + b + b + c; |
75 } | 86 } |
76 | 87 |
| 88 template <typename T> T shift_right(const T& x, int bits) { |
| 89 return x >> bits; |
| 90 } |
| 91 |
| 92 Sk4f shift_right(const Sk4f& x, int bits) { |
| 93 return x * (1.0f / (1 << bits)); |
| 94 } |
| 95 |
| 96 template <typename T> T shift_left(const T& x, int bits) { |
| 97 return x << bits; |
| 98 } |
| 99 |
| 100 Sk4f shift_left(const Sk4f& x, int bits) { |
| 101 return x * (1 << bits); |
| 102 } |
| 103 |
77 // | 104 // |
78 // To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50
,50) | 105 // To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50
,50) |
79 // If the starting dimension is odd, we floor the size of the lower level (e.g.
101 -> 50) | 106 // If the starting dimension is odd, we floor the size of the lower level (e.g.
101 -> 50) |
80 // In those (odd) cases, we use a triangle filter, with 1-pixel overlap between
samplings, | 107 // In those (odd) cases, we use a triangle filter, with 1-pixel overlap between
samplings, |
81 // else for even cases, we just use a 2x box filter. | 108 // else for even cases, we just use a 2x box filter. |
82 // | 109 // |
83 // This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indica
tes the number of | 110 // This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indica
tes the number of |
84 // src pixels we need to sample in each dimension to produce 1 dst pixel. | 111 // src pixels we need to sample in each dimension to produce 1 dst pixel. |
85 // | 112 // |
86 // OpenGL expects a full mipmap stack to contain anisotropic space as well. | 113 // OpenGL expects a full mipmap stack to contain anisotropic space as well. |
87 // This means a 100x1 image would continue down to a 50x1 image, 25x1 image... | 114 // This means a 100x1 image would continue down to a 50x1 image, 25x1 image... |
88 // Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1. | 115 // Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1. |
89 | 116 |
90 template <typename F> void downsample_1_2(void* dst, const void* src, size_t src
RB, int count) { | 117 template <typename F> void downsample_1_2(void* dst, const void* src, size_t src
RB, int count) { |
91 SkASSERT(count > 0); | 118 SkASSERT(count > 0); |
92 auto p0 = static_cast<const typename F::Type*>(src); | 119 auto p0 = static_cast<const typename F::Type*>(src); |
93 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 120 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
94 auto d = static_cast<typename F::Type*>(dst); | 121 auto d = static_cast<typename F::Type*>(dst); |
95 | 122 |
96 for (int i = 0; i < count; ++i) { | 123 for (int i = 0; i < count; ++i) { |
97 auto c00 = F::Expand(p0[0]); | 124 auto c00 = F::Expand(p0[0]); |
98 auto c10 = F::Expand(p1[0]); | 125 auto c10 = F::Expand(p1[0]); |
99 | 126 |
100 auto c = c00 + c10; | 127 auto c = c00 + c10; |
101 d[i] = F::Compact(c >> 1); | 128 d[i] = F::Compact(shift_right(c, 1)); |
102 p0 += 2; | 129 p0 += 2; |
103 p1 += 2; | 130 p1 += 2; |
104 } | 131 } |
105 } | 132 } |
106 | 133 |
107 template <typename F> void downsample_1_3(void* dst, const void* src, size_t src
RB, int count) { | 134 template <typename F> void downsample_1_3(void* dst, const void* src, size_t src
RB, int count) { |
108 SkASSERT(count > 0); | 135 SkASSERT(count > 0); |
109 auto p0 = static_cast<const typename F::Type*>(src); | 136 auto p0 = static_cast<const typename F::Type*>(src); |
110 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 137 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
111 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 138 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
112 auto d = static_cast<typename F::Type*>(dst); | 139 auto d = static_cast<typename F::Type*>(dst); |
113 | 140 |
114 for (int i = 0; i < count; ++i) { | 141 for (int i = 0; i < count; ++i) { |
115 auto c00 = F::Expand(p0[0]); | 142 auto c00 = F::Expand(p0[0]); |
116 auto c10 = F::Expand(p1[0]); | 143 auto c10 = F::Expand(p1[0]); |
117 auto c20 = F::Expand(p2[0]); | 144 auto c20 = F::Expand(p2[0]); |
118 | 145 |
119 auto c = add_121(c00, c10, c20); | 146 auto c = add_121(c00, c10, c20); |
120 d[i] = F::Compact(c >> 2); | 147 d[i] = F::Compact(shift_right(c, 2)); |
121 p0 += 2; | 148 p0 += 2; |
122 p1 += 2; | 149 p1 += 2; |
123 p2 += 2; | 150 p2 += 2; |
124 } | 151 } |
125 } | 152 } |
126 | 153 |
127 template <typename F> void downsample_2_1(void* dst, const void* src, size_t src
RB, int count) { | 154 template <typename F> void downsample_2_1(void* dst, const void* src, size_t src
RB, int count) { |
128 SkASSERT(count > 0); | 155 SkASSERT(count > 0); |
129 auto p0 = static_cast<const typename F::Type*>(src); | 156 auto p0 = static_cast<const typename F::Type*>(src); |
130 auto d = static_cast<typename F::Type*>(dst); | 157 auto d = static_cast<typename F::Type*>(dst); |
131 | 158 |
132 for (int i = 0; i < count; ++i) { | 159 for (int i = 0; i < count; ++i) { |
133 auto c00 = F::Expand(p0[0]); | 160 auto c00 = F::Expand(p0[0]); |
134 auto c01 = F::Expand(p0[1]); | 161 auto c01 = F::Expand(p0[1]); |
135 | 162 |
136 auto c = c00 + c01; | 163 auto c = c00 + c01; |
137 d[i] = F::Compact(c >> 1); | 164 d[i] = F::Compact(shift_right(c, 1)); |
138 p0 += 2; | 165 p0 += 2; |
139 } | 166 } |
140 } | 167 } |
141 | 168 |
142 template <typename F> void downsample_2_2(void* dst, const void* src, size_t src
RB, int count) { | 169 template <typename F> void downsample_2_2(void* dst, const void* src, size_t src
RB, int count) { |
143 SkASSERT(count > 0); | 170 SkASSERT(count > 0); |
144 auto p0 = static_cast<const typename F::Type*>(src); | 171 auto p0 = static_cast<const typename F::Type*>(src); |
145 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 172 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
146 auto d = static_cast<typename F::Type*>(dst); | 173 auto d = static_cast<typename F::Type*>(dst); |
147 | 174 |
148 for (int i = 0; i < count; ++i) { | 175 for (int i = 0; i < count; ++i) { |
149 auto c00 = F::Expand(p0[0]); | 176 auto c00 = F::Expand(p0[0]); |
150 auto c01 = F::Expand(p0[1]); | 177 auto c01 = F::Expand(p0[1]); |
151 auto c10 = F::Expand(p1[0]); | 178 auto c10 = F::Expand(p1[0]); |
152 auto c11 = F::Expand(p1[1]); | 179 auto c11 = F::Expand(p1[1]); |
153 | 180 |
154 auto c = c00 + c10 + c01 + c11; | 181 auto c = c00 + c10 + c01 + c11; |
155 d[i] = F::Compact(c >> 2); | 182 d[i] = F::Compact(shift_right(c, 2)); |
156 p0 += 2; | 183 p0 += 2; |
157 p1 += 2; | 184 p1 += 2; |
158 } | 185 } |
159 } | 186 } |
160 | 187 |
161 template <typename F> void downsample_2_3(void* dst, const void* src, size_t src
RB, int count) { | 188 template <typename F> void downsample_2_3(void* dst, const void* src, size_t src
RB, int count) { |
162 SkASSERT(count > 0); | 189 SkASSERT(count > 0); |
163 auto p0 = static_cast<const typename F::Type*>(src); | 190 auto p0 = static_cast<const typename F::Type*>(src); |
164 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 191 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
165 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 192 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
166 auto d = static_cast<typename F::Type*>(dst); | 193 auto d = static_cast<typename F::Type*>(dst); |
167 | 194 |
168 for (int i = 0; i < count; ++i) { | 195 for (int i = 0; i < count; ++i) { |
169 auto c00 = F::Expand(p0[0]); | 196 auto c00 = F::Expand(p0[0]); |
170 auto c01 = F::Expand(p0[1]); | 197 auto c01 = F::Expand(p0[1]); |
171 auto c10 = F::Expand(p1[0]); | 198 auto c10 = F::Expand(p1[0]); |
172 auto c11 = F::Expand(p1[1]); | 199 auto c11 = F::Expand(p1[1]); |
173 auto c20 = F::Expand(p2[0]); | 200 auto c20 = F::Expand(p2[0]); |
174 auto c21 = F::Expand(p2[1]); | 201 auto c21 = F::Expand(p2[1]); |
175 | 202 |
176 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); | 203 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); |
177 d[i] = F::Compact(c >> 3); | 204 d[i] = F::Compact(shift_right(c, 3)); |
178 p0 += 2; | 205 p0 += 2; |
179 p1 += 2; | 206 p1 += 2; |
180 p2 += 2; | 207 p2 += 2; |
181 } | 208 } |
182 } | 209 } |
183 | 210 |
184 template <typename F> void downsample_3_1(void* dst, const void* src, size_t src
RB, int count) { | 211 template <typename F> void downsample_3_1(void* dst, const void* src, size_t src
RB, int count) { |
185 SkASSERT(count > 0); | 212 SkASSERT(count > 0); |
186 auto p0 = static_cast<const typename F::Type*>(src); | 213 auto p0 = static_cast<const typename F::Type*>(src); |
187 auto d = static_cast<typename F::Type*>(dst); | 214 auto d = static_cast<typename F::Type*>(dst); |
188 | 215 |
189 auto c02 = F::Expand(p0[0]); | 216 auto c02 = F::Expand(p0[0]); |
190 for (int i = 0; i < count; ++i) { | 217 for (int i = 0; i < count; ++i) { |
191 auto c00 = c02; | 218 auto c00 = c02; |
192 auto c01 = F::Expand(p0[1]); | 219 auto c01 = F::Expand(p0[1]); |
193 c02 = F::Expand(p0[2]); | 220 c02 = F::Expand(p0[2]); |
194 | 221 |
195 auto c = add_121(c00, c01, c02); | 222 auto c = add_121(c00, c01, c02); |
196 d[i] = F::Compact(c >> 2); | 223 d[i] = F::Compact(shift_right(c, 2)); |
197 p0 += 2; | 224 p0 += 2; |
198 } | 225 } |
199 } | 226 } |
200 | 227 |
201 template <typename F> void downsample_3_2(void* dst, const void* src, size_t src
RB, int count) { | 228 template <typename F> void downsample_3_2(void* dst, const void* src, size_t src
RB, int count) { |
202 SkASSERT(count > 0); | 229 SkASSERT(count > 0); |
203 auto p0 = static_cast<const typename F::Type*>(src); | 230 auto p0 = static_cast<const typename F::Type*>(src); |
204 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 231 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
205 auto d = static_cast<typename F::Type*>(dst); | 232 auto d = static_cast<typename F::Type*>(dst); |
206 | 233 |
207 auto c02 = F::Expand(p0[0]); | 234 auto c02 = F::Expand(p0[0]); |
208 auto c12 = F::Expand(p1[0]); | 235 auto c12 = F::Expand(p1[0]); |
209 for (int i = 0; i < count; ++i) { | 236 for (int i = 0; i < count; ++i) { |
210 auto c00 = c02; | 237 auto c00 = c02; |
211 auto c01 = F::Expand(p0[1]); | 238 auto c01 = F::Expand(p0[1]); |
212 c02 = F::Expand(p0[2]); | 239 c02 = F::Expand(p0[2]); |
213 auto c10 = c12; | 240 auto c10 = c12; |
214 auto c11 = F::Expand(p1[1]); | 241 auto c11 = F::Expand(p1[1]); |
215 c12 = F::Expand(p1[2]); | 242 c12 = F::Expand(p1[2]); |
216 | 243 |
217 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); | 244 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); |
218 d[i] = F::Compact(c >> 3); | 245 d[i] = F::Compact(shift_right(c, 3)); |
219 p0 += 2; | 246 p0 += 2; |
220 p1 += 2; | 247 p1 += 2; |
221 } | 248 } |
222 } | 249 } |
223 | 250 |
224 template <typename F> void downsample_3_3(void* dst, const void* src, size_t src
RB, int count) { | 251 template <typename F> void downsample_3_3(void* dst, const void* src, size_t src
RB, int count) { |
225 SkASSERT(count > 0); | 252 SkASSERT(count > 0); |
226 auto p0 = static_cast<const typename F::Type*>(src); | 253 auto p0 = static_cast<const typename F::Type*>(src); |
227 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 254 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
228 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 255 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
229 auto d = static_cast<typename F::Type*>(dst); | 256 auto d = static_cast<typename F::Type*>(dst); |
230 | 257 |
231 auto c02 = F::Expand(p0[0]); | 258 auto c02 = F::Expand(p0[0]); |
232 auto c12 = F::Expand(p1[0]); | 259 auto c12 = F::Expand(p1[0]); |
233 auto c22 = F::Expand(p2[0]); | 260 auto c22 = F::Expand(p2[0]); |
234 for (int i = 0; i < count; ++i) { | 261 for (int i = 0; i < count; ++i) { |
235 auto c00 = c02; | 262 auto c00 = c02; |
236 auto c01 = F::Expand(p0[1]); | 263 auto c01 = F::Expand(p0[1]); |
237 c02 = F::Expand(p0[2]); | 264 c02 = F::Expand(p0[2]); |
238 auto c10 = c12; | 265 auto c10 = c12; |
239 auto c11 = F::Expand(p1[1]); | 266 auto c11 = F::Expand(p1[1]); |
240 c12 = F::Expand(p1[2]); | 267 c12 = F::Expand(p1[2]); |
241 auto c20 = c22; | 268 auto c20 = c22; |
242 auto c21 = F::Expand(p2[1]); | 269 auto c21 = F::Expand(p2[1]); |
243 c22 = F::Expand(p2[2]); | 270 c22 = F::Expand(p2[2]); |
244 | 271 |
245 auto c = add_121(c00, c01, c02) + (add_121(c10, c11, c12) << 1) + add_12
1(c20, c21, c22); | 272 auto c = |
246 d[i] = F::Compact(c >> 4); | 273 add_121(c00, c01, c02) + |
| 274 shift_left(add_121(c10, c11, c12), 1) + |
| 275 add_121(c20, c21, c22); |
| 276 d[i] = F::Compact(shift_right(c, 4)); |
247 p0 += 2; | 277 p0 += 2; |
248 p1 += 2; | 278 p1 += 2; |
249 p2 += 2; | 279 p2 += 2; |
250 } | 280 } |
251 } | 281 } |
252 | 282 |
253 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 283 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
254 | 284 |
255 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { | 285 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { |
256 if (levelCount < 0) { | 286 if (levelCount < 0) { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 case kGray_8_SkColorType: | 343 case kGray_8_SkColorType: |
314 proc_1_2 = downsample_1_2<ColorTypeFilter_8>; | 344 proc_1_2 = downsample_1_2<ColorTypeFilter_8>; |
315 proc_1_3 = downsample_1_3<ColorTypeFilter_8>; | 345 proc_1_3 = downsample_1_3<ColorTypeFilter_8>; |
316 proc_2_1 = downsample_2_1<ColorTypeFilter_8>; | 346 proc_2_1 = downsample_2_1<ColorTypeFilter_8>; |
317 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; | 347 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; |
318 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; | 348 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; |
319 proc_3_1 = downsample_3_1<ColorTypeFilter_8>; | 349 proc_3_1 = downsample_3_1<ColorTypeFilter_8>; |
320 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; | 350 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; |
321 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; | 351 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; |
322 break; | 352 break; |
| 353 case kRGBA_F16_SkColorType: |
| 354 proc_1_2 = downsample_1_2<ColorTypeFilter_F16>; |
| 355 proc_1_3 = downsample_1_3<ColorTypeFilter_F16>; |
| 356 proc_2_1 = downsample_2_1<ColorTypeFilter_F16>; |
| 357 proc_2_2 = downsample_2_2<ColorTypeFilter_F16>; |
| 358 proc_2_3 = downsample_2_3<ColorTypeFilter_F16>; |
| 359 proc_3_1 = downsample_3_1<ColorTypeFilter_F16>; |
| 360 proc_3_2 = downsample_3_2<ColorTypeFilter_F16>; |
| 361 proc_3_3 = downsample_3_3<ColorTypeFilter_F16>; |
| 362 break; |
323 default: | 363 default: |
324 // TODO: We could build miplevels for kIndex8 if the levels were in
8888. | 364 // TODO: We could build miplevels for kIndex8 if the levels were in
8888. |
325 // Means using more ram, but the quality would be fine. | 365 // Means using more ram, but the quality would be fine. |
326 return nullptr; | 366 return nullptr; |
327 } | 367 } |
328 | 368 |
329 if (src.width() <= 1 && src.height() <= 1) { | 369 if (src.width() <= 1 && src.height() <= 1) { |
330 return nullptr; | 370 return nullptr; |
331 } | 371 } |
332 // whip through our loop to compute the exact size needed | 372 // whip through our loop to compute the exact size needed |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 return false; | 580 return false; |
541 } | 581 } |
542 if (index > fCount - 1) { | 582 if (index > fCount - 1) { |
543 return false; | 583 return false; |
544 } | 584 } |
545 if (levelPtr) { | 585 if (levelPtr) { |
546 *levelPtr = fLevels[index]; | 586 *levelPtr = fLevels[index]; |
547 } | 587 } |
548 return true; | 588 return true; |
549 } | 589 } |
OLD | NEW |