1 /*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkBitmapCache.h"
9 #include "SkPixelRef.h"
10 #include "SkThread.h"
11 #include "SkTraceEvent.h"
12
13 #ifdef SK_BUILD_FOR_WIN32
14 // We don't have SK_BASE_MUTEX_INIT on Windows.
15
16 // must be a power-of-2. undef to just use 1 mutex
17 #define PIXELREF_MUTEX_RING_COUNT 32
18 static SkBaseMutex gPixelRefMutexRing[PIXELREF_MUTEX_RING_COUNT];
19
20 #else
21 static SkBaseMutex gPixelRefMutexRing[] = {
22 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
23 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
24 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
25 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
26
27 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
28 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
29 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
30 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
31
32 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
33 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
34 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
35 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
36
37 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
38 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
39 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
40 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
41 };
42 // must be a power-of-2. undef to just use 1 mutex
43 #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing)
44
45 #endif
46
get_default_mutex()47 static SkBaseMutex* get_default_mutex() {
48 static int32_t gPixelRefMutexRingIndex;
49
50 SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT));
51
52 // atomic_inc might be overkill here. It may be fine if once in a while
53 // we hit a race-condition and two subsequent calls get the same index...
54 int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
55 return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
56 }
57
58 ///////////////////////////////////////////////////////////////////////////////
59
next_gen_id()60 static uint32_t next_gen_id() {
61 static uint32_t gNextGenID = 0;
62 uint32_t genID;
63 // Loop in case our global wraps around, as we never want to return a 0.
64 do {
65 genID = sk_atomic_fetch_add(&gNextGenID, 2u) + 2; // Never set the low bit.
66 } while (0 == genID);
67 return genID;
68 }
69
70 ///////////////////////////////////////////////////////////////////////////////
71
setMutex(SkBaseMutex * mutex)72 void SkPixelRef::setMutex(SkBaseMutex* mutex) {
73 if (NULL == mutex) {
74 mutex = get_default_mutex();
75 }
76 fMutex = mutex;
77 }
78
79 // just need a > 0 value, so pick a funny one to aid in debugging
80 #define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789
81
validate_info(const SkImageInfo & info)82 static SkImageInfo validate_info(const SkImageInfo& info) {
83 SkAlphaType newAlphaType = info.alphaType();
84 SkAssertResult(SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAlphaType));
85 return info.makeAlphaType(newAlphaType);
86 }
87
SkPixelRef(const SkImageInfo & info)88 SkPixelRef::SkPixelRef(const SkImageInfo& info)
89 : fInfo(validate_info(info))
90 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
91 , fStableID(next_gen_id())
92 #endif
93
94 {
95 this->setMutex(NULL);
96 fRec.zero();
97 fLockCount = 0;
98 this->needsNewGenID();
99 fIsImmutable = false;
100 fPreLocked = false;
101 fAddedToCache.store(false);
102 }
103
104
SkPixelRef(const SkImageInfo & info,SkBaseMutex * mutex)105 SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex)
106 : fInfo(validate_info(info))
107 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
108 , fStableID(next_gen_id())
109 #endif
110 {
111 this->setMutex(mutex);
112 fRec.zero();
113 fLockCount = 0;
114 this->needsNewGenID();
115 fIsImmutable = false;
116 fPreLocked = false;
117 fAddedToCache.store(false);
118 }
119
~SkPixelRef()120 SkPixelRef::~SkPixelRef() {
121 this->callGenIDChangeListeners();
122 }
123
needsNewGenID()124 void SkPixelRef::needsNewGenID() {
125 fTaggedGenID.store(0);
126 SkASSERT(!this->genIDIsUnique()); // This method isn't threadsafe, so the assert should be fine.
127 }
128
cloneGenID(const SkPixelRef & that)129 void SkPixelRef::cloneGenID(const SkPixelRef& that) {
130 // This is subtle. We must call that.getGenerationID() to make sure its genID isn't 0.
131 uint32_t genID = that.getGenerationID();
132
133 // Neither ID is unique any more.
134 // (These & ~1u are actually redundant. that.getGenerationID() just did it for us.)
135 this->fTaggedGenID.store(genID & ~1u);
136 that. fTaggedGenID.store(genID & ~1u);
137
138 // This method isn't threadsafe, so these asserts should be fine.
139 SkASSERT(!this->genIDIsUnique());
140 SkASSERT(!that. genIDIsUnique());
141 }
142
setPreLocked(void * pixels,size_t rowBytes,SkColorTable * ctable)143 void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) {
144 #ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
145 // only call me in your constructor, otherwise fLockCount tracking can get
146 // out of sync.
147 fRec.fPixels = pixels;
148 fRec.fColorTable = ctable;
149 fRec.fRowBytes = rowBytes;
150 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
151 fPreLocked = true;
152 #endif
153 }
154
lockPixels(LockRec * rec)155 bool SkPixelRef::lockPixels(LockRec* rec) {
156 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
157
158 if (!fPreLocked) {
159 TRACE_EVENT_BEGIN0("skia", "SkPixelRef::lockPixelsMutex");
160 SkAutoMutexAcquire ac(*fMutex);
161 TRACE_EVENT_END0("skia", "SkPixelRef::lockPixelsMutex");
162
163 if (1 == ++fLockCount) {
164 SkASSERT(fRec.isZero());
165
166 LockRec rec;
167 if (!this->onNewLockPixels(&rec)) {
168 return false;
169 }
170 SkASSERT(!rec.isZero()); // else why did onNewLock return true?
171 fRec = rec;
172 }
173 }
174 *rec = fRec;
175 return true;
176 }
177
lockPixels()178 bool SkPixelRef::lockPixels() {
179 LockRec rec;
180 return this->lockPixels(&rec);
181 }
182
unlockPixels()183 void SkPixelRef::unlockPixels() {
184 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
185
186 if (!fPreLocked) {
187 SkAutoMutexAcquire ac(*fMutex);
188
189 SkASSERT(fLockCount > 0);
190 if (0 == --fLockCount) {
191 // don't call onUnlockPixels unless onLockPixels succeeded
192 if (fRec.fPixels) {
193 this->onUnlockPixels();
194 fRec.zero();
195 } else {
196 SkASSERT(fRec.isZero());
197 }
198 }
199 }
200 }
201
lockPixelsAreWritable() const202 bool SkPixelRef::lockPixelsAreWritable() const {
203 return this->onLockPixelsAreWritable();
204 }
205
onLockPixelsAreWritable() const206 bool SkPixelRef::onLockPixelsAreWritable() const {
207 return true;
208 }
209
getGenerationID() const210 uint32_t SkPixelRef::getGenerationID() const {
211 uint32_t id = fTaggedGenID.load();
212 if (0 == id) {
213 uint32_t next = next_gen_id() | 1u;
214 if (fTaggedGenID.compare_exchange(&id, next)) {
215 id = next; // There was no race or we won the race. fTaggedGenID is next now.
216 } else {
217 // We lost a race to set fTaggedGenID. compare_exchange() filled id with the winner.
218 }
219 // We can't quite SkASSERT(this->genIDIsUnique()). It could be non-unique
220 // if we got here via the else path (pretty unlikely, but possible).
221 }
222 return id & ~1u; // Mask off bottom unique bit.
223 }
224
addGenIDChangeListener(GenIDChangeListener * listener)225 void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) {
226 if (NULL == listener || !this->genIDIsUnique()) {
227 // No point in tracking this if we're not going to call it.
228 SkDELETE(listener);
229 return;
230 }
231 *fGenIDChangeListeners.append() = listener;
232 }
233
234 // we need to be called *before* the genID gets changed or zerod
callGenIDChangeListeners()235 void SkPixelRef::callGenIDChangeListeners() {
236 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID.
237 if (this->genIDIsUnique()) {
238 for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
239 fGenIDChangeListeners[i]->onChange();
240 }
241
242 // TODO: SkAtomic could add "old_value = atomic.xchg(new_value)" to make this clearer.
243 if (fAddedToCache.load()) {
244 SkNotifyBitmapGenIDIsStale(this->getGenerationID());
245 fAddedToCache.store(false);
246 }
247 }
248 // Listeners get at most one shot, so whether these triggered or not, blow them away.
249 fGenIDChangeListeners.deleteAll();
250 }
251
notifyPixelsChanged()252 void SkPixelRef::notifyPixelsChanged() {
253 #ifdef SK_DEBUG
254 if (fIsImmutable) {
255 SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
256 }
257 #endif
258 this->callGenIDChangeListeners();
259 this->needsNewGenID();
260 }
261
changeAlphaType(SkAlphaType at)262 void SkPixelRef::changeAlphaType(SkAlphaType at) {
263 *const_cast<SkImageInfo*>(&fInfo) = fInfo.makeAlphaType(at);
264 }
265
setImmutable()266 void SkPixelRef::setImmutable() {
267 fIsImmutable = true;
268 }
269
readPixels(SkBitmap * dst,const SkIRect * subset)270 bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
271 return this->onReadPixels(dst, subset);
272 }
273
onReadPixels(SkBitmap * dst,const SkIRect * subset)274 bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
275 return false;
276 }
277
onRefEncodedData()278 SkData* SkPixelRef::onRefEncodedData() {
279 return NULL;
280 }
281
onGetYUV8Planes(SkISize sizes[3],void * planes[3],size_t rowBytes[3],SkYUVColorSpace * colorSpace)282 bool SkPixelRef::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
283 SkYUVColorSpace* colorSpace) {
284 return false;
285 }
286
getAllocatedSizeInBytes() const287 size_t SkPixelRef::getAllocatedSizeInBytes() const {
288 return 0;
289 }
290
291