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