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 12SK_DEFINE_INST_COUNT(SkPixelRef) 13 14 15#ifdef SK_USE_POSIX_THREADS 16 17 static SkBaseMutex gPixelRefMutexRing[] = { 18 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 19 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 20 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 21 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 22 23 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 24 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 25 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 26 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 27 28 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 29 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 30 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 31 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 32 33 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 34 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 35 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 36 { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, 37 }; 38 39 // must be a power-of-2. undef to just use 1 mutex 40 #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing) 41 42#else // not pthreads 43 44 // must be a power-of-2. undef to just use 1 mutex 45 #define PIXELREF_MUTEX_RING_COUNT 32 46 static SkBaseMutex gPixelRefMutexRing[PIXELREF_MUTEX_RING_COUNT]; 47 48#endif 49 50static SkBaseMutex* get_default_mutex() { 51 static int32_t gPixelRefMutexRingIndex; 52 53 SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT)); 54 55 // atomic_inc might be overkill here. It may be fine if once in a while 56 // we hit a race-condition and two subsequent calls get the same index... 57 int index = sk_atomic_inc(&gPixelRefMutexRingIndex); 58 return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)]; 59} 60 61/////////////////////////////////////////////////////////////////////////////// 62 63int32_t SkNextPixelRefGenerationID(); 64 65int32_t SkNextPixelRefGenerationID() { 66 static int32_t gPixelRefGenerationID; 67 // do a loop in case our global wraps around, as we never want to 68 // return a 0 69 int32_t genID; 70 do { 71 genID = sk_atomic_inc(&gPixelRefGenerationID) + 1; 72 } while (0 == genID); 73 return genID; 74} 75 76/////////////////////////////////////////////////////////////////////////////// 77 78void SkPixelRef::setMutex(SkBaseMutex* mutex) { 79 if (NULL == mutex) { 80 mutex = get_default_mutex(); 81 } 82 fMutex = mutex; 83} 84 85// just need a > 0 value, so pick a funny one to aid in debugging 86#define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789 87 88SkPixelRef::SkPixelRef(SkBaseMutex* mutex) : fPreLocked(false) { 89 this->setMutex(mutex); 90 fPixels = NULL; 91 fColorTable = NULL; // we do not track ownership of this 92 fLockCount = 0; 93 fGenerationID = 0; // signal to rebuild 94 fIsImmutable = false; 95 fPreLocked = false; 96} 97 98SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) 99 : INHERITED(buffer) { 100 this->setMutex(mutex); 101 fPixels = NULL; 102 fColorTable = NULL; // we do not track ownership of this 103 fLockCount = 0; 104 fIsImmutable = buffer.readBool(); 105 fGenerationID = buffer.readUInt(); 106 fPreLocked = false; 107} 108 109void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) { 110#ifndef SK_IGNORE_PIXELREF_SETPRELOCKED 111 // only call me in your constructor, otherwise fLockCount tracking can get 112 // out of sync. 113 fPixels = pixels; 114 fColorTable = ctable; 115 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT; 116 fPreLocked = true; 117#endif 118} 119 120void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { 121 this->INHERITED::flatten(buffer); 122 buffer.writeBool(fIsImmutable); 123 // We write the gen ID into the picture for within-process recording. This 124 // is safe since the same genID will never refer to two different sets of 125 // pixels (barring overflow). However, each process has its own "namespace" 126 // of genIDs. So for cross-process recording we write a zero which will 127 // trigger assignment of a new genID in playback. 128 if (buffer.isCrossProcess()) { 129 buffer.writeUInt(0); 130 } else { 131 buffer.writeUInt(fGenerationID); 132 } 133} 134 135void SkPixelRef::lockPixels() { 136 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 137 138 if (!fPreLocked) { 139 SkAutoMutexAcquire ac(*fMutex); 140 141 if (1 == ++fLockCount) { 142 fPixels = this->onLockPixels(&fColorTable); 143 } 144 } 145} 146 147void SkPixelRef::unlockPixels() { 148 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 149 150 if (!fPreLocked) { 151 SkAutoMutexAcquire ac(*fMutex); 152 153 SkASSERT(fLockCount > 0); 154 if (0 == --fLockCount) { 155 this->onUnlockPixels(); 156 fPixels = NULL; 157 fColorTable = NULL; 158 } 159 } 160} 161 162bool SkPixelRef::lockPixelsAreWritable() const { 163 return this->onLockPixelsAreWritable(); 164} 165 166bool SkPixelRef::onLockPixelsAreWritable() const { 167 return true; 168} 169 170uint32_t SkPixelRef::getGenerationID() const { 171 if (0 == fGenerationID) { 172 fGenerationID = SkNextPixelRefGenerationID(); 173 } 174 return fGenerationID; 175} 176 177void SkPixelRef::notifyPixelsChanged() { 178#ifdef SK_DEBUG 179 if (fIsImmutable) { 180 SkDebugf("========== notifyPixelsChanged called on immutable pixelref"); 181 } 182#endif 183 // this signals us to recompute this next time around 184 fGenerationID = 0; 185} 186 187void SkPixelRef::setImmutable() { 188 fIsImmutable = true; 189} 190 191bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) { 192 return this->onReadPixels(dst, subset); 193} 194 195bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { 196 return false; 197} 198 199SkData* SkPixelRef::onRefEncodedData() { 200 return NULL; 201} 202 203/////////////////////////////////////////////////////////////////////////////// 204 205#ifdef SK_BUILD_FOR_ANDROID 206void SkPixelRef::globalRef(void* data) { 207 this->ref(); 208} 209 210void SkPixelRef::globalUnref() { 211 this->unref(); 212} 213#endif 214