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 SK_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 
     50 static 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 
     63 int32_t SkNextPixelRefGenerationID();
     64 
     65 int32_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 
     78 void 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 
     88 SkPixelRef::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 
     98 SkPixelRef::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 
    109 void 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 
    120 void 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 
    135 void 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 
    147 void 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 
    162 bool SkPixelRef::lockPixelsAreWritable() const {
    163     return this->onLockPixelsAreWritable();
    164 }
    165 
    166 bool SkPixelRef::onLockPixelsAreWritable() const {
    167     return true;
    168 }
    169 
    170 uint32_t SkPixelRef::getGenerationID() const {
    171     if (0 == fGenerationID) {
    172         fGenerationID = SkNextPixelRefGenerationID();
    173     }
    174     return fGenerationID;
    175 }
    176 
    177 void 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 
    187 void SkPixelRef::setImmutable() {
    188     fIsImmutable = true;
    189 }
    190 
    191 bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
    192     return this->onReadPixels(dst, subset);
    193 }
    194 
    195 bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
    196     return false;
    197 }
    198 
    199 SkData* SkPixelRef::onRefEncodedData() {
    200     return NULL;
    201 }
    202 
    203 ///////////////////////////////////////////////////////////////////////////////
    204 
    205 #ifdef SK_BUILD_FOR_ANDROID
    206 void SkPixelRef::globalRef(void* data) {
    207     this->ref();
    208 }
    209 
    210 void SkPixelRef::globalUnref() {
    211     this->unref();
    212 }
    213 #endif
    214