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

Commit e4ac2d6b authored by Patrick Dubroy's avatar Patrick Dubroy
Browse files

Allocate bitmap backing buffers in the Java heap.

Change-Id: I60f6ccff13357c1c518e9d56b02fe0171637edd1
parent 89f8d63a
Loading
Loading
Loading
Loading
+15 −13
Original line number Original line Diff line number Diff line
@@ -459,35 +459,37 @@ class GLES20Canvas extends HardwareCanvas {
        // Shaders are ignored when drawing patches
        // Shaders are ignored when drawing patches
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top,
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
                dst.right, dst.bottom, nativePaint);
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
        if (hasColorFilter) nResetModifiers(mRenderer);
        if (hasColorFilter) nResetModifiers(mRenderer);
    }
    }


    private native void nDrawPatch(int renderer, int bitmap, byte[] chunks, float left, float top,
    private native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
            float right, float bottom, int paint);
            float left, float top, float right, float bottom, int paint);


    @Override
    @Override
    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
        // Shaders are ignored when drawing bitmaps
        // Shaders are ignored when drawing bitmaps
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
        if (hasColorFilter) nResetModifiers(mRenderer);
        if (hasColorFilter) nResetModifiers(mRenderer);
    }
    }


    private native void nDrawBitmap(int renderer, int bitmap, float left, float top, int paint);
    private native void nDrawBitmap(
            int renderer, int bitmap, byte[] buffer, float left, float top, int paint);


    @Override
    @Override
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
        // Shaders are ignored when drawing bitmaps
        // Shaders are ignored when drawing bitmaps
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
                matrix.native_instance, nativePaint);
        if (hasColorFilter) nResetModifiers(mRenderer);
        if (hasColorFilter) nResetModifiers(mRenderer);
    }
    }


    private native void nDrawBitmap(int renderer, int bitmap, int matrix, int paint);
    private native void nDrawBitmap(int renderer, int bitmap, byte[] buff, int matrix, int paint);


    @Override
    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
@@ -507,7 +509,7 @@ class GLES20Canvas extends HardwareCanvas {
            bottom = src.bottom;
            bottom = src.bottom;
        }
        }


        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, right, bottom,
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
        if (hasColorFilter) nResetModifiers(mRenderer);
        if (hasColorFilter) nResetModifiers(mRenderer);
    }
    }
@@ -517,12 +519,12 @@ class GLES20Canvas extends HardwareCanvas {
        // Shaders are ignored when drawing bitmaps
        // Shaders are ignored when drawing bitmaps
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        boolean hasColorFilter = paint != null && setupColorFilter(paint);
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, src.left, src.top, src.right,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
                src.bottom, dst.left, dst.top, dst.right, dst.bottom, nativePaint);
        if (hasColorFilter) nResetModifiers(mRenderer);
        if (hasColorFilter) nResetModifiers(mRenderer);
    }
    }


    private native void nDrawBitmap(int renderer, int bitmap,
    private native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
            float srcLeft, float srcTop, float srcRight, float srcBottom,
            float srcLeft, float srcTop, float srcRight, float srcBottom,
            float left, float top, float right, float bottom, int paint);
            float left, float top, float right, float bottom, int paint);


@@ -534,7 +536,7 @@ class GLES20Canvas extends HardwareCanvas {
        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, b.mNativeBitmap, x, y, nativePaint);
        nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
        b.recycle();
        b.recycle();
        if (hasColorFilter) nResetModifiers(mRenderer);
        if (hasColorFilter) nResetModifiers(mRenderer);
    }
    }
