SkPixelRef.cpp revision c73dd5c6880739f26216f198c757028fd28df1a4
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
12SK_DEFINE_INST_COUNT(SkPixelRef)
13
14// must be a power-of-2. undef to just use 1 mutex
15#define PIXELREF_MUTEX_RING_COUNT       32
16
17#ifdef PIXELREF_MUTEX_RING_COUNT
18    static int32_t gPixelRefMutexRingIndex;
19    static SK_DECLARE_MUTEX_ARRAY(gPixelRefMutexRing, PIXELREF_MUTEX_RING_COUNT);
20#else
21    SK_DECLARE_STATIC_MUTEX(gPixelRefMutex);
22#endif
23
24static SkBaseMutex* get_default_mutex() {
25#ifdef PIXELREF_MUTEX_RING_COUNT
26    // atomic_inc might be overkill here. It may be fine if once in a while
27    // we hit a race-condition and two subsequent calls get the same index...
28    int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
29    return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
30#else
31    return &gPixelRefMutex;
32#endif
33}
34
35///////////////////////////////////////////////////////////////////////////////
36
37int32_t SkNextPixelRefGenerationID() {
38    static int32_t  gPixelRefGenerationID;
39    // do a loop in case our global wraps around, as we never want to
40    // return a 0
41    int32_t genID;
42    do {
43        genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
44    } while (0 == genID);
45    return genID;
46}
47
48///////////////////////////////////////////////////////////////////////////////
49
50void SkPixelRef::setMutex(SkBaseMutex* mutex) {
51    if (NULL == mutex) {
52        mutex = get_default_mutex();
53    }
54    fMutex = mutex;
55}
56
57// just need a > 0 value, so pick a funny one to aid in debugging
58#define SKPIXELREF_PRELOCKED_LOCKCOUNT     123456789
59
60SkPixelRef::SkPixelRef(SkBaseMutex* mutex) : fPreLocked(false) {
61    this->setMutex(mutex);
62    fPixels = NULL;
63    fColorTable = NULL; // we do not track ownership of this
64    fLockCount = 0;
65    fGenerationID = 0;  // signal to rebuild
66    fIsImmutable = false;
67    fPreLocked = false;
68}
69
70SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
71        : INHERITED(buffer) {
72    this->setMutex(mutex);
73    fPixels = NULL;
74    fColorTable = NULL; // we do not track ownership of this
75    fLockCount = 0;
76    fIsImmutable = buffer.readBool();
77    fGenerationID = buffer.readUInt();
78    fPreLocked = false;
79}
80
81void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) {
82    // only call me in your constructor, otherwise fLockCount tracking can get
83    // out of sync.
84    fPixels = pixels;
85    fColorTable = ctable;
86    fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
87    fPreLocked = true;
88}
89
90void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
91    this->INHERITED::flatten(buffer);
92    buffer.writeBool(fIsImmutable);
93    // We write the gen ID into the picture for within-process recording. This
94    // is safe since the same genID will never refer to two different sets of
95    // pixels (barring overflow). However, each process has its own "namespace"
96    // of genIDs. So for cross-process recording we write a zero which will
97    // trigger assignment of a new genID in playback.
98    if (buffer.isCrossProcess()) {
99        buffer.writeUInt(0);
100    } else {
101        buffer.writeUInt(fGenerationID);
102    }
103}
104
105void SkPixelRef::lockPixels() {
106    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
107
108    if (!fPreLocked) {
109        SkAutoMutexAcquire  ac(*fMutex);
110
111        if (1 == ++fLockCount) {
112            fPixels = this->onLockPixels(&fColorTable);
113        }
114    }
115}
116
117void SkPixelRef::unlockPixels() {
118    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
119
120    if (!fPreLocked) {
121        SkAutoMutexAcquire  ac(*fMutex);
122
123        SkASSERT(fLockCount > 0);
124        if (0 == --fLockCount) {
125            this->onUnlockPixels();
126            fPixels = NULL;
127            fColorTable = NULL;
128        }
129    }
130}
131
132bool SkPixelRef::lockPixelsAreWritable() const {
133    return this->onLockPixelsAreWritable();
134}
135
136bool SkPixelRef::onLockPixelsAreWritable() const {
137    return true;
138}
139
140uint32_t SkPixelRef::getGenerationID() const {
141    if (0 == fGenerationID) {
142        fGenerationID = SkNextPixelRefGenerationID();
143    }
144    return fGenerationID;
145}
146
147void SkPixelRef::notifyPixelsChanged() {
148#ifdef SK_DEBUG
149    if (fIsImmutable) {
150        SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
151    }
152#endif
153    // this signals us to recompute this next time around
154    fGenerationID = 0;
155}
156
157void SkPixelRef::setImmutable() {
158    fIsImmutable = true;
159}
160
161bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
162    return this->onReadPixels(dst, subset);
163}
164
165bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
166    return false;
167}
168
169///////////////////////////////////////////////////////////////////////////////
170
171#ifdef SK_BUILD_FOR_ANDROID
172void SkPixelRef::globalRef(void* data) {
173    this->ref();
174}
175
176void SkPixelRef::globalUnref() {
177    this->unref();
178}
179#endif
180