blob: e93882a465ddd0cc2702df8c553d56648d3504cb [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkPixelRef.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00009#include "SkFlattenableBuffers.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkThread.h"
11
reed@google.comdd96eb42013-04-12 15:34:53 +000012#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
reed@google.comff0da4f2012-05-17 13:14:52 +000045#endif
46
caryclark@google.com803eceb2012-06-06 12:09:34 +000047static SkBaseMutex* get_default_mutex() {
reed@google.comdd96eb42013-04-12 15:34:53 +000048 static int32_t gPixelRefMutexRingIndex;
49
50 SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT));
51
reed@google.comff0da4f2012-05-17 13:14:52 +000052 // 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)];
reed@google.comff0da4f2012-05-17 13:14:52 +000056}
57
58///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com586f48c2011-04-14 15:07:22 +000059
bsalomon@google.com100abf42012-09-05 17:40:04 +000060int32_t SkNextPixelRefGenerationID();
61
reed@google.com9c49bc32011-07-07 13:42:37 +000062int32_t SkNextPixelRefGenerationID() {
bsalomon@google.com586f48c2011-04-14 15:07:22 +000063 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
reed@google.comff0da4f2012-05-17 13:14:52 +000073///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000074
reed@google.comff0da4f2012-05-17 13:14:52 +000075void SkPixelRef::setMutex(SkBaseMutex* mutex) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 if (NULL == mutex) {
reed@google.comff0da4f2012-05-17 13:14:52 +000077 mutex = get_default_mutex();
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 }
79 fMutex = mutex;
reed@google.comff0da4f2012-05-17 13:14:52 +000080}
81
82// just need a > 0 value, so pick a funny one to aid in debugging
83#define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789
84
scroggo@google.com728f2a62013-12-12 15:19:30 +000085SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) {
reed@google.com398337b2013-12-11 21:22:39 +000086 this->setMutex(mutex);
scroggo@google.com728f2a62013-12-12 15:19:30 +000087 fInfo = info;
reed@google.com398337b2013-12-11 21:22:39 +000088 fPixels = NULL;
89 fColorTable = NULL; // we do not track ownership of this
reed@google.com6a32add2013-12-11 18:19:10 +000090 fLockCount = 0;
91 this->needsNewGenID();
92 fIsImmutable = false;
93 fPreLocked = false;
94}
reed@google.com6a32add2013-12-11 18:19:10 +000095
scroggo@google.com728f2a62013-12-12 15:19:30 +000096SkPixelRef::SkPixelRef(const SkImageInfo& info) {
reed@google.com398337b2013-12-11 21:22:39 +000097 this->setMutex(NULL);
scroggo@google.com728f2a62013-12-12 15:19:30 +000098 fInfo = info;
reed@google.com398337b2013-12-11 21:22:39 +000099 fPixels = NULL;
100 fColorTable = NULL; // we do not track ownership of this
commit-bot@chromium.orgff9c6c92013-12-11 20:55:41 +0000101 fLockCount = 0;
102 this->needsNewGenID();
103 fIsImmutable = false;
104 fPreLocked = false;
105}
commit-bot@chromium.orgff9c6c92013-12-11 20:55:41 +0000106
reed@google.com398337b2013-12-11 21:22:39 +0000107#ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
108// THIS GUY IS DEPRECATED -- don't use me!
109SkPixelRef::SkPixelRef(SkBaseMutex* mutex) {
110 this->setMutex(mutex);
scroggo@google.com728f2a62013-12-12 15:19:30 +0000111 // Fill with dummy values.
112 sk_bzero(&fInfo, sizeof(fInfo));
reed@google.com398337b2013-12-11 21:22:39 +0000113 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
djsollen@google.com5370cd92012-03-28 20:47:01 +0000122SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
123 : INHERITED(buffer) {
reed@google.comff0da4f2012-05-17 13:14:52 +0000124 this->setMutex(mutex);
reed@google.com398337b2013-12-11 21:22:39 +0000125 fPixels = NULL;
126 fColorTable = NULL; // we do not track ownership of this
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 fLockCount = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 fIsImmutable = buffer.readBool();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000129 fGenerationID = buffer.readUInt();
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000130 fUniqueGenerationID = false; // Conservatively assuming the original still exists.
reed@google.comff0da4f2012-05-17 13:14:52 +0000131 fPreLocked = false;
132}
133
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000134SkPixelRef::~SkPixelRef() {
135 this->callGenIDChangeListeners();
136}
137
138void SkPixelRef::needsNewGenID() {
139 fGenerationID = 0;
140 fUniqueGenerationID = false;
141}
142
143void SkPixelRef::cloneGenID(const SkPixelRef& that) {
144 // This is subtle. We must call that.getGenerationID() to make sure its genID isn't 0.
145 this->fGenerationID = that.getGenerationID();
146 this->fUniqueGenerationID = false;
147 that.fUniqueGenerationID = false;
148}
149
reed@google.com398337b2013-12-11 21:22:39 +0000150void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) {
reed@google.com2a3f08b2012-12-13 21:41:00 +0000151#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
reed@google.comff0da4f2012-05-17 13:14:52 +0000152 // only call me in your constructor, otherwise fLockCount tracking can get
153 // out of sync.
reed@google.com398337b2013-12-11 21:22:39 +0000154 fPixels = pixels;
155 fColorTable = ctable;
reed@google.comff0da4f2012-05-17 13:14:52 +0000156 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
157 fPreLocked = true;
reed@google.com2a3f08b2012-12-13 21:41:00 +0000158#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159}
160
djsollen@google.com54924242012-03-29 15:18:04 +0000161void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
djsollen@google.com5370cd92012-03-28 20:47:01 +0000162 this->INHERITED::flatten(buffer);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 buffer.writeBool(fIsImmutable);
bsalomon@google.com7aa876b2012-06-21 20:13:04 +0000164 // We write the gen ID into the picture for within-process recording. This
165 // is safe since the same genID will never refer to two different sets of
166 // pixels (barring overflow). However, each process has its own "namespace"
167 // of genIDs. So for cross-process recording we write a zero which will
168 // trigger assignment of a new genID in playback.
169 if (buffer.isCrossProcess()) {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000170 buffer.writeUInt(0);
bsalomon@google.com7aa876b2012-06-21 20:13:04 +0000171 } else {
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000172 buffer.writeUInt(fGenerationID);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000173 fUniqueGenerationID = false; // Conservative, a copy is probably about to exist.
bsalomon@google.com7aa876b2012-06-21 20:13:04 +0000174 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175}
176
reed@google.com398337b2013-12-11 21:22:39 +0000177void SkPixelRef::lockPixels() {
reed@google.comff0da4f2012-05-17 13:14:52 +0000178 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
reed@google.com398337b2013-12-11 21:22:39 +0000179
reed@google.comff0da4f2012-05-17 13:14:52 +0000180 if (!fPreLocked) {
181 SkAutoMutexAcquire ac(*fMutex);
reed@google.com398337b2013-12-11 21:22:39 +0000182
reed@google.comff0da4f2012-05-17 13:14:52 +0000183 if (1 == ++fLockCount) {
reed@google.com398337b2013-12-11 21:22:39 +0000184 fPixels = this->onLockPixels(&fColorTable);
reed@google.comff0da4f2012-05-17 13:14:52 +0000185 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 }
187}
188
189void SkPixelRef::unlockPixels() {
reed@google.comff0da4f2012-05-17 13:14:52 +0000190 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000191
reed@google.comff0da4f2012-05-17 13:14:52 +0000192 if (!fPreLocked) {
193 SkAutoMutexAcquire ac(*fMutex);
reed@google.com93c5f9e2011-02-24 18:09:46 +0000194
reed@google.comff0da4f2012-05-17 13:14:52 +0000195 SkASSERT(fLockCount > 0);
196 if (0 == --fLockCount) {
commit-bot@chromium.org281713e2013-12-12 18:08:08 +0000197 this->onUnlockPixels();
198 fPixels = NULL;
199 fColorTable = NULL;
reed@google.comff0da4f2012-05-17 13:14:52 +0000200 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 }
202}
203
reed@google.com9c49bc32011-07-07 13:42:37 +0000204bool SkPixelRef::lockPixelsAreWritable() const {
205 return this->onLockPixelsAreWritable();
206}
207
208bool SkPixelRef::onLockPixelsAreWritable() const {
209 return true;
210}
211
reed@google.comcee9dcb2013-09-13 16:04:49 +0000212bool SkPixelRef::onImplementsDecodeInto() {
213 return false;
214}
215
216bool SkPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) {
217 return false;
218}
219
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220uint32_t SkPixelRef::getGenerationID() const {
bsalomon@google.com586f48c2011-04-14 15:07:22 +0000221 if (0 == fGenerationID) {
222 fGenerationID = SkNextPixelRefGenerationID();
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000223 fUniqueGenerationID = true; // The only time we can be sure of this!
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 }
bsalomon@google.com586f48c2011-04-14 15:07:22 +0000225 return fGenerationID;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226}
227
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000228void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) {
229 if (NULL == listener || !fUniqueGenerationID) {
230 // No point in tracking this if we're not going to call it.
231 SkDELETE(listener);
232 return;
233 }
234 *fGenIDChangeListeners.append() = listener;
235}
236
237void SkPixelRef::callGenIDChangeListeners() {
238 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID.
239 if (fUniqueGenerationID) {
240 for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
241 fGenIDChangeListeners[i]->onChange();
242 }
243 }
244 // Listeners get at most one shot, so whether these triggered or not, blow them away.
245 fGenIDChangeListeners.deleteAll();
246}
247
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248void SkPixelRef::notifyPixelsChanged() {
reed@android.com3eab80c2009-03-24 18:47:35 +0000249#ifdef SK_DEBUG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 if (fIsImmutable) {
251 SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 }
reed@android.com3eab80c2009-03-24 18:47:35 +0000253#endif
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000254 this->callGenIDChangeListeners();
255 this->needsNewGenID();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256}
257
258void SkPixelRef::setImmutable() {
259 fIsImmutable = true;
260}
261
reed@google.com50dfa012011-04-01 19:05:36 +0000262bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
263 return this->onReadPixels(dst, subset);
264}
265
266bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
267 return false;
268}
269
reed@google.comeb776122012-12-06 14:26:02 +0000270SkData* SkPixelRef::onRefEncodedData() {
271 return NULL;
272}
273
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000274size_t SkPixelRef::getAllocatedSizeInBytes() const {
275 return 0;
276}
277
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278///////////////////////////////////////////////////////////////////////////////
279
djsollen@google.com56c69772011-11-08 19:00:26 +0000280#ifdef SK_BUILD_FOR_ANDROID
djsollen@google.com57f49692011-02-23 20:46:31 +0000281void SkPixelRef::globalRef(void* data) {
282 this->ref();
283}
284
285void SkPixelRef::globalUnref() {
286 this->unref();
287}
reed@google.com93c5f9e2011-02-24 18:09:46 +0000288#endif