Merge change 7696 into donut

* changes:
  add hidden Options field for native allocations
This commit is contained in:
Android (Google) Code Review
2009-07-17 11:04:06 -07:00
5 changed files with 60 additions and 31 deletions

View File

@ -224,7 +224,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
SkBitmap bitmap;
bitmap.setConfig(config, width, height);
if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL)) {
if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true)) {
return NULL;
}
@ -240,7 +240,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
static jobject Bitmap_copy(JNIEnv* env, jobject, const SkBitmap* src,
SkBitmap::Config dstConfig, jboolean isMutable) {
SkBitmap result;
JavaPixelAllocator allocator(env);
JavaPixelAllocator allocator(env, true);
if (!src->copyTo(&result, dstConfig, &allocator)) {
return NULL;
@ -356,7 +356,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
}
}
if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable)) {
if (!GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, true)) {
ctable->safeUnref();
delete bitmap;
return NULL;

View File

@ -23,6 +23,7 @@ static jfieldID gOptions_configFieldID;
static jfieldID gOptions_ditherFieldID;
static jfieldID gOptions_purgeableFieldID;
static jfieldID gOptions_shareableFieldID;
static jfieldID gOptions_nativeAllocFieldID;
static jfieldID gOptions_widthFieldID;
static jfieldID gOptions_heightFieldID;
static jfieldID gOptions_mimeFieldID;
@ -300,6 +301,11 @@ static bool optionsShareable(JNIEnv* env, jobject options) {
env->GetBooleanField(options, gOptions_shareableFieldID);
}
static bool optionsReportSizeToVM(JNIEnv* env, jobject options) {
return NULL == options ||
!env->GetBooleanField(options, gOptions_nativeAllocFieldID);
}
static jobject nullObjectReturn(const char msg[]) {
if (msg) {
SkDebugf("--- %s\n", msg);
@ -330,6 +336,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
bool doDither = true;
bool isPurgeable = allowPurgeable && optionsPurgeable(env, options);
bool reportSizeToVM = optionsReportSizeToVM(env, options);
if (NULL != options) {
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
@ -355,7 +362,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
decoder->setDitherImage(doDither);
NinePatchPeeker peeker;
JavaPixelAllocator javaAllocator(env);
JavaPixelAllocator javaAllocator(env, reportSizeToVM);
SkBitmap* bitmap = new SkBitmap;
Res_png_9patch dummy9Patch;
@ -699,6 +706,7 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) {
gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z");
gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");

View File

@ -5,6 +5,7 @@
#include "SkRegion.h"
#include <android_runtime/AndroidRuntime.h>
//#define REPORT_SIZE_TO_JVM
//#define TRACK_LOCK_COUNT
void doThrow(JNIEnv* env, const char* exc, const char* msg) {
@ -444,7 +445,7 @@ private:
};
bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
SkColorTable* ctable) {
SkColorTable* ctable, bool reportSizeToVM) {
Sk64 size64 = bitmap->getSize64();
if (size64.isNeg() || !size64.is32()) {
doThrow(env, "java/lang/IllegalArgumentException",
@ -453,35 +454,41 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
}
size_t size = size64.get32();
// SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
jlong jsize = size; // the VM wants longs for the size
bool r = env->CallBooleanMethod(gVMRuntime_singleton,
gVMRuntime_trackExternalAllocationMethodID,
jsize);
if (GraphicsJNI::hasException(env)) {
return false;
if (reportSizeToVM) {
// SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
bool r = env->CallBooleanMethod(gVMRuntime_singleton,
gVMRuntime_trackExternalAllocationMethodID,
jsize);
if (GraphicsJNI::hasException(env)) {
return false;
}
if (!r) {
LOGE("VM won't let us allocate %zd bytes\n", size);
doThrowOOME(env, "bitmap size exceeds VM budget");
return false;
}
}
if (!r) {
LOGE("VM won't let us allocate %zd bytes\n", size);
doThrowOOME(env, "bitmap size exceeds VM budget");
return false;
}
// call the version of malloc that returns null on failure
void* addr = sk_malloc_flags(size, 0);
if (NULL == addr) {
// 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");
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;
}
bitmap->setPixelRef(new AndroidPixelRef(env, addr, size, ctable))->unref();
SkPixelRef* pr = reportSizeToVM ?
new AndroidPixelRef(env, addr, size, ctable) :
new SkMallocPixelRef(addr, size, ctable);
bitmap->setPixelRef(pr)->unref();
// since we're already allocated, we lockPixels right away
// HeapAllocator behaves this way too
bitmap->lockPixels();
@ -490,12 +497,11 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
///////////////////////////////////////////////////////////////////////////////
JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) : fEnv(env)
{
}
JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM)
: fEnv(env), fReportSizeToVM(reportSizeToVM) {}
bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable);
return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -59,7 +59,8 @@ public:
Returns true on success. If it returns false, then it failed, and the
appropriate exception will have been raised.
*/
static bool setJavaPixelRef(JNIEnv*, SkBitmap*, SkColorTable* ctable);
static bool setJavaPixelRef(JNIEnv*, SkBitmap*, SkColorTable* ctable,
bool reportSizeToVM);
/** Copy the colors in colors[] to the bitmap, convert to the correct
format along the way.
@ -71,12 +72,13 @@ public:
class JavaPixelAllocator : public SkBitmap::Allocator {
public:
JavaPixelAllocator(JNIEnv* env);
JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM);
// overrides
virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
private:
JNIEnv* fEnv;
bool fReportSizeToVM;
};
class AutoJavaFloatArray {

View File

@ -128,6 +128,19 @@ public class BitmapFactory {
*/
public boolean inInputShareable;
/**
* Normally bitmap allocations count against the dalvik heap, which
* means they help trigger GCs when a lot have been allocated. However,
* in rare cases, the caller may want to allocate the bitmap outside of
* that heap. To request that, set inNativeAlloc to true. In these
* rare instances, it is solely up to the caller to ensure that OOM is
* managed explicitly by calling bitmap.recycle() as soon as such a
* bitmap is no longer needed.
*
* @hide pending API council approval
*/
public boolean inNativeAlloc;
/**
* The resulting width of the bitmap, set independent of the state of
* inJustDecodeBounds. However, if there is an error trying to decode,