1 /* 2 * Copyright 2008 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkPixelRef_DEFINED 9 #define SkPixelRef_DEFINED 10 11 #include "../private/SkAtomics.h" 12 #include "../private/SkMutex.h" 13 #include "../private/SkTDArray.h" 14 #include "SkBitmap.h" 15 #include "SkFilterQuality.h" 16 #include "SkImageInfo.h" 17 #include "SkPixmap.h" 18 #include "SkRefCnt.h" 19 #include "SkSize.h" 20 #include "SkString.h" 21 22 class SkColorTable; 23 struct SkIRect; 24 25 class GrTexture; 26 class SkDiscardableMemory; 27 28 /** \class SkPixelRef 29 30 This class is the smart container for pixel memory, and is used with 31 SkBitmap. A pixelref is installed into a bitmap, and then the bitmap can 32 access the actual pixel memory by calling lockPixels/unlockPixels. 33 34 This class can be shared/accessed between multiple threads. 35 */ 36 class SK_API SkPixelRef : public SkRefCnt { 37 public: 38 explicit SkPixelRef(const SkImageInfo&); 39 virtual ~SkPixelRef(); 40 info()41 const SkImageInfo& info() const { 42 return fInfo; 43 } 44 45 /** Return the pixel memory returned from lockPixels, or null if the 46 lockCount is 0. 47 */ pixels()48 void* pixels() const { return fRec.fPixels; } 49 50 /** Return the current colorTable (if any) if pixels are locked, or null. 51 */ colorTable()52 SkColorTable* colorTable() const { return fRec.fColorTable; } 53 rowBytes()54 size_t rowBytes() const { return fRec.fRowBytes; } 55 56 /** 57 * To access the actual pixels of a pixelref, it must be "locked". 58 * Calling lockPixels returns a LockRec struct (on success). 59 */ 60 struct LockRec { LockRecLockRec61 LockRec() : fPixels(NULL), fColorTable(NULL) {} 62 63 void* fPixels; 64 SkColorTable* fColorTable; 65 size_t fRowBytes; 66 zeroLockRec67 void zero() { sk_bzero(this, sizeof(*this)); } 68 isZeroLockRec69 bool isZero() const { 70 return NULL == fPixels && NULL == fColorTable && 0 == fRowBytes; 71 } 72 }; 73 74 SkDEBUGCODE(bool isLocked() const { return fLockCount > 0; }) 75 SkDEBUGCODE(int getLockCount() const { return fLockCount; }) 76 77 /** 78 * Call to access the pixel memory. Return true on success. Balance this 79 * with a call to unlockPixels(). 80 */ 81 bool lockPixels(); 82 83 /** 84 * Call to access the pixel memory. On success, return true and fill out 85 * the specified rec. On failure, return false and ignore the rec parameter. 86 * Balance this with a call to unlockPixels(). 87 */ 88 bool lockPixels(LockRec* rec); 89 90 /** Call to balanace a previous call to lockPixels(). Returns the pixels 91 (or null) after the unlock. NOTE: lock calls can be nested, but the 92 matching number of unlock calls must be made in order to free the 93 memory (if the subclass implements caching/deferred-decoding.) 94 */ 95 void unlockPixels(); 96 97 /** 98 * Some bitmaps can return a copy of their pixels for lockPixels(), but 99 * that copy, if modified, will not be pushed back. These bitmaps should 100 * not be used as targets for a raster device/canvas (since all pixels 101 * modifications will be lost when unlockPixels() is called.) 102 */ 103 bool lockPixelsAreWritable() const; 104 105 /** Returns a non-zero, unique value corresponding to the pixels in this 106 pixelref. Each time the pixels are changed (and notifyPixelsChanged is 107 called), a different generation ID will be returned. 108 */ 109 uint32_t getGenerationID() const; 110 111 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 112 /** Returns a non-zero, unique value corresponding to this SkPixelRef. 113 Unlike the generation ID, this ID remains the same even when the pixels 114 are changed. IDs are not reused (until uint32_t wraps), so it is safe 115 to consider this ID unique even after this SkPixelRef is deleted. 116 117 Can be used as a key which uniquely identifies this SkPixelRef 118 regardless of changes to its pixels or deletion of this object. 119 */ getStableID()120 uint32_t getStableID() const { return fStableID; } 121 #endif 122 123 /** 124 * Call this if you have changed the contents of the pixels. This will in- 125 * turn cause a different generation ID value to be returned from 126 * getGenerationID(). 127 */ 128 void notifyPixelsChanged(); 129 130 /** 131 * Change the info's AlphaType. Note that this does not automatically 132 * invalidate the generation ID. If the pixel values themselves have 133 * changed, then you must explicitly call notifyPixelsChanged() as well. 134 */ 135 void changeAlphaType(SkAlphaType at); 136 137 /** Returns true if this pixelref is marked as immutable, meaning that the 138 contents of its pixels will not change for the lifetime of the pixelref. 139 */ isImmutable()140 bool isImmutable() const { return fMutability != kMutable; } 141 142 /** Marks this pixelref is immutable, meaning that the contents of its 143 pixels will not change for the lifetime of the pixelref. This state can 144 be set on a pixelref, but it cannot be cleared once it is set. 145 */ 146 void setImmutable(); 147 148 /** Return the optional URI string associated with this pixelref. May be 149 null. 150 */ getURI()151 const char* getURI() const { return fURI.size() ? fURI.c_str() : NULL; } 152 153 /** Copy a URI string to this pixelref, or clear the URI if the uri is null 154 */ setURI(const char uri[])155 void setURI(const char uri[]) { 156 fURI.set(uri); 157 } 158 159 /** Copy a URI string to this pixelref 160 */ setURI(const char uri[],size_t len)161 void setURI(const char uri[], size_t len) { 162 fURI.set(uri, len); 163 } 164 165 /** Assign a URI string to this pixelref. 166 */ setURI(const SkString & uri)167 void setURI(const SkString& uri) { fURI = uri; } 168 169 struct LockRequest { 170 SkISize fSize; 171 SkFilterQuality fQuality; 172 }; 173 174 struct LockResult { LockResultLockResult175 LockResult() : fPixels(NULL), fCTable(NULL) {} 176 177 void (*fUnlockProc)(void* ctx); 178 void* fUnlockContext; 179 180 const void* fPixels; 181 SkColorTable* fCTable; // should be NULL unless colortype is kIndex8 182 size_t fRowBytes; 183 SkISize fSize; 184 unlockLockResult185 void unlock() { 186 if (fUnlockProc) { 187 fUnlockProc(fUnlockContext); 188 fUnlockProc = NULL; // can't unlock twice! 189 } 190 } 191 }; 192 193 bool requestLock(const LockRequest&, LockResult*); 194 195 // Register a listener that may be called the next time our generation ID changes. 196 // 197 // We'll only call the listener if we're confident that we are the only SkPixelRef with this 198 // generation ID. If our generation ID changes and we decide not to call the listener, we'll 199 // never call it: you must add a new listener for each generation ID change. We also won't call 200 // the listener when we're certain no one knows what our generation ID is. 201 // 202 // This can be used to invalidate caches keyed by SkPixelRef generation ID. 203 struct GenIDChangeListener { ~GenIDChangeListenerGenIDChangeListener204 virtual ~GenIDChangeListener() {} 205 virtual void onChange() = 0; 206 }; 207 208 // Takes ownership of listener. 209 void addGenIDChangeListener(GenIDChangeListener* listener); 210 211 // Call when this pixelref is part of the key to a resourcecache entry. This allows the cache 212 // to know automatically those entries can be purged when this pixelref is changed or deleted. notifyAddedToCache()213 void notifyAddedToCache() { 214 fAddedToCache.store(true); 215 } 216 diagnostic_only_getDiscardable()217 virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return NULL; } 218 219 /** 220 * Returns true if the pixels are generated on-the-fly (when required). 221 */ isLazyGenerated()222 bool isLazyGenerated() const { return this->onIsLazyGenerated(); } 223 224 protected: 225 /** 226 * On success, returns true and fills out the LockRec for the pixels. On 227 * failure returns false and ignores the LockRec parameter. 228 * 229 * The caller will have already acquired a mutex for thread safety, so this 230 * method need not do that. 231 */ 232 virtual bool onNewLockPixels(LockRec*) = 0; 233 234 /** 235 * Balancing the previous successful call to onNewLockPixels. The locked 236 * pixel address will no longer be referenced, so the subclass is free to 237 * move or discard that memory. 238 * 239 * The caller will have already acquired a mutex for thread safety, so this 240 * method need not do that. 241 */ 242 virtual void onUnlockPixels() = 0; 243 244 /** Default impl returns true */ 245 virtual bool onLockPixelsAreWritable() const; 246 247 // default impl does nothing. 248 virtual void onNotifyPixelsChanged(); 249 250 /** 251 * Returns the size (in bytes) of the internally allocated memory. 252 * This should be implemented in all serializable SkPixelRef derived classes. 253 * SkBitmap::fPixelRefOffset + SkBitmap::getSafeSize() should never overflow this value, 254 * otherwise the rendering code may attempt to read memory out of bounds. 255 * 256 * @return default impl returns 0. 257 */ 258 virtual size_t getAllocatedSizeInBytes() const; 259 260 virtual bool onRequestLock(const LockRequest&, LockResult*); 261 onIsLazyGenerated()262 virtual bool onIsLazyGenerated() const { return false; } 263 264 /** Return the mutex associated with this pixelref. This value is assigned 265 in the constructor, and cannot change during the lifetime of the object. 266 */ mutex()267 SkBaseMutex* mutex() const { return &fMutex; } 268 269 // only call from constructor. Flags this to always be locked, removing 270 // the need to grab the mutex and call onLockPixels/onUnlockPixels. 271 // Performance tweak to avoid those calls (esp. in multi-thread use case). 272 void setPreLocked(void*, size_t rowBytes, SkColorTable*); 273 274 private: 275 mutable SkMutex fMutex; 276 277 // mostly const. fInfo.fAlpahType can be changed at runtime. 278 const SkImageInfo fInfo; 279 280 // LockRec is only valid if we're in a locked state (isLocked()) 281 LockRec fRec; 282 int fLockCount; 283 284 bool lockPixelsInsideMutex(); 285 286 // Bottom bit indicates the Gen ID is unique. genIDIsUnique()287 bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); } 288 mutable SkAtomic<uint32_t> fTaggedGenID; 289 290 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 291 const uint32_t fStableID; 292 #endif 293 294 SkTDArray<GenIDChangeListener*> fGenIDChangeListeners; // pointers are owned 295 296 SkString fURI; 297 298 // Set true by caches when they cache content that's derived from the current pixels. 299 SkAtomic<bool> fAddedToCache; 300 301 enum { 302 kMutable, // PixelRefs begin mutable. 303 kTemporarilyImmutable, // Considered immutable, but can revert to mutable. 304 kImmutable, // Once set to this state, it never leaves. 305 } fMutability : 8; // easily fits inside a byte 306 307 // only ever set in constructor, const after that 308 bool fPreLocked; 309 310 void needsNewGenID(); 311 void callGenIDChangeListeners(); 312 313 void setTemporarilyImmutable(); 314 void restoreMutability(); 315 friend class SkSurface_Raster; // For the two methods above. 316 isPreLocked()317 bool isPreLocked() const { return fPreLocked; } 318 friend class SkImage_Raster; 319 friend class SkSpecialImage_Raster; 320 321 // When copying a bitmap to another with the same shape and config, we can safely 322 // clone the pixelref generation ID too, which makes them equivalent under caching. 323 friend class SkBitmap; // only for cloneGenID 324 void cloneGenID(const SkPixelRef&); 325 326 void setImmutableWithID(uint32_t genID); 327 friend class SkImage_Gpu; 328 friend class SkImageCacherator; 329 friend class SkSpecialImage_Gpu; 330 331 typedef SkRefCnt INHERITED; 332 }; 333 334 class SkPixelRefFactory : public SkRefCnt { 335 public: 336 /** 337 * Allocate a new pixelref matching the specified ImageInfo, allocating 338 * the memory for the pixels. If the ImageInfo requires a ColorTable, 339 * the pixelref will ref() the colortable. 340 * On failure return NULL. 341 */ 342 virtual SkPixelRef* create(const SkImageInfo&, size_t rowBytes, SkColorTable*) = 0; 343 }; 344 345 #endif 346