Update HWUI to store its own SkBitmap objects

This enables us to...

1) simplify the lifecycle/ownership between Java and HWUI
2) remove DisplayListRenderer::drawBitmapData and associated logic
3) track pixel lifecycle using standard SkPixelRef refcounting
4) Remove uncessary calls to ref/unref the bitmap's pixels and colorTable

Change-Id: I3c95078da20995444f6388a029414280fd654318
This commit is contained in:
Derek Sollenberger
2014-12-04 15:20:29 -05:00
parent 83eb4443a9
commit 3d4eed7f1a
17 changed files with 202 additions and 203 deletions

View File

@@ -19,8 +19,6 @@
#include <jni.h>
#include <ResourceCache.h>
///////////////////////////////////////////////////////////////////////////////
// Conversions to/from SkColor, for get/setPixels, and the create method, which
// is basically like setPixels
@@ -360,20 +358,11 @@ static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
if (android::uirenderer::ResourceCache::hasInstance()) {
android::uirenderer::ResourceCache::getInstance().destructor(bitmap);
} else {
delete bitmap;
}
delete bitmap;
}
static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
if (android::uirenderer::ResourceCache::hasInstance()) {
bool result;
result = android::uirenderer::ResourceCache::getInstance().recycle(bitmap);
return result ? JNI_TRUE : JNI_FALSE;
}
bitmap->setPixels(NULL, NULL);
return JNI_TRUE;
}

View File

@@ -11,6 +11,9 @@
#include "SkRegion.h"
#include <android_runtime/AndroidRuntime.h>
#include <Caches.h>
#include <TextureCache.h>
void doThrowNPE(JNIEnv* env) {
jniThrowNullPointerException(env, NULL);
}
@@ -500,10 +503,28 @@ AndroidPixelRef::~AndroidPixelRef() {
JNIEnv* env = vm2env(fVM);
env->DeleteGlobalRef(fStorageObj);
}
if (android::uirenderer::Caches::hasInstance()) {
android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
}
}
///////////////////////////////////////////////////////////////////////////////
static bool computeAllocationSize(const SkImageInfo& info, size_t* size, size_t* rowBytes) {
int32_t rowBytes32 = SkToS32(info.minRowBytes());
int64_t bigSize = (int64_t)info.height() * rowBytes32;
if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
return false; // allocation will be too large
}
*size = sk_64_asS32(bigSize);
*rowBytes = rowBytes32;
SkASSERT(*size >= info.getSafeSize(*rowBytes));
return true;
}
jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
SkColorTable* ctable) {
const SkImageInfo& info = bitmap->info();
@@ -512,7 +533,11 @@ jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
return NULL;
}
const size_t size = bitmap->getSize();
size_t size, rowBytes;
if (!computeAllocationSize(info, &size, &rowBytes)) {
return NULL;
}
jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
gVMRuntime_newNonMovableArray,
gByte_class, size);
@@ -525,8 +550,7 @@ jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
return NULL;
}
SkASSERT(addr);
SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr,
bitmap->rowBytes(), arrayObj, ctable);
SkPixelRef* pr = new AndroidPixelRef(env, info, (void*) addr, rowBytes, arrayObj, ctable);
bitmap->setPixelRef(pr)->unref();
// since we're already allocated, we lockPixels right away
// HeapAllocator behaves this way too
@@ -535,6 +559,56 @@ jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
return arrayObj;
}
struct AndroidPixelRefContext {
int32_t stableID;
};
static void allocatePixelsReleaseProc(void* ptr, void* ctx) {
AndroidPixelRefContext* context = (AndroidPixelRefContext*)ctx;
if (android::uirenderer::Caches::hasInstance()) {
android::uirenderer::Caches::getInstance().textureCache.releaseTexture(context->stableID);
}
sk_free(ptr);
delete context;
}
bool GraphicsJNI::allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) {
const SkImageInfo& info = bitmap->info();
if (info.fColorType == kUnknown_SkColorType) {
doThrowIAE(env, "unknown bitmap configuration");
return NULL;
}
size_t size, rowBytes;
if (!computeAllocationSize(info, &size, &rowBytes)) {
return false;
}
void* addr = sk_malloc_flags(size, 0);
if (NULL == addr) {
return false;
}
AndroidPixelRefContext* context = new AndroidPixelRefContext;
SkMallocPixelRef* pr = SkMallocPixelRef::NewWithProc(info, rowBytes, ctable, addr,
&allocatePixelsReleaseProc, context);
if (!pr) {
delete context;
return false;
}
// set the stableID in the context so that it can be used later in
// allocatePixelsReleaseProc to remove the texture from the cache.
context->stableID = pr->getStableID();
bitmap->setPixelRef(pr)->unref();
// since we're already allocated, we can lockPixels right away
bitmap->lockPixels();
return true;
}
///////////////////////////////////////////////////////////////////////////////
JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env)

