aboutsummaryrefslogtreecommitdiffhomepage
path: root/include/core/SkPixelRef.h
blob: 651176ebbbba0fc6a9e07826a44f86cb157c11d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
/*
 * Copyright 2008 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkPixelRef_DEFINED
#define SkPixelRef_DEFINED

#include "../private/SkAtomics.h"
#include "../private/SkMutex.h"
#include "../private/SkTDArray.h"
#include "SkBitmap.h"
#include "SkFilterQuality.h"
#include "SkImageInfo.h"
#include "SkPixmap.h"
#include "SkRefCnt.h"
#include "SkSize.h"
#include "SkString.h"
#include "SkYUVSizeInfo.h"

class SkColorTable;
class SkData;
struct SkIRect;

class GrTexture;
class SkDiscardableMemory;

/** \class SkPixelRef

    This class is the smart container for pixel memory, and is used with
    SkBitmap. A pixelref is installed into a bitmap, and then the bitmap can
    access the actual pixel memory by calling lockPixels/unlockPixels.

    This class can be shared/accessed between multiple threads.
*/
class SK_API SkPixelRef : public SkRefCnt {
public:
    explicit SkPixelRef(const SkImageInfo&);
    virtual ~SkPixelRef();

    const SkImageInfo& info() const {
        return fInfo;
    }

    /** Return the pixel memory returned from lockPixels, or null if the
        lockCount is 0.
    */
    void* pixels() const { return fRec.fPixels; }

    /** Return the current colorTable (if any) if pixels are locked, or null.
    */
    SkColorTable* colorTable() const { return fRec.fColorTable; }

    size_t rowBytes() const { return fRec.fRowBytes; }

    /**
     *  To access the actual pixels of a pixelref, it must be "locked".
     *  Calling lockPixels returns a LockRec struct (on success).
     */
    struct LockRec {
        LockRec() : fPixels(NULL), fColorTable(NULL) {}

        void*           fPixels;
        SkColorTable*   fColorTable;
        size_t          fRowBytes;

        void zero() { sk_bzero(this, sizeof(*this)); }

        bool isZero() const {
            return NULL == fPixels && NULL == fColorTable && 0 == fRowBytes;
        }
    };

    SkDEBUGCODE(bool isLocked() const { return fLockCount > 0; })
    SkDEBUGCODE(int getLockCount() const { return fLockCount; })

    /**
     *  Call to access the pixel memory. Return true on success. Balance this
     *  with a call to unlockPixels().
     */
    bool lockPixels();

    /**
     *  Call to access the pixel memory. On success, return true and fill out
     *  the specified rec. On failure, return false and ignore the rec parameter.
     *  Balance this with a call to unlockPixels().
     */
    bool lockPixels(LockRec* rec);

    /** Call to balanace a previous call to lockPixels(). Returns the pixels
        (or null) after the unlock. NOTE: lock calls can be nested, but the
        matching number of unlock calls must be made in order to free the
        memory (if the subclass implements caching/deferred-decoding.)
    */
    void unlockPixels();

    /**
     *  Some bitmaps can return a copy of their pixels for lockPixels(), but
     *  that copy, if modified, will not be pushed back. These bitmaps should
     *  not be used as targets for a raster device/canvas (since all pixels
     *  modifications will be lost when unlockPixels() is called.)
     */
    bool lockPixelsAreWritable() const;

    /** Returns a non-zero, unique value corresponding to the pixels in this
        pixelref. Each time the pixels are changed (and notifyPixelsChanged is
        called), a different generation ID will be returned.
    */
    uint32_t getGenerationID() const;

#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    /** Returns a non-zero, unique value corresponding to this SkPixelRef.
        Unlike the generation ID, this ID remains the same even when the pixels
        are changed. IDs are not reused (until uint32_t wraps), so it is safe
        to consider this ID unique even after this SkPixelRef is deleted.

        Can be used as a key which uniquely identifies this SkPixelRef
        regardless of changes to its pixels or deletion of this object.
     */
    uint32_t getStableID() const { return fStableID; }
#endif

    /**
     *  Call this if you have changed the contents of the pixels. This will in-
     *  turn cause a different generation ID value to be returned from
     *  getGenerationID().
     */
    void notifyPixelsChanged();

    /**
     *  Change the info's AlphaType. Note that this does not automatically
     *  invalidate the generation ID. If the pixel values themselves have
     *  changed, then you must explicitly call notifyPixelsChanged() as well.
     */
    void changeAlphaType(SkAlphaType at);

    /** Returns true if this pixelref is marked as immutable, meaning that the
        contents of its pixels will not change for the lifetime of the pixelref.
    */
    bool isImmutable() const { return fMutability != kMutable; }

