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