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 "SkFlattenableBuffers.h"
10#include "SkThread.h"
11
12SK_DEFINE_INST_COUNT(SkPixelRef)
13
14
15#ifdef SK_USE_POSIX_THREADS
16
17    static SkBaseMutex gPixelRefMutexRing[] = {
18        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
19        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
20        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
21        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
22
23        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
24        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
25        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
26        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
27
28        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
29        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
30        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
31        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
32
33        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
34        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
35        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
36        { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
37    };
38
39    // must be a power-of-2. undef to just use 1 mutex
40    #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing)
41
42#else // not pthreads
43
44    // must be a power-of-2. undef to just use 1 mutex
45    #define PIXELREF_MUTEX_RING_COUNT       32
46    static SkBaseMutex gPixelRefMutexRing[PIXELREF_MUTEX_RING_COUNT];
47
48#endif
49
50static SkBaseMutex* get_default_mutex() {
51    static int32_t gPixelRefMutexRingIndex;
52
53    SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT));
54
55    // atomic_inc might be overkill here. It may be fine if once in a while
56    // we hit a race-condition and two subsequent calls get the same index...
57    int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
58    return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
59}
60
61///////////////////////////////////////////////////////////////////////////////
62
63int32_t SkNextPixelRefGenerationID();
64
65int32_t SkNextPixelRefGenerationID() {
66    static int32_t  gPixelRefGenerationID;
67    // do a loop in case our global wraps around, as we never want to
68    // return a 0
69    int32_t genID;
70    do {
71        genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
72    } while (0 == genID);
73    return genID;
74}
75
76///////////////////////////////////////////////////////////////////////////////
77
78void SkPixelRef::setMutex(SkBaseMutex* mutex) {
79    if (NULL == mutex) {
80        mutex = get_default_mutex();
81    }
82    fMutex = mutex;
83}
84
85// just need a > 0 value, so pick a funny one to aid in debugging
86#define SKPIXELREF_PRELOCKED_LOCKCOUNT     123456789
87
88SkPixelRef::SkPixelRef(SkBaseMutex* mutex) : fPreLocked(false) {
89    this->setMutex(mutex);
90    fPixels = NULL;
91    fColorTable = NULL; // we do not track ownership of this
92    fLockCount = 0;
93    fGenerationID = 0;  // signal to rebuild
94    fIsImmutable = false;
95    fPreLocked = false;
96}
97
98SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
99        : INHERITED(buffer) {
100    this->setMutex(mutex);
101    fPixels = NULL;
102    fColorTable = NULL; // we do not track ownership of this
103    fLockCount = 0;
104    fIsImmutable = buffer.readBool();
105    fGenerationID = buffer.readUInt();
106    fPreLocked = false;
107}
108
109void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) {
110#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
111    // only call me in your constructor, otherwise fLockCount tracking can get
112    // out of sync.
113    fPixels = pixels;
114    fColorTable = ctable;
115    fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
116    fPreLocked = true;
117#endif
118}
119
120void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
121    this->INHERITED::flatten(buffer);
122    buffer.writeBool(fIsImmutable);
123    // We write the gen ID into the picture for within-process recording. This
124    // is safe since the same genID will never refer to two different sets of
125    // pixels (barring overflow). However, each process has its own "namespace"
126    // of genIDs. So for cross-process recording we write a zero which will
127    // trigger assignment of a new genID in playback.
128    if (buffer.isCrossProcess()) {
129        buffer.writeUInt(0);
130    } else {
131        buffer.writeUInt(fGenerationID);
132    }
133}
134
135void SkPixelRef::lockPixels() {
136    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
137
138    if (!fPreLocked) {
139        SkAutoMutexAcquire  ac(*fMutex);
140
141        if (1 == ++fLockCount) {
142            fPixels = this->onLockPixels(&fColorTable);
143        }
144    }
145}
146
147void SkPixelRef::unlockPixels() {
148    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
149
150    if (!fPreLocked) {
151        SkAutoMutexAcquire  ac(*fMutex);
152
153        SkASSERT(fLockCount > 0);
154        if (0 == --fLockCount) {
155            this->onUnlockPixels();
156            fPixels = NULL;
157            fColorTable = NULL;
158        }
159    }
160}
161
162bool SkPixelRef::lockPixelsAreWritable() const {
163    return this->onLockPixelsAreWritable();
164}
165
166bool SkPixelRef::onLockPixelsAreWritable() const {
167    return true;
168}
169
170uint32_t SkPixelRef::getGenerationID() const {
171    if (0 == fGenerationID) {
172        fGenerationID = SkNextPixelRefGenerationID();
173    }
174    return fGenerationID;
175}
176
177void SkPixelRef::notifyPixelsChanged() {
178#ifdef SK_DEBUG
179    if (fIsImmutable) {
180        SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
181    }
182#endif
183    // this signals us to recompute this next time around
184    fGenerationID = 0;
185}
186
187void SkPixelRef::setImmutable() {
188    fIsImmutable = true;
189}
190
191bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
192    return this->onReadPixels(dst, subset);
193}
194
195bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
196    return false;
197}
198
199SkData* SkPixelRef::onRefEncodedData() {
200    return NULL;
201}
202
203///////////////////////////////////////////////////////////////////////////////
204
205#ifdef SK_BUILD_FOR_ANDROID
206void SkPixelRef::globalRef(void* data) {
207    this->ref();
208}
209
210void SkPixelRef::globalUnref() {
211    this->unref();
212}
213#endif
214