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

Commit 982b71bf authored by Patrick Dubroy's avatar Patrick Dubroy Committed by Android (Google) Code Review
Browse files

Merge "Allocate bitmap backing buffers in the Java heap."

parents 52e08834 e4ac2d6b
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