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 | 11 |
12 #ifdef SK_SUPPORT_LEGACY_MIPLEVEL_BUILDER | |
13 | |
14 static void downsample32_nocheck(void* dst, int, int, const void* srcPtr, const
SkPixmap& srcPM) { | |
15 const uint32_t* p = static_cast<const uint32_t*>(srcPtr); | |
16 const uint32_t* baseP = p; | |
17 uint32_t c, ag, rb; | |
18 | |
19 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; | |
20 p += 1; | |
21 | |
22 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
23 | |
24 p = baseP; | |
25 p += srcPM.rowBytes() >> 2; | |
26 | |
27 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
28 p += 1; | |
29 | |
30 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
31 | |
32 *(uint32_t*)dst = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); | |
33 } | |
34 | |
35 static void downsample32_check(void* dst, int x, int y, const void* srcPtr, cons
t SkPixmap& srcPM) { | |
36 const uint32_t* p = static_cast<const uint32_t*>(srcPtr); | |
37 const uint32_t* baseP = p; | |
38 | |
39 x <<= 1; | |
40 y <<= 1; | |
41 SkASSERT(srcPM.addr32(x, y) == p); | |
42 | |
43 SkPMColor c, ag, rb; | |
44 | |
45 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; | |
46 if (x < srcPM.width() - 1) { | |
47 p += 1; | |
48 } | |
49 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
50 | |
51 p = baseP; | |
52 if (y < srcPM.height() - 1) { | |
53 p += srcPM.rowBytes() >> 2; | |
54 } | |
55 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
56 if (x < srcPM.width() - 1) { | |
57 p += 1; | |
58 } | |
59 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
60 | |
61 *((uint32_t*)dst) = ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); | |
62 } | |
63 | |
64 static inline uint32_t expand16(U16CPU c) { | |
65 return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16); | |
66 } | |
67 | |
68 // returns dirt in the top 16bits, but we don't care, since we only | |
69 // store the low 16bits. | |
70 static inline U16CPU pack16(uint32_t c) { | |
71 return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE); | |
72 } | |
73 | |
74 static void downsample16(void* dst, int x, int y, const void* srcPtr, const SkPi
xmap& srcPM) { | |
75 const uint16_t* p = static_cast<const uint16_t*>(srcPtr); | |
76 const uint16_t* baseP = p; | |
77 | |
78 x <<= 1; | |
79 y <<= 1; | |
80 SkASSERT(srcPM.addr16(x, y) == p); | |
81 | |
82 SkPMColor c; | |
83 | |
84 c = expand16(*p); | |
85 if (x < srcPM.width() - 1) { | |
86 p += 1; | |
87 } | |
88 c += expand16(*p); | |
89 | |
90 p = baseP; | |
91 if (y < srcPM.height() - 1) { | |
92 p += srcPM.rowBytes() >> 1; | |
93 } | |
94 c += expand16(*p); | |
95 if (x < srcPM.width() - 1) { | |
96 p += 1; | |
97 } | |
98 c += expand16(*p); | |
99 | |
100 *((uint16_t*)dst) = (uint16_t)pack16(c >> 2); | |
101 } | |
102 | |
103 static uint32_t expand4444(U16CPU c) { | |
104 return (c & 0xF0F) | ((c & ~0xF0F) << 12); | |
105 } | |
106 | |
107 static U16CPU collaps4444(uint32_t c) { | |
108 return (c & 0xF0F) | ((c >> 12) & ~0xF0F); | |
109 } | |
110 | |
111 static void downsample4444(void* dst, int x, int y, const void* srcPtr, const Sk
Pixmap& srcPM) { | |
112 const uint16_t* p = static_cast<const uint16_t*>(srcPtr); | |
113 const uint16_t* baseP = p; | |
114 | |
115 x <<= 1; | |
116 y <<= 1; | |
117 SkASSERT(srcPM.addr16(x, y) == p); | |
118 | |
119 uint32_t c; | |
120 | |
121 c = expand4444(*p); | |
122 if (x < srcPM.width() - 1) { | |
123 p += 1; | |
124 } | |
125 c += expand4444(*p); | |
126 | |
127 p = baseP; | |
128 if (y < srcPM.height() - 1) { | |
129 p += srcPM.rowBytes() >> 1; | |
130 } | |
131 c += expand4444(*p); | |
132 if (x < srcPM.width() - 1) { | |
133 p += 1; | |
134 } | |
135 c += expand4444(*p); | |
136 | |
137 *((uint16_t*)dst) = (uint16_t)collaps4444(c >> 2); | |
138 } | |
139 | |
140 static void downsample8_nocheck(void* dst, int, int, const void* srcPtr, const S
kPixmap& srcPM) { | |
141 const size_t rb = srcPM.rowBytes(); | |
142 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); | |
143 *(uint8_t*)dst = (p[0] + p[1] + p[rb] + p[rb + 1]) >> 2; | |
144 } | |
145 | |
146 static void downsample8_check(void* dst, int x, int y, const void* srcPtr, const
SkPixmap& srcPM) { | |
147 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); | |
148 const uint8_t* baseP = p; | |
149 | |
150 x <<= 1; | |
151 y <<= 1; | |
152 SkASSERT(srcPM.addr8(x, y) == p); | |
153 | |
154 unsigned c = *p; | |
155 if (x < srcPM.width() - 1) { | |
156 p += 1; | |
157 } | |
158 c += *p; | |
159 | |
160 p = baseP; | |
161 if (y < srcPM.height() - 1) { | |
162 p += srcPM.rowBytes(); | |
163 } | |
164 c += *p; | |
165 if (x < srcPM.width() - 1) { | |
166 p += 1; | |
167 } | |
168 c += *p; | |
169 | |
170 *(uint8_t*)dst = c >> 2; | |
171 } | |
172 | |
173 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { | |
174 if (levelCount < 0) { | |
175 return 0; | |
176 } | |
177 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; | |
178 if (!sk_64_isS32(size)) { | |
179 return 0; | |
180 } | |
181 return sk_64_asS32(size); | |
182 } | |
183 | |
184 typedef void SkDownSampleProc(void*, int x, int y, const void* srcPtr, const SkP
ixmap& srcPM); | |
185 | |
186 SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { | |
187 SkDownSampleProc* proc_nocheck, *proc_check; | |
188 | |
189 const SkColorType ct = src.colorType(); | |
190 const SkAlphaType at = src.alphaType(); | |
191 switch (ct) { | |
192 case kRGBA_8888_SkColorType: | |
193 case kBGRA_8888_SkColorType: | |
194 proc_check = downsample32_check; | |
195 proc_nocheck = downsample32_nocheck; | |
196 break; | |
197 case kRGB_565_SkColorType: | |
198 proc_check = downsample16; | |
199 proc_nocheck = proc_check; | |
200 break; | |
201 case kARGB_4444_SkColorType: | |
202 proc_check = downsample4444; | |
203 proc_nocheck = proc_check; | |
204 break; | |
205 case kAlpha_8_SkColorType: | |
206 case kGray_8_SkColorType: | |
207 proc_check = downsample8_check; | |
208 proc_nocheck = downsample8_nocheck; | |
209 break; | |
210 default: | |
211 return nullptr; // don't build mipmaps for any other colortypes (yet
) | |
212 } | |
213 | |
214 // whip through our loop to compute the exact size needed | |
215 size_t size = 0; | |
216 int countLevels = 0; | |
217 { | |
218 int width = src.width(); | |
219 int height = src.height(); | |
220 for (;;) { | |
221 width >>= 1; | |
222 height >>= 1; | |
223 if (0 == width || 0 == height) { | |
224 break; | |
225 } | |
226 size += SkColorTypeMinRowBytes(ct, width) * height; | |
227 countLevels += 1; | |
228 } | |
229 } | |
230 if (0 == countLevels) { | |
231 return nullptr; | |
232 } | |
233 | |
234 size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); | |
235 if (0 == storageSize) { | |
236 return nullptr; | |
237 } | |
238 | |
239 SkMipMap* mipmap; | |
240 if (fact) { | |
241 SkDiscardableMemory* dm = fact(storageSize); | |
242 if (nullptr == dm) { | |
243 return nullptr; | |
244 } | |
245 mipmap = new SkMipMap(storageSize, dm); | |
246 } else { | |
247 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); | |
248 } | |
249 | |
250 // init | |
251 mipmap->fCount = countLevels; | |
252 mipmap->fLevels = (Level*)mipmap->writable_data(); | |
253 | |
254 Level* levels = mipmap->fLevels; | |
255 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; | |
256 uint8_t* addr = baseAddr; | |
257 int width = src.width(); | |
258 int height = src.height(); | |
259 uint32_t rowBytes; | |
260 SkPixmap srcPM(src); | |
261 | |
262 for (int i = 0; i < countLevels; ++i) { | |
263 width >>= 1; | |
264 height >>= 1; | |
265 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); | |
266 | |
267 levels[i].fPixmap = SkPixmap(SkImageInfo::Make(width, height, ct, at), a
ddr, rowBytes); | |
268 levels[i].fScale = (float)width / src.width(); | |
269 | |
270 SkPixmap dstPM(SkImageInfo::Make(width, height, ct, at), addr, rowBytes)
; | |
271 | |
272 const int widthEven = width & ~1; | |
273 const int heightEven = height & ~1; | |
274 const size_t pixelSize = srcPM.info().bytesPerPixel(); | |
275 | |
276 const void* srcBasePtr = srcPM.addr(); | |
277 void* dstBasePtr = dstPM.writable_addr(); | |
278 for (int y = 0; y < heightEven; y++) { | |
279 const void* srcPtr = srcBasePtr; | |
280 void* dstPtr = dstBasePtr; | |
281 for (int x = 0; x < widthEven; x++) { | |
282 proc_nocheck(dstPtr, x, y, srcPtr, srcPM); | |
283 srcPtr = (char*)srcPtr + pixelSize * 2; | |
284 dstPtr = (char*)dstPtr + pixelSize; | |
285 } | |
286 if (width & 1) { | |
287 proc_check(dstPtr, widthEven, y, srcPtr, srcPM); | |
288 } | |
289 | |
290 srcBasePtr = (char*)srcBasePtr + srcPM.rowBytes() * 2; | |
291 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | |
292 } | |
293 if (height & 1) { | |
294 const void* srcPtr = srcBasePtr; | |
295 void* dstPtr = dstBasePtr; | |
296 for (int x = 0; x < width; x++) { | |
297 proc_check(dstPtr, x, heightEven, srcPtr, srcPM); | |
298 srcPtr = (char*)srcPtr + pixelSize * 2; | |
299 dstPtr = (char*)dstPtr + pixelSize; | |
300 } | |
301 } | |
302 srcPM = dstPM; | |
303 addr += height * rowBytes; | |
304 } | |
305 SkASSERT(addr == baseAddr + size); | |
306 | |
307 return mipmap; | |
308 } | |
309 | |
310 #else // new technique that handles odd dimensions better | |
311 | |
312 // | 12 // |
313 // ColorTypeFilter is the "Type" we pass to some downsample template functions. | 13 // ColorTypeFilter is the "Type" we pass to some downsample template functions. |
314 // It controls how we expand a pixel into a large type, with space between each
component, | 14 // It controls how we expand a pixel into a large type, with space between each
component, |
315 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates | 15 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates |
316 // in the expanded type. | 16 // in the expanded type. |
317 // | 17 // |
318 | 18 |
319 struct ColorTypeFilter_8888 { | 19 struct ColorTypeFilter_8888 { |
320 typedef uint32_t Type; | 20 typedef uint32_t Type; |
321 static uint64_t Expand(uint32_t x) { | 21 static uint64_t Expand(uint32_t x) { |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
597 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows | 297 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |
598 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | 298 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |
599 } | 299 } |
600 srcPM = dstPM; | 300 srcPM = dstPM; |
601 addr += height * rowBytes; | 301 addr += height * rowBytes; |
602 } | 302 } |
603 SkASSERT(addr == baseAddr + size); | 303 SkASSERT(addr == baseAddr + size); |
604 | 304 |
605 return mipmap; | 305 return mipmap; |
606 } | 306 } |
607 #endif | |
608 | 307 |
609 /////////////////////////////////////////////////////////////////////////////// | 308 /////////////////////////////////////////////////////////////////////////////// |
610 | 309 |
611 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { | 310 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { |
612 if (nullptr == fLevels) { | 311 if (nullptr == fLevels) { |
613 return false; | 312 return false; |
614 } | 313 } |
615 | 314 |
616 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { | 315 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { |
617 return false; | 316 return false; |
(...skipping 30 matching lines...) Expand all Loading... |
648 return nullptr; | 347 return nullptr; |
649 } | 348 } |
650 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); | 349 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); |
651 // Try to catch where we might have returned nullptr for src crbug.com/49281
8 | 350 // Try to catch where we might have returned nullptr for src crbug.com/49281
8 |
652 if (nullptr == srcPixmap.addr()) { | 351 if (nullptr == srcPixmap.addr()) { |
653 sk_throw(); | 352 sk_throw(); |
654 } | 353 } |
655 return Build(srcPixmap, fact); | 354 return Build(srcPixmap, fact); |
656 } | 355 } |
657 | 356 |
OLD | NEW |