SkPixelRef.cpp revision f1ce05288a8fee6e691c3dff5db9dcd47818060f
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 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 60int32_t SkNextPixelRefGenerationID(); 61 62int32_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 75void 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 85SkPixelRef::SkPixelRef(const SkImageInfo& info) : fInfo(info) { 86 this->setMutex(NULL); 87 fRec.zero(); 88 fLockCount = 0; 89 this->needsNewGenID(); 90 fIsImmutable = false; 91 fPreLocked = false; 92} 93 94 95SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) : fInfo(info) { 96 this->setMutex(mutex); 97 fRec.zero(); 98 fLockCount = 0; 99 this->needsNewGenID(); 100 fIsImmutable = false; 101 fPreLocked = false; 102} 103 104static SkImageInfo read_info(SkFlattenableReadBuffer& buffer) { 105 SkImageInfo info; 106 info.unflatten(buffer); 107 return info; 108} 109 110SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) 111 : INHERITED(buffer) 112 , fInfo(read_info(buffer)) 113{ 114 this->setMutex(mutex); 115 fRec.zero(); 116 fLockCount = 0; 117 fIsImmutable = buffer.readBool(); 118 fGenerationID = buffer.readUInt(); 119 fUniqueGenerationID = false; // Conservatively assuming the original still exists. 120 fPreLocked = false; 121} 122 123SkPixelRef::~SkPixelRef() { 124 this->callGenIDChangeListeners(); 125} 126 127void SkPixelRef::needsNewGenID() { 128 fGenerationID = 0; 129 fUniqueGenerationID = false; 130} 131 132void SkPixelRef::cloneGenID(const SkPixelRef& that) { 133 // This is subtle. We must call that.getGenerationID() to make sure its genID isn't 0. 134 this->fGenerationID = that.getGenerationID(); 135 this->fUniqueGenerationID = false; 136 that.fUniqueGenerationID = false; 137} 138 139void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) { 140#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED 141 // only call me in your constructor, otherwise fLockCount tracking can get 142 // out of sync. 143 fRec.fPixels = pixels; 144 fRec.fColorTable = ctable; 145 fRec.fRowBytes = rowBytes; 146 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT; 147 fPreLocked = true; 148#endif 149} 150 151void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { 152 this->INHERITED::flatten(buffer); 153 fInfo.flatten(buffer); 154 buffer.writeBool(fIsImmutable); 155 // We write the gen ID into the picture for within-process recording. This 156 // is safe since the same genID will never refer to two different sets of 157 // pixels (barring overflow). However, each process has its own "namespace" 158 // of genIDs. So for cross-process recording we write a zero which will 159 // trigger assignment of a new genID in playback. 160 if (buffer.isCrossProcess()) { 161 buffer.writeUInt(0); 162 } else { 163 buffer.writeUInt(fGenerationID); 164 fUniqueGenerationID = false; // Conservative, a copy is probably about to exist. 165 } 166} 167 168bool SkPixelRef::lockPixels(LockRec* rec) { 169 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 170 171 if (!fPreLocked) { 172 SkAutoMutexAcquire ac(*fMutex); 173 174 if (1 == ++fLockCount) { 175 SkASSERT(fRec.isZero()); 176 177 LockRec rec; 178 if (!this->onNewLockPixels(&rec)) { 179 return false; 180 } 181 SkASSERT(!rec.isZero()); // else why did onNewLock return true? 182 fRec = rec; 183 } 184 } 185 *rec = fRec; 186 return true; 187} 188 189bool SkPixelRef::lockPixels() { 190 LockRec rec; 191 return this->lockPixels(&rec); 192} 193 194void SkPixelRef::unlockPixels() { 195 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 196 197 if (!fPreLocked) { 198 SkAutoMutexAcquire ac(*fMutex); 199 200 SkASSERT(fLockCount > 0); 201 if (0 == --fLockCount) { 202 // don't call onUnlockPixels unless onLockPixels succeeded 203 if (fRec.fPixels) { 204 this->onUnlockPixels(); 205 fRec.zero(); 206 } else { 207 SkASSERT(fRec.isZero()); 208 } 209 } 210 } 211} 212 213bool SkPixelRef::lockPixelsAreWritable() const { 214 return this->onLockPixelsAreWritable(); 215} 216 217bool SkPixelRef::onLockPixelsAreWritable() const { 218 return true; 219} 220 221bool SkPixelRef::onImplementsDecodeInto() { 222 return false; 223} 224 225bool SkPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) { 226 return false; 227} 228 229uint32_t SkPixelRef::getGenerationID() const { 230 if (0 == fGenerationID) { 231 fGenerationID = SkNextPixelRefGenerationID(); 232 fUniqueGenerationID = true; // The only time we can be sure of this! 233 } 234 return fGenerationID; 235} 236 237void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) { 238 if (NULL == listener || !fUniqueGenerationID) { 239 // No point in tracking this if we're not going to call it. 240 SkDELETE(listener); 241 return; 242 } 243 *fGenIDChangeListeners.append() = listener; 244} 245 246void SkPixelRef::callGenIDChangeListeners() { 247 // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID. 248 if (fUniqueGenerationID) { 249 for (int i = 0; i < fGenIDChangeListeners.count(); i++) { 250 fGenIDChangeListeners[i]->onChange(); 251 } 252 } 253 // Listeners get at most one shot, so whether these triggered or not, blow them away. 254 fGenIDChangeListeners.deleteAll(); 255} 256 257void SkPixelRef::notifyPixelsChanged() { 258#ifdef SK_DEBUG 259 if (fIsImmutable) { 260 SkDebugf("========== notifyPixelsChanged called on immutable pixelref"); 261 } 262#endif 263 this->callGenIDChangeListeners(); 264 this->needsNewGenID(); 265} 266 267void SkPixelRef::setImmutable() { 268 fIsImmutable = true; 269} 270 271bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) { 272 return this->onReadPixels(dst, subset); 273} 274 275bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { 276 return false; 277} 278 279SkData* SkPixelRef::onRefEncodedData() { 280 return NULL; 281} 282 283size_t SkPixelRef::getAllocatedSizeInBytes() const { 284 return 0; 285} 286 287/////////////////////////////////////////////////////////////////////////////// 288 289#ifdef SK_SUPPORT_LEGACY_ONLOCKPIXELS 290 291void* SkPixelRef::onLockPixels(SkColorTable** ctable) { 292 return NULL; 293} 294 295bool SkPixelRef::onNewLockPixels(LockRec* rec) { 296 SkColorTable* ctable; 297 void* pixels = this->onLockPixels(&ctable); 298 if (!pixels) { 299 return false; 300 } 301 302 rec->fPixels = pixels; 303 rec->fColorTable = ctable; 304 rec->fRowBytes = 0; // callers don't currently need this (thank goodness) 305 return true; 306} 307 308#endif 309 310/////////////////////////////////////////////////////////////////////////////// 311 312#ifdef SK_BUILD_FOR_ANDROID 313void SkPixelRef::globalRef(void* data) { 314 this->ref(); 315} 316 317void SkPixelRef::globalUnref() { 318 this->unref(); 319} 320#endif 321