+13 −15
Original line number Original line Diff line number Diff line
#include "SkBitmap.h"
#include "SkBitmap.h"
#include "SkPixelRef.h"
#include "SkImageEncoder.h"
#include "SkImageEncoder.h"
#include "SkColorPriv.h"
#include "SkColorPriv.h"
#include "GraphicsJNI.h"
#include "GraphicsJNI.h"
@@ -210,11 +211,6 @@ static ToColorProc ChooseToColorProc(const SkBitmap& src) {
static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
                              int offset, int stride, int width, int height,
                              int offset, int stride, int width, int height,
                              SkBitmap::Config config, jboolean isMutable) {
                              SkBitmap::Config config, jboolean isMutable) {
    if (width <= 0 || height <= 0) {
        doThrowIAE(env, "width and height must be > 0");
        return NULL;
    }

    if (NULL != jColors) {
    if (NULL != jColors) {
        size_t n = env->GetArrayLength(jColors);
        size_t n = env->GetArrayLength(jColors);
        if (n < SkAbs32(stride) * (size_t)height) {
        if (n < SkAbs32(stride) * (size_t)height) {
@@ -226,7 +222,9 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
    SkBitmap bitmap;
    SkBitmap bitmap;


    bitmap.setConfig(config, width, height);
    bitmap.setConfig(config, width, height);
    if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true)) {

    jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
    if (NULL == buff) {
        return NULL;
        return NULL;
    }
    }


@@ -235,21 +233,19 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
                               0, 0, width, height, bitmap);
                               0, 0, width, height, bitmap);
    }
    }


    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), isMutable,
    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff, isMutable, NULL);
                                     NULL);
}
}


static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
                           SkBitmap::Config dstConfig, jboolean isMutable) {
                           SkBitmap::Config dstConfig, jboolean isMutable) {
    SkBitmap            result;
    SkBitmap            result;
    JavaPixelAllocator  allocator(env, true);
    JavaPixelAllocator  allocator(env);


    if (!src->copyTo(&result, dstConfig, &allocator)) {
    if (!src->copyTo(&result, dstConfig, &allocator)) {
        return NULL;
        return NULL;
    }
    }


    return GraphicsJNI::createBitmap(env, new SkBitmap(result), isMutable,
    return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(), isMutable, NULL);
                                     NULL);
}
}


static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {
@@ -380,7 +376,8 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
        }
        }
    }
    }


    if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, true)) {
    jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
    if (NULL == buffer) {
        ctable->safeUnref();
        ctable->safeUnref();
        delete bitmap;
        delete bitmap;
        return NULL;
        return NULL;
@@ -393,7 +390,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
    memcpy(bitmap->getPixels(), p->readInplace(size), size);
    memcpy(bitmap->getPixels(), p->readInplace(size), size);
    bitmap->unlockPixels();
    bitmap->unlockPixels();


    return GraphicsJNI::createBitmap(env, bitmap, isMutable, NULL, density);
    return GraphicsJNI::createBitmap(env, bitmap, buffer, isMutable, NULL, density);
}
}


static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
@@ -447,8 +444,9 @@ static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
                                   jintArray offsetXY) {
                                   jintArray offsetXY) {
    SkIPoint  offset;
    SkIPoint  offset;
    SkBitmap* dst = new SkBitmap;
    SkBitmap* dst = new SkBitmap;
    JavaPixelAllocator allocator(env);


    src->extractAlpha(dst, paint, &offset);
    src->extractAlpha(dst, paint, &allocator, &offset);
    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
        int* array = env->GetIntArrayElements(offsetXY, NULL);
        int* array = env->GetIntArrayElements(offsetXY, NULL);
        array[0] = offset.fX;
        array[0] = offset.fX;
@@ -456,7 +454,7 @@ static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
        env->ReleaseIntArrayElements(offsetXY, array, 0);
        env->ReleaseIntArrayElements(offsetXY, array, 0);
    }
    }


    return GraphicsJNI::createBitmap(env, dst, true, NULL);
    return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(), true, NULL);
}
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+2 −2
Original line number Original line Diff line number Diff line
@@ -291,7 +291,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
        env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
        env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
    }
    }


    // detach bitmap from its autotdeleter, since we want to own it now
    // detach bitmap from its autodeleter, since we want to own it now
    adb.detach();
    adb.detach();


    if (padding) {
    if (padding) {
@@ -322,7 +322,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
        return javaBitmap;
        return javaBitmap;
    }
    }
    // now create the java bitmap
    // now create the java bitmap
    return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk);
    return GraphicsJNI::createBitmap(env, bitmap, javaAllocator.getStorageObj(), false, ninePatchChunk);
}
}


static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
+6 −5
Original line number Original line Diff line number Diff line
@@ -79,7 +79,7 @@ static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream) {
        return nullObjectReturn("SkImageDecoder::Factory returned null");
        return nullObjectReturn("SkImageDecoder::Factory returned null");
    }
    }


    JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
    JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env);
    decoder->setAllocator(javaAllocator);
    decoder->setAllocator(javaAllocator);
    JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
    JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
    decoder->setReporter(javaMemoryReporter);
    decoder->setReporter(javaMemoryReporter);
