SkPixelRef.cpp revision 7aa876bfbf0cf6f2a9d19bd4669ae50658f20821
17cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 27cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov/* 37cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov * Copyright 2011 Google Inc. 47cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov * 57cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov * Use of this source code is governed by a BSD-style license that can be 67cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov * found in the LICENSE file. 77cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov */ 87cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#include "SkPixelRef.h" 97cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#include "SkFlattenable.h" 107cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#include "SkThread.h" 117cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 127cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov// must be a power-of-2. undef to just use 1 mutex 137cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#define PIXELREF_MUTEX_RING_COUNT 32 147cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 157cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#ifdef PIXELREF_MUTEX_RING_COUNT 167cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov static int32_t gPixelRefMutexRingIndex; 17d6e4f03acf5fa1e76b75e33af7a26f248a92be9aSteven Moreland static SK_DECLARE_MUTEX_ARRAY(gPixelRefMutexRing, PIXELREF_MUTEX_RING_COUNT); 18d6e4f03acf5fa1e76b75e33af7a26f248a92be9aSteven Moreland#else 197cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov SK_DECLARE_STATIC_MUTEX(gPixelRefMutex); 207cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#endif 217cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 227cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganovstatic SkBaseMutex* get_default_mutex() { 237cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#ifdef PIXELREF_MUTEX_RING_COUNT 247cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov // atomic_inc might be overkill here. It may be fine if once in a while 257cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov // we hit a race-condition and two subsequent calls get the same index... 267cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov int index = sk_atomic_inc(&gPixelRefMutexRingIndex); 277cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)]; 287cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#else 297cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov return &gPixelRefMutex; 307cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#endif 317cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov} 327cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 337cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov/////////////////////////////////////////////////////////////////////////////// 347cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 357cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganovextern int32_t SkNextPixelRefGenerationID(); 367cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganovint32_t SkNextPixelRefGenerationID() { 377cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov static int32_t gPixelRefGenerationID; 387cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov // do a loop in case our global wraps around, as we never want to 397cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov // return a 0 407cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov int32_t genID; 417cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov do { 427cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov genID = sk_atomic_inc(&gPixelRefGenerationID) + 1; 437cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov } while (0 == genID); 447cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov return genID; 457cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov} 467cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 477cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov/////////////////////////////////////////////////////////////////////////////// 487cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 497cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganovvoid SkPixelRef::setMutex(SkBaseMutex* mutex) { 5070b9a15df00a42b319279d903bf5923564920e3bMartijn Coenen if (NULL == mutex) { 517cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov mutex = get_default_mutex(); 527cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov } 537cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov fMutex = mutex; 547cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov} 557cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 567cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov// just need a > 0 value, so pick a funny one to aid in debugging 577cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov#define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789 587cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov 597cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail NaganovSkPixelRef::SkPixelRef(SkBaseMutex* mutex) : fPreLocked(false) { 607cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov this->setMutex(mutex); 617cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov fPixels = NULL; 627cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov fColorTable = NULL; // we do not track ownership of this 637cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov fLockCount = 0; 647cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov fGenerationID = 0; // signal to rebuild 657cbf2f1fb15a2a7d9b8b61ca81ad93fa9ddcaea3Mikhail Naganov fIsImmutable = false; 66d6e4f03acf5fa1e76b75e33af7a26f248a92be9aSteven Moreland fPreLocked = false; 67} 68 69SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) 70 : INHERITED(buffer) { 71 this->setMutex(mutex); 72 fPixels = NULL; 73 fColorTable = NULL; // we do not track ownership of this 74 fLockCount = 0; 75 fIsImmutable = buffer.readBool(); 76 fGenerationID = buffer.readU32(); 77 fPreLocked = false; 78} 79 80void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) { 81 // only call me in your constructor, otherwise fLockCount tracking can get 82 // out of sync. 83 fPixels = pixels; 84 fColorTable = ctable; 85 fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT; 86 fPreLocked = true; 87} 88 89void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { 90 this->INHERITED::flatten(buffer); 91 buffer.writeBool(fIsImmutable); 92 // We write the gen ID into the picture for within-process recording. This 93 // is safe since the same genID will never refer to two different sets of 94 // pixels (barring overflow). However, each process has its own "namespace" 95 // of genIDs. So for cross-process recording we write a zero which will 96 // trigger assignment of a new genID in playback. 97 if (buffer.isCrossProcess()) { 98 buffer.write32(0); 99 } else { 100 buffer.write32(fGenerationID); 101 } 102} 103 104void SkPixelRef::lockPixels() { 105 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 106 107 if (!fPreLocked) { 108 SkAutoMutexAcquire ac(*fMutex); 109 110 if (1 == ++fLockCount) { 111 fPixels = this->onLockPixels(&fColorTable); 112 } 113 } 114} 115 116void SkPixelRef::unlockPixels() { 117 SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); 118 119 if (!fPreLocked) { 120 SkAutoMutexAcquire ac(*fMutex); 121 122 SkASSERT(fLockCount > 0); 123 if (0 == --fLockCount) { 124 this->onUnlockPixels(); 125 fPixels = NULL; 126 fColorTable = NULL; 127 } 128 } 129} 130 131bool SkPixelRef::lockPixelsAreWritable() const { 132 return this->onLockPixelsAreWritable(); 133} 134 135bool SkPixelRef::onLockPixelsAreWritable() const { 136 return true; 137} 138 139uint32_t SkPixelRef::getGenerationID() const { 140 if (0 == fGenerationID) { 141 fGenerationID = SkNextPixelRefGenerationID(); 142 } 143 return fGenerationID; 144} 145 146void SkPixelRef::notifyPixelsChanged() { 147#ifdef SK_DEBUG 148 if (fIsImmutable) { 149 SkDebugf("========== notifyPixelsChanged called on immutable pixelref"); 150 } 151#endif 152 // this signals us to recompute this next time around 153 fGenerationID = 0; 154} 155 156void SkPixelRef::setImmutable() { 157 fIsImmutable = true; 158} 159 160bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) { 161 return this->onReadPixels(dst, subset); 162} 163 164bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { 165 return false; 166} 167 168/////////////////////////////////////////////////////////////////////////////// 169 170#ifdef SK_BUILD_FOR_ANDROID 171void SkPixelRef::globalRef(void* data) { 172 this->ref(); 173} 174 175void SkPixelRef::globalUnref() { 176 this->unref(); 177} 178#endif 179