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); |
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); |
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 = SkTMax(1, width >> 1); |
242 height >>= 1; | 340 height = SkTMax(1, height >> 1); |
243 if (0 == width || 0 == 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 = SkTMax(1, width >> 1); |
300 height >>= 1; | 411 height = SkTMax(1, height >> 1); |
301 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); | 412 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); |
302 | 413 |
303 levels[i].fPixmap = SkPixmap(SkImageInfo::Make(width, height, ct, at), a
ddr, rowBytes); | 414 levels[i].fPixmap = SkPixmap(SkImageInfo::Make(width, height, ct, at), a
ddr, rowBytes); |
304 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), | 415 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), |
305 SkIntToScalar(height) / src.height()); | 416 SkIntToScalar(height) / src.height()); |
306 | 417 |
307 const SkPixmap& dstPM = levels[i].fPixmap; | 418 const SkPixmap& dstPM = levels[i].fPixmap; |
308 const void* srcBasePtr = srcPM.addr(); | 419 const void* srcBasePtr = srcPM.addr(); |
309 void* dstBasePtr = dstPM.writable_addr(); | 420 void* dstBasePtr = dstPM.writable_addr(); |
310 | 421 |
311 const size_t srcRB = srcPM.rowBytes(); | 422 const size_t srcRB = srcPM.rowBytes(); |
312 for (int y = 0; y < height; y++) { | 423 for (int y = 0; y < height; y++) { |
313 proc(dstBasePtr, srcBasePtr, srcRB, width); | 424 proc(dstBasePtr, srcBasePtr, srcRB, width); |
314 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows | 425 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |
315 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | 426 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |
316 } | 427 } |
317 srcPM = dstPM; | 428 srcPM = dstPM; |
318 addr += height * rowBytes; | 429 addr += height * rowBytes; |
319 } | 430 } |
320 SkASSERT(addr == baseAddr + size); | 431 SkASSERT(addr == baseAddr + size); |
321 | 432 |
322 return mipmap; | 433 return mipmap; |
323 } | 434 } |
324 | 435 |
325 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { | 436 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { |
| 437 if (baseWidth < 1 || baseHeight < 1) { |
| 438 return 0; |
| 439 } |
| 440 |
326 // OpenGL's spec requires that each mipmap level have height/width equal to | 441 // OpenGL's spec requires that each mipmap level have height/width equal to |
327 // max(1, floor(original_height / 2^i) | 442 // max(1, floor(original_height / 2^i) |
328 // (or original_width) where i is the mipmap level. | 443 // (or original_width) where i is the mipmap level. |
329 // Continue scaling down until both axes are size 1. | 444 // 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 | 445 |
341 const int smallestAxis = SkTMin(baseWidth, baseHeight); | 446 const int largestAxis = SkTMax(baseWidth, baseHeight); |
342 if (smallestAxis < 2) { | 447 if (largestAxis < 2) { |
343 // SkMipMap::Build requires a minimum size of 2. | 448 // SkMipMap::Build requires a minimum size of 2. |
344 return 0; | 449 return 0; |
345 } | 450 } |
346 const int leadingZeros = SkCLZ(static_cast<uint32_t>(smallestAxis)); | 451 const int leadingZeros = SkCLZ(static_cast<uint32_t>(largestAxis)); |
347 // If the value 00011010 has 3 leading 0s then it has 5 significant bits | 452 // If the value 00011010 has 3 leading 0s then it has 5 significant bits |
348 // (the bits which are not leading zeros) | 453 // (the bits which are not leading zeros) |
349 const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; | 454 const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; |
350 // This is making the assumption that the size of a byte is 8 bits | 455 // 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. | 456 // and that sizeof(uint32_t)'s implementation-defined behavior is 4. |
352 int mipLevelCount = significantBits; | 457 int mipLevelCount = significantBits; |
353 | 458 |
354 // SkMipMap does not include the base mip level. | 459 // SkMipMap does not include the base mip level. |
355 // For example, it contains levels 1-x instead of 0-x. | 460 // 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. | 461 // 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; | 540 return false; |
436 } | 541 } |
437 if (index > fCount - 1) { | 542 if (index > fCount - 1) { |
438 return false; | 543 return false; |
439 } | 544 } |
440 if (levelPtr) { | 545 if (levelPtr) { |
441 *levelPtr = fLevels[index]; | 546 *levelPtr = fLevels[index]; |
442 } | 547 } |
443 return true; | 548 return true; |
444 } | 549 } |
OLD | NEW |