@@ -241,15 +241,16 @@ static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *b
                            getMimeTypeString(env, decoder->getFormat()));
                            getMimeTypeString(env, decoder->getFormat()));
    }
    }


    // detach bitmap from its autotdeleter, since we want to own it now
    // detach bitmap from its autodeleter, since we want to own it now
    adb.detach();
    adb.detach();


    SkPixelRef* pr;
    SkPixelRef* pr = bitmap->pixelRef();
    pr = bitmap->pixelRef();
    // promise we will never change our pixels (great for sharing and pictures)
    // promise we will never change our pixels (great for sharing and pictures)
    pr->setImmutable();
    pr->setImmutable();

    // now create the java bitmap
    // now create the java bitmap
    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
    jbyteArray buff = ((AndroidPixelRef*) pr)->getStorageObj();
    return GraphicsJNI::createBitmap(env, bitmap, buff, false, NULL, -1);
}
}


static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+150 −74
Original line number Original line Diff line number Diff line
@@ -2,6 +2,9 @@


#include "jni.h"
#include "jni.h"
#include "GraphicsJNI.h"
#include "GraphicsJNI.h"

#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkPicture.h"
#include "SkPicture.h"
#include "SkRegion.h"
#include "SkRegion.h"
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/AndroidRuntime.h>
@@ -163,7 +166,6 @@ static jfieldID gPointF_yFieldID;
static jclass   gBitmap_class;
static jclass   gBitmap_class;
static jfieldID gBitmap_nativeInstanceID;
static jfieldID gBitmap_nativeInstanceID;
static jmethodID gBitmap_constructorMethodID;
static jmethodID gBitmap_constructorMethodID;
static jmethodID gBitmap_allocBufferMethodID;


static jclass   gBitmapConfig_class;
static jclass   gBitmapConfig_class;
static jfieldID gBitmapConfig_nativeInstanceID;
static jfieldID gBitmapConfig_nativeInstanceID;
@@ -360,16 +362,16 @@ SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)


///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////


jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buffer,
                                  jbyteArray ninepatch, int density)
                                  bool isMutable, jbyteArray ninepatch, int density)
{
{
    SkASSERT(bitmap != NULL);
    SkASSERT(bitmap);
    SkASSERT(NULL != bitmap->pixelRef());
    SkASSERT(bitmap->pixelRef());
    
    
    jobject obj = env->AllocObject(gBitmap_class);
    jobject obj = env->AllocObject(gBitmap_class);
    if (obj) {
    if (obj) {
        env->CallVoidMethod(obj, gBitmap_constructorMethodID,
        env->CallVoidMethod(obj, gBitmap_constructorMethodID,
                            (jint)bitmap, isMutable, ninepatch, density);
                            (jint)bitmap, buffer, isMutable, ninepatch, density);
        if (hasException(env)) {
        if (hasException(env)) {
            obj = NULL;
            obj = NULL;
        }
        }
@@ -377,6 +379,13 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
    return obj;
    return obj;
}
}


jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
                            jbyteArray ninepatch, int density)
{
    return createBitmap(env, bitmap, NULL, isMutable, ninepatch, density);
}


jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
{
{
    SkASSERT(bitmap != NULL);
    SkASSERT(bitmap != NULL);
@@ -408,8 +417,6 @@ jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
    return obj;
    return obj;
}
}


#include "SkPixelRef.h"

static JNIEnv* vm2env(JavaVM* vm)
static JNIEnv* vm2env(JavaVM* vm)
{
{
    JNIEnv* env = NULL;
    JNIEnv* env = NULL;
@@ -427,17 +434,7 @@ static JNIEnv* vm2env(JavaVM* vm)


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


#include "SkMallocPixelRef.h"
AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj,

/*  Extend SkMallocPixelRef to inform the VM when we free up the storage
*/
class AndroidPixelRef : public SkMallocPixelRef {
public:
    /** Allocate the specified buffer for pixels. The memory is freed when the
        last owner of this pixelref is gone. Our caller has already informed
        the VM of our allocation.
    */
    AndroidPixelRef(JNIEnv* env, void* storage, size_t size,
        SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) {
        SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) {
    SkASSERT(storage);
    SkASSERT(storage);
    SkASSERT(env);
    SkASSERT(env);
@@ -446,68 +443,116 @@ public:
        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
        sk_throw();
        sk_throw();
    }
    }
    fStorageObj = storageObj;
    fHasGlobalRef = false;
    fGlobalRefCnt = 0;

    // If storageObj is NULL, the memory was NOT allocated on the Java heap
    fOnJavaHeap = (storageObj != NULL);
    
}
}


    virtual ~AndroidPixelRef() {
AndroidPixelRef::~AndroidPixelRef() {
    if (fOnJavaHeap) {
        JNIEnv* env = vm2env(fVM);
        JNIEnv* env = vm2env(fVM);
//        SkDebugf("-------------- inform VM we're releasing %d bytes\n", this->getSize());

        jlong jsize = this->getSize();  // the VM wants longs for the size
        if (fStorageObj && fHasGlobalRef) {
        env->CallVoidMethod(gVMRuntime_singleton,
            env->DeleteGlobalRef(fStorageObj);
                            gVMRuntime_trackExternalFreeMethodID,
        }
                            jsize);
        fStorageObj = NULL;
        if (GraphicsJNI::hasException(env)) {

            env->ExceptionClear();
        // Set this to NULL to prevent the SkMallocPixelRef destructor
        // from freeing the memory.
        fStorage = NULL;
    }
    }
}
}


private:
void AndroidPixelRef::setLocalJNIRef(jbyteArray arr) {
    JavaVM* fVM;
    if (!fHasGlobalRef) {
};
        fStorageObj = arr;
    }
}


bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
void AndroidPixelRef::globalRef() {
                                  SkColorTable* ctable, bool reportSizeToVM) {
    if (fOnJavaHeap && sk_atomic_inc(&fGlobalRefCnt) == 0) {
        JNIEnv *env = vm2env(fVM);
        if (fStorageObj == NULL) {
            SkDebugf("Cannot create a global ref, fStorage obj is NULL");
            sk_throw();
        }
        if (fHasGlobalRef) {
            // This should never happen
            SkDebugf("Already holding a global ref");
            sk_throw();
        }

        fStorageObj = (jbyteArray) env->NewGlobalRef(fStorageObj);
        // TODO: Check for failure here
        fHasGlobalRef = true;
    }
    ref();
}

void AndroidPixelRef::globalUnref() {
    if (fOnJavaHeap && sk_atomic_dec(&fGlobalRefCnt) == 1) {
        JNIEnv *env = vm2env(fVM);
        if (!fHasGlobalRef) {
            SkDebugf("We don't have a global ref!");
            sk_throw();
        }
        env->DeleteGlobalRef(fStorageObj);
        fStorageObj = NULL;
        fHasGlobalRef = false;
    }
    unref();
}

///////////////////////////////////////////////////////////////////////////////

jbyteArray GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
                                             SkColorTable* ctable) {
    Sk64 size64 = bitmap->getSize64();
    Sk64 size64 = bitmap->getSize64();
    if (size64.isNeg() || !size64.is32()) {
    if (size64.isNeg() || !size64.is32()) {
        doThrow(env, "java/lang/IllegalArgumentException",
        doThrow(env, "java/lang/IllegalArgumentException",
                     "bitmap size exceeds 32bits");
                     "bitmap size exceeds 32bits");
        return false;
        return NULL;
    }
    }
    
    
    size_t size = size64.get32();
    size_t size = size64.get32();
    jlong jsize = size;  // the VM wants longs for the size
    jbyteArray arrayObj = env->NewByteArray(size);
    if (reportSizeToVM) {
    if (arrayObj) {
        //    SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
        jbyte *addr = env->GetByteArrayElements(arrayObj, NULL);
        bool r = env->CallBooleanMethod(gVMRuntime_singleton,
        env->ReleaseByteArrayElements(arrayObj, addr, 0);
                                    gVMRuntime_trackExternalAllocationMethodID,
        if (addr) {
                                    jsize);
            SkPixelRef* pr = new AndroidPixelRef(env, (void*) addr, size, arrayObj, ctable);
        if (GraphicsJNI::hasException(env)) {
            bitmap->setPixelRef(pr)->unref();
            return false;
            // since we're already allocated, we lockPixels right away
            // HeapAllocator behaves this way too
            bitmap->lockPixels();
        }
        }
        if (!r) {
            LOGE("VM won't let us allocate %zd bytes\n", size);
            doThrowOOME(env, "bitmap size exceeds VM budget");
            return false;
    }
    }

    return arrayObj;
}
}

