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
47static 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
60static 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
72void 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
82static 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
88SkPixelRef::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
105SkPixelRef::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
120SkPixelRef::~SkPixelRef() {
121    this->callGenIDChangeListeners();
122}
123
124void SkPixelRef::needsNewGenID() {
125    fTaggedGenID.store(0);
126    SkASSERT(!this->genIDIsUnique()); // This method isn't threadsafe, so the assert should be fine.
127}
128
129void 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
143void 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
155bool 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
178bool SkPixelRef::lockPixels() {
179    LockRec rec;
180    return this->lockPixels(&rec);
181}
182
183void 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
202bool SkPixelRef::lockPixelsAreWritable() const {
203    return this->onLockPixelsAreWritable();
204}
205
206bool SkPixelRef::onLockPixelsAreWritable() const {
207    return true;
208}
209
210uint32_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
225void 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
235void 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
252void 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
262void SkPixelRef::changeAlphaType(SkAlphaType at) {
263    *const_cast<SkImageInfo*>(&fInfo) = fInfo.makeAlphaType(at);
264}
265
266void SkPixelRef::setImmutable() {
267    fIsImmutable = true;
268}
269
270bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
271    return this->onReadPixels(dst, subset);
272}
273
274bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
275    return false;
276}
277
278SkData* SkPixelRef::onRefEncodedData() {
279    return NULL;
280}
281
282bool SkPixelRef::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
283                                 SkYUVColorSpace* colorSpace) {
284    return false;
285}
286
287size_t SkPixelRef::getAllocatedSizeInBytes() const {
288    return 0;
289}
290
291