View File

@@ -95,6 +95,14 @@ public:
static jbyteArray allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
SkColorTable* ctable);
/**
* Given a bitmap we natively allocate a memory block to store the contents
* of that bitmap. The memory is then attached to the bitmap via an
* SkPixelRef, which ensures that upon deletion the appropriate caches
* are notified.
*/
static bool allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable);
/** Copy the colors in colors[] to the bitmap, convert to the correct
format along the way.
Whether to use premultiplied pixels is determined by dstBitmap's alphaType.

View File

@@ -383,7 +383,8 @@ static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle,
hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
kPremul_SkAlphaType);
SkBitmap bitmap;
if (!bitmap.tryAllocPixels(info)) {
bitmap.setInfo(info);
if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
return;
}

View File

@@ -46,12 +46,6 @@ void DisplayListData::cleanupResources() {
resourceCache.decrementRefcountLocked(bitmapResources.itemAt(i));
}
for (size_t i = 0; i < ownedBitmapResources.size(); i++) {
const SkBitmap* bitmap = ownedBitmapResources.itemAt(i);
resourceCache.decrementRefcountLocked(bitmap);
resourceCache.destructorLocked(bitmap);
}
for (size_t i = 0; i < patchResources.size(); i++) {
resourceCache.decrementRefcountLocked(patchResources.itemAt(i));
}
@@ -63,7 +57,6 @@ void DisplayListData::cleanupResources() {
resourceCache.unlock();
bitmapResources.clear();
ownedBitmapResources.clear();
patchResources.clear();
sourcePaths.clear();
paints.clear();

View File

@@ -134,7 +134,6 @@ public:
int projectionReceiveIndex;
Vector<const SkBitmap*> bitmapResources;
Vector<const SkBitmap*> ownedBitmapResources;
Vector<const Res_png_9patch*> patchResources;
std::vector<std::unique_ptr<const SkPaint>> paints;

View File

@@ -734,27 +734,6 @@ private:
Rect mSrc;
};
class DrawBitmapDataOp : public DrawBitmapOp {
public:
DrawBitmapDataOp(const SkBitmap* bitmap, const SkPaint* paint)
: DrawBitmapOp(bitmap, paint) {}
virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
renderer.drawBitmapData(mBitmap, mPaint);
}
virtual void output(int level, uint32_t logFlags) const override {
OP_LOG("Draw bitmap %p", mBitmap);
}
virtual const char* name() override { return "DrawBitmapData"; }
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
const DeferredDisplayState& state) override {
deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
}
};
class DrawBitmapMeshOp : public DrawBoundedOp {
public:
DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight,

View File

@@ -266,13 +266,6 @@ void DisplayListRenderer::drawBitmap(const SkBitmap& bitmap, float srcLeft, floa
}
}
void DisplayListRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
bitmap = refBitmapData(bitmap);
paint = refPaint(paint);
addDrawOp(new (alloc()) DrawBitmapDataOp(bitmap, paint));
}
void DisplayListRenderer::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
int vertexCount = (meshWidth + 1) * (meshHeight + 1);

View File

@@ -101,8 +101,6 @@ public:
// Bitmap-based
void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
// TODO: move drawBitmapData() to Canvas.h
void drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint);
// TODO: move drawPatch() to Canvas.h
void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
float left, float top, float right, float bottom, const SkPaint* paint);
@@ -367,15 +365,9 @@ private:
// correctly, such as creating the bitmap from scratch, drawing with it, changing its
// contents, and drawing again. The only fix would be to always copy it the first time,
// which doesn't seem worth the extra cycles for this unlikely case.
mDisplayListData->bitmapResources.add(bitmap);
mResourceCache.incrementRefcount(bitmap);
return bitmap;
}
inline const SkBitmap* refBitmapData(const SkBitmap* bitmap) {
mDisplayListData->ownedBitmapResources.add(bitmap);
mResourceCache.incrementRefcount(bitmap);
return bitmap;
const SkBitmap* cachedBitmap = mResourceCache.insert(bitmap);
mDisplayListData->bitmapResources.add(cachedBitmap);
return cachedBitmap;
}
inline const Res_png_9patch* refPatch(const Res_png_9patch* patch) {

View File

@@ -2006,24 +2006,6 @@ void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
mDirty = true;
}
void OpenGLRenderer::drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) {
if (quickRejectSetupScissor(0, 0, bitmap->width(), bitmap->height())) {
return;
}
mCaches.activeTexture(0);
Texture* texture = mCaches.textureCache.getTransient(bitmap);
const AutoTexture autoCleanup(texture);
if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
drawAlphaBitmap(texture, 0, 0, paint);
} else {
drawTextureRect(0, 0, bitmap->width(), bitmap->height(), texture, paint);
}
mDirty = true;
}
void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
if (!vertices || mState.currentlyIgnored()) {

View File

@@ -162,7 +162,6 @@ public:
virtual void drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, const SkPaint* paint) override;
virtual void drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) override;
virtual void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) override;
void drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,

View File

@@ -338,11 +338,6 @@ void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
if (subtree) {
TextureCache& cache = Caches::getInstance().textureCache;
info.out.hasFunctors |= subtree->functors.size();
// TODO: Fix ownedBitmapResources to not require disabling prepareTextures
// and thus falling out of async drawing path.
if (subtree->ownedBitmapResources.size()) {
info.prepareTextures = false;
}
for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]);
}

View File

@@ -155,7 +155,6 @@ public:
virtual void drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, const SkPaint* paint) = 0;
virtual void drawBitmapData(const SkBitmap* bitmap, const SkPaint* paint) = 0;
virtual void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) = 0;
virtual void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,

View File

@@ -16,7 +16,6 @@
#define LOG_TAG "OpenGLRenderer"
#include <SkPixelRef.h>
#include "ResourceCache.h"
#include "Caches.h"
@@ -37,8 +36,8 @@ void ResourceCache::logCache() {
ResourceReference* ref = mCache->valueAt(i);
ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
i, mCache->keyAt(i), mCache->valueAt(i));
ALOGD(" ResourceCache: mCache(%zu): refCount, recycled, destroyed, type = %d, %d, %d, %d",
i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d",
i, ref->refCount, ref->destroyed, ref->resourceType);
}
}
@@ -60,15 +59,26 @@ void ResourceCache::unlock() {
mLock.unlock();
}
const SkBitmap* ResourceCache::insert(const SkBitmap* bitmapResource) {
Mutex::Autolock _l(mLock);
BitmapKey bitmapKey(bitmapResource);
ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
if (index == NAME_NOT_FOUND) {
SkBitmap* cachedBitmap = new SkBitmap(*bitmapResource);
index = mBitmapCache.add(bitmapKey, cachedBitmap);
return cachedBitmap;
}
mBitmapCache.keyAt(index).mRefCount++;
return mBitmapCache.valueAt(index);
}
void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
Mutex::Autolock _l(mLock);
incrementRefcountLocked(resource, resourceType);
}
void ResourceCache::incrementRefcount(const SkBitmap* bitmapResource) {
incrementRefcount((void*) bitmapResource, kBitmap);
}
void ResourceCache::incrementRefcount(const SkPath* pathResource) {
incrementRefcount((void*) pathResource, kPath);
}
@@ -87,25 +97,14 @@ void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourc
ref->refCount++;
}
void ResourceCache::incrementRefcountLocked(const SkBitmap* bitmapResource) {
incrementRefcountLocked((void*) bitmapResource, kBitmap);
}
void ResourceCache::incrementRefcountLocked(const SkPath* pathResource) {
incrementRefcountLocked((void*) pathResource, kPath);
}
void ResourceCache::incrementRefcountLocked(const Res_png_9patch* patchResource) {
incrementRefcountLocked((void*) patchResource, kNinePatch);
}
void ResourceCache::decrementRefcount(void* resource) {
Mutex::Autolock _l(mLock);
decrementRefcountLocked(resource);
}
void ResourceCache::decrementRefcount(const SkBitmap* bitmapResource) {
decrementRefcount((void*) bitmapResource);
Mutex::Autolock _l(mLock);
decrementRefcountLocked(bitmapResource);
}
void ResourceCache::decrementRefcount(const SkPath* pathResource) {
@@ -130,7 +129,20 @@ void ResourceCache::decrementRefcountLocked(void* resource) {
}
void ResourceCache::decrementRefcountLocked(const SkBitmap* bitmapResource) {
decrementRefcountLocked((void*) bitmapResource);
BitmapKey bitmapKey(bitmapResource);
ssize_t index = mBitmapCache.indexOfKey(bitmapKey);
LOG_ALWAYS_FATAL_IF(index == NAME_NOT_FOUND,
"Decrementing the reference of an untracked Bitmap");
const BitmapKey& cacheEntry = mBitmapCache.keyAt(index);
if (cacheEntry.mRefCount == 1) {
// delete the bitmap and remove it from the cache
delete mBitmapCache.valueAt(index);
mBitmapCache.removeItemsAt(index);
} else {
cacheEntry.mRefCount--;
}
}
void ResourceCache::decrementRefcountLocked(const SkPath* pathResource) {
@@ -164,28 +176,6 @@ void ResourceCache::destructorLocked(SkPath* resource) {
}
}
void ResourceCache::destructor(const SkBitmap* resource) {
Mutex::Autolock _l(mLock);
destructorLocked(resource);
}
void ResourceCache::destructorLocked(const SkBitmap* resource) {
ssize_t index = mCache->indexOfKey(resource);
ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr;
if (ref == nullptr) {
// If we're not tracking this resource, just delete it
if (Caches::hasInstance()) {
Caches::getInstance().textureCache.releaseTexture(resource);
}
delete resource;
return;
}
ref->destroyed = true;
if (ref->refCount == 0) {
deleteResourceReferenceLocked(resource, ref);
}
}
void ResourceCache::destructor(Res_png_9patch* resource) {
Mutex::Autolock _l(mLock);
destructorLocked(resource);
@@ -211,65 +201,13 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) {
}
}
/**
* Return value indicates whether resource was actually recycled, which happens when RefCnt
* reaches 0.
*/
bool ResourceCache::recycle(SkBitmap* resource) {
Mutex::Autolock _l(mLock);
return recycleLocked(resource);
}
/**
* Return value indicates whether resource was actually recycled, which happens when RefCnt
* reaches 0.
*/
bool ResourceCache::recycleLocked(SkBitmap* resource) {
ssize_t index = mCache->indexOfKey(resource);
if (index < 0) {
if (Caches::hasInstance()) {
Caches::getInstance().textureCache.releaseTexture(resource);
}
// not tracking this resource; just recycle the pixel data
resource->setPixels(nullptr, nullptr);
return true;
}
ResourceReference* ref = mCache->valueAt(index);
if (ref == nullptr) {
// Should not get here - shouldn't get a call to recycle if we're not yet tracking it
return true;
}
ref->recycled = true;
if (ref->refCount == 0) {
deleteResourceReferenceLocked(resource, ref);
return true;
}
// Still referring to resource, don't recycle yet
return false;
}
/**
* This method should only be called while the mLock mutex is held (that mutex is grabbed
* by the various destructor() and recycle() methods which call this method).
*/
void ResourceCache::deleteResourceReferenceLocked(const void* resource, ResourceReference* ref) {
if (ref->recycled && ref->resourceType == kBitmap) {
SkBitmap* bitmap = (SkBitmap*) resource;
if (Caches::hasInstance()) {
Caches::getInstance().textureCache.releaseTexture(bitmap);
}
bitmap->setPixels(nullptr, nullptr);
}
if (ref->destroyed) {
switch (ref->resourceType) {
case kBitmap: {
SkBitmap* bitmap = (SkBitmap*) resource;
if (Caches::hasInstance()) {
Caches::getInstance().textureCache.releaseTexture(bitmap);
}
delete bitmap;
}
break;
case kPath: {
SkPath* path = (SkPath*) resource;
if (Caches::hasInstance()) {
@@ -296,5 +234,38 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource
delete ref;
}
///////////////////////////////////////////////////////////////////////////////
// Bitmap Key
///////////////////////////////////////////////////////////////////////////////
void BitmapKey::operator=(const BitmapKey& other) {
this->mRefCount = other.mRefCount;
this->mBitmapDimensions = other.mBitmapDimensions;
this->mPixelRefOrigin = other.mPixelRefOrigin;
this->mPixelRefStableID = other.mPixelRefStableID;
}
bool BitmapKey::operator==(const BitmapKey& other) const {
return mPixelRefStableID == other.mPixelRefStableID &&
mPixelRefOrigin == other.mPixelRefOrigin &&
mBitmapDimensions == other.mBitmapDimensions;
}
bool BitmapKey::operator<(const BitmapKey& other) const {
if (mPixelRefStableID != other.mPixelRefStableID) {
return mPixelRefStableID < other.mPixelRefStableID;
}
if (mPixelRefOrigin.x() != other.mPixelRefOrigin.x()) {
return mPixelRefOrigin.x() < other.mPixelRefOrigin.x();
}
if (mPixelRefOrigin.y() != other.mPixelRefOrigin.y()) {
return mPixelRefOrigin.y() < other.mPixelRefOrigin.y();
}
if (mBitmapDimensions.width() != other.mBitmapDimensions.width()) {
return mBitmapDimensions.width() < other.mBitmapDimensions.width();
}
return mBitmapDimensions.height() < other.mBitmapDimensions.height();
}
}; // namespace uirenderer
}; // namespace android

View File

@@ -21,6 +21,7 @@
#include <SkBitmap.h>
#include <SkPath.h>
#include <SkPixelRef.h>
#include <utils/KeyedVector.h>
#include <utils/Singleton.h>
@@ -36,7 +37,6 @@ class Layer;
* Type of Resource being cached
*/
enum ResourceType {
kBitmap,
kNinePatch,
kPath
};
@@ -45,15 +45,45 @@ class ResourceReference {
public:
ResourceReference(ResourceType type) {
refCount = 0; recycled = false; destroyed = false; resourceType = type;
refCount = 0; destroyed = false; resourceType = type;
}
int refCount;
bool recycled;
bool destroyed;
ResourceType resourceType;
};
class BitmapKey {
public:
BitmapKey(const SkBitmap* bitmap)
: mRefCount(1)
, mBitmapDimensions(bitmap->dimensions())
, mPixelRefOrigin(bitmap->pixelRefOrigin())
, mPixelRefStableID(bitmap->pixelRef()->getStableID()) { }
void operator=(const BitmapKey& other);
bool operator==(const BitmapKey& other) const;
bool operator<(const BitmapKey& other) const;
private:
// This constructor is only used by the KeyedVector implementation
BitmapKey()
: mRefCount(-1)
, mBitmapDimensions(SkISize::Make(0,0))
, mPixelRefOrigin(SkIPoint::Make(0,0))
, mPixelRefStableID(0) { }
// reference count of all HWUI object using this bitmap
mutable int mRefCount;
SkISize mBitmapDimensions;
SkIPoint mPixelRefOrigin;
uint32_t mPixelRefStableID;
friend class ResourceCache;
friend class android::key_value_pair_t<BitmapKey, SkBitmap*>;
};
class ANDROID_API ResourceCache: public Singleton<ResourceCache> {
ResourceCache();
~ResourceCache();
@@ -69,13 +99,14 @@ public:
void lock();
void unlock();
void incrementRefcount(const SkPath* resource);
void incrementRefcount(const SkBitmap* resource);
void incrementRefcount(const Res_png_9patch* resource);
/**
* The cache stores a copy of the provided resource or refs an existing resource
* if the bitmap has previously been inserted and returns the cached copy.
*/
const SkBitmap* insert(const SkBitmap* resource);
void incrementRefcountLocked(const SkPath* resource);
void incrementRefcountLocked(const SkBitmap* resource);
void incrementRefcountLocked(const Res_png_9patch* resource);
void incrementRefcount(const SkPath* resource);
void incrementRefcount(const Res_png_9patch* resource);
void decrementRefcount(const SkBitmap* resource);
void decrementRefcount(const SkPath* resource);
@@ -86,16 +117,11 @@ public:
void decrementRefcountLocked(const Res_png_9patch* resource);
void destructor(SkPath* resource);
void destructor(const SkBitmap* resource);
void destructor(Res_png_9patch* resource);
void destructorLocked(SkPath* resource);
void destructorLocked(const SkBitmap* resource);
void destructorLocked(Res_png_9patch* resource);
bool recycle(SkBitmap* resource);
bool recycleLocked(SkBitmap* resource);
private:
void deleteResourceReferenceLocked(const void* resource, ResourceReference* ref);
@@ -115,6 +141,7 @@ private:
mutable Mutex mLock;
KeyedVector<const void*, ResourceReference*>* mCache;
KeyedVector<BitmapKey, SkBitmap*> mBitmapCache;
};
}; // namespace uirenderer

View File

@@ -233,11 +233,9 @@ Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
return texture;
}
void TextureCache::releaseTexture(const SkBitmap* bitmap) {
if (!bitmap || !bitmap->pixelRef()) return;
void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
Mutex::Autolock _l(mLock);
mGarbage.push(bitmap->pixelRef()->getStableID());
mGarbage.push(pixelRefStableID);
}
void TextureCache::clearGarbage() {

View File

@@ -88,10 +88,10 @@ public:
Texture* getTransient(const SkBitmap* bitmap);
/**
* Removes the texture associated with the specified bitmap. This is meant
* Removes the texture associated with the specified pixelRef. This is meant
* to be called from threads that are not the EGL context thread.
*/
void releaseTexture(const SkBitmap* bitmap);
ANDROID_API void releaseTexture(uint32_t pixelRefStableID);
/**
* Process deferred removals.
*/