bool GraphicsJNI::mallocPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) {
    Sk64 size64 = bitmap->getSize64();
    if (size64.isNeg() || !size64.is32()) {
        doThrow(env, "java/lang/IllegalArgumentException",
                     "bitmap size exceeds 32bits");
        return false;
    }

    size_t size = size64.get32();

    // call the version of malloc that returns null on failure
    // call the version of malloc that returns null on failure
    void* addr = sk_malloc_flags(size, 0);
    void* addr = sk_malloc_flags(size, 0);

    if (NULL == addr) {
    if (NULL == addr) {
        if (reportSizeToVM) {
            //        SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size);
            // we didn't actually allocate it, so inform the VM
            env->CallVoidMethod(gVMRuntime_singleton,
                                 gVMRuntime_trackExternalFreeMethodID,
                                 jsize);
            if (!GraphicsJNI::hasException(env)) {
                doThrowOOME(env, "bitmap size too large for malloc");
            }
        }
        return false;
        return false;
    }
    }


    SkPixelRef* pr = reportSizeToVM ?
    SkPixelRef* pr = new AndroidPixelRef(env, addr, size, NULL, ctable);
                        new AndroidPixelRef(env, addr, size, ctable) :
                        new SkMallocPixelRef(addr, size, ctable);
    bitmap->setPixelRef(pr)->unref();
    bitmap->setPixelRef(pr)->unref();
    // since we're already allocated, we lockPixels right away
    // since we're already allocated, we lockPixels right away
    // HeapAllocator behaves this way too
    // HeapAllocator behaves this way too
@@ -517,8 +562,9 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////


JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM)
JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool allocateInJavaHeap)
    : fReportSizeToVM(reportSizeToVM) {
    : fAllocateInJavaHeap(allocateInJavaHeap),
      fStorageObj(NULL) {
    if (env->GetJavaVM(&fVM) != JNI_OK) {
    if (env->GetJavaVM(&fVM) != JNI_OK) {
        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
        sk_throw();
        sk_throw();
@@ -527,7 +573,19 @@ JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM)
    
    
bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
    JNIEnv* env = vm2env(fVM);
    JNIEnv* env = vm2env(fVM);
    return GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, fReportSizeToVM);

    // If allocating in the Java heap, only allow a single object to be
    // allocated for the lifetime of this object.
    if (fStorageObj != NULL) {
        SkDebugf("ERROR: One-shot allocator has already allocated\n");
        sk_throw();
    }

    if (fAllocateInJavaHeap) {
        fStorageObj = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
        return fStorageObj != NULL;
    }
    return GraphicsJNI::mallocPixelRef(env, bitmap, ctable);
}
}


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
@@ -568,6 +626,25 @@ bool JavaMemoryUsageReporter::reportMemory(size_t memorySize) {


////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


JavaHeapBitmapRef::JavaHeapBitmapRef(JNIEnv* env, SkBitmap* nativeBitmap, jbyteArray buffer) {
    fEnv = env;
    fNativeBitmap = nativeBitmap;
    fBuffer = buffer;

    // If the buffer is NULL, the backing memory wasn't allocated on the Java heap
    if (fBuffer) {
        ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(fBuffer);
    }
}

JavaHeapBitmapRef::~JavaHeapBitmapRef() {
    if (fBuffer) {
        ((AndroidPixelRef*) fNativeBitmap->pixelRef())->setLocalJNIRef(NULL);
    }
}

////////////////////////////////////////////////////////////////////////////////

static jclass make_globalref(JNIEnv* env, const char classname[])
static jclass make_globalref(JNIEnv* env, const char classname[])
{
{
    jclass c = env->FindClass(classname);
    jclass c = env->FindClass(classname);
@@ -611,8 +688,7 @@ int register_android_graphics_Graphics(JNIEnv* env)
    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
    gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
    gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
                                            "(IZ[BI)V");
                                            "(I[BZ[BI)V");

    gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
    gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
    gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
    gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");


Loading