| 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 |