• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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