blob: 9cdcd85a798b5faf5f27c809fb8b07292d10848a [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
8#ifndef SkPixelRef_DEFINED
9#define SkPixelRef_DEFINED
10
herbe6e41a82015-09-28 11:24:13 -070011#include "../private/SkAtomics.h"
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +000012#include "SkBitmap.h"
reed92fc2ae2015-05-22 08:06:21 -070013#include "SkFilterQuality.h"
mtklein86821b52015-02-24 14:38:12 -080014#include "SkImageInfo.h"
herb62a69c22015-09-29 11:47:45 -070015#include "../private/SkMutex.h"
reed92fc2ae2015-05-22 08:06:21 -070016#include "SkPixmap.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#include "SkRefCnt.h"
sugoi518d83d2014-07-21 11:37:39 -070018#include "SkSize.h"
mtklein86821b52015-02-24 14:38:12 -080019#include "SkString.h"
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000020#include "SkTDArray.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000021
22class SkColorTable;
reed@google.comeb776122012-12-06 14:26:02 +000023class SkData;
reed@google.com50dfa012011-04-01 19:05:36 +000024struct SkIRect;
reed@android.com8a1c16f2008-12-17 15:59:43 +000025
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +000026class GrTexture;
reed216b6432015-08-19 12:25:40 -070027class SkDiscardableMemory;
reed@android.comce4e53a2010-09-09 16:01:26 +000028
reed@android.com8a1c16f2008-12-17 15:59:43 +000029/** \class SkPixelRef
30
31 This class is the smart container for pixel memory, and is used with
32 SkBitmap. A pixelref is installed into a bitmap, and then the bitmap can
33 access the actual pixel memory by calling lockPixels/unlockPixels.
34
35 This class can be shared/accessed between multiple threads.
36*/
reeded458682014-07-14 09:21:31 -070037class SK_API SkPixelRef : public SkRefCnt {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038public:
reed@google.comf1715702013-12-06 22:07:17 +000039 explicit SkPixelRef(const SkImageInfo&);
commit-bot@chromium.org50a30432013-10-24 17:44:27 +000040 virtual ~SkPixelRef();
reed@google.com93c5f9e2011-02-24 18:09:46 +000041
reed@google.com9230ea22013-12-09 22:01:03 +000042 const SkImageInfo& info() const {
43 return fInfo;
44 }
45
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 /** Return the pixel memory returned from lockPixels, or null if the
47 lockCount is 0.
48 */
reed@google.comd0419b12014-01-06 17:08:27 +000049 void* pixels() const { return fRec.fPixels; }
reed@android.com8a1c16f2008-12-17 15:59:43 +000050
51 /** Return the current colorTable (if any) if pixels are locked, or null.
52 */
reed@google.comd0419b12014-01-06 17:08:27 +000053 SkColorTable* colorTable() const { return fRec.fColorTable; }
reed@android.com8a1c16f2008-12-17 15:59:43 +000054
reed@google.com672588b2014-01-08 15:42:01 +000055 size_t rowBytes() const { return fRec.fRowBytes; }
56
reed@google.comff0da4f2012-05-17 13:14:52 +000057 /**
reed@google.com92713892014-01-03 17:58:57 +000058 * To access the actual pixels of a pixelref, it must be "locked".
59 * Calling lockPixels returns a LockRec struct (on success).
60 */
61 struct LockRec {
reeddb74f622015-05-30 13:41:15 -070062 LockRec() : fPixels(NULL), fColorTable(NULL) {}
63
reed@google.com92713892014-01-03 17:58:57 +000064 void* fPixels;
65 SkColorTable* fColorTable;
66 size_t fRowBytes;
skia.committer@gmail.com98272d92014-01-04 07:01:40 +000067
reed@google.com92713892014-01-03 17:58:57 +000068 void zero() { sk_bzero(this, sizeof(*this)); }
69
70 bool isZero() const {
71 return NULL == fPixels && NULL == fColorTable && 0 == fRowBytes;
72 }
73 };
skia.committer@gmail.com98272d92014-01-04 07:01:40 +000074
mtklein96d68b72015-02-20 12:40:40 -080075 SkDEBUGCODE(bool isLocked() const { return fLockCount > 0; })
reed@google.comea033602012-12-14 13:13:55 +000076 SkDEBUGCODE(int getLockCount() const { return fLockCount; })
77
reed@google.comd0419b12014-01-06 17:08:27 +000078 /**
79 * Call to access the pixel memory. Return true on success. Balance this
80 * with a call to unlockPixels().
81 */
82 bool lockPixels();
83
84 /**
85 * Call to access the pixel memory. On success, return true and fill out
86 * the specified rec. On failure, return false and ignore the rec parameter.
87 * Balance this with a call to unlockPixels().
88 */
89 bool lockPixels(LockRec* rec);
90
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 /** Call to balanace a previous call to lockPixels(). Returns the pixels
92 (or null) after the unlock. NOTE: lock calls can be nested, but the
93 matching number of unlock calls must be made in order to free the
94 memory (if the subclass implements caching/deferred-decoding.)
95 */
96 void unlockPixels();
reed@google.com93c5f9e2011-02-24 18:09:46 +000097
reed@google.com9c49bc32011-07-07 13:42:37 +000098 /**
99 * Some bitmaps can return a copy of their pixels for lockPixels(), but
100 * that copy, if modified, will not be pushed back. These bitmaps should
101 * not be used as targets for a raster device/canvas (since all pixels
102 * modifications will be lost when unlockPixels() is called.)
103 */
104 bool lockPixelsAreWritable() const;
105
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106 /** Returns a non-zero, unique value corresponding to the pixels in this
107 pixelref. Each time the pixels are changed (and notifyPixelsChanged is
108 called), a different generation ID will be returned.
109 */
110 uint32_t getGenerationID() const;
reed@google.com93c5f9e2011-02-24 18:09:46 +0000111
scroggof3ca41c2014-11-25 13:42:12 -0800112#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
113 /** Returns a non-zero, unique value corresponding to this SkPixelRef.
114 Unlike the generation ID, this ID remains the same even when the pixels
115 are changed. IDs are not reused (until uint32_t wraps), so it is safe
116 to consider this ID unique even after this SkPixelRef is deleted.
117
118 Can be used as a key which uniquely identifies this SkPixelRef
119 regardless of changes to its pixels or deletion of this object.
120 */
121 uint32_t getStableID() const { return fStableID; }
122#endif
123
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000124 /**
125 * Call this if you have changed the contents of the pixels. This will in-
126 * turn cause a different generation ID value to be returned from
127 * getGenerationID().
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000128 */
reed@google.comc1587f92014-01-28 16:05:39 +0000129 void notifyPixelsChanged();
130
131 /**
132 * Change the info's AlphaType. Note that this does not automatically
133 * invalidate the generation ID. If the pixel values themselves have
134 * changed, then you must explicitly call notifyPixelsChanged() as well.
135 */
136 void changeAlphaType(SkAlphaType at);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137
138 /** Returns true if this pixelref is marked as immutable, meaning that the
139 contents of its pixels will not change for the lifetime of the pixelref.
140 */
reed26e0e582015-07-29 11:44:52 -0700141 bool isImmutable() const { return fMutability != kMutable; }
reed@google.com93c5f9e2011-02-24 18:09:46 +0000142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 /** Marks this pixelref is immutable, meaning that the contents of its
144 pixels will not change for the lifetime of the pixelref. This state can
145 be set on a pixelref, but it cannot be cleared once it is set.
146 */
147 void setImmutable();
148
149 /** Return the optional URI string associated with this pixelref. May be
150 null.
151 */
152 const char* getURI() const { return fURI.size() ? fURI.c_str() : NULL; }
153
154 /** Copy a URI string to this pixelref, or clear the URI if the uri is null
155 */
156 void setURI(const char uri[]) {
157 fURI.set(uri);
158 }
reed@google.com93c5f9e2011-02-24 18:09:46 +0000159
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 /** Copy a URI string to this pixelref
161 */
162 void setURI(const char uri[], size_t len) {
163 fURI.set(uri, len);
164 }
reed@google.com93c5f9e2011-02-24 18:09:46 +0000165
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 /** Assign a URI string to this pixelref.
167 */
168 void setURI(const SkString& uri) { fURI = uri; }
169
reed@google.comeb776122012-12-06 14:26:02 +0000170 /**
171 * If the pixelRef has an encoded (i.e. compressed) representation,
172 * return a ref to its data. If the pixelRef
173 * is uncompressed or otherwise does not have this form, return NULL.
174 *
175 * If non-null is returned, the caller is responsible for calling unref()
176 * on the data when it is finished.
177 */
178 SkData* refEncodedData() {
179 return this->onRefEncodedData();
180 }
181
reed92fc2ae2015-05-22 08:06:21 -0700182 struct LockRequest {
183 SkISize fSize;
184 SkFilterQuality fQuality;
185 };
186
187 struct LockResult {
reeddb74f622015-05-30 13:41:15 -0700188 LockResult() : fPixels(NULL), fCTable(NULL) {}
189
reed92fc2ae2015-05-22 08:06:21 -0700190 void (*fUnlockProc)(void* ctx);
191 void* fUnlockContext;
192
reed11e833d2015-05-30 09:20:29 -0700193 const void* fPixels;
reeddb74f622015-05-30 13:41:15 -0700194 SkColorTable* fCTable; // should be NULL unless colortype is kIndex8
reed92fc2ae2015-05-22 08:06:21 -0700195 size_t fRowBytes;
196 SkISize fSize;
197
198 void unlock() {
199 if (fUnlockProc) {
200 fUnlockProc(fUnlockContext);
201 fUnlockProc = NULL; // can't unlock twice!
202 }
203 }
204 };
205
206 bool requestLock(const LockRequest&, LockResult*);
207
reed@android.comce4e53a2010-09-09 16:01:26 +0000208 /** Are we really wrapping a texture instead of a bitmap?
209 */
commit-bot@chromium.orgb8d00db2013-06-26 19:18:23 +0000210 virtual GrTexture* getTexture() { return NULL; }
reed@android.comce4e53a2010-09-09 16:01:26 +0000211
sugoi518d83d2014-07-21 11:37:39 -0700212 /**
213 * If any planes or rowBytes is NULL, this should output the sizes and return true
214 * if it can efficiently return YUV planar data. If it cannot, it should return false.
215 *
216 * If all planes and rowBytes are not NULL, then it should copy the associated Y,U,V data
217 * into those planes of memory supplied by the caller. It should validate that the sizes
218 * match what it expected. If the sizes do not match, it should return false.
rileyaabaef862014-09-12 17:45:58 -0700219 *
220 * If colorSpace is not NULL, the YUV color space of the data should be stored in the address
221 * it points at.
sugoi518d83d2014-07-21 11:37:39 -0700222 */
rileyaabaef862014-09-12 17:45:58 -0700223 bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
224 SkYUVColorSpace* colorSpace) {
225 return this->onGetYUV8Planes(sizes, planes, rowBytes, colorSpace);
sugoi518d83d2014-07-21 11:37:39 -0700226 }
227
bsalomon9d22fd62016-01-11 11:14:17 -0800228 /** Populates dst with the pixels of this pixelRef, converting them to colorType. */
229 bool readPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset = NULL);
reed@google.com50dfa012011-04-01 19:05:36 +0000230
scroggo@google.coma2a31922012-12-07 19:14:45 +0000231 /**
232 * Makes a deep copy of this PixelRef, respecting the requested config.
reede4538f52014-06-11 06:09:50 -0700233 * @param colorType Desired colortype.
jvanverthfa1e8a72014-12-22 08:31:49 -0800234 * @param profileType Desired colorprofiletype.
scroggo@google.coma2a31922012-12-07 19:14:45 +0000235 * @param subset Subset of this PixelRef to copy. Must be fully contained within the bounds of
236 * of this PixelRef.
237 * @return A new SkPixelRef, or NULL if either there is an error (e.g. the destination could
238 * not be created with the given config), or this PixelRef does not support deep
239 * copies.
240 */
jvanverthfa1e8a72014-12-22 08:31:49 -0800241 virtual SkPixelRef* deepCopy(SkColorType, SkColorProfileType, const SkIRect* /*subset*/) {
scroggo@google.coma2a31922012-12-07 19:14:45 +0000242 return NULL;
243 }
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000244
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000245 // Register a listener that may be called the next time our generation ID changes.
246 //
247 // We'll only call the listener if we're confident that we are the only SkPixelRef with this
248 // generation ID. If our generation ID changes and we decide not to call the listener, we'll
249 // never call it: you must add a new listener for each generation ID change. We also won't call
250 // the listener when we're certain no one knows what our generation ID is.
251 //
252 // This can be used to invalidate caches keyed by SkPixelRef generation ID.
253 struct GenIDChangeListener {
254 virtual ~GenIDChangeListener() {}
255 virtual void onChange() = 0;
256 };
257
258 // Takes ownership of listener.
259 void addGenIDChangeListener(GenIDChangeListener* listener);
260
reed83787d02015-02-25 07:17:11 -0800261 // Call when this pixelref is part of the key to a resourcecache entry. This allows the cache
262 // to know automatically those entries can be purged when this pixelref is changed or deleted.
263 void notifyAddedToCache() {
mtklein61010772015-02-25 08:27:41 -0800264 fAddedToCache.store(true);
reed83787d02015-02-25 07:17:11 -0800265 }
266
reed216b6432015-08-19 12:25:40 -0700267 virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return NULL; }
268
fmalitaddbbdda2015-08-20 08:47:26 -0700269 /**
270 * Returns true if the pixels are generated on-the-fly (when required).
271 */
272 bool isLazyGenerated() const { return this->onIsLazyGenerated(); }
273
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274protected:
reed@google.comd0419b12014-01-06 17:08:27 +0000275 /**
276 * On success, returns true and fills out the LockRec for the pixels. On
277 * failure returns false and ignores the LockRec parameter.
278 *
279 * The caller will have already acquired a mutex for thread safety, so this
280 * method need not do that.
281 */
282 virtual bool onNewLockPixels(LockRec*) = 0;
skia.committer@gmail.com96f5fa02013-12-16 07:01:40 +0000283
reed@google.comc83a91f2013-12-13 13:41:14 +0000284 /**
reed@google.comd0419b12014-01-06 17:08:27 +0000285 * Balancing the previous successful call to onNewLockPixels. The locked
286 * pixel address will no longer be referenced, so the subclass is free to
287 * move or discard that memory.
reed@google.comc83a91f2013-12-13 13:41:14 +0000288 *
reed@google.comd0419b12014-01-06 17:08:27 +0000289 * The caller will have already acquired a mutex for thread safety, so this
290 * method need not do that.
reed@google.comc83a91f2013-12-13 13:41:14 +0000291 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 virtual void onUnlockPixels() = 0;
293
reed@google.com9c49bc32011-07-07 13:42:37 +0000294 /** Default impl returns true */
295 virtual bool onLockPixelsAreWritable() const;
296
reed@google.com50dfa012011-04-01 19:05:36 +0000297 /**
298 * For pixelrefs that don't have access to their raw pixels, they may be
299 * able to make a copy of them (e.g. if the pixels are on the GPU).
300 *
301 * The base class implementation returns false;
302 */
bsalomon9d22fd62016-01-11 11:14:17 -0800303 virtual bool onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subsetOrNull);
reed@google.com50dfa012011-04-01 19:05:36 +0000304
reed@google.comeb776122012-12-06 14:26:02 +0000305 // default impl returns NULL.
306 virtual SkData* onRefEncodedData();
307
junovda5469d2015-06-15 09:48:15 -0700308 // default impl does nothing.
309 virtual void onNotifyPixelsChanged();
310
sugoi518d83d2014-07-21 11:37:39 -0700311 // default impl returns false.
rileyaabaef862014-09-12 17:45:58 -0700312 virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
313 SkYUVColorSpace* colorSpace);
sugoi518d83d2014-07-21 11:37:39 -0700314
commit-bot@chromium.orgcd3b15c2013-12-04 17:06:49 +0000315 /**
316 * Returns the size (in bytes) of the internally allocated memory.
317 * This should be implemented in all serializable SkPixelRef derived classes.
318 * SkBitmap::fPixelRefOffset + SkBitmap::getSafeSize() should never overflow this value,
319 * otherwise the rendering code may attempt to read memory out of bounds.
320 *
321 * @return default impl returns 0.
322 */
323 virtual size_t getAllocatedSizeInBytes() const;
324
reed92fc2ae2015-05-22 08:06:21 -0700325 virtual bool onRequestLock(const LockRequest&, LockResult*);
326
fmalitaddbbdda2015-08-20 08:47:26 -0700327 virtual bool onIsLazyGenerated() const { return false; }
328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 /** Return the mutex associated with this pixelref. This value is assigned
330 in the constructor, and cannot change during the lifetime of the object.
331 */
mtklein7e6d9c02015-08-13 14:02:06 -0700332 SkBaseMutex* mutex() const { return &fMutex; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333
reed@google.comff0da4f2012-05-17 13:14:52 +0000334 // only call from constructor. Flags this to always be locked, removing
335 // the need to grab the mutex and call onLockPixels/onUnlockPixels.
336 // Performance tweak to avoid those calls (esp. in multi-thread use case).
reed@google.comd0419b12014-01-06 17:08:27 +0000337 void setPreLocked(void*, size_t rowBytes, SkColorTable*);
reed@google.comff0da4f2012-05-17 13:14:52 +0000338
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339private:
mtklein7e6d9c02015-08-13 14:02:06 -0700340 mutable SkMutex fMutex;
reed@google.com33cc9892014-01-02 18:07:46 +0000341
commit-bot@chromium.org0e8d0d62014-01-27 15:41:07 +0000342 // mostly const. fInfo.fAlpahType can be changed at runtime.
reed@google.com33cc9892014-01-02 18:07:46 +0000343 const SkImageInfo fInfo;
robertphillips@google.com0daa1ad2013-12-13 15:24:37 +0000344
reed@google.comd0419b12014-01-06 17:08:27 +0000345 // LockRec is only valid if we're in a locked state (isLocked())
346 LockRec fRec;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 int fLockCount;
reed@google.com93c5f9e2011-02-24 18:09:46 +0000348
reeddb74f622015-05-30 13:41:15 -0700349 bool lockPixelsInsideMutex();
reed92fc2ae2015-05-22 08:06:21 -0700350
mtklein63d00242015-02-25 09:10:57 -0800351 // Bottom bit indicates the Gen ID is unique.
352 bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); }
353 mutable SkAtomic<uint32_t> fTaggedGenID;
354
scroggof3ca41c2014-11-25 13:42:12 -0800355#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
356 const uint32_t fStableID;
357#endif
reed@google.com93c5f9e2011-02-24 18:09:46 +0000358
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000359 SkTDArray<GenIDChangeListener*> fGenIDChangeListeners; // pointers are owned
scroggo@google.comd5764e82012-08-22 15:00:05 +0000360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 SkString fURI;
362
mtklein63d00242015-02-25 09:10:57 -0800363 // Set true by caches when they cache content that's derived from the current pixels.
364 SkAtomic<bool> fAddedToCache;
reed26e0e582015-07-29 11:44:52 -0700365
366 enum {
367 kMutable, // PixelRefs begin mutable.
368 kTemporarilyImmutable, // Considered immutable, but can revert to mutable.
369 kImmutable, // Once set to this state, it never leaves.
370 } fMutability : 8; // easily fits inside a byte
371
reed@google.comff0da4f2012-05-17 13:14:52 +0000372 // only ever set in constructor, const after that
mtklein63d00242015-02-25 09:10:57 -0800373 bool fPreLocked;
reed@google.comff0da4f2012-05-17 13:14:52 +0000374
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000375 void needsNewGenID();
376 void callGenIDChangeListeners();
377
reed26e0e582015-07-29 11:44:52 -0700378 void setTemporarilyImmutable();
379 void restoreMutability();
380 friend class SkSurface_Raster; // For the two methods above.
381
reed02d91d12015-07-30 20:13:43 -0700382 bool isPreLocked() const { return fPreLocked; }
383 friend class SkImage_Raster;
384
commit-bot@chromium.org50a30432013-10-24 17:44:27 +0000385 // When copying a bitmap to another with the same shape and config, we can safely
386 // clone the pixelref generation ID too, which makes them equivalent under caching.
387 friend class SkBitmap; // only for cloneGenID
388 void cloneGenID(const SkPixelRef&);
389
reed6f1216a2015-08-04 08:10:13 -0700390 void setImmutableWithID(uint32_t genID);
391 friend class SkImage_Gpu;
reed8f343722015-08-13 13:32:39 -0700392 friend class SkImageCacherator;
reed6f1216a2015-08-04 08:10:13 -0700393
reeded458682014-07-14 09:21:31 -0700394 typedef SkRefCnt INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000395};
396
reed@google.com9ebcac52014-01-24 18:53:42 +0000397class SkPixelRefFactory : public SkRefCnt {
398public:
399 /**
400 * Allocate a new pixelref matching the specified ImageInfo, allocating
401 * the memory for the pixels. If the ImageInfo requires a ColorTable,
402 * the pixelref will ref() the colortable.
403 * On failure return NULL.
404 */
reedf0aed972014-07-01 12:48:11 -0700405 virtual SkPixelRef* create(const SkImageInfo&, size_t rowBytes, SkColorTable*) = 0;
reed@google.com9ebcac52014-01-24 18:53:42 +0000406};
407
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408#endif