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