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