OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 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 "Sk64.h" | 8 #include "Sk64.h" |
9 #include "SkLazyPixelRef.h" | 9 #include "SkLazyPixelRef.h" |
10 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
11 #include "SkData.h" | 11 #include "SkData.h" |
12 #include "SkImageCache.h" | 12 #include "SkImageCache.h" |
13 #include "SkImagePriv.h" | 13 #include "SkImagePriv.h" |
| 14 #include "SkScaledImageCache.h" |
14 | 15 |
15 #if LAZY_CACHE_STATS | 16 #if LAZY_CACHE_STATS |
16 #include "SkThread.h" | 17 #include "SkThread.h" |
17 | 18 |
18 int32_t SkLazyPixelRef::gCacheHits; | 19 int32_t SkLazyPixelRef::gCacheHits; |
19 int32_t SkLazyPixelRef::gCacheMisses; | 20 int32_t SkLazyPixelRef::gCacheMisses; |
20 #endif | 21 #endif |
21 | 22 |
22 SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, S
kImageCache* cache) | 23 SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, S
kImageCache* cache) |
23 // Pass NULL for the Mutex so that the default (ring buffer) will be used. | 24 // Pass NULL for the Mutex so that the default (ring buffer) will be used. |
24 : INHERITED(NULL) | 25 : INHERITED(NULL) |
| 26 , fErrorInDecoding(false) |
25 , fDecodeProc(proc) | 27 , fDecodeProc(proc) |
26 , fImageCache(cache) | 28 , fImageCache(cache) |
27 , fCacheId(SkImageCache::UNINITIALIZED_ID) | |
28 , fRowBytes(0) { | 29 , fRowBytes(0) { |
29 SkASSERT(fDecodeProc != NULL); | 30 SkASSERT(fDecodeProc != NULL); |
30 if (NULL == data) { | 31 if (NULL == data) { |
31 fData = SkData::NewEmpty(); | 32 fData = SkData::NewEmpty(); |
32 fErrorInDecoding = true; | 33 fErrorInDecoding = true; |
33 } else { | 34 } else { |
34 fData = data; | 35 fData = data; |
35 fData->ref(); | 36 fData->ref(); |
36 fErrorInDecoding = data->size() == 0; | 37 fErrorInDecoding = data->size() == 0; |
37 } | 38 } |
38 SkASSERT(cache != NULL); | 39 if (fImageCache != NULL) { |
39 cache->ref(); | 40 fImageCache->ref(); |
| 41 fCacheId = SkImageCache::UNINITIALIZED_ID; |
| 42 } else { |
| 43 fScaledCacheId = NULL; |
| 44 } |
40 | 45 |
41 // mark as uninitialized -- all fields are -1 | 46 // mark as uninitialized -- all fields are -1 |
42 memset(&fLazilyCachedInfo, 0xFF, sizeof(fLazilyCachedInfo)); | 47 memset(&fLazilyCachedInfo, 0xFF, sizeof(fLazilyCachedInfo)); |
43 | 48 |
44 // Since this pixel ref bases its data on encoded data, it should never chan
ge. | 49 // Since this pixel ref bases its data on encoded data, it should never chan
ge. |
45 this->setImmutable(); | 50 this->setImmutable(); |
46 } | 51 } |
47 | 52 |
48 SkLazyPixelRef::~SkLazyPixelRef() { | 53 SkLazyPixelRef::~SkLazyPixelRef() { |
49 SkASSERT(fData != NULL); | 54 SkASSERT(fData != NULL); |
50 fData->unref(); | 55 fData->unref(); |
| 56 if (NULL == fImageCache) { |
| 57 if (fScaledCacheId != NULL) { |
| 58 SkScaledImageCache::Unlock(fScaledCacheId); |
| 59 // TODO(halcanary): SkScaledImageCache needs a |
| 60 // throwAwayCache(id) method. |
| 61 } |
| 62 return; |
| 63 } |
51 SkASSERT(fImageCache); | 64 SkASSERT(fImageCache); |
52 if (fCacheId != SkImageCache::UNINITIALIZED_ID) { | 65 if (fCacheId != SkImageCache::UNINITIALIZED_ID) { |
53 fImageCache->throwAwayCache(fCacheId); | 66 fImageCache->throwAwayCache(fCacheId); |
54 } | 67 } |
55 fImageCache->unref(); | 68 fImageCache->unref(); |
56 } | 69 } |
57 | 70 |
58 static size_t ComputeMinRowBytesAndSize(const SkImage::Info& info, size_t* rowBy
tes) { | 71 static size_t ComputeMinRowBytesAndSize(const SkImage::Info& info, size_t* rowBy
tes) { |
59 *rowBytes = SkImageMinRowBytes(info); | 72 *rowBytes = SkImageMinRowBytes(info); |
60 | 73 |
(...skipping 11 matching lines...) Expand all Loading... |
72 SkImage::Info info; | 85 SkImage::Info info; |
73 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NUL
L); | 86 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NUL
L); |
74 if (fErrorInDecoding) { | 87 if (fErrorInDecoding) { |
75 return NULL; | 88 return NULL; |
76 } | 89 } |
77 fLazilyCachedInfo = info; | 90 fLazilyCachedInfo = info; |
78 } | 91 } |
79 return &fLazilyCachedInfo; | 92 return &fLazilyCachedInfo; |
80 } | 93 } |
81 | 94 |
| 95 /** |
| 96 Returns bitmap->getPixels() on success; NULL on failure */ |
| 97 static void* decode_into_bitmap(SkImage::Info* info, |
| 98 SkBitmapFactory::DecodeProc decodeProc, |
| 99 size_t* rowBytes, |
| 100 SkData* data, |
| 101 SkBitmap* bm) { |
| 102 SkASSERT(info && decodeProc && rowBytes && data && bm); |
| 103 if (!(bm->setConfig(SkImageInfoToBitmapConfig(*info), info->fWidth, |
| 104 info->fHeight, *rowBytes, info->fAlphaType) |
| 105 && bm->allocPixels(NULL, NULL))) { |
| 106 // Use the default allocator. It may be necessary for the |
| 107 // SkLazyPixelRef to have a allocator field which is passed |
| 108 // into allocPixels(). |
| 109 return NULL; |
| 110 } |
| 111 SkBitmapFactory::Target target; |
| 112 target.fAddr = bm->getPixels(); |
| 113 target.fRowBytes = bm->rowBytes(); |
| 114 *rowBytes = target.fRowBytes; |
| 115 if (!decodeProc(data->data(), data->size(), info, &target)) { |
| 116 return NULL; |
| 117 } |
| 118 return target.fAddr; |
| 119 } |
| 120 |
| 121 void* SkLazyPixelRef::lockScaledImageCachePixels() { |
| 122 SkASSERT(!fErrorInDecoding); |
| 123 SkASSERT(NULL == fImageCache); |
| 124 SkBitmap bitmap; |
| 125 const SkImage::Info* info = this->getCachedInfo(); |
| 126 if (info == NULL) { |
| 127 return NULL; |
| 128 } |
| 129 // If this is the first time though, this is guaranteed to fail. |
| 130 // Maybe we should have a flag that says "don't even bother looking" |
| 131 fScaledCacheId = SkScaledImageCache::FindAndLock(this->getGenerationID(), |
| 132 info->fWidth, |
| 133 info->fHeight, |
| 134 &bitmap); |
| 135 if (fScaledCacheId != NULL) { |
| 136 SkAutoLockPixels autoLockPixels(bitmap); |
| 137 void* pixels = bitmap.getPixels(); |
| 138 SkASSERT(NULL != pixels); |
| 139 // At this point, the autoLockPixels will unlockPixels() |
| 140 // to remove bitmap's lock on the pixels. We will then |
| 141 // destroy bitmap. The *only* guarantee that this pointer |
| 142 // remains valid is the guarantee made by |
| 143 // SkScaledImageCache that it will not destroy the *other* |
| 144 // bitmap (SkScaledImageCache::Rec.fBitmap) that holds a |
| 145 // reference to the concrete PixelRef while this record is |
| 146 // locked. |
| 147 return pixels; |
| 148 } else { |
| 149 // Cache has been purged, must re-decode. |
| 150 void* pixels = decode_into_bitmap(const_cast<SkImage::Info*>(info), |
| 151 fDecodeProc, &fRowBytes, fData, |
| 152 &bitmap); |
| 153 if (NULL == pixels) { |
| 154 fErrorInDecoding = true; |
| 155 return NULL; |
| 156 } |
| 157 fScaledCacheId = SkScaledImageCache::AddAndLock(this->getGenerationID(), |
| 158 info->fWidth, |
| 159 info->fHeight, |
| 160 bitmap); |
| 161 SkASSERT(fScaledCacheId != NULL); |
| 162 return pixels; |
| 163 } |
| 164 } |
| 165 |
82 void* SkLazyPixelRef::onLockPixels(SkColorTable**) { | 166 void* SkLazyPixelRef::onLockPixels(SkColorTable**) { |
83 if (fErrorInDecoding) { | 167 if (fErrorInDecoding) { |
84 return NULL; | 168 return NULL; |
85 } | 169 } |
| 170 if (NULL == fImageCache) { |
| 171 return this->lockScaledImageCachePixels(); |
| 172 } else { |
| 173 return this->lockImageCachePixels(); |
| 174 } |
| 175 } |
| 176 |
| 177 void* SkLazyPixelRef::lockImageCachePixels() { |
| 178 SkASSERT(fImageCache != NULL); |
| 179 SkASSERT(!fErrorInDecoding); |
86 SkBitmapFactory::Target target; | 180 SkBitmapFactory::Target target; |
87 // Check to see if the pixels still exist in the cache. | 181 // Check to see if the pixels still exist in the cache. |
88 if (SkImageCache::UNINITIALIZED_ID == fCacheId) { | 182 if (SkImageCache::UNINITIALIZED_ID == fCacheId) { |
89 target.fAddr = NULL; | 183 target.fAddr = NULL; |
90 } else { | 184 } else { |
91 SkImageCache::DataStatus status; | 185 SkImageCache::DataStatus status; |
92 target.fAddr = fImageCache->pinCache(fCacheId, &status); | 186 target.fAddr = fImageCache->pinCache(fCacheId, &status); |
93 if (target.fAddr == NULL) { | 187 if (target.fAddr == NULL) { |
94 fCacheId = SkImageCache::UNINITIALIZED_ID; | 188 fCacheId = SkImageCache::UNINITIALIZED_ID; |
95 } else { | 189 } else { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 } | 234 } |
141 // Upon success, store fRowBytes so it can be used in case pinCache later re
turns purged memory. | 235 // Upon success, store fRowBytes so it can be used in case pinCache later re
turns purged memory. |
142 fRowBytes = target.fRowBytes; | 236 fRowBytes = target.fRowBytes; |
143 return target.fAddr; | 237 return target.fAddr; |
144 } | 238 } |
145 | 239 |
146 void SkLazyPixelRef::onUnlockPixels() { | 240 void SkLazyPixelRef::onUnlockPixels() { |
147 if (fErrorInDecoding) { | 241 if (fErrorInDecoding) { |
148 return; | 242 return; |
149 } | 243 } |
150 if (fCacheId != SkImageCache::UNINITIALIZED_ID) { | 244 if (NULL == fImageCache) { |
151 fImageCache->releaseCache(fCacheId); | 245 // onUnlockPixels() should never be called a second time from |
| 246 // PixelRef::Unlock() without calling onLockPixels() first. |
| 247 SkASSERT(NULL != fScaledCacheId); |
| 248 if (NULL != fScaledCacheId) { |
| 249 SkScaledImageCache::Unlock(fScaledCacheId); |
| 250 fScaledCacheId = NULL; |
| 251 } |
| 252 } else { // use fImageCache |
| 253 SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId); |
| 254 if (SkImageCache::UNINITIALIZED_ID != fCacheId) { |
| 255 fImageCache->releaseCache(fCacheId); |
| 256 } |
152 } | 257 } |
153 } | 258 } |
154 | 259 |
155 SkData* SkLazyPixelRef::onRefEncodedData() { | 260 SkData* SkLazyPixelRef::onRefEncodedData() { |
156 fData->ref(); | 261 fData->ref(); |
157 return fData; | 262 return fData; |
158 } | 263 } |
159 | 264 |
160 #include "SkImagePriv.h" | |
161 | |
162 static bool init_from_info(SkBitmap* bm, const SkImage::Info& info, | 265 static bool init_from_info(SkBitmap* bm, const SkImage::Info& info, |
163 size_t rowBytes) { | 266 size_t rowBytes) { |
164 SkBitmap::Config config = SkImageInfoToBitmapConfig(info); | 267 SkBitmap::Config config = SkImageInfoToBitmapConfig(info); |
165 if (SkBitmap::kNo_Config == config) { | 268 if (SkBitmap::kNo_Config == config) { |
166 return false; | 269 return false; |
167 } | 270 } |
168 | 271 |
169 return bm->setConfig(config, info.fWidth, info.fHeight, rowBytes, info.fAlph
aType) | 272 return bm->setConfig(config, info.fWidth, info.fHeight, rowBytes, info.fAlph
aType) |
170 && | 273 && |
171 bm->allocPixels(); | 274 bm->allocPixels(); |
(...skipping 27 matching lines...) Expand all Loading... |
199 | 302 |
200 target.fAddr = tmp.getPixels(); | 303 target.fAddr = tmp.getPixels(); |
201 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target
); | 304 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target
); |
202 if (fErrorInDecoding) { | 305 if (fErrorInDecoding) { |
203 return false; | 306 return false; |
204 } | 307 } |
205 | 308 |
206 *bitmap = tmp; | 309 *bitmap = tmp; |
207 return true; | 310 return true; |
208 } | 311 } |
| 312 |
OLD | NEW |