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

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') | no next file with comments »
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 {
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 // forgets the ID, so it won't call Unlock
120 void release() {
121 fIDPtr = NULL;
122 }
123
124 private:
125 SkScaledImageCache::ID** fIDPtr;
126 };
127 #define AutoScaledCacheUnlocker(...) SK_REQUIRE_LOCAL_VAR(AutoScaledCacheUnlocke r)
128
109 // TODO -- we may want to pass the clip into this function so we only scale 129 // 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 130 // 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. 131 // the interface to the cache, but might be well worth it.
112 132
113 bool SkBitmapProcState::possiblyScaleImage() { 133 bool SkBitmapProcState::possiblyScaleImage() {
134 AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
135
114 SkASSERT(NULL == fBitmap); 136 SkASSERT(NULL == fBitmap);
115 SkASSERT(NULL == fScaledCacheID); 137 SkASSERT(NULL == fScaledCacheID);
116 138
117 if (fFilterLevel <= SkPaint::kLow_FilterLevel) { 139 if (fFilterLevel <= SkPaint::kLow_FilterLevel) {
118 return false; 140 return false;
119 } 141 }
120 142
121 // Check to see if the transformation matrix is simple, and if we're 143 // 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 144 // doing high quality scaling. If so, do the bitmap scale here and
123 // remove the scaling component from the matrix. 145 // remove the scaling component from the matrix.
124 146
125 if (SkPaint::kHigh_FilterLevel == fFilterLevel && 147 if (SkPaint::kHigh_FilterLevel == fFilterLevel &&
126 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma sk) && 148 fInvMatrix.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Ma sk) &&
127 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) { 149 fOrigBitmap.config() == SkBitmap::kARGB_8888_Config) {
128 150
129 SkScalar invScaleX = fInvMatrix.getScaleX(); 151 SkScalar invScaleX = fInvMatrix.getScaleX();
130 SkScalar invScaleY = fInvMatrix.getScaleY(); 152 SkScalar invScaleY = fInvMatrix.getScaleY();
131 153
132 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, 154 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
133 invScaleX, invScaleY, 155 invScaleX, invScaleY,
134 &fScaledBitmap); 156 &fScaledBitmap);
157 if (fScaledCacheID) {
158 fScaledBitmap.lockPixels();
159 if (!fScaledBitmap.getPixels()) {
160 fScaledBitmap.unlockPixels();
161 // found a purged entry (discardablememory?), release it
162 SkScaledImageCache::Unlock(fScaledCacheID);
163 fScaledCacheID = NULL;
164 // fall through to rebuild
165 }
166 }
167
135 if (NULL == fScaledCacheID) { 168 if (NULL == fScaledCacheID) {
136 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX) ; 169 int dest_width = SkScalarCeilToInt(fOrigBitmap.width() / invScaleX) ;
137 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY ); 170 int dest_height = SkScalarCeilToInt(fOrigBitmap.height() / invScaleY );
138 171
139 // All the criteria are met; let's make a new bitmap. 172 // All the criteria are met; let's make a new bitmap.
140 173
141 SkConvolutionProcs simd; 174 SkConvolutionProcs simd;
142 sk_bzero(&simd, sizeof(simd)); 175 sk_bzero(&simd, sizeof(simd));
143 this->platformConvolutionProcs(&simd); 176 this->platformConvolutionProcs(&simd);
144 177
145 if (!SkBitmapScaler::Resize(&fScaledBitmap, 178 if (!SkBitmapScaler::Resize(&fScaledBitmap,
146 fOrigBitmap, 179 fOrigBitmap,
147 SkBitmapScaler::RESIZE_BEST, 180 SkBitmapScaler::RESIZE_BEST,
148 dest_width, 181 dest_width,
149 dest_height, 182 dest_height,
150 simd, 183 simd,
151 SkScaledImageCache::GetAllocator())) { 184 SkScaledImageCache::GetAllocator())) {
152 // we failed to create fScaledBitmap, so just return and let 185 // we failed to create fScaledBitmap, so just return and let
153 // the scanline proc handle it. 186 // the scanline proc handle it.
154 return false; 187 return false;
155 188
156 } 189 }
190 SkASSERT(NULL != fScaledBitmap.getPixels());
157 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, 191 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
158 invScaleX, 192 invScaleX,
159 invScaleY, 193 invScaleY,
160 fScaledBitmap); 194 fScaledBitmap);
161 } 195 if (!fScaledCacheID) {
162 fScaledBitmap.lockPixels(); // wonder if Resize() should have locked thi s 196 fScaledBitmap.reset();
163 if (!fScaledBitmap.getPixels()) { 197 return false;
164 // TODO: find out how this can happen, and add a unittest to exercis e 198 }
165 // inspired by BUG=chromium:295895 199 SkASSERT(NULL != fScaledBitmap.getPixels());
166 return false;
167 } 200 }
168 201
202 SkASSERT(NULL != fScaledBitmap.getPixels());
169 fBitmap = &fScaledBitmap; 203 fBitmap = &fScaledBitmap;
170 204
171 // set the inv matrix type to translate-only; 205 // set the inv matrix type to translate-only;
172 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale X(), 206 fInvMatrix.setTranslate(fInvMatrix.getTranslateX() / fInvMatrix.getScale X(),
173 fInvMatrix.getTranslateY() / fInvMatrix.getScale Y()); 207 fInvMatrix.getTranslateY() / fInvMatrix.getScale Y());
174 208
175 // no need for any further filtering; we just did it! 209 // no need for any further filtering; we just did it!
176 fFilterLevel = SkPaint::kNone_FilterLevel; 210 fFilterLevel = SkPaint::kNone_FilterLevel;
211 unlocker.release();
177 return true; 212 return true;
178 } 213 }
179 214
180 /* 215 /*
181 * If High, then our special-case for scale-only did not take, and so we 216 * If High, then our special-case for scale-only did not take, and so we
182 * have to make a choice: 217 * have to make a choice:
183 * 1. fall back on mipmaps + bilerp 218 * 1. fall back on mipmaps + bilerp
184 * 2. fall back on scanline bicubic filter 219 * 2. fall back on scanline bicubic filter
185 * For now, we compute the "scale" value from the matrix, and have a 220 * 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. 221 * 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)) { 276 if (mip->extractLevel(levelScale, &level)) {
242 SkScalar invScaleFixup = level.fScale; 277 SkScalar invScaleFixup = level.fScale;
243 fInvMatrix.postScale(invScaleFixup, invScaleFixup); 278 fInvMatrix.postScale(invScaleFixup, invScaleFixup);
244 279
245 fScaledBitmap.setConfig(fOrigBitmap.config(), 280 fScaledBitmap.setConfig(fOrigBitmap.config(),
246 level.fWidth, level.fHeight, 281 level.fWidth, level.fHeight,
247 level.fRowBytes); 282 level.fRowBytes);
248 fScaledBitmap.setPixels(level.fPixels); 283 fScaledBitmap.setPixels(level.fPixels);
249 fBitmap = &fScaledBitmap; 284 fBitmap = &fScaledBitmap;
250 fFilterLevel = SkPaint::kLow_FilterLevel; 285 fFilterLevel = SkPaint::kLow_FilterLevel;
286 unlocker.release();
251 return true; 287 return true;
252 } 288 }
253 } 289 }
254 } 290 }
255 291
256 return false; 292 return false;
257 } 293 }
258 294
259 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) { 295 static bool get_locked_pixels(const SkBitmap& src, int pow2, SkBitmap* dst) {
260 SkPixelRef* pr = src.pixelRef(); 296 SkPixelRef* pr = src.pixelRef();
261 if (pr && pr->decodeInto(pow2, dst)) { 297 if (pr && pr->decodeInto(pow2, dst)) {
262 return true; 298 return true;
263 } 299 }
264 300
265 /* 301 /*
266 * If decodeInto() fails, it is possibe that we have an old subclass that 302 * 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 303 * 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. 304 * older protocol of having the pixelRef handle the caching for us.
269 */ 305 */
270 *dst = src; 306 *dst = src;
271 dst->lockPixels(); 307 dst->lockPixels();
272 return SkToBool(dst->getPixels()); 308 return SkToBool(dst->getPixels());
273 } 309 }
274 310
275 bool SkBitmapProcState::lockBaseBitmap() { 311 bool SkBitmapProcState::lockBaseBitmap() {
312 AutoScaledCacheUnlocker unlocker(&fScaledCacheID);
313
276 SkPixelRef* pr = fOrigBitmap.pixelRef(); 314 SkPixelRef* pr = fOrigBitmap.pixelRef();
277 315
316 SkASSERT(NULL == fScaledCacheID);
317
278 if (pr->isLocked() || !pr->implementsDecodeInto()) { 318 if (pr->isLocked() || !pr->implementsDecodeInto()) {
279 // fast-case, no need to look in our cache 319 // fast-case, no need to look in our cache
280 fScaledBitmap = fOrigBitmap; 320 fScaledBitmap = fOrigBitmap;
321 fScaledBitmap.lockPixels();
322 if (NULL == fScaledBitmap.getPixels()) {
323 return false;
324 }
281 } else { 325 } else {
282 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap, 326 fScaledCacheID = SkScaledImageCache::FindAndLock(fOrigBitmap,
283 SK_Scalar1, SK_Scalar1, 327 SK_Scalar1, SK_Scalar1,
284 &fScaledBitmap); 328 &fScaledBitmap);
329 if (fScaledCacheID) {
330 fScaledBitmap.lockPixels();
331 if (!fScaledBitmap.getPixels()) {
332 fScaledBitmap.unlockPixels();
333 // found a purged entry (discardablememory?), release it
334 SkScaledImageCache::Unlock(fScaledCacheID);
335 fScaledCacheID = NULL;
336 // fall through to rebuild
337 }
338 }
339
285 if (NULL == fScaledCacheID) { 340 if (NULL == fScaledCacheID) {
286 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) { 341 if (!get_locked_pixels(fOrigBitmap, 0, &fScaledBitmap)) {
287 return false; 342 return false;
288 } 343 }
289 344
290 // TODO: if fScaled comes back at a different width/height than fOri g, 345 // 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 . 346 // we need to update the matrix we are using to sample from this guy .
292 347
293 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap, 348 fScaledCacheID = SkScaledImageCache::AddAndLock(fOrigBitmap,
294 SK_Scalar1, SK_Scala r1, 349 SK_Scalar1, SK_Scala r1,
295 fScaledBitmap); 350 fScaledBitmap);
296 if (!fScaledCacheID) { 351 if (!fScaledCacheID) {
297 fScaledBitmap.reset(); 352 fScaledBitmap.reset();
298 return false; 353 return false;
299 } 354 }
300 } 355 }
301 } 356 }
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; 357 fBitmap = &fScaledBitmap;
358 unlocker.release();
309 return true; 359 return true;
310 } 360 }
311 361
312 void SkBitmapProcState::endContext() { 362 void SkBitmapProcState::endContext() {
313 SkDELETE(fBitmapFilter); 363 SkDELETE(fBitmapFilter);
314 fBitmapFilter = NULL; 364 fBitmapFilter = NULL;
315 fScaledBitmap.reset(); 365 fScaledBitmap.reset();
316 366
317 if (fScaledCacheID) { 367 if (fScaledCacheID) {
318 SkScaledImageCache::Unlock(fScaledCacheID); 368 SkScaledImageCache::Unlock(fScaledCacheID);
319 fScaledCacheID = NULL; 369 fScaledCacheID = NULL;
320 } 370 }
321 } 371 }
322 372
323 SkBitmapProcState::~SkBitmapProcState() { 373 SkBitmapProcState::~SkBitmapProcState() {
324 if (fScaledCacheID) { 374 if (fScaledCacheID) {
325 SkScaledImageCache::Unlock(fScaledCacheID); 375 SkScaledImageCache::Unlock(fScaledCacheID);
326 } 376 }
327 SkDELETE(fBitmapFilter); 377 SkDELETE(fBitmapFilter);
328 } 378 }
329 379
330 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { 380 bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
331 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height()); 381 SkASSERT(fOrigBitmap.width() && fOrigBitmap.height());
332 382
333 fBitmap = NULL; 383 fBitmap = NULL;
334 fInvMatrix = inv; 384 fInvMatrix = inv;
335 fFilterLevel = paint.getFilterLevel(); 385 fFilterLevel = paint.getFilterLevel();
336 386
387 SkASSERT(NULL == fScaledCacheID);
388
337 // possiblyScaleImage will look to see if it can rescale the image as a 389 // 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 390 // 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 391 // 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 392 // matrix as well as the working bitmap. It may also adjust the filter
341 // quality to avoid re-filtering an already perfectly scaled image. 393 // quality to avoid re-filtering an already perfectly scaled image.
342 if (!this->possiblyScaleImage()) { 394 if (!this->possiblyScaleImage()) {
343 if (!this->lockBaseBitmap()) { 395 if (!this->lockBaseBitmap()) {
344 return false; 396 return false;
345 } 397 }
346 } 398 }
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after
981 } else { 1033 } else {
982 size >>= 2; 1034 size >>= 2;
983 } 1035 }
984 1036
985 if (fFilterLevel != SkPaint::kNone_FilterLevel) { 1037 if (fFilterLevel != SkPaint::kNone_FilterLevel) {
986 size >>= 1; 1038 size >>= 1;
987 } 1039 }
988 1040
989 return size; 1041 return size;
990 } 1042 }
OLDNEW
« no previous file with comments | « no previous file | src/core/SkBitmapScaler.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698