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" |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
73 template <typename T> T add_121(const T& a, const T& b, const T& c) { | 73 template <typename T> T add_121(const T& a, const T& b, const T& c) { |
74 return a + b + b + c; | 74 return a + b + b + c; |
75 } | 75 } |
76 | 76 |
77 // | 77 // |
78 // To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50 ,50) | 78 // 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) | 79 // 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, | 80 // 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. | 81 // else for even cases, we just use a 2x box filter. |
82 // | 82 // |
83 // This produces 4 possible filters: 2x2 2x3 3x2 3x3 where WxH indicates the nu mber of src pixels | 83 // This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indica tes the number of |
84 // we need to sample in each dimension to produce 1 dst pixel. | 84 // src pixels we need to sample in each dimension to produce 1 dst pixel. |
85 // | 85 // |
86 // 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... | |
88 // Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1. | |
89 | |
90 template <typename F> void downsample_1_2(void* dst, const void* src, size_t src RB, int count) { | |
91 SkASSERT(count > 0); | |
92 auto p0 = static_cast<const typename F::Type*>(src); | |
93 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | |
94 auto d = static_cast<typename F::Type*>(dst); | |
95 | |
96 for (int i = 0; i < count; ++i) { | |
97 auto c00 = F::Expand(p0[0]); | |
98 auto c10 = F::Expand(p1[0]); | |
99 | |
100 auto c = c00 + c10; | |
101 d[i] = F::Compact(c >> 1); | |
102 p0 += 2; | |
103 p1 += 2; | |
104 } | |
105 } | |
106 | |
107 template <typename F> void downsample_1_3(void* dst, const void* src, size_t src RB, int count) { | |
108 SkASSERT(count > 0); | |
109 auto p0 = static_cast<const typename F::Type*>(src); | |
110 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | |
111 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | |
112 auto d = static_cast<typename F::Type*>(dst); | |
113 | |
114 for (int i = 0; i < count; ++i) { | |
115 auto c00 = F::Expand(p0[0]); | |
116 auto c10 = F::Expand(p1[0]); | |
117 auto c20 = F::Expand(p2[0]); | |
118 | |
119 auto c = add_121(c00, c10, c20); | |
120 d[i] = F::Compact(c >> 2); | |
121 p0 += 2; | |
122 p1 += 2; | |
123 p2 += 2; | |
124 } | |
125 } | |
126 | |
127 template <typename F> void downsample_2_1(void* dst, const void* src, size_t src RB, int count) { | |
128 SkASSERT(count > 0); | |
129 auto p0 = static_cast<const typename F::Type*>(src); | |
130 auto d = static_cast<typename F::Type*>(dst); | |
131 | |
132 for (int i = 0; i < count; ++i) { | |
133 auto c00 = F::Expand(p0[0]); | |
134 auto c01 = F::Expand(p0[1]); | |
135 | |
136 auto c = c00 + c01; | |
137 d[i] = F::Compact(c >> 1); | |
138 p0 += 2; | |
139 } | |
140 } | |
86 | 141 |
87 template <typename F> void downsample_2_2(void* dst, const void* src, size_t src RB, int count) { | 142 template <typename F> void downsample_2_2(void* dst, const void* src, size_t src RB, int count) { |
143 SkASSERT(count > 0); | |
reed1
2016/03/01 20:17:46
why remove this assert?
cblume
2016/03/01 20:39:29
I'm adding it.
The existing code has the assert so
| |
88 auto p0 = static_cast<const typename F::Type*>(src); | 144 auto p0 = static_cast<const typename F::Type*>(src); |
89 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 145 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
90 auto d = static_cast<typename F::Type*>(dst); | 146 auto d = static_cast<typename F::Type*>(dst); |
91 | 147 |
92 for (int i = 0; i < count; ++i) { | 148 for (int i = 0; i < count; ++i) { |
93 auto c00 = F::Expand(p0[0]); | 149 auto c00 = F::Expand(p0[0]); |
94 auto c01 = F::Expand(p0[1]); | 150 auto c01 = F::Expand(p0[1]); |
95 auto c10 = F::Expand(p1[0]); | 151 auto c10 = F::Expand(p1[0]); |
96 auto c11 = F::Expand(p1[1]); | 152 auto c11 = F::Expand(p1[1]); |
97 | 153 |
98 auto c = c00 + c10 + c01 + c11; | 154 auto c = c00 + c10 + c01 + c11; |
99 d[i] = F::Compact(c >> 2); | 155 d[i] = F::Compact(c >> 2); |
100 p0 += 2; | 156 p0 += 2; |
101 p1 += 2; | 157 p1 += 2; |
102 } | 158 } |
103 } | 159 } |
104 | 160 |
105 template <typename F> void downsample_3_2(void* dst, const void* src, size_t src RB, int count) { | 161 template <typename F> void downsample_2_3(void* dst, const void* src, size_t src RB, int count) { |
106 SkASSERT(count > 0); | 162 SkASSERT(count > 0); |
107 auto p0 = static_cast<const typename F::Type*>(src); | 163 auto p0 = static_cast<const typename F::Type*>(src); |
108 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 164 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
109 auto d = static_cast<typename F::Type*>(dst); | |
110 | |
111 auto c02 = F::Expand(p0[0]); | |
112 auto c12 = F::Expand(p1[0]); | |
113 for (int i = 0; i < count; ++i) { | |
114 auto c00 = c02; | |
115 auto c01 = F::Expand(p0[1]); | |
116 c02 = F::Expand(p0[2]); | |
117 auto c10 = c12; | |
118 auto c11 = F::Expand(p1[1]); | |
119 c12 = F::Expand(p1[2]); | |
120 | |
121 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); | |
122 d[i] = F::Compact(c >> 3); | |
123 p0 += 2; | |
124 p1 += 2; | |
125 } | |
126 } | |
127 | |
128 template <typename F> void downsample_2_3(void* dst, const void* src, size_t src RB, int count) { | |
129 auto p0 = static_cast<const typename F::Type*>(src); | |
130 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | |
131 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 165 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
132 auto d = static_cast<typename F::Type*>(dst); | 166 auto d = static_cast<typename F::Type*>(dst); |
133 | 167 |
134 for (int i = 0; i < count; ++i) { | 168 for (int i = 0; i < count; ++i) { |
135 auto c00 = F::Expand(p0[0]); | 169 auto c00 = F::Expand(p0[0]); |
136 auto c01 = F::Expand(p0[1]); | 170 auto c01 = F::Expand(p0[1]); |
137 auto c10 = F::Expand(p1[0]); | 171 auto c10 = F::Expand(p1[0]); |
138 auto c11 = F::Expand(p1[1]); | 172 auto c11 = F::Expand(p1[1]); |
139 auto c20 = F::Expand(p2[0]); | 173 auto c20 = F::Expand(p2[0]); |
140 auto c21 = F::Expand(p2[1]); | 174 auto c21 = F::Expand(p2[1]); |
141 | 175 |
142 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); | 176 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); |
143 d[i] = F::Compact(c >> 3); | 177 d[i] = F::Compact(c >> 3); |
144 p0 += 2; | 178 p0 += 2; |
145 p1 += 2; | 179 p1 += 2; |
146 p2 += 2; | 180 p2 += 2; |
147 } | 181 } |
148 } | 182 } |
149 | 183 |
184 template <typename F> void downsample_3_1(void* dst, const void* src, size_t src RB, int count) { | |
185 SkASSERT(count > 0); | |
186 auto p0 = static_cast<const typename F::Type*>(src); | |
187 auto d = static_cast<typename F::Type*>(dst); | |
188 | |
189 auto c02 = F::Expand(p0[0]); | |
190 for (int i = 0; i < count; ++i) { | |
191 auto c00 = c02; | |
192 auto c01 = F::Expand(p0[1]); | |
193 c02 = F::Expand(p0[2]); | |
194 | |
195 auto c = add_121(c00, c01, c02); | |
196 d[i] = F::Compact(c >> 2); | |
197 p0 += 2; | |
198 } | |
199 } | |
200 | |
201 template <typename F> void downsample_3_2(void* dst, const void* src, size_t src RB, int count) { | |
202 SkASSERT(count > 0); | |
203 auto p0 = static_cast<const typename F::Type*>(src); | |
204 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | |
205 auto d = static_cast<typename F::Type*>(dst); | |
206 | |
207 auto c02 = F::Expand(p0[0]); | |
208 auto c12 = F::Expand(p1[0]); | |
209 for (int i = 0; i < count; ++i) { | |
210 auto c00 = c02; | |
211 auto c01 = F::Expand(p0[1]); | |
212 c02 = F::Expand(p0[2]); | |
213 auto c10 = c12; | |
214 auto c11 = F::Expand(p1[1]); | |
215 c12 = F::Expand(p1[2]); | |
216 | |
217 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); | |
218 d[i] = F::Compact(c >> 3); | |
219 p0 += 2; | |
220 p1 += 2; | |
221 } | |
222 } | |
223 | |
150 template <typename F> void downsample_3_3(void* dst, const void* src, size_t src RB, int count) { | 224 template <typename F> void downsample_3_3(void* dst, const void* src, size_t src RB, int count) { |
225 SkASSERT(count > 0); | |
reed1
2016/03/01 20:17:46
curious why we remove this assert?
| |
151 auto p0 = static_cast<const typename F::Type*>(src); | 226 auto p0 = static_cast<const typename F::Type*>(src); |
152 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); | 227 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
153 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); | 228 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
154 auto d = static_cast<typename F::Type*>(dst); | 229 auto d = static_cast<typename F::Type*>(dst); |
155 | 230 |
156 auto c02 = F::Expand(p0[0]); | 231 auto c02 = F::Expand(p0[0]); |
157 auto c12 = F::Expand(p1[0]); | 232 auto c12 = F::Expand(p1[0]); |
158 auto c22 = F::Expand(p2[0]); | 233 auto c22 = F::Expand(p2[0]); |
159 for (int i = 0; i < count; ++i) { | 234 for (int i = 0; i < count; ++i) { |
160 auto c00 = c02; | 235 auto c00 = c02; |
(...skipping 23 matching lines...) Expand all Loading... | |
184 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; | 259 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; |
185 if (!sk_64_isS32(size)) { | 260 if (!sk_64_isS32(size)) { |
186 return 0; | 261 return 0; |
187 } | 262 } |
188 return sk_64_asS32(size); | 263 return sk_64_asS32(size); |
189 } | 264 } |
190 | 265 |
191 SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { | 266 SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { |
192 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); | 267 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); |
193 | 268 |
269 FilterProc* proc_1_2 = nullptr; | |
270 FilterProc* proc_1_3 = nullptr; | |
271 FilterProc* proc_2_1 = nullptr; | |
194 FilterProc* proc_2_2 = nullptr; | 272 FilterProc* proc_2_2 = nullptr; |
195 FilterProc* proc_2_3 = nullptr; | 273 FilterProc* proc_2_3 = nullptr; |
274 FilterProc* proc_3_1 = nullptr; | |
196 FilterProc* proc_3_2 = nullptr; | 275 FilterProc* proc_3_2 = nullptr; |
197 FilterProc* proc_3_3 = nullptr; | 276 FilterProc* proc_3_3 = nullptr; |
198 | 277 |
199 const SkColorType ct = src.colorType(); | 278 const SkColorType ct = src.colorType(); |
200 const SkAlphaType at = src.alphaType(); | 279 const SkAlphaType at = src.alphaType(); |
201 switch (ct) { | 280 switch (ct) { |
202 case kRGBA_8888_SkColorType: | 281 case kRGBA_8888_SkColorType: |
203 case kBGRA_8888_SkColorType: | 282 case kBGRA_8888_SkColorType: |
283 proc_1_2 = downsample_1_2<ColorTypeFilter_8888>; | |
284 proc_1_3 = downsample_1_3<ColorTypeFilter_8888>; | |
285 proc_2_1 = downsample_2_1<ColorTypeFilter_8888>; | |
204 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; | 286 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; |
205 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; | 287 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; |
288 proc_3_1 = downsample_3_1<ColorTypeFilter_8888>; | |
206 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; | 289 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; |
207 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; | 290 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; |
208 break; | 291 break; |
209 case kRGB_565_SkColorType: | 292 case kRGB_565_SkColorType: |
293 proc_1_2 = downsample_1_2<ColorTypeFilter_565>; | |
294 proc_1_3 = downsample_1_3<ColorTypeFilter_565>; | |
295 proc_2_1 = downsample_2_1<ColorTypeFilter_565>; | |
210 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; | 296 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; |
211 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; | 297 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; |
298 proc_3_1 = downsample_3_1<ColorTypeFilter_565>; | |
212 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; | 299 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; |
213 proc_3_3 = downsample_3_3<ColorTypeFilter_565>; | 300 proc_3_3 = downsample_3_3<ColorTypeFilter_565>; |
214 break; | 301 break; |
215 case kARGB_4444_SkColorType: | 302 case kARGB_4444_SkColorType: |
303 proc_1_2 = downsample_1_2<ColorTypeFilter_4444>; | |
304 proc_1_3 = downsample_1_3<ColorTypeFilter_4444>; | |
305 proc_2_1 = downsample_2_1<ColorTypeFilter_4444>; | |
216 proc_2_2 = downsample_2_2<ColorTypeFilter_4444>; | 306 proc_2_2 = downsample_2_2<ColorTypeFilter_4444>; |
217 proc_2_3 = downsample_2_3<ColorTypeFilter_4444>; | 307 proc_2_3 = downsample_2_3<ColorTypeFilter_4444>; |
308 proc_3_1 = downsample_3_1<ColorTypeFilter_4444>; | |
218 proc_3_2 = downsample_3_2<ColorTypeFilter_4444>; | 309 proc_3_2 = downsample_3_2<ColorTypeFilter_4444>; |
219 proc_3_3 = downsample_3_3<ColorTypeFilter_4444>; | 310 proc_3_3 = downsample_3_3<ColorTypeFilter_4444>; |
220 break; | 311 break; |
221 case kAlpha_8_SkColorType: | 312 case kAlpha_8_SkColorType: |
222 case kGray_8_SkColorType: | 313 case kGray_8_SkColorType: |
314 proc_1_2 = downsample_1_2<ColorTypeFilter_8>; | |
315 proc_1_3 = downsample_1_3<ColorTypeFilter_8>; | |
316 proc_2_1 = downsample_2_1<ColorTypeFilter_8>; | |
223 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; | 317 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; |
224 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; | 318 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; |
319 proc_3_1 = downsample_3_1<ColorTypeFilter_8>; | |
225 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; | 320 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; |
226 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; | 321 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; |
227 break; | 322 break; |
228 default: | 323 default: |
229 // TODO: We could build miplevels for kIndex8 if the levels were in 8888. | 324 // TODO: We could build miplevels for kIndex8 if the levels were in 8888. |
230 // Means using more ram, but the quality would be fine. | 325 // Means using more ram, but the quality would be fine. |
231 return nullptr; | 326 return nullptr; |
232 } | 327 } |
233 | 328 |
329 if (src.width() <= 1 && src.height() <= 1) { | |
330 return nullptr; | |
331 } | |
234 // whip through our loop to compute the exact size needed | 332 // whip through our loop to compute the exact size needed |
235 size_t size = 0; | 333 size_t size = 0; |
236 int countLevels = 0; | 334 int countLevels = 0; |
237 { | 335 { |
238 int width = src.width(); | 336 int width = src.width(); |
239 int height = src.height(); | 337 int height = src.height(); |
240 for (;;) { | 338 for (;;) { |
241 width >>= 1; | 339 width >>= 1; |
340 width = SkTMax(1, width); | |
reed1
2016/03/01 20:17:46
nit: width = SkTMax(1, width >> 1) ?
cblume
2016/03/01 20:39:29
Done.
| |
242 height >>= 1; | 341 height >>= 1; |
243 if (0 == width || 0 == height) { | 342 height = SkTMax(1, height); |
343 size += SkColorTypeMinRowBytes(ct, width) * height; | |
344 countLevels += 1; | |
345 if (1 == width && 1 == height) { | |
244 break; | 346 break; |
245 } | 347 } |
246 size += SkColorTypeMinRowBytes(ct, width) * height; | |
247 countLevels += 1; | |
248 } | 348 } |
249 } | 349 } |
250 if (0 == countLevels) { | |
251 return nullptr; | |
252 } | |
253 | 350 |
254 SkASSERT(countLevels == SkMipMap::ComputeLevelCount(src.width(), src.height( ))); | 351 SkASSERT(countLevels == SkMipMap::ComputeLevelCount(src.width(), src.height( ))); |
255 | 352 |
256 size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); | 353 size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); |
257 if (0 == storageSize) { | 354 if (0 == storageSize) { |
258 return nullptr; | 355 return nullptr; |
259 } | 356 } |
260 | 357 |
261 SkMipMap* mipmap; | 358 SkMipMap* mipmap; |
262 if (fact) { | 359 if (fact) { |
(...skipping 13 matching lines...) Expand all Loading... | |
276 Level* levels = mipmap->fLevels; | 373 Level* levels = mipmap->fLevels; |
277 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; | 374 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; |
278 uint8_t* addr = baseAddr; | 375 uint8_t* addr = baseAddr; |
279 int width = src.width(); | 376 int width = src.width(); |
280 int height = src.height(); | 377 int height = src.height(); |
281 uint32_t rowBytes; | 378 uint32_t rowBytes; |
282 SkPixmap srcPM(src); | 379 SkPixmap srcPM(src); |
283 | 380 |
284 for (int i = 0; i < countLevels; ++i) { | 381 for (int i = 0; i < countLevels; ++i) { |
285 FilterProc* proc; | 382 FilterProc* proc; |
286 if (height & 1) { // src-height is 3 | 383 if (height & 1) { |
287 if (width & 1) { // src-width is 3 | 384 if (height == 1) { // src-height is 1 |
288 proc = proc_3_3; | 385 if (width & 1) { // src-width is 3 |
289 } else { // src-width is 2 | 386 proc = proc_3_1; |
290 proc = proc_2_3; | 387 } else { // src-width is 2 |
388 proc = proc_2_1; | |
389 } | |
390 } else { // src-height is 3 | |
391 if (width & 1) { | |
392 if (width == 1) { // src-width is 1 | |
393 proc = proc_1_3; | |
394 } else { // src-width is 3 | |
395 proc = proc_3_3; | |
396 } | |
397 } else { // src-width is 2 | |
398 proc = proc_2_3; | |
399 } | |
291 } | 400 } |
292 } else { // src-height is 2 | 401 } else { // src-height is 2 |
293 if (width & 1) { // src-width is 3 | 402 if (width & 1) { |
294 proc = proc_3_2; | 403 if (width == 1) { // src-width is 1 |
295 } else { // src-width is 2 | 404 proc = proc_1_2; |
405 } else { // src-width is 3 | |
406 proc = proc_3_2; | |
407 } | |
408 } else { // src-width is 2 | |
296 proc = proc_2_2; | 409 proc = proc_2_2; |
297 } | 410 } |
298 } | 411 } |
299 width >>= 1; | 412 width >>= 1; |
413 width = SkTMax(1, width); | |
reed1
2016/03/01 20:17:46
same nit: width = SkTMax(1, width >> 1);
cblume
2016/03/01 20:39:29
Done.
| |
300 height >>= 1; | 414 height >>= 1; |
415 height = SkTMax(1, height); | |
301 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); | 416 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); |
302 | 417 |
303 levels[i].fPixmap = SkPixmap(SkImageInfo::Make(width, height, ct, at), a ddr, rowBytes); | 418 levels[i].fPixmap = SkPixmap(SkImageInfo::Make(width, height, ct, at), a ddr, rowBytes); |
304 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), | 419 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), |
305 SkIntToScalar(height) / src.height()); | 420 SkIntToScalar(height) / src.height()); |
306 | 421 |
307 const SkPixmap& dstPM = levels[i].fPixmap; | 422 const SkPixmap& dstPM = levels[i].fPixmap; |
308 const void* srcBasePtr = srcPM.addr(); | 423 const void* srcBasePtr = srcPM.addr(); |
309 void* dstBasePtr = dstPM.writable_addr(); | 424 void* dstBasePtr = dstPM.writable_addr(); |
310 | 425 |
311 const size_t srcRB = srcPM.rowBytes(); | 426 const size_t srcRB = srcPM.rowBytes(); |
312 for (int y = 0; y < height; y++) { | 427 for (int y = 0; y < height; y++) { |
313 proc(dstBasePtr, srcBasePtr, srcRB, width); | 428 proc(dstBasePtr, srcBasePtr, srcRB, width); |
314 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows | 429 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |
315 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | 430 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |
316 } | 431 } |
317 srcPM = dstPM; | 432 srcPM = dstPM; |
318 addr += height * rowBytes; | 433 addr += height * rowBytes; |
319 } | 434 } |
320 SkASSERT(addr == baseAddr + size); | 435 SkASSERT(addr == baseAddr + size); |
321 | 436 |
322 return mipmap; | 437 return mipmap; |
323 } | 438 } |
324 | 439 |
325 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { | 440 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { |
441 if (baseWidth < 1 || baseHeight < 1) { | |
442 return 0; | |
443 } | |
444 | |
326 // OpenGL's spec requires that each mipmap level have height/width equal to | 445 // OpenGL's spec requires that each mipmap level have height/width equal to |
327 // max(1, floor(original_height / 2^i) | 446 // max(1, floor(original_height / 2^i) |
328 // (or original_width) where i is the mipmap level. | 447 // (or original_width) where i is the mipmap level. |
329 // Continue scaling down until both axes are size 1. | 448 // Continue scaling down until both axes are size 1. |
330 // | |
331 // This means it maintains isotropic space (both axes scaling down | |
332 // at the same rate) until one axis hits size 1. | |
333 // At that point, OpenGL continues to scale down into anisotropic space | |
334 // (where the scales are not the same between axes). | |
335 // | |
336 // Skia currently does not go into anisotropic space. | |
337 // Once an axis hits size 1 we stop. | |
338 // All this means is rather than use the largest axis we will use the | |
339 // smallest axis. | |
340 | 449 |
341 const int smallestAxis = SkTMin(baseWidth, baseHeight); | 450 const int largestAxis = SkTMax(baseWidth, baseHeight); |
342 if (smallestAxis < 2) { | 451 if (largestAxis < 2) { |
343 // SkMipMap::Build requires a minimum size of 2. | 452 // SkMipMap::Build requires a minimum size of 2. |
344 return 0; | 453 return 0; |
345 } | 454 } |
346 const int leadingZeros = SkCLZ(static_cast<uint32_t>(smallestAxis)); | 455 const int leadingZeros = SkCLZ(static_cast<uint32_t>(largestAxis)); |
347 // If the value 00011010 has 3 leading 0s then it has 5 significant bits | 456 // If the value 00011010 has 3 leading 0s then it has 5 significant bits |
348 // (the bits which are not leading zeros) | 457 // (the bits which are not leading zeros) |
349 const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; | 458 const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; |
350 // This is making the assumption that the size of a byte is 8 bits | 459 // This is making the assumption that the size of a byte is 8 bits |
351 // and that sizeof(uint32_t)'s implementation-defined behavior is 4. | 460 // and that sizeof(uint32_t)'s implementation-defined behavior is 4. |
352 int mipLevelCount = significantBits; | 461 int mipLevelCount = significantBits; |
353 | 462 |
354 // SkMipMap does not include the base mip level. | 463 // SkMipMap does not include the base mip level. |
355 // For example, it contains levels 1-x instead of 0-x. | 464 // For example, it contains levels 1-x instead of 0-x. |
356 // This is because the image used to create SkMipMap is the base level. | 465 // This is because the image used to create SkMipMap is the base level. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
435 return false; | 544 return false; |
436 } | 545 } |
437 if (index > fCount - 1) { | 546 if (index > fCount - 1) { |
438 return false; | 547 return false; |
439 } | 548 } |
440 if (levelPtr) { | 549 if (levelPtr) { |
441 *levelPtr = fLevels[index]; | 550 *levelPtr = fLevels[index]; |
442 } | 551 } |
443 return true; | 552 return true; |
444 } | 553 } |
OLD | NEW |