Home | History | Annotate | Download | only in core
      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