OLD | NEW |
---|---|
(Empty) | |
1 #include "SkMipMap.h" | |
tfarina
2013/07/18 21:02:07
copyright missing.
| |
2 #include "SkBitmap.h" | |
3 #include "SkColorPriv.h" | |
4 | |
5 static void downsampleby2_proc32(SkBitmap* dst, int x, int y, | |
6 const SkBitmap& src) { | |
7 x <<= 1; | |
8 y <<= 1; | |
9 const SkPMColor* p = src.getAddr32(x, y); | |
10 const SkPMColor* baseP = p; | |
11 SkPMColor c, ag, rb; | |
12 | |
13 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; | |
14 if (x < src.width() - 1) { | |
15 p += 1; | |
16 } | |
17 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
18 | |
19 p = baseP; | |
20 if (y < src.height() - 1) { | |
21 p += src.rowBytes() >> 2; | |
22 } | |
23 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
24 if (x < src.width() - 1) { | |
25 p += 1; | |
26 } | |
27 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | |
28 | |
29 *dst->getAddr32(x >> 1, y >> 1) = | |
30 ((rb >> 2) & 0xFF00FF) | ((ag << 6) & 0xFF00FF00); | |
31 } | |
32 | |
33 static inline uint32_t expand16(U16CPU c) { | |
34 return (c & ~SK_G16_MASK_IN_PLACE) | ((c & SK_G16_MASK_IN_PLACE) << 16); | |
35 } | |
36 | |
37 // returns dirt in the top 16bits, but we don't care, since we only | |
38 // store the low 16bits. | |
39 static inline U16CPU pack16(uint32_t c) { | |
40 return (c & ~SK_G16_MASK_IN_PLACE) | ((c >> 16) & SK_G16_MASK_IN_PLACE); | |
41 } | |
42 | |
43 static void downsampleby2_proc16(SkBitmap* dst, int x, int y, | |
44 const SkBitmap& src) { | |
45 x <<= 1; | |
46 y <<= 1; | |
47 const uint16_t* p = src.getAddr16(x, y); | |
48 const uint16_t* baseP = p; | |
49 SkPMColor c; | |
50 | |
51 c = expand16(*p); | |
52 if (x < src.width() - 1) { | |
53 p += 1; | |
54 } | |
55 c += expand16(*p); | |
56 | |
57 p = baseP; | |
58 if (y < src.height() - 1) { | |
59 p += src.rowBytes() >> 1; | |
60 } | |
61 c += expand16(*p); | |
62 if (x < src.width() - 1) { | |
63 p += 1; | |
64 } | |
65 c += expand16(*p); | |
66 | |
67 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)pack16(c >> 2); | |
68 } | |
69 | |
70 static uint32_t expand4444(U16CPU c) { | |
71 return (c & 0xF0F) | ((c & ~0xF0F) << 12); | |
72 } | |
73 | |
74 static U16CPU collaps4444(uint32_t c) { | |
75 return (c & 0xF0F) | ((c >> 12) & ~0xF0F); | |
76 } | |
77 | |
78 static void downsampleby2_proc4444(SkBitmap* dst, int x, int y, | |
79 const SkBitmap& src) { | |
80 x <<= 1; | |
81 y <<= 1; | |
82 const uint16_t* p = src.getAddr16(x, y); | |
83 const uint16_t* baseP = p; | |
84 uint32_t c; | |
85 | |
86 c = expand4444(*p); | |
87 if (x < src.width() - 1) { | |
88 p += 1; | |
89 } | |
90 c += expand4444(*p); | |
91 | |
92 p = baseP; | |
93 if (y < src.height() - 1) { | |
94 p += src.rowBytes() >> 1; | |
95 } | |
96 c += expand4444(*p); | |
97 if (x < src.width() - 1) { | |
98 p += 1; | |
99 } | |
100 c += expand4444(*p); | |
101 | |
102 *dst->getAddr16(x >> 1, y >> 1) = (uint16_t)collaps4444(c >> 2); | |
103 } | |
104 | |
105 static bool isPos32Bits(const Sk64& value) { | |
106 return !value.isNeg() && value.is32(); | |
107 } | |
108 | |
109 SkMipMap::Level* SkMipMap::AllocLevels(int levelCount, size_t pixelSize) { | |
110 if (levelCount < 0) { | |
111 return NULL; | |
112 } | |
113 Sk64 size; | |
114 size.setMul(levelCount + 1, sizeof(Level)); | |
115 size.add(SkToS32(pixelSize)); | |
116 if (!isPos32Bits(size)) { | |
117 return NULL; | |
118 } | |
119 return (Level*)sk_malloc_throw(size.get32()); | |
120 } | |
121 | |
122 SkMipMap* SkMipMap::Build(const SkBitmap& src) { | |
123 void (*proc)(SkBitmap* dst, int x, int y, const SkBitmap& src); | |
124 | |
125 const SkBitmap::Config config = src.getConfig(); | |
126 switch (config) { | |
127 case SkBitmap::kARGB_8888_Config: | |
128 proc = downsampleby2_proc32; | |
129 break; | |
130 case SkBitmap::kRGB_565_Config: | |
131 proc = downsampleby2_proc16; | |
132 break; | |
133 case SkBitmap::kARGB_4444_Config: | |
134 proc = downsampleby2_proc4444; | |
135 break; | |
136 case SkBitmap::kIndex8_Config: | |
137 case SkBitmap::kA8_Config: | |
138 default: | |
139 return NULL; // don't build mipmaps for these configs | |
140 } | |
141 | |
142 SkAutoLockPixels alp(src); | |
143 if (!src.readyToDraw()) { | |
144 return NULL; | |
145 } | |
146 | |
147 // whip through our loop to compute the exact size needed | |
148 size_t size = 0; | |
149 int countLevels = 0; | |
150 { | |
151 int width = src.width(); | |
152 int height = src.height(); | |
153 for (;;) { | |
154 width >>= 1; | |
155 height >>= 1; | |
156 if (0 == width || 0 == height) { | |
157 break; | |
158 } | |
159 size += SkBitmap::ComputeRowBytes(config, width) * height; | |
160 countLevels += 1; | |
161 } | |
162 } | |
163 if (0 == countLevels) { | |
164 return NULL; | |
165 } | |
166 | |
167 Level* levels = SkMipMap::AllocLevels(countLevels, size); | |
168 if (NULL == levels) { | |
169 return NULL; | |
170 } | |
171 | |
172 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; | |
173 uint8_t* addr = baseAddr; | |
174 int width = src.width(); | |
175 int height = src.height(); | |
176 uint32_t rowBytes; | |
177 SkBitmap srcBM(src); | |
178 | |
179 for (int i = 0; i < countLevels; ++i) { | |
180 width >>= 1; | |
181 height >>= 1; | |
182 rowBytes = SkToU32(SkBitmap::ComputeRowBytes(config, width)); | |
183 | |
184 levels[i].fPixels = addr; | |
185 levels[i].fWidth = width; | |
186 levels[i].fHeight = height; | |
187 levels[i].fRowBytes = rowBytes; | |
188 | |
189 SkBitmap dstBM; | |
190 dstBM.setConfig(config, width, height, rowBytes); | |
191 dstBM.setPixels(addr); | |
192 | |
193 srcBM.lockPixels(); | |
194 for (int y = 0; y < height; y++) { | |
195 for (int x = 0; x < width; x++) { | |
196 proc(&dstBM, x, y, srcBM); | |
197 } | |
198 } | |
199 srcBM.unlockPixels(); | |
200 | |
201 srcBM = dstBM; | |
202 addr += height * rowBytes; | |
203 } | |
204 SkASSERT(addr == baseAddr + size); | |
205 | |
206 return SkNEW_ARGS(SkMipMap, (levels, countLevels)); | |
207 } | |
208 | |
209 static SkFixed compute_level(SkScalar scale) { | |
210 SkFixed s = SkAbs32(SkScalarToFixed(SkScalarInvert(scale))); | |
211 | |
212 if (s < SK_Fixed1) { | |
213 return 0; | |
214 } | |
215 int clz = SkCLZ(s); | |
216 SkASSERT(clz >= 1 && clz <= 15); | |
217 return SkIntToFixed(15 - clz) + ((unsigned)(s << (clz + 1)) >> 16); | |
218 } | |
219 | |
220 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { | |
221 if (scale >= SK_Scalar1) { | |
222 return false; | |
223 } | |
224 | |
225 int level = compute_level(scale) >> 16; | |
226 SkASSERT(level >= 0); | |
227 if (level <= 0) { | |
228 return false; | |
229 } | |
230 | |
231 if (level > fCount) { | |
232 level = fCount; | |
233 } | |
234 if (levelPtr) { | |
235 *levelPtr = fLevels[level - 1]; | |
236 } | |
237 return true; | |
238 } | |
239 | |
OLD | NEW |