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 "SkFlattenable.h"
10#include "SkThread.h"
11
12// must be a power-of-2. undef to just use 1 mutex
13#define PIXELREF_MUTEX_RING_COUNT       32
14
15#ifdef PIXELREF_MUTEX_RING_COUNT
16    static int32_t gPixelRefMutexRingIndex;
17    static SK_DECLARE_MUTEX_ARRAY(gPixelRefMutexRing, PIXELREF_MUTEX_RING_COUNT);
18#else
19    SK_DECLARE_STATIC_MUTEX(gPixelRefMutex);
20#endif
21
22SkBaseMutex* get_default_mutex() {
23#ifdef PIXELREF_MUTEX_RING_COUNT
24    // atomic_inc might be overkill here. It may be fine if once in a while
25    // we hit a race-condition and two subsequent calls get the same index...
26    int index = sk_atomic_inc(&gPixelRefMutexRingIndex);
27    return &gPixelRefMutexRing[index & (PIXELREF_MUTEX_RING_COUNT - 1)];
28#else
29    return &gPixelRefMutex;
30#endif
31}
32
33///////////////////////////////////////////////////////////////////////////////
34
35extern int32_t SkNextPixelRefGenerationID();
36int32_t SkNextPixelRefGenerationID() {
37    static int32_t  gPixelRefGenerationID;
38    // do a loop in case our global wraps around, as we never want to
39    // return a 0
40    int32_t genID;
41    do {
42        genID = sk_atomic_inc(&gPixelRefGenerationID) + 1;
43    } while (0 == genID);
44    return genID;
45}
46
47///////////////////////////////////////////////////////////////////////////////
48
49void SkPixelRef::setMutex(SkBaseMutex* mutex) {
50    if (NULL == mutex) {
51        mutex = get_default_mutex();
52    }
53    fMutex = mutex;
54}
55
56// just need a > 0 value, so pick a funny one to aid in debugging
57#define SKPIXELREF_PRELOCKED_LOCKCOUNT     123456789
58
59SkPixelRef::SkPixelRef(SkBaseMutex* mutex) : fPreLocked(false) {
60    this->setMutex(mutex);
61    fPixels = NULL;
62    fColorTable = NULL; // we do not track ownership of this
63    fLockCount = 0;
64    fGenerationID = 0;  // signal to rebuild
65    fIsImmutable = false;
66    fPreLocked = false;
67}
68
69SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) {
70    this->setMutex(mutex);
71    fPixels = NULL;
72    fColorTable = NULL; // we do not track ownership of this
73    fLockCount = 0;
74    fGenerationID = 0;  // signal to rebuild
75    fIsImmutable = buffer.readBool();
76    fPreLocked = false;
77}
78
79void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) {
80    // only call me in your constructor, otherwise fLockCount tracking can get
81    // out of sync.
82    fPixels = pixels;
83    fColorTable = ctable;
84    fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT;
85    fPreLocked = true;
86}
87
88void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
89    buffer.writeBool(fIsImmutable);
90}
91
92void SkPixelRef::lockPixels() {
93    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
94
95    if (!fPreLocked) {
96        SkAutoMutexAcquire  ac(*fMutex);
97
98        if (1 == ++fLockCount) {
99            fPixels = this->onLockPixels(&fColorTable);
100        }
101    }
102}
103
104void SkPixelRef::unlockPixels() {
105    SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount);
106
107    if (!fPreLocked) {
108        SkAutoMutexAcquire  ac(*fMutex);
109
110        SkASSERT(fLockCount > 0);
111        if (0 == --fLockCount) {
112            this->onUnlockPixels();
113            fPixels = NULL;
114            fColorTable = NULL;
115        }
116    }
117}
118
119bool SkPixelRef::lockPixelsAreWritable() const {
120    return this->onLockPixelsAreWritable();
121}
122
123bool SkPixelRef::onLockPixelsAreWritable() const {
124    return true;
125}
126
127uint32_t SkPixelRef::getGenerationID() const {
128    if (0 == fGenerationID) {
129        fGenerationID = SkNextPixelRefGenerationID();
130    }
131    return fGenerationID;
132}
133
134void SkPixelRef::notifyPixelsChanged() {
135#ifdef SK_DEBUG
136    if (fIsImmutable) {
137        SkDebugf("========== notifyPixelsChanged called on immutable pixelref");
138    }
139#endif
140    // this signals us to recompute this next time around
141    fGenerationID = 0;
142}
143
144void SkPixelRef::setImmutable() {
145    fIsImmutable = true;
146}
147
148bool SkPixelRef::readPixels(SkBitmap* dst, const SkIRect* subset) {
149    return this->onReadPixels(dst, subset);
150}
151
152bool SkPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
153    return false;
154}
155
156///////////////////////////////////////////////////////////////////////////////
157
158#define MAX_PAIR_COUNT  16
159
160struct Pair {
161    const char*          fName;
162    SkPixelRef::Factory  fFactory;
163};
164
165static int gCount;
166static Pair gPairs[MAX_PAIR_COUNT];
167
168void SkPixelRef::Register(const char name[], Factory factory) {
169    SkASSERT(name);
170    SkASSERT(factory);
171
172    static bool gOnce;
173    if (!gOnce) {
174        gCount = 0;
175        gOnce = true;
176    }
177
178    SkASSERT(gCount < MAX_PAIR_COUNT);
179
180    gPairs[gCount].fName = name;
181    gPairs[gCount].fFactory = factory;
182    gCount += 1;
183}
184
185#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
186static void report_no_entries(const char* functionName) {
187    if (!gCount) {
188        SkDebugf("%s has no registered name/factory pairs."
189                 " Call SkGraphics::Init() at process initialization time.",
190                 functionName);
191    }
192}
193#endif
194
195SkPixelRef::Factory SkPixelRef::NameToFactory(const char name[]) {
196#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
197    report_no_entries(__FUNCTION__);
198#endif
199    const Pair* pairs = gPairs;
200    for (int i = gCount - 1; i >= 0; --i) {
201        if (strcmp(pairs[i].fName, name) == 0) {
202            return pairs[i].fFactory;
203        }
204    }
205    return NULL;
206}
207
208const char* SkPixelRef::FactoryToName(Factory fact) {
209#if !SK_ALLOW_STATIC_GLOBAL_INITIALIZERS && defined(SK_DEBUG)
210    report_no_entries(__FUNCTION__);
211#endif
212    const Pair* pairs = gPairs;
213    for (int i = gCount - 1; i >= 0; --i) {
214        if (pairs[i].fFactory == fact) {
215            return pairs[i].fName;
216        }
217    }
218    return NULL;
219}
220
221///////////////////////////////////////////////////////////////////////////////
222
223#ifdef SK_BUILD_FOR_ANDROID
224void SkPixelRef::globalRef(void* data) {
225    this->ref();
226}
227
228void SkPixelRef::globalUnref() {
229    this->unref();
230}
231#endif
232