    /** Marks this pixelref is immutable, meaning that the contents of its
        pixels will not change for the lifetime of the pixelref. This state can
        be set on a pixelref, but it cannot be cleared once it is set.
    */
    void setImmutable();

    /** Return the optional URI string associated with this pixelref. May be
        null.
    */
    const char* getURI() const { return fURI.size() ? fURI.c_str() : NULL; }

    /** Copy a URI string to this pixelref, or clear the URI if the uri is null
     */
    void setURI(const char uri[]) {
        fURI.set(uri);
    }

    /** Copy a URI string to this pixelref
     */
    void setURI(const char uri[], size_t len) {
        fURI.set(uri, len);
    }

    /** Assign a URI string to this pixelref.
    */
    void setURI(const SkString& uri) { fURI = uri; }

    /**
     *  If the pixelRef has an encoded (i.e. compressed) representation,
     *  return a ref to its data. If the pixelRef
     *  is uncompressed or otherwise does not have this form, return NULL.
     *
     *  If non-null is returned, the caller is responsible for calling unref()
     *  on the data when it is finished.
     */
    SkData* refEncodedData() {
        return this->onRefEncodedData();
    }

    struct LockRequest {
        SkISize         fSize;
        SkFilterQuality fQuality;
    };

    struct LockResult {
        LockResult() : fPixels(NULL), fCTable(NULL) {}

        void        (*fUnlockProc)(void* ctx);
        void*       fUnlockContext;

        const void* fPixels;
        SkColorTable* fCTable;  // should be NULL unless colortype is kIndex8
        size_t      fRowBytes;
        SkISize     fSize;

        void unlock() {
            if (fUnlockProc) {
                fUnlockProc(fUnlockContext);
                fUnlockProc = NULL; // can't unlock twice!
            }
        }
    };

    bool requestLock(const LockRequest&, LockResult*);

    /** Are we really wrapping a texture instead of a bitmap?
     */
    virtual GrTexture* getTexture() { return NULL; }

    /**
     *  If this can efficiently return YUV data, this should return true.
     *  Otherwise this returns false and does not modify any of the parameters.
     *
     *  @param sizeInfo   Output parameter indicating the sizes and required
     *                    allocation widths of the Y, U, and V planes.
     *  @param colorSpace Output parameter.
     */
    bool queryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const {
        return this->onQueryYUV8(sizeInfo, colorSpace);
    }

    /**
     *  Returns true on success and false on failure.
     *  Copies YUV data into the provided YUV planes.
     *
     *  @param sizeInfo   Needs to exactly match the values returned by the
     *                    query, except the WidthBytes may be larger than the
     *                    recommendation (but not smaller).
     *  @param planes     Memory for each of the Y, U, and V planes.
     */
    bool getYUV8Planes(const SkYUVSizeInfo& sizeInfo, void* planes[3]) {
        return this->onGetYUV8Planes(sizeInfo, planes);
    }

    /** Populates dst with the pixels of this pixelRef, converting them to colorType. */
    bool readPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset = NULL);

    /**
     *  Makes a deep copy of this PixelRef, respecting the requested config.
     *  @param colorType Desired colortype.
     *  @param profileType Desired colorprofiletype.
     *  @param subset Subset of this PixelRef to copy. Must be fully contained within the bounds of
     *         of this PixelRef.
     *  @return A new SkPixelRef, or NULL if either there is an error (e.g. the destination could
     *          not be created with the given config), or this PixelRef does not support deep
     *          copies.
     */
    virtual SkPixelRef* deepCopy(SkColorType, SkColorProfileType, const SkIRect* /*subset*/) {
        return NULL;
    }

    // Register a listener that may be called the next time our generation ID changes.
    //
    // We'll only call the listener if we're confident that we are the only SkPixelRef with this
    // generation ID.  If our generation ID changes and we decide not to call the listener, we'll
    // never call it: you must add a new listener for each generation ID change.  We also won't call
    // the listener when we're certain no one knows what our generation ID is.
    //
    // This can be used to invalidate caches keyed by SkPixelRef generation ID.
    struct GenIDChangeListener {
        virtual ~GenIDChangeListener() {}
        virtual void onChange() = 0;
    };

    // Takes ownership of listener.
    void addGenIDChangeListener(GenIDChangeListener* listener);

    // Call when this pixelref is part of the key to a resourcecache entry. This allows the cache
    // to know automatically those entries can be purged when this pixelref is changed or deleted.
    void notifyAddedToCache() {
        fAddedToCache.store(true);
    }

    virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return NULL; }

    /**
     *  Returns true if the pixels are generated on-the-fly (when required).
     */
    bool isLazyGenerated() const { return this->onIsLazyGenerated(); }

