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