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 class SkData; 24 struct SkIRect; 25 26 class GrTexture; 27 class SkDiscardableMemory; 28 29 /** \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 */ 37 class SK_API SkPixelRef : public SkRefCnt { 38 public: 39 explicit SkPixelRef(const SkImageInfo&); 40 virtual ~SkPixelRef(); 41 info()42 const SkImageInfo& info() const { 43 return fInfo; 44 } 45 46 /** Return the pixel memory returned from lockPixels, or null if the 47 lockCount is 0. 48 */ pixels()49 void* pixels() const { return fRec.fPixels; } 50 51 /** Return the current colorTable (if any) if pixels are locked, or null. 52 */ colorTable()53 SkColorTable* colorTable() const { return fRec.fColorTable; } 54 rowBytes()55 size_t rowBytes() const { return fRec.fRowBytes; } 56 57 /** 58 * 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 { LockRecLockRec62 LockRec() : fPixels(NULL), fColorTable(NULL) {} 63 64 void* fPixels; 65 SkColorTable* fColorTable; 66 size_t fRowBytes; 67 zeroLockRec68 void zero() { sk_bzero(this, sizeof(*this)); } 69 isZeroLockRec70 bool isZero() const { 71 return NULL == fPixels && NULL == fColorTable && 0 == fRowBytes; 72 } 73 }; 74 75 SkDEBUGCODE(bool isLocked() const { return fLockCount > 0; }) 76 SkDEBUGCODE(int getLockCount() const { return fLockCount; }) 77 78 /** 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 91 /** 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(); 97 98 /** 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 106 /** 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; 111 112 #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 */ getStableID()121 uint32_t getStableID() const { return fStableID; } 122 #endif 123 124 /** 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(). 128 */ 129 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); 137 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 */ isImmutable()141 bool isImmutable() const { return fMutability != kMutable; } 142 143 /** 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 */ getURI()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 */ setURI(const char uri[])156 void setURI(const char uri[]) { 157 fURI.set(uri); 158 } 159 160 /** Copy a URI string to this pixelref 161 */ setURI(const char uri[],size_t len)162 void setURI(const char uri[], size_t len) { 163 fURI.set(uri, len); 164 } 165 166 /** Assign a URI string to this pixelref. 167 */ setURI(const SkString & uri)168 void setURI(const SkString& uri) { fURI = uri; } 169 170 /** 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 */ refEncodedData()178 SkData* refEncodedData() { 179 return this->onRefEncodedData(); 180 } 181 182 struct LockRequest { 183 SkISize fSize; 184 SkFilterQuality fQuality; 185 }; 186 187 struct LockResult { LockResultLockResult188 LockResult() : fPixels(NULL), fCTable(NULL) {} 189 190 void (*fUnlockProc)(void* ctx); 191 void* fUnlockContext; 192 193 const void* fPixels; 194 SkColorTable* fCTable; // should be NULL unless colortype is kIndex8 195 size_t fRowBytes; 196 SkISize fSize; 197 unlockLockResult198 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 208 /** Are we really wrapping a texture instead of a bitmap? 209 */ getTexture()210 virtual GrTexture* getTexture() { return NULL; } 211 212 /** 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. 219 * 220 * If colorSpace is not NULL, the YUV color space of the data should be stored in the address 221 * it points at. 222 */ getYUV8Planes(SkISize sizes[3],void * planes[3],size_t rowBytes[3],SkYUVColorSpace * colorSpace)223 bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], 224 SkYUVColorSpace* colorSpace) { 225 return this->onGetYUV8Planes(sizes, planes, rowBytes, colorSpace); 226 } 227 228 /** Populates dst with the pixels of this pixelRef, converting them to colorType. */ 229 bool readPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset = NULL); 230 231 /** 232 * Makes a deep copy of this PixelRef, respecting the requested config. 233 * @param colorType Desired colortype. 234 * @param profileType Desired colorprofiletype. 235 * @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 */ deepCopy(SkColorType,SkColorProfileType,const SkIRect *)241 virtual SkPixelRef* deepCopy(SkColorType, SkColorProfileType, const SkIRect* /*subset*/) { 242 return NULL; 243 } 244 245 // 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 { ~GenIDChangeListenerGenIDChangeListener254 virtual ~GenIDChangeListener() {} 255 virtual void onChange() = 0; 256 }; 257 258 // Takes ownership of listener. 259 void addGenIDChangeListener(GenIDChangeListener* listener); 260 261 // 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. notifyAddedToCache()263 void notifyAddedToCache() { 264 fAddedToCache.store(true); 265 } 266 diagnostic_only_getDiscardable()267 virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return NULL; } 268 269 /** 270 * Returns true if the pixels are generated on-the-fly (when required). 271 */ isLazyGenerated()272 bool isLazyGenerated() const { return this->onIsLazyGenerated(); } 273 274 protected: 275 /** 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; 283 284 /** 285 * 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. 288 * 289 * The caller will have already acquired a mutex for thread safety, so this 290 * method need not do that. 291 */ 292 virtual void onUnlockPixels() = 0; 293 294 /** Default impl returns true */ 295 virtual bool onLockPixelsAreWritable() const; 296 297 /** 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 */ 303 virtual bool onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subsetOrNull); 304 305 // default impl returns NULL. 306 virtual SkData* onRefEncodedData(); 307 308 // default impl does nothing. 309 virtual void onNotifyPixelsChanged(); 310 311 // default impl returns false. 312 virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3], 313 SkYUVColorSpace* colorSpace); 314 315 /** 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 325 virtual bool onRequestLock(const LockRequest&, LockResult*); 326 onIsLazyGenerated()327 virtual bool onIsLazyGenerated() const { return false; } 328 329 /** 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 */ mutex()332 SkBaseMutex* mutex() const { return &fMutex; } 333 334 // 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). 337 void setPreLocked(void*, size_t rowBytes, SkColorTable*); 338 339 private: 340 mutable SkMutex fMutex; 341 342 // mostly const. fInfo.fAlpahType can be changed at runtime. 343 const SkImageInfo fInfo; 344 345 // LockRec is only valid if we're in a locked state (isLocked()) 346 LockRec fRec; 347 int fLockCount; 348 349 bool lockPixelsInsideMutex(); 350 351 // Bottom bit indicates the Gen ID is unique. genIDIsUnique()352 bool genIDIsUnique() const { return SkToBool(fTaggedGenID.load() & 1); } 353 mutable SkAtomic<uint32_t> fTaggedGenID; 354 355 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 356 const uint32_t fStableID; 357 #endif 358 359 SkTDArray<GenIDChangeListener*> fGenIDChangeListeners; // pointers are owned 360 361 SkString fURI; 362 363 // Set true by caches when they cache content that's derived from the current pixels. 364 SkAtomic<bool> fAddedToCache; 365 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 372 // only ever set in constructor, const after that 373 bool fPreLocked; 374 375 void needsNewGenID(); 376 void callGenIDChangeListeners(); 377 378 void setTemporarilyImmutable(); 379 void restoreMutability(); 380 friend class SkSurface_Raster; // For the two methods above. 381 isPreLocked()382 bool isPreLocked() const { return fPreLocked; } 383 friend class SkImage_Raster; 384 friend class SkSpecialImage_Raster; 385 386 // When copying a bitmap to another with the same shape and config, we can safely 387 // clone the pixelref generation ID too, which makes them equivalent under caching. 388 friend class SkBitmap; // only for cloneGenID 389 void cloneGenID(const SkPixelRef&); 390 391 void setImmutableWithID(uint32_t genID); 392 friend class SkImage_Gpu; 393 friend class SkImageCacherator; 394 395 typedef SkRefCnt INHERITED; 396 }; 397 398 class SkPixelRefFactory : public SkRefCnt { 399 public: 400 /** 401 * Allocate a new pixelref matching the specified ImageInfo, allocating 402 * the memory for the pixels. If the ImageInfo requires a ColorTable, 403 * the pixelref will ref() the colortable. 404 * On failure return NULL. 405 */ 406 virtual SkPixelRef* create(const SkImageInfo&, size_t rowBytes, SkColorTable*) = 0; 407 }; 408 409 #endif 410