Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(808)

Side by Side Diff: src/core/SkBitmapProcState.cpp

Issue 110383005: detect if the scaledimagecache returns a purged bitmap (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/core/SkBitmapScaler.cpp » ('j') | src/core/SkScaledImageCache.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | src/core/SkBitmapScaler.cpp » ('j') | src/core/SkScaledImageCache.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698