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 "SkReadBuffer.h"
     10 #include "SkWriteBuffer.h"
     11 #include "SkThread.h"
     12 
     13 #ifdef SK_USE_POSIX_THREADS
     14 
     15     static SkBaseMutex gPixelRefMutexRing[] = {
     16         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     17         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     18         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     19         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     20 
     21         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     22         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     23         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     24         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     25 
     26         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     27         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     28         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     29         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     30 
     31         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     32         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     33         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     34         SK_BASE_MUTEX_INIT, SK_BASE_MUTEX_INIT,
     35     };
     36 
     37     // must be a power-of-2. undef to just use 1 mutex
     38     #define PIXELREF_MUTEX_RING_COUNT SK_ARRAY_COUNT(gPixelRefMutexRing)
     39 
     40 #else // not pthreads
     41 
     42     // must be a power-of-2. undef to just use 1 mutex
     43     #define PIXELREF_MUTEX_RING_COUNT       32
     44     static SkBaseMutex gPixelRefMutexRing[PIXELREF_MUTEX_RING_COUNT];
     45 
     46 #endif
     47 
     48 static SkBaseMutex* get_default_mutex() {
     49     static int32_t gPixelRefMutexRingIndex;
     50 
     51     SkASSERT(SkIsPow2(PIXELREF_MUTEX_RING_COUNT));
     52 
     53     // atomic_inc might be overkill here. It may be fine if once in a while
     54     // we hit a race-condition and two subsequent calls get the same index...
     55     int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
     56     return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
     57 }
     58 
     59 ///////////////////////////////////////////////////////////////////////////////
     60 
     61 int32_t SkNextPixelRefGenerationID();
     62 
     63 int32_t SkNextPixelRefGenerationID() {
     64     static int32_t  gPixelRefGenerationID;
     65     // do a loop in case our global wraps around, as we never want to
     66     // return a 0
     67     int32_t genID;
     68     do {
     69         genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
     70     } while (0 == genID);
     71     return genID;
     72 }
     73 
     74 ///////////////////////////////////////////////////////////////////////////////
     75 
     76 void SkPixelRef::setMutex(SkBaseMutex* mutex) {
     77     if (NULL == mutex) {
     78         mutex = get_default_mutex();
     79     }
     80     fMutex = mutex;
     81 }
     82 
     83 // just need a > 0 value, so pick a funny one to aid in debugging
     84 #define SKPIXELREF_PRELOCKED_LOCKCOUNT     123456789
     85 
     86 SkPixelRef::SkPixelRef(const SkImageInfo& info)
     87         : fInfo(info)
     88 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
     89         , fStableID(SkNextPixelRefGenerationID())
     90 #endif
     91 {
     92     this->setMutex(NULL);
     93     fRec.zero();
     94     fLockCount = 0;
     95     this->needsNewGenID();
     96     fIsImmutable = false;
     97     fPreLocked = false;
     98 }
     99 
    100 
    101 SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex)
    102         : fInfo(info)
    103 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    104         , fStableID(SkNextPixelRefGenerationID())
    105 #endif
    106 {
    107     this->setMutex(mutex);
    108     fRec.zero();
    109     fLockCount = 0;
    110     this->needsNewGenID();
    111     fIsImmutable = false;
    112     fPreLocked = false;
    113 }
    114 
    115 static SkImageInfo read_info(SkReadBuffer& buffer) {
    116     SkImageInfo info;
    117     info.unflatten(buffer);
    118     return info;
    119 }
    120 
    121 SkPixelRef::SkPixelRef(SkReadBuffer& buffer, SkBaseMutex* mutex)
    122         : INHERITED(buffer)
    123         , fInfo(read_info(buffer))
    124 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    125         , fStableID(SkNextPixelRefGenerationID())
    126 #endif
    127 {
    128     this->setMutex(mutex);
    129     fRec.zero();
    130     fLockCount = 0;
    131     fIsImmutable = buffer.readBool();
    132     fGenerationID = buffer.readUInt();
    133     fUniqueGenerationID = false;  // Conservatively assuming the original still exists.
    134     fPreLocked = false;
    135 }
    136 
    137 SkPixelRef::~SkPixelRef() {
    138     this->callGenIDChangeListeners();
    139 }
    140 
    141 void SkPixelRef::needsNewGenID() {
    142     fGenerationID = 0;
    143     fUniqueGenerationID = false;
    144 }
    145 
    146 void SkPixelRef::cloneGenID(const SkPixelRef& that) {
    147     // This is subtle.  We must call that.getGenerationID() to make sure its genID isn't 0.
    148     this->fGenerationID = that.getGenerationID();
    149     this->fUniqueGenerationID = false;
    150     that.fUniqueGenerationID = false;
    151 }
    152 
    153 void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) {
    154 #ifndef SK_IGNORE_PIXELREF_SETPRELOCKED
    155     // only call me in your constructor, otherwise fLockCount tracking can get
    156     // out of sync.
    157     fRec.fPixels = pixels;
    158     fRec.fColorTable = ctable;
    159     fRec.fRowBytes = rowBytes;
    160     fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
    161     fPreLocked = true;
    162 #endif
    163 }
    164 
    165 void SkPixelRef::flatten(SkWriteBuffer& buffer) const {
    166     this->INHERITED::flatten(buffer);
    167     fInfo.flatten(buffer);
    168     buffer.writeBool(fIsImmutable);
    169     // We write the gen ID into the picture for within-process recording. This
    170     // is safe since the same genID will never refer to two different sets of
    171     // pixels (barring overflow). However, each process has its own "namespace"
    172     // of genIDs. So for cross-process recording we write a zero which will
    173     // trigger assignment of a new genID in playback.
    174     if (buffer.isCrossProcess()) {
    175         buffer.writeUInt(0);
    176     } else {
    177         buffer.writeUInt(fGenerationID);
    178         fUniqueGenerationID = false;  // Conservative, a copy is probably about to exist.
    179     }
    180 }
    181 
    182 bool SkPixelRef::lockPixels(LockRec* rec) {
    183     SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
    184 
    185     if (!fPreLocked) {
    186         SkAutoMutexAcquire  ac(*fMutex);
    187 
    188         if (1 == ++fLockCount) {
    189             SkASSERT(fRec.isZero());
    190 
    191             LockRec rec;
    192             if (!this->onNewLockPixels(&rec)) {
    193                 return false;
    194             }
    195             SkASSERT(!rec.isZero());    // else why did onNewLock return true?
    196             fRec = rec;
    197         }
    198     }
    199     *rec = fRec;
    200     return true;
    201 }
    202 
    203 bool SkPixelRef::lockPixels() {
    204     LockRec rec;
    205     return this->lockPixels(&rec);
    206 }
    207 
    208 void SkPixelRef::unlockPixels() {
    209     SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
    210 
    211     if (!fPreLocked) {
    212         SkAutoMutexAcquire  ac(*fMutex);
    213 
    214         SkASSERT(fLockCount > 0);
    215         if (0 == --fLockCount) {
    216             // don't call onUnlockPixels unless onLockPixels succeeded
    217             if (fRec.fPixels) {
    218                 this->onUnlockPixels();
    219                 fRec.zero();
    220             } else {
    221                 SkASSERT(fRec.isZero());
    222             }
    223         }
    224     }
    225 }
    226 
    227 bool SkPixelRef::lockPixelsAreWritable() const {
    228     return this->onLockPixelsAreWritable();
    229 }
    230 
    231 bool SkPixelRef::onLockPixelsAreWritable() const {
    232     return true;
    233 }
    234 
    235 bool SkPixelRef::onImplementsDecodeInto() {
    236     return false;
    237 }
    238 
    239 bool SkPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) {
    240     return false;
    241 }
    242 
    243 uint32_t SkPixelRef::getGenerationID() const {
    244     if (0 == fGenerationID) {
    245         fGenerationID = SkNextPixelRefGenerationID();
    246         fUniqueGenerationID = true;  // The only time we can be sure of this!
    247     }
    248     return fGenerationID;
    249 }
    250 
    251 void SkPixelRef::addGenIDChangeListener(GenIDChangeListener* listener) {
    252     if (NULL == listener || !fUniqueGenerationID) {
    253         // No point in tracking this if we're not going to call it.
    254         SkDELETE(listener);
    255         return;
    256     }
    257     *fGenIDChangeListeners.append() = listener;
    258 }
    259 
    260 void SkPixelRef::callGenIDChangeListeners() {
    261     // We don't invalidate ourselves if we think another SkPixelRef is sharing our genID.
    262     if (fUniqueGenerationID) {
    263         for (int i = 0; i < fGenIDChangeListeners.count(); i++) {
    264             fGenIDChangeListeners[i]->onChange();
    265         }
    266     }
    267     // Listeners get at most one shot, so whether these triggered or not, blow them away.
    268     fGenIDChangeListeners.deleteAll();
    269 }
    270 
    271 void SkPixelRef::notifyPixelsChanged() {
    272 #ifdef SK_DEBUG
    273     if (fIsImmutable) {
    274         SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
    275     }
    276 #endif
    277     this->callGenIDChangeListeners();
    278     this->needsNewGenID();
    279 }
    280 
    281 void SkPixelRef::changeAlphaType(SkAlphaType at) {
    282     *const_cast<SkAlphaType*>(&fInfo.fAlphaType) = at;
    283 }
    284 
    285 void SkPixelRef::setImmutable() {
    286     fIsImmutable = true;
    287 }
    288 
    289 bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
    290     return this->onReadPixels(dst, subset);
    291 }
    292 
    293 bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
    294     return false;
    295 }
    296 
    297 SkData* SkPixelRef::onRefEncodedData() {
    298     return NULL;
    299 }
    300 
    301 size_t SkPixelRef::getAllocatedSizeInBytes() const {
    302     return 0;
    303 }
    304 
    305 ///////////////////////////////////////////////////////////////////////////////
    306 
    307 #ifdef SK_BUILD_FOR_ANDROID
    308 void SkPixelRef::globalRef(void* data) {
    309     this->ref();
    310 }
    311 
    312 void SkPixelRef::globalUnref() {
    313     this->unref();
    314 }
    315 #endif
    316