OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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 "SkBitmapCache.h" | 8 #include "SkBitmapCache.h" |
9 #include "SkBitmapProcState.h" | 9 #include "SkBitmapProcState.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 v1.fY = mat.getSkewY(); | 102 v1.fY = mat.getSkewY(); |
103 | 103 |
104 v2.fX = mat.getSkewX(); | 104 v2.fX = mat.getSkewX(); |
105 v2.fY = mat.getScaleY(); | 105 v2.fY = mat.getScaleY(); |
106 | 106 |
107 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd()); | 107 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd()); |
108 } | 108 } |
109 | 109 |
110 class AutoScaledCacheUnlocker { | 110 class AutoScaledCacheUnlocker { |
111 public: | 111 public: |
112 AutoScaledCacheUnlocker(SkScaledImageCache::ID** idPtr) : fIDPtr(idPtr) {} | 112 AutoScaledCacheUnlocker(SkScaledImageCache::ID* idPtr) : fIDPtr(idPtr) {} |
113 ~AutoScaledCacheUnlocker() { | 113 ~AutoScaledCacheUnlocker() { |
114 if (fIDPtr && *fIDPtr) { | 114 if (fIDPtr && *fIDPtr) { |
115 SkScaledImageCache::Unlock(*fIDPtr); | 115 SkScaledImageCache::Unlock(*fIDPtr); |
116 *fIDPtr = NULL; | 116 *fIDPtr = NULL; |
117 } | 117 } |
118 } | 118 } |
119 | 119 |
120 // forgets the ID, so it won't call Unlock | 120 // forgets the ID, so it won't call Unlock |
121 void release() { | 121 void release() { |
122 fIDPtr = NULL; | 122 fIDPtr = NULL; |
123 } | 123 } |
124 | 124 |
125 private: | 125 private: |
126 SkScaledImageCache::ID** fIDPtr; | 126 SkScaledImageCache::ID* fIDPtr; |
127 }; | 127 }; |
128 #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocke
r) | 128 #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocke
r) |
129 | 129 |
130 // Check to see that the size of the bitmap that would be produced by | 130 // Check to see that the size of the bitmap that would be produced by |
131 // scaling by the given inverted matrix is less than the maximum allowed. | 131 // scaling by the given inverted matrix is less than the maximum allowed. |
132 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { | 132 static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { |
133 size_t maximumAllocation | 133 size_t maximumAllocation |
134 = SkScaledImageCache::GetSingleAllocationByteLimit(); | 134 = SkScaledImageCache::GetSingleAllocationByteLimit(); |
135 if (0 == maximumAllocation) { | 135 if (0 == maximumAllocation) { |
136 return true; | 136 return true; |
137 } | 137 } |
138 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY); | 138 // float matrixScaleFactor = 1.0 / (invMat.scaleX * invMat.scaleY); |
139 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize); | 139 // return ((origBitmapSize * matrixScaleFactor) < maximumAllocationSize); |
140 // Skip the division step: | 140 // Skip the division step: |
141 return bm.info().getSafeSize(bm.info().minRowBytes()) | 141 return bm.info().getSafeSize(bm.info().minRowBytes()) |
142 < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY()); | 142 < (maximumAllocation * invMat.getScaleX() * invMat.getScaleY()); |
143 } | 143 } |
144 | 144 |
145 // TODO -- we may want to pass the clip into this function so we only scale | 145 // TODO -- we may want to pass the clip into this function so we only scale |
146 // the portion of the image that we're going to need. This will complicate | 146 // the portion of the image that we're going to need. This will complicate |
147 // the interface to the cache, but might be well worth it. | 147 // the interface to the cache, but might be well worth it. |
148 | 148 |
149 bool SkBitmapProcState::possiblyScaleImage() { | 149 bool SkBitmapProcState::possiblyScaleImage() { |
150 AutoScaledCacheUnlocker unlocker(&fScaledCacheID); | |
151 | |
152 SkASSERT(NULL == fBitmap); | 150 SkASSERT(NULL == fBitmap); |
153 SkASSERT(NULL == fScaledCacheID); | |
154 | 151 |
155 if (fFilterLevel <= SkPaint::kLow_FilterLevel) { | 152 if (fFilterLevel <= SkPaint::kLow_FilterLevel) { |
156 return false; | 153 return false; |
157 } | 154 } |
158 // Check to see if the transformation matrix is simple, and if we're | 155 // Check to see if the transformation matrix is simple, and if we're |
159 // doing high quality scaling. If so, do the bitmap scale here and | 156 // doing high quality scaling. If so, do the bitmap scale here and |
160 // remove the scaling component from the matrix. | 157 // remove the scaling component from the matrix. |
161 | 158 |
162 if (SkPaint::kHigh_FilterLevel == fFilterLevel && | 159 if (SkPaint::kHigh_FilterLevel == fFilterLevel && |
163 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma
sk) && | 160 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma
sk) && |
(...skipping 12 matching lines...) Expand all Loading... |
176 // are close to -1 as well, since the flip doesn't require | 173 // are close to -1 as well, since the flip doesn't require |
177 // any fancy re-sampling... | 174 // any fancy re-sampling... |
178 | 175 |
179 // Set our filter level to low -- the only post-filtering this | 176 // Set our filter level to low -- the only post-filtering this |
180 // image might require is some interpolation if the translation | 177 // image might require is some interpolation if the translation |
181 // is fractional. | 178 // is fractional. |
182 fFilterLevel = SkPaint::kLow_FilterLevel; | 179 fFilterLevel = SkPaint::kLow_FilterLevel; |
183 return false; | 180 return false; |
184 } | 181 } |
185 | 182 |
186 fScaledCacheID = SkBitmapCache::FindAndLock(fOrigBitmap, invScaleX, invS
caleY, | 183 if (!SkBitmapCache::Find(fOrigBitmap, invScaleX, invScaleY, &fScaledBitm
ap)) { |
187 &fScaledBitmap); | |
188 if (fScaledCacheID) { | |
189 fScaledBitmap.lockPixels(); | |
190 if (!fScaledBitmap.getPixels()) { | |
191 fScaledBitmap.unlockPixels(); | |
192 // found a purged entry (discardablememory?), release it | |
193 SkScaledImageCache::Unlock(fScaledCacheID); | |
194 fScaledCacheID = NULL; | |
195 // fall through to rebuild | |
196 } | |
197 } | |
198 | |
199 if (NULL == fScaledCacheID) { | |
200 float dest_width = fOrigBitmap.width() / invScaleX; | 184 float dest_width = fOrigBitmap.width() / invScaleX; |
201 float dest_height = fOrigBitmap.height() / invScaleY; | 185 float dest_height = fOrigBitmap.height() / invScaleY; |
202 | 186 |
203 // All the criteria are met; let's make a new bitmap. | 187 // All the criteria are met; let's make a new bitmap. |
204 | 188 |
205 if (!SkBitmapScaler::Resize(&fScaledBitmap, | 189 if (!SkBitmapScaler::Resize(&fScaledBitmap, |
206 fOrigBitmap, | 190 fOrigBitmap, |
207 SkBitmapScaler::RESIZE_BEST, | 191 SkBitmapScaler::RESIZE_BEST, |
208 dest_width, | 192 dest_width, |
209 dest_height, | 193 dest_height, |
210 SkScaledImageCache::GetAllocator())) { | 194 SkScaledImageCache::GetAllocator())) { |
211 // we failed to create fScaledBitmap, so just return and let | 195 // we failed to create fScaledBitmap, so just return and let |
212 // the scanline proc handle it. | 196 // the scanline proc handle it. |
213 return false; | 197 return false; |
214 | 198 |
215 } | 199 } |
216 | 200 |
217 SkASSERT(NULL != fScaledBitmap.getPixels()); | 201 SkASSERT(NULL != fScaledBitmap.getPixels()); |
218 fScaledCacheID = SkBitmapCache::AddAndLock(fOrigBitmap, invScaleX, i
nvScaleY, | 202 SkBitmapCache::Add(fOrigBitmap, invScaleX, invScaleY, fScaledBitmap)
; |
219 fScaledBitmap); | |
220 if (!fScaledCacheID) { | |
221 fScaledBitmap.reset(); | |
222 return false; | |
223 } | |
224 SkASSERT(NULL != fScaledBitmap.getPixels()); | |
225 } | 203 } |
226 | 204 |
227 SkASSERT(NULL != fScaledBitmap.getPixels()); | 205 SkASSERT(NULL != fScaledBitmap.getPixels()); |
228 fBitmap = &fScaledBitmap; | 206 fBitmap = &fScaledBitmap; |
229 | 207 |
230 // set the inv matrix type to translate-only; | 208 // set the inv matrix type to translate-only; |
231 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale
X(), | 209 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale
X(), |
232 fInvMatrix.getTranslateY() / fInvMatrix.getScale
Y()); | 210 fInvMatrix.getTranslateY() / fInvMatrix.getScale
Y()); |
233 | 211 |
234 // Set our filter level to low -- the only post-filtering this | 212 // Set our filter level to low -- the only post-filtering this |
235 // image might require is some interpolation if the translation | 213 // image might require is some interpolation if the translation |
236 // is fractional. | 214 // is fractional. |
237 fFilterLevel = SkPaint::kLow_FilterLevel; | 215 fFilterLevel = SkPaint::kLow_FilterLevel; |
238 unlocker.release(); | |
239 return true; | 216 return true; |
240 } | 217 } |
241 | 218 |
242 /* | 219 /* |
243 * If High, then our special-case for scale-only did not take, and so we | 220 * If High, then our special-case for scale-only did not take, and so we |
244 * have to make a choice: | 221 * have to make a choice: |
245 * 1. fall back on mipmaps + bilerp | 222 * 1. fall back on mipmaps + bilerp |
246 * 2. fall back on scanline bicubic filter | 223 * 2. fall back on scanline bicubic filter |
247 * For now, we compute the "scale" value from the matrix, and have a | 224 * For now, we compute the "scale" value from the matrix, and have a |
248 * threshold to decide when bicubic is better, and when mips are better. | 225 * threshold to decide when bicubic is better, and when mips are better. |
(...skipping 24 matching lines...) Expand all Loading... |
273 } | 250 } |
274 | 251 |
275 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel); | 252 SkASSERT(SkPaint::kMedium_FilterLevel == fFilterLevel); |
276 | 253 |
277 /** | 254 /** |
278 * Medium quality means use a mipmap for down-scaling, and just bilper | 255 * Medium quality means use a mipmap for down-scaling, and just bilper |
279 * for upscaling. Since we're examining the inverse matrix, we look for | 256 * for upscaling. Since we're examining the inverse matrix, we look for |
280 * a scale > 1 to indicate down scaling by the CTM. | 257 * a scale > 1 to indicate down scaling by the CTM. |
281 */ | 258 */ |
282 if (scaleSqd > SK_Scalar1) { | 259 if (scaleSqd > SK_Scalar1) { |
283 const SkMipMap* mip = NULL; | 260 fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap)); |
284 | 261 if (NULL == fCurrMip.get()) { |
285 SkASSERT(NULL == fScaledCacheID); | 262 fCurrMip.reset(SkMipMap::Build(fOrigBitmap)); |
286 fScaledCacheID = SkMipMapCache::FindAndLock(fOrigBitmap, &mip); | 263 if (NULL == fCurrMip.get()) { |
287 if (!fScaledCacheID) { | 264 return false; |
288 SkASSERT(NULL == mip); | |
289 mip = SkMipMap::Build(fOrigBitmap); | |
290 if (mip) { | |
291 fScaledCacheID = SkMipMapCache::AddAndLock(fOrigBitmap, mip); | |
292 SkASSERT(mip->getRefCnt() > 1); | |
293 mip->unref(); // the cache took a ref | |
294 SkASSERT(fScaledCacheID); | |
295 } | 265 } |
296 } else { | 266 SkMipMapCache::Add(fOrigBitmap, fCurrMip); |
297 SkASSERT(mip); | |
298 } | 267 } |
299 | 268 |
300 if (mip) { | 269 SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd)); |
301 SkScalar levelScale = SkScalarInvert(SkScalarSqrt(scaleSqd)); | 270 SkMipMap::Level level; |
302 SkMipMap::Level level; | 271 if (fCurrMip->extractLevel(levelScale, &level)) { |
303 if (mip->extractLevel(levelScale, &level)) { | 272 SkScalar invScaleFixup = level.fScale; |
304 SkScalar invScaleFixup = level.fScale; | 273 fInvMatrix.postScale(invScaleFixup, invScaleFixup); |
305 fInvMatrix.postScale(invScaleFixup, invScaleFixup); | |
306 | 274 |
307 SkImageInfo info = fOrigBitmap.info(); | 275 SkImageInfo info = fOrigBitmap.info(); |
308 info.fWidth = level.fWidth; | 276 info.fWidth = level.fWidth; |
309 info.fHeight = level.fHeight; | 277 info.fHeight = level.fHeight; |
310 fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes
); | 278 // todo: if we could wrap the fCurrMip in a pixelref, then we could
just install |
311 fBitmap = &fScaledBitmap; | 279 // that here, and not need to explicitly track it ourselves. |
312 fFilterLevel = SkPaint::kLow_FilterLevel; | 280 fScaledBitmap.installPixels(info, level.fPixels, level.fRowBytes); |
313 unlocker.release(); | 281 fBitmap = &fScaledBitmap; |
314 return true; | 282 fFilterLevel = SkPaint::kLow_FilterLevel; |
315 } | 283 return true; |
316 } | 284 } |
317 } | 285 } |
318 | 286 |
319 return false; | 287 return false; |
320 } | 288 } |
321 | 289 |
322 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { | 290 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { |
323 SkPixelRef* pr = src.pixelRef(); | 291 SkPixelRef* pr = src.pixelRef(); |
324 if (pr && pr->decodeInto(pow2, dst)) { | 292 if (pr && pr->decodeInto(pow2, dst)) { |
325 return true; | 293 return true; |
326 } | 294 } |
327 | 295 |
328 /* | 296 /* |
329 * If decodeInto() fails, it is possibe that we have an old subclass that | 297 * If decodeInto() fails, it is possibe that we have an old subclass that |
330 * does not, or cannot, implement that. In that case we fall back to the | 298 * does not, or cannot, implement that. In that case we fall back to the |
331 * older protocol of having the pixelRef handle the caching for us. | 299 * older protocol of having the pixelRef handle the caching for us. |
332 */ | 300 */ |
333 *dst = src; | 301 *dst = src; |
334 dst->lockPixels(); | 302 dst->lockPixels(); |
335 return SkToBool(dst->getPixels()); | 303 return SkToBool(dst->getPixels()); |
336 } | 304 } |
337 | 305 |
338 bool SkBitmapProcState::lockBaseBitmap() { | 306 bool SkBitmapProcState::lockBaseBitmap() { |
339 AutoScaledCacheUnlocker unlocker(&fScaledCacheID); | |
340 | |
341 SkPixelRef* pr = fOrigBitmap.pixelRef(); | 307 SkPixelRef* pr = fOrigBitmap.pixelRef(); |
342 | 308 |
343 SkASSERT(NULL == fScaledCacheID); | |
344 | |
345 if (pr->isLocked() || !pr->implementsDecodeInto()) { | 309 if (pr->isLocked() || !pr->implementsDecodeInto()) { |
346 // fast-case, no need to look in our cache | 310 // fast-case, no need to look in our cache |
347 fScaledBitmap = fOrigBitmap; | 311 fScaledBitmap = fOrigBitmap; |
348 fScaledBitmap.lockPixels(); | 312 fScaledBitmap.lockPixels(); |
349 if (NULL == fScaledBitmap.getPixels()) { | 313 if (NULL == fScaledBitmap.getPixels()) { |
350 return false; | 314 return false; |
351 } | 315 } |
352 } else { | 316 } else { |
353 fScaledCacheID = SkBitmapCache::FindAndLock(fOrigBitmap, 1, 1, &fScaledB
itmap); | 317 if (!SkBitmapCache::Find(fOrigBitmap, 1, 1, &fScaledBitmap)) { |
354 if (fScaledCacheID) { | |
355 fScaledBitmap.lockPixels(); | |
356 if (!fScaledBitmap.getPixels()) { | |
357 fScaledBitmap.unlockPixels(); | |
358 // found a purged entry (discardablememory?), release it | |
359 SkScaledImageCache::Unlock(fScaledCacheID); | |
360 fScaledCacheID = NULL; | |
361 // fall through to rebuild | |
362 } | |
363 } | |
364 | |
365 if (NULL == fScaledCacheID) { | |
366 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) { | 318 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) { |
367 return false; | 319 return false; |
368 } | 320 } |
369 | 321 |
370 // TODO: if fScaled comes back at a different width/height than fOri
g, | 322 // TODO: if fScaled comes back at a different width/height than fOri
g, |
371 // we need to update the matrix we are using to sample from this guy
. | 323 // we need to update the matrix we are using to sample from this guy
. |
372 | 324 |
373 fScaledCacheID = SkBitmapCache::AddAndLock(fOrigBitmap, 1, 1, fScale
dBitmap); | 325 SkBitmapCache::Add(fOrigBitmap, 1, 1, fScaledBitmap); |
374 if (!fScaledCacheID) { | |
375 fScaledBitmap.reset(); | |
376 return false; | |
377 } | |
378 } | 326 } |
379 } | 327 } |
380 fBitmap = &fScaledBitmap; | 328 fBitmap = &fScaledBitmap; |
381 unlocker.release(); | |
382 return true; | 329 return true; |
383 } | 330 } |
384 | 331 |
385 SkBitmapProcState::~SkBitmapProcState() { | 332 SkBitmapProcState::~SkBitmapProcState() { |
386 if (fScaledCacheID) { | |
387 SkScaledImageCache::Unlock(fScaledCacheID); | |
388 } | |
389 SkDELETE(fBitmapFilter); | 333 SkDELETE(fBitmapFilter); |
390 } | 334 } |
391 | 335 |
392 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { | 336 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
393 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height()); | 337 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height()); |
394 | 338 |
395 fBitmap = NULL; | 339 fBitmap = NULL; |
396 fInvMatrix = inv; | 340 fInvMatrix = inv; |
397 fFilterLevel = paint.getFilterLevel(); | 341 fFilterLevel = paint.getFilterLevel(); |
398 | 342 |
399 SkASSERT(NULL == fScaledCacheID); | |
400 | |
401 // possiblyScaleImage will look to see if it can rescale the image as a | 343 // possiblyScaleImage will look to see if it can rescale the image as a |
402 // preprocess; either by scaling up to the target size, or by selecting | 344 // preprocess; either by scaling up to the target size, or by selecting |
403 // a nearby mipmap level. If it does, it will adjust the working | 345 // a nearby mipmap level. If it does, it will adjust the working |
404 // matrix as well as the working bitmap. It may also adjust the filter | 346 // matrix as well as the working bitmap. It may also adjust the filter |
405 // quality to avoid re-filtering an already perfectly scaled image. | 347 // quality to avoid re-filtering an already perfectly scaled image. |
406 if (!this->possiblyScaleImage()) { | 348 if (!this->possiblyScaleImage()) { |
407 if (!this->lockBaseBitmap()) { | 349 if (!this->lockBaseBitmap()) { |
408 return false; | 350 return false; |
409 } | 351 } |
410 } | 352 } |
(...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1065 } else { | 1007 } else { |
1066 size >>= 2; | 1008 size >>= 2; |
1067 } | 1009 } |
1068 | 1010 |
1069 if (fFilterLevel != SkPaint::kNone_FilterLevel) { | 1011 if (fFilterLevel != SkPaint::kNone_FilterLevel) { |
1070 size >>= 1; | 1012 size >>= 1; |
1071 } | 1013 } |
1072 | 1014 |
1073 return size; | 1015 return size; |
1074 } | 1016 } |
OLD | NEW |