SkPixelRef.cpp revision 63d0024cde57eba4f7802fdc4fe49467867f52ba
1/* 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 */ 7 8#include "SkBitmapCache.h" 9#include "SkPixelRef.h" 10#include "SkThread.h" 11 12#ifdef SK_BUILD_FOR_WIN32 13 // We don't have SK_BASE_MUTEX_INIT on Windows. 14 15 // 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 20 static SkBaseMutex gPixelRefMutexRing[] = { 21 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, 25 26 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, 30 31 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, 35 36 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, 40 }; 41 // must be a power-of-2. undef to just use 1 mutex 42 #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing) 43 44#endif 45 46static SkBaseMutex* get_default_mutex() { 47 static int32_t gPixelRefMutexRingIndex; 48 49 SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT)); 50 51 // 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)]; 55} 56 57/////////////////////////////////////////////////////////////////////////////// 58 59static uint32_t next_gen_id() { 60 static uint32_t gNextGenID = 0; 61 uint32_t genID; 62 // Loop in case our global wraps around, as we never want to return a 0. 63 do { 64 genID = sk_atomic_fetch_add(&gNextGenID, 2u) + 2; // Never set the low bit. 65 } while (0 == genID); 66 return genID; 67} 68 69/////////////////////////////////////////////////////////////////////////////// 70 71void SkPixelRef::setMutex(SkBaseMutex* mutex) { 72 if (NULL == mutex) { 73 mutex = get_default_mutex(); 74 } 75 fMutex = mutex; 76} 77 78// just need a > 0 value, so pick a funny one to aid in debugging 79#define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789 80 81static SkImageInfo validate_info(const SkImageInfo& info) { 82 SkAlphaType newAlphaType = info.alphaType(); 83 SkAssertResult(SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAlphaType)); 84 return info.makeAlphaType(newAlphaType); 85} 86 87SkPixelRef::SkPixelRef(const SkImageInfo& info) 88 : fInfo(validate_info(info)) 89#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 90 , fStableID(next_gen_id()) 91#endif 92 93{ 94 this->setMutex(NULL); 95 fRec.zero(); 96 fLockCount = 0; 97 this->needsNewGenID(); 98 fIsImmutable = false; 99 fPreLocked = false; 100 fAddedToCache.store(false); 101} 102 103 104SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) 105 : fInfo(validate_info(info)) 106#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 107 , fStableID(next_gen_id()) 108#endif 109{ 110 this->setMutex(mutex); 111 fRec.zero(); 112 fLockCount = 0; 113 this->needsNewGenID(); 114 fIsImmutable = false; 115 fPreLocked = false; 116 fAddedToCache.store(false); 117} 118 119SkPixelRef::~SkPixelRef() { 120 this->callGenIDChangeListeners(); 121} 122 123void SkPixelRef::needsNewGenID() { 124 fTaggedGenID.store(0); 125 SkASSERT(!this->genIDIsUnique()); // This method isn't threadsafe, so the assert should be fine. 126} 127 128void SkPixelRef::cloneGenID(const SkPixelRef& that) { 129 // This is subtle. We must call that.getGenerationID() to make sure its genID isn't 0. 130 uint32_t genID = that.getGenerationID(); 131 132 // Neither ID is unique any more. 133 // (These & ~1u are actually redundant. that.getGenerationID() just did it for us.) 134 this->fTaggedGenID.store(genID & ~1u); 135 that. fTaggedGenID.store(genID & ~1u); 136 137 // This method isn't threadsafe, so these asserts should be fine. 138 SkASSERT(!this->genIDIsUnique()); 139 SkASSERT(!that. genIDIsUnique()); 140} 141 142void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) { 143#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED 144 // only call me in your constructor, otherwise fLockCount tracking can get 145 // out of sync. 146 fRec.fPixels = pixels; 147 fRec.fColorTable = ctable; 148 fRec.fRowBytes = rowBytes; 149 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT; 150 fPreLocked = true; 151#endif 152} 153 154bool SkPixelRef::lockPixels(LockRec* rec) { 155 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 156 157 if (!fPreLocked) { 158 SkAutoMutexAcquire ac(*fMutex); 159 160 if (1 == ++fLockCount) { 161 SkASSERT(fRec.isZero()); 162 163 LockRec rec; 164 if (!this->onNewLockPixels(&rec)) { 165 return false; 166 } 167 SkASSERT(!rec.isZero()); // else why did onNewLock return true? 168 fRec = rec; 169 } 170 } 171 *rec = fRec; 172 return true; 173} 174 175bool SkPixelRef::lockPixels() { 176 LockRec rec; 177 return this->lockPixels(&rec); 178} 179 180void SkPixelRef::unlockPixels() { 181 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 182 183 if (!fPreLocked) { 184 SkAutoMutexAcquire ac(*fMutex); 185 186 SkASSERT(fLockCount > 0); 187 if (0 == --fLockCount) { 188 // don't call onUnlockPixels unless onLockPixels succeeded 189 if (fRec.fPixels) { 190 this->onUnlockPixels(); 191 fRec.zero(); 192 } else { 193 SkASSERT(fRec.isZero()); 194 } 195 } 196 } 197} 198 199bool SkPixelRef::lockPixelsAreWritable() const { 200 return this->onLockPixelsAreWritable(); 201} 202 203bool SkPixelRef::onLockPixelsAreWritable() const { 204 return true; 205} 206 207uint32_t SkPixelRef::getGenerationID() const { 208 uint32_t id = fTaggedGenID.load(); 209 if (0 == id) { 210 id = next_gen_id(); 211 fTaggedGenID.store(id | 1u); // TODO(mtklein): should become a compare-and-swap 212 SkASSERT(this->genIDIsUnique()); 213 } 214 return id & ~1u; // Mask off bottom unique bit. 215} 216 217void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) { 218 if (NULL == listener || !this->genIDIsUnique()) { 219 // No point in tracking this if we're not going to call it. 220 SkDELETE(listener); 221 return; 222 } 223 *fGenIDChangeListeners.append() = listener; 224} 225 226// we need to be called *before* the genID gets changed or zerod 227void SkPixelRef::callGenIDChangeListeners() { 228 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID. 229 if (this->genIDIsUnique()) { 230 for (int i = 0; i < fGenIDChangeListeners.count(); i++) { 231 fGenIDChangeListeners[i]->onChange(); 232 } 233 234 // TODO: SkAtomic could add "old_value = atomic.xchg(new_value)" to make this clearer. 235 if (fAddedToCache.load()) { 236 SkNotifyBitmapGenIDIsStale(this->getGenerationID()); 237 fAddedToCache.store(false); 238 } 239 } 240 // Listeners get at most one shot, so whether these triggered or not, blow them away. 241 fGenIDChangeListeners.deleteAll(); 242} 243 244void SkPixelRef::notifyPixelsChanged() { 245#ifdef SK_DEBUG 246 if (fIsImmutable) { 247 SkDebugf("========== notifyPixelsChanged called on immutable pixelref"); 248 } 249#endif 250 this->callGenIDChangeListeners(); 251 this->needsNewGenID(); 252} 253 254void SkPixelRef::changeAlphaType(SkAlphaType at) { 255 *const_cast<SkImageInfo*>(&fInfo) = fInfo.makeAlphaType(at); 256} 257 258void SkPixelRef::setImmutable() { 259 fIsImmutable = true; 260} 261 262bool 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 270SkData* SkPixelRef::onRefEncodedData() { 271 return NULL; 272} 273 274bool SkPixelRef::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], 275 SkYUVColorSpace* colorSpace) { 276 return false; 277} 278 279size_t SkPixelRef::getAllocatedSizeInBytes() const { 280 return 0; 281} 282 283