|
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 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
17 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
18 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
19 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
20 |
|
21 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
22 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
23 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
24 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
25 |
|
26 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
27 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
28 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
29 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
30 |
|
31 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
32 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
33 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
34 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, |
|
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 |
|
48 static 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 |
|
61 int32_t SkNextPixelRefGenerationID(); |
|
62 |
|
63 int32_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 |
|
76 void 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 |
|
86 SkPixelRef::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 |
|
96 SkPixelRef::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 |
|
105 static SkImageInfo read_info(SkReadBuffer& buffer) { |
|
106 SkImageInfo info; |
|
107 info.unflatten(buffer); |
|
108 return info; |
|
109 } |
|
110 |
|
111 SkPixelRef::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 |
|
124 SkPixelRef::~SkPixelRef() { |
|
125 this->callGenIDChangeListeners(); |
|
126 } |
|
127 |
|
128 void SkPixelRef::needsNewGenID() { |
|
129 fGenerationID = 0; |
|
130 fUniqueGenerationID = false; |
|
131 } |
|
132 |
|
133 void 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 |
|
140 void 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 |
|
152 void 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 |
|
169 bool 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 |
|
190 bool SkPixelRef::lockPixels() { |
|
191 LockRec rec; |
|
192 return this->lockPixels(&rec); |
|
193 } |
|
194 |
|
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 (fRec.fPixels) { |
|
205 this->onUnlockPixels(); |
|
206 fRec.zero(); |
|
207 } else { |
|
208 SkASSERT(fRec.isZero()); |
|
209 } |
|
210 } |
|
211 } |
|
212 } |
|
213 |
|
214 bool SkPixelRef::lockPixelsAreWritable() const { |
|
215 return this->onLockPixelsAreWritable(); |
|
216 } |
|
217 |
|
218 bool SkPixelRef::onLockPixelsAreWritable() const { |
|
219 return true; |
|
220 } |
|
221 |
|
222 bool SkPixelRef::onImplementsDecodeInto() { |
|
223 return false; |
|
224 } |
|
225 |
|
226 bool SkPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) { |
|
227 return false; |
|
228 } |
|
229 |
|
230 uint32_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 |
|
238 void 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 |
|
247 void 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 |
|
258 void 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 |
|
268 void SkPixelRef::changeAlphaType(SkAlphaType at) { |
|
269 *const_cast<SkAlphaType*>(&fInfo.fAlphaType) = at; |
|
270 } |
|
271 |
|
272 void SkPixelRef::setImmutable() { |
|
273 fIsImmutable = true; |
|
274 } |
|
275 |
|
276 bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) { |
|
277 return this->onReadPixels(dst, subset); |
|
278 } |
|
279 |
|
280 bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { |
|
281 return false; |
|
282 } |
|
283 |
|
284 SkData* SkPixelRef::onRefEncodedData() { |
|
285 return NULL; |
|
286 } |
|
287 |
|
288 size_t SkPixelRef::getAllocatedSizeInBytes() const { |
|
289 return 0; |
|
290 } |
|
291 |
|
292 /////////////////////////////////////////////////////////////////////////////// |
|
293 |
|
294 #ifdef SK_BUILD_FOR_ANDROID |
|
295 void SkPixelRef::globalRef(void* data) { |
|
296 this->ref(); |
|
297 } |
|
298 |
|
299 void SkPixelRef::globalUnref() { |
|
300 this->unref(); |
|
301 } |
|
302 #endif |