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