protected:
    /**
     *  On success, returns true and fills out the LockRec for the pixels. On
     *  failure returns false and ignores the LockRec parameter.
     *
     *  The caller will have already acquired a mutex for thread safety, so this
     *  method need not do that.
     */
    virtual bool onNewLockPixels(LockRec*) = 0;

    /**
     *  Balancing the previous successful call to onNewLockPixels. The locked
     *  pixel address will no longer be referenced, so the subclass is free to
     *  move or discard that memory.
     *
     *  The caller will have already acquired a mutex for thread safety, so this
     *  method need not do that.
     */
    virtual void onUnlockPixels() = 0;

    /** Default impl returns true */
    virtual bool onLockPixelsAreWritable() const;

    /**
     *  For pixelrefs that don't have access to their raw pixels, they may be
     *  able to make a copy of them (e.g. if the pixels are on the GPU).
     *
     *  The base class implementation returns false;
     */
    virtual bool onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subsetOrNull);

    // default impl returns NULL.
    virtual SkData* onRefEncodedData();

    // default impl does nothing.
    virtual void onNotifyPixelsChanged();

    virtual bool onQueryYUV8(SkYUVSizeInfo*, SkYUVColorSpace*) const {
        return false;
    }
    virtual bool onGetYUV8Planes(const SkYUVSizeInfo&, void*[3] /*planes*/) {
        return false;
    }

    /**
     *  Returns the size (in bytes) of the internally allocated memory.
     *  This should be implemented in all serializable SkPixelRef derived classes.
     *  SkBitmap::fPixelRefOffset + SkBitmap::getSafeSize() should never overflow this value,
     *  otherwise the rendering code may attempt to read memory out of bounds.
     *
     *  @return default impl returns 0.
     */
    virtual size_t getAllocatedSizeInBytes() const;

    virtual bool onRequestLock(const LockRequest&, LockResult*);

    virtual bool onIsLazyGenerated() const { return false; }

    /** Return the mutex associated with this pixelref. This value is assigned
        in the constructor, and cannot change during the lifetime of the object.
    */
    SkBaseMutex* mutex() const { return &fMutex; }

    // only call from constructor. Flags this to always be locked, removing
    // the need to grab the mutex and call onLockPixels/onUnlockPixels.
    // Performance tweak to avoid those calls (esp. in multi-thread use case).
    void setPreLocked(void*, size_t rowBytes, SkColorTable*);

private:
    mutable SkMutex fMutex;

    // mostly const. fInfo.fAlpahType can be changed at runtime.
    const SkImageInfo fInfo;

    // LockRec is only valid if we're in a locked state (isLocked())
    LockRec         fRec;
    int             fLockCount;

    bool lockPixelsInsideMutex();

    // Bottom bit indicates the Gen ID is unique.
    bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); }
    mutable SkAtomic<uint32_t> fTaggedGenID;

#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    const uint32_t fStableID;
#endif

    SkTDArray<GenIDChangeListener*> fGenIDChangeListeners;  // pointers are owned

    SkString    fURI;

    // Set true by caches when they cache content that's derived from the current pixels.
    SkAtomic<bool> fAddedToCache;

    enum {
        kMutable,               // PixelRefs begin mutable.
        kTemporarilyImmutable,  // Considered immutable, but can revert to mutable.
        kImmutable,             // Once set to this state, it never leaves.
    } fMutability : 8;          // easily fits inside a byte

    // only ever set in constructor, const after that
    bool fPreLocked;

    void needsNewGenID();
    void callGenIDChangeListeners();

    void setTemporarilyImmutable();
    void restoreMutability();
    friend class SkSurface_Raster;   // For the two methods above.

    bool isPreLocked() const { return fPreLocked; }
    friend class SkImage_Raster;
    friend class SkSpecialImage_Raster;

    // When copying a bitmap to another with the same shape and config, we can safely
    // clone the pixelref generation ID too, which makes them equivalent under caching.
    friend class SkBitmap;  // only for cloneGenID
    void cloneGenID(const SkPixelRef&);

    void setImmutableWithID(uint32_t genID);
    friend class SkImage_Gpu;
    friend class SkImageCacherator;

    typedef SkRefCnt INHERITED;
};

class SkPixelRefFactory : public SkRefCnt {
public:
    /**
     *  Allocate a new pixelref matching the specified ImageInfo, allocating
     *  the memory for the pixels. If the ImageInfo requires a ColorTable,
     *  the pixelref will ref() the colortable.
     *  On failure return NULL.
     */
    virtual SkPixelRef* create(const SkImageInfo&, size_t rowBytes, SkColorTable*) = 0;
};

#endif