Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d4eed7f authored by Derek Sollenberger's avatar Derek Sollenberger
Browse files

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
parent 83eb4443
Loading
Loading
Loading
Loading
+1 −12
Original line number Diff line number Diff line
@@ -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;
}
}

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;
}
+77 −3
Original line number Diff line number Diff line
@@ -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)
+8 −0
Original line number Diff line number Diff line
@@ -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.
+2 −1
Original line number Diff line number Diff line
@@ -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;
    }

+0 −7
Original line number Diff line number Diff line
@@ -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();
Loading