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