1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkPixelRef.h"
9#include "SkReadBuffer.h"
10#include "SkWriteBuffer.h"
11#include "SkThread.h"
12
13#ifdef SK_USE_POSIX_THREADS
14
15    static SkBaseMutex gPixelRefMutexRing[] = {
16        SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
17        SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
18        SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
19        SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
20
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
37    // must be a power-of-2. undef to just use 1 mutex
38    #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing)
39
40#else // not pthreads
41
42    // must be a power-of-2. undef to just use 1 mutex
43    #define PIXELREF_MUTEX_RING_COUNT       32
44    static SkBaseMutex gPixelRefMutexRing[PIXELREF_MUTEX_RING_COUNT];
45
46#endif
47
48static SkBaseMutex* get_default_mutex() {
49    static int32_t gPixelRefMutexRingIndex;
50
51    SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT));
52
53    // atomic_inc might be overkill here. It may be fine if once in a while
54    // we hit a race-condition and two subsequent calls get the same index...
55    int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
56    return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
57}
58
59///////////////////////////////////////////////////////////////////////////////
60
61int32_t SkNextPixelRefGenerationID();
62
63int32_t SkNextPixelRefGenerationID() {
64    static int32_t  gPixelRefGenerationID;
65    // do a loop in case our global wraps around, as we never want to
66    // return a 0
67    int32_t genID;
68    do {
69        genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
70    } while (0 == genID);
71    return genID;
72}
73
74///////////////////////////////////////////////////////////////////////////////
75
76void SkPixelRef::setMutex(SkBaseMutex* mutex) {
77    if (NULL == mutex) {
78        mutex = get_default_mutex();
79    }
80    fMutex = mutex;
81}
82
83// just need a > 0 value, so pick a funny one to aid in debugging
84#define SKPIXELREF_PRELOCKED_LOCKCOUNT     123456789
85
86SkPixelRef::SkPixelRef(const SkImageInfo& info) : fInfo(info) {
87    this->setMutex(NULL);
88    fRec.zero();
89    fLockCount = 0;
90    this->needsNewGenID();
91    fIsImmutable = false;
92    fPreLocked = false;
93}
94
95
96SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) : fInfo(info) {
97    this->setMutex(mutex);
98    fRec.zero();
99    fLockCount = 0;
100    this->needsNewGenID();
101    fIsImmutable = false;
102    fPreLocked = false;
103}
104
105static SkImageInfo read_info(SkReadBuffer& buffer) {
106    SkImageInfo info;
107    info.unflatten(buffer);
108    return info;
109}
110
111SkPixelRef::SkPixelRef(SkReadBuffer& buffer, SkBaseMutex* mutex)
112        : INHERITED(buffer)
113        , fInfo(read_info(buffer))
114{
115    this->setMutex(mutex);
116    fRec.zero();
117    fLockCount = 0;
118    fIsImmutable = buffer.readBool();
119    fGenerationID = buffer.readUInt();
120    fUniqueGenerationID = false;  // Conservatively assuming the original still exists.
121    fPreLocked = false;
122}
123
124SkPixelRef::~SkPixelRef() {
125    this->callGenIDChangeListeners();
126}
127
128void SkPixelRef::needsNewGenID() {
129    fGenerationID = 0;
130    fUniqueGenerationID = false;
131}
132
133void SkPixelRef::cloneGenID(const SkPixelRef& that) {
134    // This is subtle.  We must call that.getGenerationID() to make sure its genID isn't 0.
135    this->fGenerationID = that.getGenerationID();
136    this->fUniqueGenerationID = false;
137    that.fUniqueGenerationID = false;
138}
139
140void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) {
141#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
142    // only call me in your constructor, otherwise fLockCount tracking can get
143    // out of sync.
144    fRec.fPixels = pixels;
145    fRec.fColorTable = ctable;
146    fRec.fRowBytes = rowBytes;
147    fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
148    fPreLocked = true;
149#endif
150}
151
152void SkPixelRef::flatten(SkWriteBuffer& buffer) const {
153    this->INHERITED::flatten(buffer);
154    fInfo.flatten(buffer);
155    buffer.writeBool(fIsImmutable);
156    // We write the gen ID into the picture for within-process recording. This
157    // is safe since the same genID will never refer to two different sets of
158    // pixels (barring overflow). However, each process has its own "namespace"
159    // of genIDs. So for cross-process recording we write a zero which will
160    // trigger assignment of a new genID in playback.
161    if (buffer.isCrossProcess()) {
162        buffer.writeUInt(0);
163    } else {
164        buffer.writeUInt(fGenerationID);
165        fUniqueGenerationID = false;  // Conservative, a copy is probably about to exist.
166    }
167}
168
169bool SkPixelRef::lockPixels(LockRec* rec) {
170    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
171
172    if (!fPreLocked) {
173        SkAutoMutexAcquire  ac(*fMutex);
174
175        if (1 == ++fLockCount) {
176            SkASSERT(fRec.isZero());
177
178            LockRec rec;
179            if (!this->onNewLockPixels(&rec)) {
180                return false;
181            }
182            SkASSERT(!rec.isZero());    // else why did onNewLock return true?
183            fRec = rec;
184        }
185    }
186    *rec = fRec;
187    return true;
188}
189
190bool SkPixelRef::lockPixels() {
191    LockRec rec;
192    return this->lockPixels(&rec);
193}
194
195void SkPixelRef::unlockPixels() {
196    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
197
198    if (!fPreLocked) {
199        SkAutoMutexAcquire  ac(*fMutex);
200
201        SkASSERT(fLockCount > 0);
202        if (0 == --fLockCount) {
203            // don't call onUnlockPixels unless onLockPixels succeeded
204            if (fRec.fPixels) {
205                this->onUnlockPixels();
206                fRec.zero();
207            } else {
208                SkASSERT(fRec.isZero());
209            }
210        }
211    }
212}
213
214bool SkPixelRef::lockPixelsAreWritable() const {
215    return this->onLockPixelsAreWritable();
216}
217
218bool SkPixelRef::onLockPixelsAreWritable() const {
219    return true;
220}
221
222bool SkPixelRef::onImplementsDecodeInto() {
223    return false;
224}
225
226bool SkPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) {
227    return false;
228}
229
230uint32_t SkPixelRef::getGenerationID() const {
231    if (0 == fGenerationID) {
232        fGenerationID = SkNextPixelRefGenerationID();
233        fUniqueGenerationID = true;  // The only time we can be sure of this!
234    }
235    return fGenerationID;
236}
237
238void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) {
239    if (NULL == listener || !fUniqueGenerationID) {
240        // No point in tracking this if we're not going to call it.
241        SkDELETE(listener);
242        return;
243    }
244    *fGenIDChangeListeners.append() = listener;
245}
246
247void SkPixelRef::callGenIDChangeListeners() {
248    // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID.
249    if (fUniqueGenerationID) {
250        for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
251            fGenIDChangeListeners[i]->onChange();
252        }
253    }
254    // Listeners get at most one shot, so whether these triggered or not, blow them away.
255    fGenIDChangeListeners.deleteAll();
256}
257
258void SkPixelRef::notifyPixelsChanged() {
259#ifdef SK_DEBUG
260    if (fIsImmutable) {
261        SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
262    }
263#endif
264    this->callGenIDChangeListeners();
265    this->needsNewGenID();
266}
267
268void SkPixelRef::changeAlphaType(SkAlphaType at) {
269    *const_cast<SkAlphaType*>(&fInfo.fAlphaType) = at;
270}
271
272void SkPixelRef::setImmutable() {
273    fIsImmutable = true;
274}
275
276bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
277    return this->onReadPixels(dst, subset);
278}
279
280bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
281    return false;
282}
283
284SkData* SkPixelRef::onRefEncodedData() {
285    return NULL;
286}
287
288size_t SkPixelRef::getAllocatedSizeInBytes() const {
289    return 0;
290}
291
292///////////////////////////////////////////////////////////////////////////////
293
294#ifdef SK_BUILD_FOR_ANDROID
295void SkPixelRef::globalRef(void* data) {
296    this->ref();
297}
298
299void SkPixelRef::globalUnref() {
300    this->unref();
301}
302#endif
303