blob: 560748c463c99dfa84cea4857085c6ff392261b8 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
reed3b72f792014-07-14 10:13:57 -07007
reed7eeba252015-02-24 13:54:23 -08008#include "SkBitmapCache.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkPixelRef.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkThread.h"
11
mtklein4daa6f62015-01-21 19:51:27 -080012#ifdef SK_BUILD_FOR_WIN32
13 // We don't have SK_BASE_MUTEX_INIT on Windows.
reed@google.comdd96eb42013-04-12 15:34:53 +000014
mtklein4daa6f62015-01-21 19:51:27 -080015 // must be a power-of-2. undef to just use 1 mutex
16 #define PIXELREF_MUTEX_RING_COUNT 32
17 static SkBaseMutex gPixelRefMutexRing[PIXELREF_MUTEX_RING_COUNT];
18
19#else
reed@google.comdd96eb42013-04-12 15:34:53 +000020 static SkBaseMutex gPixelRefMutexRing[] = {
mtkleinb83f6c32014-06-09 14:18:02 -070021 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
22 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
23 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
24 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
reed@google.comdd96eb42013-04-12 15:34:53 +000025
mtkleinb83f6c32014-06-09 14:18:02 -070026 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
27 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
28 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
29 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
reed@google.comdd96eb42013-04-12 15:34:53 +000030
mtkleinb83f6c32014-06-09 14:18:02 -070031 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
32 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
33 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
34 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
reed@google.comdd96eb42013-04-12 15:34:53 +000035
mtkleinb83f6c32014-06-09 14:18:02 -070036 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
37 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
38 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
39 SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
reed@google.comdd96eb42013-04-12 15:34:53 +000040 };
reed@google.comdd96eb42013-04-12 15:34:53 +000041 // must be a power-of-2. undef to just use 1 mutex
42 #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing)
43
reed@google.comff0da4f2012-05-17 13:14:52 +000044#endif
45
caryclark@google.com803eceb2012-06-06 12:09:34 +000046static SkBaseMutex* get_default_mutex() {
reed@google.comdd96eb42013-04-12 15:34:53 +000047 static int32_t gPixelRefMutexRingIndex;
48
49 SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT));
50
reed@google.comff0da4f2012-05-17 13:14:52 +000051 // atomic_inc might be overkill here. It may be fine if once in a while
52 // we hit a race-condition and two subsequent calls get the same index...
53 int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
54 return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
reed@google.comff0da4f2012-05-17 13:14:52 +000055}
56
57///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com586f48c2011-04-14 15:07:22 +000058
bsalomon@google.com100abf42012-09-05 17:40:04 +000059int32_t SkNextPixelRefGenerationID();
60
reed@google.com9c49bc32011-07-07 13:42:37 +000061int32_t SkNextPixelRefGenerationID() {
bsalomon@google.com586f48c2011-04-14 15:07:22 +000062 static int32_t gPixelRefGenerationID;
63 // do a loop in case our global wraps around, as we never want to
64 // return a 0
65 int32_t genID;
66 do {
67 genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
68 } while (0 == genID);
69 return genID;
70}
71
reed@google.comff0da4f2012-05-17 13:14:52 +000072///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000073
reed@google.comff0da4f2012-05-17 13:14:52 +000074void SkPixelRef::setMutex(SkBaseMutex* mutex) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 if (NULL == mutex) {
reed@google.comff0da4f2012-05-17 13:14:52 +000076 mutex = get_default_mutex();
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 }
78 fMutex = mutex;
reed@google.comff0da4f2012-05-17 13:14:52 +000079}
80
81// just need a > 0 value, so pick a funny one to aid in debugging
82#define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789
83
reede5ea5002014-09-03 11:54:58 -070084static SkImageInfo validate_info(const SkImageInfo& info) {
85 SkAlphaType newAlphaType = info.alphaType();
86 SkAssertResult(SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAlphaType));
87 return info.makeAlphaType(newAlphaType);
88}
scroggo2fd0d142014-07-01 07:08:19 -070089
scroggof3ca41c2014-11-25 13:42:12 -080090SkPixelRef::SkPixelRef(const SkImageInfo& info)
91 : fInfo(validate_info(info))
92#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
93 , fStableID(SkNextPixelRefGenerationID())
94#endif
95
96{
reed@google.comd0419b12014-01-06 17:08:27 +000097 this->setMutex(NULL);
98 fRec.zero();
commit-bot@chromium.orgff9c6c92013-12-11 20:55:41 +000099 fLockCount = 0;
100 this->needsNewGenID();
101 fIsImmutable = false;
102 fPreLocked = false;
reed83787d02015-02-25 07:17:11 -0800103 fAddedToCache.store(false);
commit-bot@chromium.orgff9c6c92013-12-11 20:55:41 +0000104}
commit-bot@chromium.orgff9c6c92013-12-11 20:55:41 +0000105
reed@google.comd0419b12014-01-06 17:08:27 +0000106
scroggof3ca41c2014-11-25 13:42:12 -0800107SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex)
108 : fInfo(validate_info(info))
109#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
110 , fStableID(SkNextPixelRefGenerationID())
111#endif
112{
reed@google.comd0419b12014-01-06 17:08:27 +0000113 this->setMutex(mutex);
114 fRec.zero();
reed@google.com398337b2013-12-11 21:22:39 +0000115 fLockCount = 0;
116 this->needsNewGenID();
117 fIsImmutable = false;
118 fPreLocked = false;
reed83787d02015-02-25 07:17:11 -0800119 fAddedToCache.store(false);
reed@google.com398337b2013-12-11 21:22:39 +0000120}
reed@google.com398337b2013-12-11 21:22:39 +0000121
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000122SkPixelRef::~SkPixelRef() {
123 this->callGenIDChangeListeners();
124}
125
126void SkPixelRef::needsNewGenID() {
mtklein86821b52015-02-24 14:38:12 -0800127 fGenerationID.store(0);
128 fUniqueGenerationID.store(false);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000129}
130
131void SkPixelRef::cloneGenID(const SkPixelRef& that) {
132 // This is subtle. We must call that.getGenerationID() to make sure its genID isn't 0.
mtklein86821b52015-02-24 14:38:12 -0800133 this->fGenerationID.store(that.getGenerationID());
134 this->fUniqueGenerationID.store(false);
135 that.fUniqueGenerationID.store(false);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000136}
137
reed@google.com7627c652014-01-06 15:01:48 +0000138void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) {
reed@google.com2a3f08b2012-12-13 21:41:00 +0000139#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
reed@google.comff0da4f2012-05-17 13:14:52 +0000140 // only call me in your constructor, otherwise fLockCount tracking can get
141 // out of sync.
reed@google.comd0419b12014-01-06 17:08:27 +0000142 fRec.fPixels = pixels;
143 fRec.fColorTable = ctable;
144 fRec.fRowBytes = rowBytes;
reed@google.comff0da4f2012-05-17 13:14:52 +0000145 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
146 fPreLocked = true;
reed@google.com2a3f08b2012-12-13 21:41:00 +0000147#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148}
149
reed@google.comd0419b12014-01-06 17:08:27 +0000150bool SkPixelRef::lockPixels(LockRec* rec) {
reed@google.comff0da4f2012-05-17 13:14:52 +0000151 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
skia.committer@gmail.com98272d92014-01-04 07:01:40 +0000152
reed@google.comff0da4f2012-05-17 13:14:52 +0000153 if (!fPreLocked) {
154 SkAutoMutexAcquire ac(*fMutex);
skia.committer@gmail.com98272d92014-01-04 07:01:40 +0000155
commit-bot@chromium.org27f89022014-01-03 16:32:45 +0000156 if (1 == ++fLockCount) {
reed@google.comd0419b12014-01-06 17:08:27 +0000157 SkASSERT(fRec.isZero());
158
159 LockRec rec;
160 if (!this->onNewLockPixels(&rec)) {
161 return false;
reed@google.comc83a91f2013-12-13 13:41:14 +0000162 }
reed@google.comd0419b12014-01-06 17:08:27 +0000163 SkASSERT(!rec.isZero()); // else why did onNewLock return true?
164 fRec = rec;
reed@google.comff0da4f2012-05-17 13:14:52 +0000165 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 }
reed@google.comd0419b12014-01-06 17:08:27 +0000167 *rec = fRec;
168 return true;
169}
170
171bool SkPixelRef::lockPixels() {
172 LockRec rec;
173 return this->lockPixels(&rec);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174}
175
176void SkPixelRef::unlockPixels() {
reed@google.comff0da4f2012-05-17 13:14:52 +0000177 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000178
reed@google.comff0da4f2012-05-17 13:14:52 +0000179 if (!fPreLocked) {
180 SkAutoMutexAcquire ac(*fMutex);
reed@google.com93c5f9e2011-02-24 18:09:46 +0000181
reed@google.comff0da4f2012-05-17 13:14:52 +0000182 SkASSERT(fLockCount > 0);
183 if (0 == --fLockCount) {
reed@google.comc83a91f2013-12-13 13:41:14 +0000184 // don't call onUnlockPixels unless onLockPixels succeeded
reed@google.comd0419b12014-01-06 17:08:27 +0000185 if (fRec.fPixels) {
reed@google.comc83a91f2013-12-13 13:41:14 +0000186 this->onUnlockPixels();
reed@google.comd0419b12014-01-06 17:08:27 +0000187 fRec.zero();
reed@google.comc83a91f2013-12-13 13:41:14 +0000188 } else {
reed@google.comd0419b12014-01-06 17:08:27 +0000189 SkASSERT(fRec.isZero());
reed@google.comc83a91f2013-12-13 13:41:14 +0000190 }
reed@google.comff0da4f2012-05-17 13:14:52 +0000191 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 }
193}
194
reed@google.com9c49bc32011-07-07 13:42:37 +0000195bool SkPixelRef::lockPixelsAreWritable() const {
196 return this->onLockPixelsAreWritable();
197}
198
199bool SkPixelRef::onLockPixelsAreWritable() const {
200 return true;
201}
202
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203uint32_t SkPixelRef::getGenerationID() const {
mtklein86821b52015-02-24 14:38:12 -0800204 uint32_t id = fGenerationID.load();
205 if (0 == id) {
206 id = SkNextPixelRefGenerationID();
207 fGenerationID.store(id);
208 fUniqueGenerationID.store(true); // The only time we can be sure of this!
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 }
mtklein86821b52015-02-24 14:38:12 -0800210 return id;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211}
212
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000213void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) {
mtklein86821b52015-02-24 14:38:12 -0800214 if (NULL == listener || !fUniqueGenerationID.load()) {
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000215 // No point in tracking this if we're not going to call it.
216 SkDELETE(listener);
217 return;
218 }
219 *fGenIDChangeListeners.append() = listener;
220}
221
reed7eeba252015-02-24 13:54:23 -0800222// we need to be called *before* the genID gets changed or zerod
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000223void SkPixelRef::callGenIDChangeListeners() {
224 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID.
mtklein86821b52015-02-24 14:38:12 -0800225 if (fUniqueGenerationID.load()) {
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000226 for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
227 fGenIDChangeListeners[i]->onChange();
228 }
reed7eeba252015-02-24 13:54:23 -0800229
reed83787d02015-02-25 07:17:11 -0800230 // TODO: SkAtomic could add "old_value = atomic.xchg(new_value)" to make this clearer.
231 if (fAddedToCache.load()) {
232 SkNotifyBitmapGenIDIsStale(this->getGenerationID());
233 fAddedToCache.store(false);
234 }
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000235 }
236 // Listeners get at most one shot, so whether these triggered or not, blow them away.
237 fGenIDChangeListeners.deleteAll();
238}
239
reed@google.comc1587f92014-01-28 16:05:39 +0000240void SkPixelRef::notifyPixelsChanged() {
reed@android.com3eab80c2009-03-24 18:47:35 +0000241#ifdef SK_DEBUG
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 if (fIsImmutable) {
243 SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244 }
reed@android.com3eab80c2009-03-24 18:47:35 +0000245#endif
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000246 this->callGenIDChangeListeners();
247 this->needsNewGenID();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248}
249
reed@google.comc1587f92014-01-28 16:05:39 +0000250void SkPixelRef::changeAlphaType(SkAlphaType at) {
reede5ea5002014-09-03 11:54:58 -0700251 *const_cast<SkImageInfo*>(&fInfo) = fInfo.makeAlphaType(at);
reed@google.comc1587f92014-01-28 16:05:39 +0000252}
253
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254void SkPixelRef::setImmutable() {
255 fIsImmutable = true;
256}
257
reed@google.com50dfa012011-04-01 19:05:36 +0000258bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
259 return this->onReadPixels(dst, subset);
260}
261
262bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
263 return false;
264}
265
reed@google.comeb776122012-12-06 14:26:02 +0000266SkData* SkPixelRef::onRefEncodedData() {
267 return NULL;
268}
269
rileyaabaef862014-09-12 17:45:58 -0700270bool SkPixelRef::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
271 SkYUVColorSpace* colorSpace) {
sugoi518d83d2014-07-21 11:37:39 -0700272 return false;
273}
274
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000275size_t SkPixelRef::getAllocatedSizeInBytes() const {
276 return 0;
277}
278