Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 #include "SkBitmapProcState.h" | 8 #include "SkBitmapProcState.h" |
| 9 #include "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
| 10 #include "SkFilterProc.h" | 10 #include "SkFilterProc.h" |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 | 99 |
| 100 v1.fX = mat.getScaleX(); | 100 v1.fX = mat.getScaleX(); |
| 101 v1.fY = mat.getSkewY(); | 101 v1.fY = mat.getSkewY(); |
| 102 | 102 |
| 103 v2.fX = mat.getSkewX(); | 103 v2.fX = mat.getSkewX(); |
| 104 v2.fY = mat.getScaleY(); | 104 v2.fY = mat.getScaleY(); |
| 105 | 105 |
| 106 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd()); | 106 return SkMaxScalar(v1.lengthSqd(), v2.lengthSqd()); |
| 107 } | 107 } |
| 108 | 108 |
| 109 class AutoScaledCacheUnlocker { | |
|
scroggo
2013/12/12 20:34:55
Maybe not necessary, since this is hidden in a sou
reed1
2013/12/12 21:13:49
Done.
| |
| 110 public: | |
| 111 AutoScaledCacheUnlocker(SkScaledImageCache::ID** idPtr) : fIDPtr(idPtr) {} | |
| 112 ~AutoScaledCacheUnlocker() { | |
| 113 if (fIDPtr && *fIDPtr) { | |
| 114 SkScaledImageCache::Unlock(*fIDPtr); | |
| 115 *fIDPtr = NULL; | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 void keepLock() { | |
|
scroggo
2013/12/12 20:34:55
How about reset? That keeps it consistent with our
hal.canary
2013/12/12 20:48:43
it's more of a detach() than a reset()
reed1
2013/12/12 21:13:49
How about release() -- release, since detach usual
| |
| 120 fIDPtr = NULL; | |
| 121 } | |
| 122 | |
| 123 private: | |
| 124 SkScaledImageCache::ID** fIDPtr; | |
| 125 }; | |
| 126 | |
| 109 // TODO -- we may want to pass the clip into this function so we only scale | 127 // TODO -- we may want to pass the clip into this function so we only scale |
| 110 // the portion of the image that we're going to need. This will complicate | 128 // the portion of the image that we're going to need. This will complicate |
| 111 // the interface to the cache, but might be well worth it. | 129 // the interface to the cache, but might be well worth it. |
| 112 | 130 |
| 113 bool SkBitmapProcState::possiblyScaleImage() { | 131 bool SkBitmapProcState::possiblyScaleImage() { |
| 132 AutoScaledCacheUnlocker unlocker(&fScaledCacheID); | |
| 133 | |
| 114 SkASSERT(NULL == fBitmap); | 134 SkASSERT(NULL == fBitmap); |
| 115 SkASSERT(NULL == fScaledCacheID); | 135 SkASSERT(NULL == fScaledCacheID); |
| 116 | 136 |
| 117 if (fFilterLevel <= SkPaint::kLow_FilterLevel) { | 137 if (fFilterLevel <= SkPaint::kLow_FilterLevel) { |
| 118 return false; | 138 return false; |
| 119 } | 139 } |
| 120 | 140 |
| 121 // Check to see if the transformation matrix is simple, and if we're | 141 // Check to see if the transformation matrix is simple, and if we're |
| 122 // doing high quality scaling. If so, do the bitmap scale here and | 142 // doing high quality scaling. If so, do the bitmap scale here and |
| 123 // remove the scaling component from the matrix. | 143 // remove the scaling component from the matrix. |
| 124 | 144 |
| 125 if (SkPaint::kHigh_FilterLevel == fFilterLevel && | 145 if (SkPaint::kHigh_FilterLevel == fFilterLevel && |
| 126 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma sk) && | 146 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma sk) && |
| 127 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) { | 147 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) { |
| 128 | 148 |
| 129 SkScalar invScaleX = fInvMatrix.getScaleX(); | 149 SkScalar invScaleX = fInvMatrix.getScaleX(); |
| 130 SkScalar invScaleY = fInvMatrix.getScaleY(); | 150 SkScalar invScaleY = fInvMatrix.getScaleY(); |
| 131 | 151 |
| 132 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, | 152 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, |
| 133 invScaleX, invScaleY, | 153 invScaleX, invScaleY, |
| 134 &fScaledBitmap); | 154 &fScaledBitmap); |
| 155 if (fScaledCacheID) { | |
| 156 fScaledBitmap.lockPixels(); | |
| 157 if (!fScaledBitmap.getPixels()) { | |
| 158 fScaledBitmap.unlockPixels(); | |
| 159 // found a purged entry (discardablememory?), release it | |
| 160 SkScaledImageCache::Unlock(fScaledCacheID); | |
| 161 fScaledCacheID = NULL; | |
| 162 // fall through to rebuild | |
| 163 } | |
| 164 } | |
| 165 | |
| 135 if (NULL == fScaledCacheID) { | 166 if (NULL == fScaledCacheID) { |
| 136 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX) ; | 167 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX) ; |
| 137 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY ); | 168 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY ); |
| 138 | 169 |
| 139 // All the criteria are met; let's make a new bitmap. | 170 // All the criteria are met; let's make a new bitmap. |
| 140 | 171 |
| 141 SkConvolutionProcs simd; | 172 SkConvolutionProcs simd; |
| 142 sk_bzero(&simd, sizeof(simd)); | 173 sk_bzero(&simd, sizeof(simd)); |
| 143 this->platformConvolutionProcs(&simd); | 174 this->platformConvolutionProcs(&simd); |
| 144 | 175 |
| 145 if (!SkBitmapScaler::Resize(&fScaledBitmap, | 176 if (!SkBitmapScaler::Resize(&fScaledBitmap, |
| 146 fOrigBitmap, | 177 fOrigBitmap, |
| 147 SkBitmapScaler::RESIZE_BEST, | 178 SkBitmapScaler::RESIZE_BEST, |
| 148 dest_width, | 179 dest_width, |
| 149 dest_height, | 180 dest_height, |
| 150 simd, | 181 simd, |
| 151 SkScaledImageCache::GetAllocator())) { | 182 SkScaledImageCache::GetAllocator())) { |
| 152 // we failed to create fScaledBitmap, so just return and let | 183 // we failed to create fScaledBitmap, so just return and let |
| 153 // the scanline proc handle it. | 184 // the scanline proc handle it. |
| 154 return false; | 185 return false; |
| 155 | 186 |
| 156 } | 187 } |
| 188 SkASSERT(NULL != fScaledBitmap.getPixels()); | |
| 157 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, | 189 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, |
| 158 invScaleX, | 190 invScaleX, |
| 159 invScaleY, | 191 invScaleY, |
| 160 fScaledBitmap); | 192 fScaledBitmap); |
| 161 } | 193 if (!fScaledCacheID) { |
| 162 fScaledBitmap.lockPixels(); // wonder if Resize() should have locked thi s | 194 fScaledBitmap.reset(); |
| 163 if (!fScaledBitmap.getPixels()) { | 195 return false; |
| 164 // TODO: find out how this can happen, and add a unittest to exercis e | 196 } |
| 165 // inspired by BUG=chromium:295895 | 197 SkASSERT(NULL != fScaledBitmap.getPixels()); |
| 166 return false; | |
| 167 } | 198 } |
| 168 | 199 |
| 200 SkASSERT(NULL != fScaledBitmap.getPixels()); | |
| 169 fBitmap = &fScaledBitmap; | 201 fBitmap = &fScaledBitmap; |
| 170 | 202 |
| 171 // set the inv matrix type to translate-only; | 203 // set the inv matrix type to translate-only; |
| 172 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale X(), | 204 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale X(), |
| 173 fInvMatrix.getTranslateY() / fInvMatrix.getScale Y()); | 205 fInvMatrix.getTranslateY() / fInvMatrix.getScale Y()); |
| 174 | 206 |
| 175 // no need for any further filtering; we just did it! | 207 // no need for any further filtering; we just did it! |
| 176 fFilterLevel = SkPaint::kNone_FilterLevel; | 208 fFilterLevel = SkPaint::kNone_FilterLevel; |
| 209 unlocker.keepLock(); | |
| 177 return true; | 210 return true; |
| 178 } | 211 } |
| 179 | 212 |
| 180 /* | 213 /* |
| 181 * If High, then our special-case for scale-only did not take, and so we | 214 * If High, then our special-case for scale-only did not take, and so we |
| 182 * have to make a choice: | 215 * have to make a choice: |
| 183 * 1. fall back on mipmaps + bilerp | 216 * 1. fall back on mipmaps + bilerp |
| 184 * 2. fall back on scanline bicubic filter | 217 * 2. fall back on scanline bicubic filter |
| 185 * For now, we compute the "scale" value from the matrix, and have a | 218 * For now, we compute the "scale" value from the matrix, and have a |
| 186 * threshold to decide when bicubic is better, and when mips are better. | 219 * threshold to decide when bicubic is better, and when mips are better. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 241 if (mip->extractLevel(levelScale, &level)) { | 274 if (mip->extractLevel(levelScale, &level)) { |
| 242 SkScalar invScaleFixup = level.fScale; | 275 SkScalar invScaleFixup = level.fScale; |
| 243 fInvMatrix.postScale(invScaleFixup, invScaleFixup); | 276 fInvMatrix.postScale(invScaleFixup, invScaleFixup); |
| 244 | 277 |
| 245 fScaledBitmap.setConfig(fOrigBitmap.config(), | 278 fScaledBitmap.setConfig(fOrigBitmap.config(), |
| 246 level.fWidth, level.fHeight, | 279 level.fWidth, level.fHeight, |
| 247 level.fRowBytes); | 280 level.fRowBytes); |
| 248 fScaledBitmap.setPixels(level.fPixels); | 281 fScaledBitmap.setPixels(level.fPixels); |
| 249 fBitmap = &fScaledBitmap; | 282 fBitmap = &fScaledBitmap; |
| 250 fFilterLevel = SkPaint::kLow_FilterLevel; | 283 fFilterLevel = SkPaint::kLow_FilterLevel; |
| 284 unlocker.keepLock(); | |
| 251 return true; | 285 return true; |
| 252 } | 286 } |
| 253 } | 287 } |
| 254 } | 288 } |
| 255 | 289 |
| 256 return false; | 290 return false; |
| 257 } | 291 } |
| 258 | 292 |
| 259 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { | 293 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { |
| 260 SkPixelRef* pr = src.pixelRef(); | 294 SkPixelRef* pr = src.pixelRef(); |
| 261 if (pr && pr->decodeInto(pow2, dst)) { | 295 if (pr && pr->decodeInto(pow2, dst)) { |
| 262 return true; | 296 return true; |
| 263 } | 297 } |
| 264 | 298 |
| 265 /* | 299 /* |
| 266 * If decodeInto() fails, it is possibe that we have an old subclass that | 300 * If decodeInto() fails, it is possibe that we have an old subclass that |
| 267 * does not, or cannot, implement that. In that case we fall back to the | 301 * does not, or cannot, implement that. In that case we fall back to the |
| 268 * older protocol of having the pixelRef handle the caching for us. | 302 * older protocol of having the pixelRef handle the caching for us. |
| 269 */ | 303 */ |
| 270 *dst = src; | 304 *dst = src; |
| 271 dst->lockPixels(); | 305 dst->lockPixels(); |
| 272 return SkToBool(dst->getPixels()); | 306 return SkToBool(dst->getPixels()); |
| 273 } | 307 } |
| 274 | 308 |
| 275 bool SkBitmapProcState::lockBaseBitmap() { | 309 bool SkBitmapProcState::lockBaseBitmap() { |
| 310 AutoScaledCacheUnlocker unlocker(&fScaledCacheID); | |
| 311 | |
| 276 SkPixelRef* pr = fOrigBitmap.pixelRef(); | 312 SkPixelRef* pr = fOrigBitmap.pixelRef(); |
| 277 | 313 |
| 314 SkASSERT(NULL == fScaledCacheID); | |
| 315 | |
| 278 if (pr->isLocked() || !pr->implementsDecodeInto()) { | 316 if (pr->isLocked() || !pr->implementsDecodeInto()) { |
| 279 // fast-case, no need to look in our cache | 317 // fast-case, no need to look in our cache |
| 280 fScaledBitmap = fOrigBitmap; | 318 fScaledBitmap = fOrigBitmap; |
| 319 fScaledBitmap.lockPixels(); | |
| 320 SkASSERT(NULL != fScaledBitmap.getPixels()); | |
| 281 } else { | 321 } else { |
| 282 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, | 322 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, |
| 283 SK_Scalar1, SK_Scalar1, | 323 SK_Scalar1, SK_Scalar1, |
| 284 &fScaledBitmap); | 324 &fScaledBitmap); |
| 325 if (fScaledCacheID) { | |
| 326 fScaledBitmap.lockPixels(); | |
| 327 if (!fScaledBitmap.getPixels()) { | |
| 328 fScaledBitmap.unlockPixels(); | |
| 329 // found a purged entry (discardablememory?), release it | |
| 330 SkScaledImageCache::Unlock(fScaledCacheID); | |
| 331 fScaledCacheID = NULL; | |
| 332 // fall through to rebuild | |
| 333 } | |
| 334 } | |
| 335 | |
| 285 if (NULL == fScaledCacheID) { | 336 if (NULL == fScaledCacheID) { |
| 286 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) { | 337 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) { |
| 287 return false; | 338 return false; |
| 288 } | 339 } |
| 289 | 340 |
| 290 // TODO: if fScaled comes back at a different width/height than fOri g, | 341 // TODO: if fScaled comes back at a different width/height than fOri g, |
| 291 // we need to update the matrix we are using to sample from this guy . | 342 // we need to update the matrix we are using to sample from this guy . |
| 292 | 343 |
| 293 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, | 344 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, |
| 294 SK_Scalar1, SK_Scala r1, | 345 SK_Scalar1, SK_Scala r1, |
| 295 fScaledBitmap); | 346 fScaledBitmap); |
| 296 if (!fScaledCacheID) { | 347 if (!fScaledCacheID) { |
| 297 fScaledBitmap.reset(); | 348 fScaledBitmap.reset(); |
| 298 return false; | 349 return false; |
| 299 } | 350 } |
| 300 } | 351 } |
| 301 } | 352 } |
| 302 fScaledBitmap.lockPixels(); // just 'cause the cache made a copy :( | |
| 303 if (!fScaledBitmap.getPixels()) { | |
| 304 // TODO: find out how this can happen, and add a unittest to exercise | |
| 305 // inspired by BUG=chromium:295895 | |
| 306 return false; | |
| 307 } | |
| 308 fBitmap = &fScaledBitmap; | 353 fBitmap = &fScaledBitmap; |
| 354 unlocker.keepLock(); | |
| 309 return true; | 355 return true; |
| 310 } | 356 } |
| 311 | 357 |
| 312 void SkBitmapProcState::endContext() { | 358 void SkBitmapProcState::endContext() { |
| 313 SkDELETE(fBitmapFilter); | 359 SkDELETE(fBitmapFilter); |
| 314 fBitmapFilter = NULL; | 360 fBitmapFilter = NULL; |
| 315 fScaledBitmap.reset(); | 361 fScaledBitmap.reset(); |
| 316 | 362 |
| 317 if (fScaledCacheID) { | 363 if (fScaledCacheID) { |
| 318 SkScaledImageCache::Unlock(fScaledCacheID); | 364 SkScaledImageCache::Unlock(fScaledCacheID); |
| 319 fScaledCacheID = NULL; | 365 fScaledCacheID = NULL; |
| 320 } | 366 } |
| 321 } | 367 } |
| 322 | 368 |
| 323 SkBitmapProcState::~SkBitmapProcState() { | 369 SkBitmapProcState::~SkBitmapProcState() { |
| 324 if (fScaledCacheID) { | 370 if (fScaledCacheID) { |
| 325 SkScaledImageCache::Unlock(fScaledCacheID); | 371 SkScaledImageCache::Unlock(fScaledCacheID); |
| 326 } | 372 } |
| 327 SkDELETE(fBitmapFilter); | 373 SkDELETE(fBitmapFilter); |
| 328 } | 374 } |
| 329 | 375 |
| 330 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { | 376 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { |
| 331 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height()); | 377 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height()); |
| 332 | 378 |
| 333 fBitmap = NULL; | 379 fBitmap = NULL; |
| 334 fInvMatrix = inv; | 380 fInvMatrix = inv; |
| 335 fFilterLevel = paint.getFilterLevel(); | 381 fFilterLevel = paint.getFilterLevel(); |
| 336 | 382 |
| 383 SkASSERT(NULL == fScaledCacheID); | |
| 384 | |
| 337 // possiblyScaleImage will look to see if it can rescale the image as a | 385 // possiblyScaleImage will look to see if it can rescale the image as a |
| 338 // preprocess; either by scaling up to the target size, or by selecting | 386 // preprocess; either by scaling up to the target size, or by selecting |
| 339 // a nearby mipmap level. If it does, it will adjust the working | 387 // a nearby mipmap level. If it does, it will adjust the working |
| 340 // matrix as well as the working bitmap. It may also adjust the filter | 388 // matrix as well as the working bitmap. It may also adjust the filter |
| 341 // quality to avoid re-filtering an already perfectly scaled image. | 389 // quality to avoid re-filtering an already perfectly scaled image. |
| 342 if (!this->possiblyScaleImage()) { | 390 if (!this->possiblyScaleImage()) { |
| 343 if (!this->lockBaseBitmap()) { | 391 if (!this->lockBaseBitmap()) { |
| 344 return false; | 392 return false; |
| 345 } | 393 } |
| 346 } | 394 } |
| (...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 981 } else { | 1029 } else { |
| 982 size >>= 2; | 1030 size >>= 2; |
| 983 } | 1031 } |
| 984 | 1032 |
| 985 if (fFilterLevel != SkPaint::kNone_FilterLevel) { | 1033 if (fFilterLevel != SkPaint::kNone_FilterLevel) { |
| 986 size >>= 1; | 1034 size >>= 1; |
| 987 } | 1035 } |
| 988 | 1036 |
| 989 return size; | 1037 return size; |
| 990 } | 1038 } |
| OLD | NEW |