diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/include/core/SkPixelRef.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/include/core/SkPixelRef.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,380 @@ +/* + * 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 "SkBitmap.h" +#include "SkRefCnt.h" +#include "SkString.h" +#include "SkFlattenable.h" +#include "SkImageInfo.h" +#include "SkTDArray.h" + +//#define xed + +#ifdef SK_DEBUG + /** + * Defining SK_IGNORE_PIXELREF_SETPRELOCKED will force all pixelref + * subclasses to correctly handle lock/unlock pixels. For performance + * reasons, simple malloc-based subclasses call setPreLocked() to skip + * the overhead of implementing these calls. + * + * This build-flag disables that optimization, to add in debugging our + * call-sites, to ensure that they correctly balance their calls of + * lock and unlock. + */ +// #define SK_IGNORE_PIXELREF_SETPRELOCKED +#endif + +class SkColorTable; +class SkData; +struct SkIRect; +class SkMutex; + +class GrTexture; + +/** \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 SkFlattenable { +public: + SK_DECLARE_INST_COUNT(SkPixelRef) + + explicit SkPixelRef(const SkImageInfo&); + SkPixelRef(const SkImageInfo&, SkBaseMutex* mutex); + 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 { + void* fPixels; + SkColorTable* fColorTable; + size_t fRowBytes; + + void zero() { sk_bzero(this, sizeof(*this)); } + + bool isZero() const { + return NULL == fPixels && NULL == fColorTable && 0 == fRowBytes; + } + }; + + /** + * Returns true if the lockcount > 0 + */ + 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; + + /** + * 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 fIsImmutable; } + + /** 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(); + } + + /** + * Experimental -- tells the caller if it is worth it to call decodeInto(). + * Just an optimization at this point, to avoid checking the cache first. + * We may remove/change this call in the future. + */ + bool implementsDecodeInto() { + return this->onImplementsDecodeInto(); + } + + /** + * Return a decoded instance of this pixelRef in bitmap. If this cannot be + * done, return false and the bitmap parameter is ignored/unchanged. + * + * pow2 is the requeste power-of-two downscale that the caller needs. This + * can be ignored, and the "original" size can be returned, but if the + * underlying codec can efficiently return a smaller size, that should be + * done. Some examples: + * + * To request the "base" version (original scale), pass 0 for pow2 + * To request 1/2 scale version (1/2 width, 1/2 height), pass 1 for pow2 + * To request 1/4 scale version (1/4 width, 1/4 height), pass 2 for pow2 + * ... + * + * If this returns true, then bitmap must be "locked" such that + * bitmap->getPixels() will return the correct address. + */ + bool decodeInto(int pow2, SkBitmap* bitmap) { + SkASSERT(pow2 >= 0); + return this->onDecodeInto(pow2, bitmap); + } + + /** Are we really wrapping a texture instead of a bitmap? + */ + virtual GrTexture* getTexture() { return NULL; } + + bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL); + + /** + * Makes a deep copy of this PixelRef, respecting the requested config. + * @param config Desired config. + * @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(SkBitmap::Config config, const SkIRect* subset = NULL) { + return NULL; + } + +#ifdef SK_BUILD_FOR_ANDROID + /** + * Acquire a "global" ref on this object. + * The default implementation just calls ref(), but subclasses can override + * this method to implement additional behavior. + */ + virtual void globalRef(void* data=NULL); + + /** + * Release a "global" ref on this object. + * The default implementation just calls unref(), but subclasses can override + * this method to implement additional behavior. + */ + virtual void globalUnref(); +#endif + + SK_DEFINE_FLATTENABLE_TYPE(SkPixelRef) + + // 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); + +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; + + // returns false; + virtual bool onImplementsDecodeInto(); + // returns false; + virtual bool onDecodeInto(int pow2, SkBitmap* bitmap); + + /** + * 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, const SkIRect* subsetOrNull); + + // default impl returns NULL. + virtual SkData* onRefEncodedData(); + + /** + * 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; + + /** 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; } + + // serialization + SkPixelRef(SkReadBuffer&, SkBaseMutex*); + virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; + + // 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: + SkBaseMutex* fMutex; // must remain in scope for the life of this object + + // 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; + + mutable uint32_t fGenerationID; + mutable bool fUniqueGenerationID; + + SkTDArray fGenIDChangeListeners; // pointers are owned + + SkString fURI; + + // can go from false to true, but never from true to false + bool fIsImmutable; + // only ever set in constructor, const after that + bool fPreLocked; + + void needsNewGenID(); + void callGenIDChangeListeners(); + + void setMutex(SkBaseMutex* mutex); + + // 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&); + + typedef SkFlattenable 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&, SkColorTable*) = 0; +}; + +#endif