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
12 #ifdef SK_USE_POSIX_THREADS
13
14 static SkBaseMutex gPixelRefMutexRing[] = {
15 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
16 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
17 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
18 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
19
20 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
21 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
22 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
23 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
24
25 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
26 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
27 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
28 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
29
30 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
31 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
32 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
33 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER },
34 };
35
36 // must be a power-of-2. undef to just use 1 mutex
37 #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing)
38
39 #else // not pthreads
40
41 // must be a power-of-2. undef to just use 1 mutex
42 #define PIXELREF_MUTEX_RING_COUNT 32
43 static SkBaseMutex gPixelRefMutexRing[PIXELREF_MUTEX_RING_COUNT];
44
45 #endif
46
get_default_mutex()47 static 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
60 int32_t SkNextPixelRefGenerationID();
61
SkNextPixelRefGenerationID()62 int32_t SkNextPixelRefGenerationID() {
63 static int32_t gPixelRefGenerationID;
64 // do a loop in case our global wraps around, as we never want to
65 // return a 0
66 int32_t genID;
67 do {
68 genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
69 } while (0 == genID);
70 return genID;
71 }
72
73 ///////////////////////////////////////////////////////////////////////////////
74
setMutex(SkBaseMutex * mutex)75 void SkPixelRef::setMutex(SkBaseMutex* mutex) {
76 if (NULL == mutex) {
77 mutex = get_default_mutex();
78 }
79 fMutex = mutex;
80 }
81
82 // just need a > 0 value, so pick a funny one to aid in debugging
83 #define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789
84
SkPixelRef(const SkImageInfo & info,SkBaseMutex * mutex)85 SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) {
86 this->setMutex(mutex);
87 fInfo = info;
88 fPixels = NULL;
89 fColorTable = NULL; // we do not track ownership of this
90 fLockCount = 0;
91 this->needsNewGenID();
92 fIsImmutable = false;
93 fPreLocked = false;
94 }
95
SkPixelRef(const SkImageInfo & info)96 SkPixelRef::SkPixelRef(const SkImageInfo& info) {
97 this->setMutex(NULL);
98 fInfo = info;
99 fPixels = NULL;
100 fColorTable = NULL; // we do not track ownership of this
101 fLockCount = 0;
102 this->needsNewGenID();
103 fIsImmutable = false;
104 fPreLocked = false;
105 }
106
107 #ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
108 // THIS GUY IS DEPRECATED -- don't use me!
SkPixelRef(SkBaseMutex * mutex)109 SkPixelRef::SkPixelRef(SkBaseMutex* mutex) {
110 this->setMutex(mutex);
111 // Fill with dummy values.
112 sk_bzero(&fInfo, sizeof(fInfo));
113 fPixels = NULL;
114 fColorTable = NULL; // we do not track ownership of this
115 fLockCount = 0;
116 this->needsNewGenID();
117 fIsImmutable = false;
118 fPreLocked = false;
119 }
120 #endif
121
SkPixelRef(SkFlattenableReadBuffer & buffer,SkBaseMutex * mutex)122 SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
123 : INHERITED(buffer) {
124 this->setMutex(mutex);
125 fInfo.unflatten(buffer);
126 fPixels = NULL;
127 fColorTable = NULL; // we do not track ownership of this
128 fLockCount = 0;
129 fIsImmutable = buffer.readBool();
130 fGenerationID = buffer.readUInt();
131 fUniqueGenerationID = false; // Conservatively assuming the original still exists.
132 fPreLocked = false;
133 }
134
~SkPixelRef()135 SkPixelRef::~SkPixelRef() {
136 this->callGenIDChangeListeners();
137 }
138
needsNewGenID()139 void SkPixelRef::needsNewGenID() {
140 fGenerationID = 0;
141 fUniqueGenerationID = false;
142 }
143
cloneGenID(const SkPixelRef & that)144 void SkPixelRef::cloneGenID(const SkPixelRef& that) {
145 // This is subtle. We must call that.getGenerationID() to make sure its genID isn't 0.
146 this->fGenerationID = that.getGenerationID();
147 this->fUniqueGenerationID = false;
148 that.fUniqueGenerationID = false;
149 }
150
setPreLocked(void * pixels,SkColorTable * ctable)151 void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) {
152 #ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
153 // only call me in your constructor, otherwise fLockCount tracking can get
154 // out of sync.
155 fPixels = pixels;
156 fColorTable = ctable;
157 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
158 fPreLocked = true;
159 #endif
160 }
161
flatten(SkFlattenableWriteBuffer & buffer) const162 void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
163 this->INHERITED::flatten(buffer);
164 fInfo.flatten(buffer);
165 buffer.writeBool(fIsImmutable);
166 // We write the gen ID into the picture for within-process recording. This
167 // is safe since the same genID will never refer to two different sets of
168 // pixels (barring overflow). However, each process has its own "namespace"
169 // of genIDs. So for cross-process recording we write a zero which will
170 // trigger assignment of a new genID in playback.
171 if (buffer.isCrossProcess()) {
172 buffer.writeUInt(0);
173 } else {
174 buffer.writeUInt(fGenerationID);
175 fUniqueGenerationID = false; // Conservative, a copy is probably about to exist.
176 }
177 }
178
lockPixels()179 void SkPixelRef::lockPixels() {
180 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
181
182 if (!fPreLocked) {
183 SkAutoMutexAcquire ac(*fMutex);
184
185 if (1 == ++fLockCount) {
186 fPixels = this->onLockPixels(&fColorTable);
187 // If onLockPixels failed, it will return NULL
188 if (NULL == fPixels) {
189 fColorTable = NULL;
190 }
191 }
192 }
193 }
194
unlockPixels()195 void 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 (fPixels) {
205 this->onUnlockPixels();
206 fPixels = NULL;
207 fColorTable = NULL;
208 } else {
209 SkASSERT(NULL == fColorTable);
210 }
211 }
212 }
213 }
214
lockPixelsAreWritable() const215 bool SkPixelRef::lockPixelsAreWritable() const {
216 return this->onLockPixelsAreWritable();
217 }
218
onLockPixelsAreWritable() const219 bool SkPixelRef::onLockPixelsAreWritable() const {
220 return true;
221 }
222
onImplementsDecodeInto()223 bool SkPixelRef::onImplementsDecodeInto() {
224 return false;
225 }
226
onDecodeInto(int pow2,SkBitmap * bitmap)227 bool SkPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) {
228 return false;
229 }
230
getGenerationID() const231 uint32_t SkPixelRef::getGenerationID() const {
232 if (0 == fGenerationID) {
233 fGenerationID = SkNextPixelRefGenerationID();
234 fUniqueGenerationID = true; // The only time we can be sure of this!
235 }
236 return fGenerationID;
237 }
238
addGenIDChangeListener(GenIDChangeListener * listener)239 void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) {
240 if (NULL == listener || !fUniqueGenerationID) {
241 // No point in tracking this if we're not going to call it.
242 SkDELETE(listener);
243 return;
244 }
245 *fGenIDChangeListeners.append() = listener;
246 }
247
callGenIDChangeListeners()248 void SkPixelRef::callGenIDChangeListeners() {
249 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID.
250 if (fUniqueGenerationID) {
251 for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
252 fGenIDChangeListeners[i]->onChange();
253 }
254 }
255 // Listeners get at most one shot, so whether these triggered or not, blow them away.
256 fGenIDChangeListeners.deleteAll();
257 }
258
notifyPixelsChanged()259 void SkPixelRef::notifyPixelsChanged() {
260 #ifdef SK_DEBUG
261 if (fIsImmutable) {
262 SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
263 }
264 #endif
265 this->callGenIDChangeListeners();
266 this->needsNewGenID();
267 }
268
setImmutable()269 void SkPixelRef::setImmutable() {
270 fIsImmutable = true;
271 }
272
readPixels(SkBitmap * dst,const SkIRect * subset)273 bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
274 return this->onReadPixels(dst, subset);
275 }
276
onReadPixels(SkBitmap * dst,const SkIRect * subset)277 bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
278 return false;
279 }
280
onRefEncodedData()281 SkData* SkPixelRef::onRefEncodedData() {
282 return NULL;
283 }
284
getAllocatedSizeInBytes() const285 size_t SkPixelRef::getAllocatedSizeInBytes() const {
286 return 0;
287 }
288
289 ///////////////////////////////////////////////////////////////////////////////
290
291 #ifdef SK_BUILD_FOR_ANDROID
globalRef(void * data)292 void SkPixelRef::globalRef(void* data) {
293 this->ref();
294 }
295
globalUnref()296 void SkPixelRef::globalUnref() {
297 this->unref();
298 }
299 #endif
300