Merge change 7696 into donut
* changes: add hidden Options field for native allocations
This commit is contained in:
@ -224,7 +224,7 @@ 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)) {
|
if (!GraphicsJNI::setJavaPixelRef(env, &bitmap, NULL, true)) {
|
||||||
return NULL;
|
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,
|
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);
|
JavaPixelAllocator allocator(env, true);
|
||||||
|
|
||||||
if (!src->copyTo(&result, dstConfig, &allocator)) {
|
if (!src->copyTo(&result, dstConfig, &allocator)) {
|
||||||
return NULL;
|
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();
|
ctable->safeUnref();
|
||||||
delete bitmap;
|
delete bitmap;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -23,6 +23,7 @@ static jfieldID gOptions_configFieldID;
|
|||||||
static jfieldID gOptions_ditherFieldID;
|
static jfieldID gOptions_ditherFieldID;
|
||||||
static jfieldID gOptions_purgeableFieldID;
|
static jfieldID gOptions_purgeableFieldID;
|
||||||
static jfieldID gOptions_shareableFieldID;
|
static jfieldID gOptions_shareableFieldID;
|
||||||
|
static jfieldID gOptions_nativeAllocFieldID;
|
||||||
static jfieldID gOptions_widthFieldID;
|
static jfieldID gOptions_widthFieldID;
|
||||||
static jfieldID gOptions_heightFieldID;
|
static jfieldID gOptions_heightFieldID;
|
||||||
static jfieldID gOptions_mimeFieldID;
|
static jfieldID gOptions_mimeFieldID;
|
||||||
@ -300,6 +301,11 @@ static bool optionsShareable(JNIEnv* env, jobject options) {
|
|||||||
env->GetBooleanField(options, gOptions_shareableFieldID);
|
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[]) {
|
static jobject nullObjectReturn(const char msg[]) {
|
||||||
if (msg) {
|
if (msg) {
|
||||||
SkDebugf("--- %s\n", msg);
|
SkDebugf("--- %s\n", msg);
|
||||||
@ -330,6 +336,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
|
|||||||
SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
|
SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
|
||||||
bool doDither = true;
|
bool doDither = true;
|
||||||
bool isPurgeable = allowPurgeable && optionsPurgeable(env, options);
|
bool isPurgeable = allowPurgeable && optionsPurgeable(env, options);
|
||||||
|
bool reportSizeToVM = optionsReportSizeToVM(env, options);
|
||||||
|
|
||||||
if (NULL != options) {
|
if (NULL != options) {
|
||||||
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
|
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
|
||||||
@ -355,7 +362,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
|
|||||||
decoder->setDitherImage(doDither);
|
decoder->setDitherImage(doDither);
|
||||||
|
|
||||||
NinePatchPeeker peeker;
|
NinePatchPeeker peeker;
|
||||||
JavaPixelAllocator javaAllocator(env);
|
JavaPixelAllocator javaAllocator(env, reportSizeToVM);
|
||||||
SkBitmap* bitmap = new SkBitmap;
|
SkBitmap* bitmap = new SkBitmap;
|
||||||
Res_png_9patch dummy9Patch;
|
Res_png_9patch dummy9Patch;
|
||||||
|
|
||||||
@ -699,6 +706,7 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) {
|
|||||||
gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
|
gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
|
||||||
gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
|
gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
|
||||||
gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "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_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
|
||||||
gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
|
gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
|
||||||
gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
|
gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "SkRegion.h"
|
#include "SkRegion.h"
|
||||||
#include <android_runtime/AndroidRuntime.h>
|
#include <android_runtime/AndroidRuntime.h>
|
||||||
|
|
||||||
|
//#define REPORT_SIZE_TO_JVM
|
||||||
//#define TRACK_LOCK_COUNT
|
//#define TRACK_LOCK_COUNT
|
||||||
|
|
||||||
void doThrow(JNIEnv* env, const char* exc, const char* msg) {
|
void doThrow(JNIEnv* env, const char* exc, const char* msg) {
|
||||||
@ -444,7 +445,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
|
bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
|
||||||
SkColorTable* ctable) {
|
SkColorTable* ctable, bool reportSizeToVM) {
|
||||||
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",
|
||||||
@ -453,35 +454,41 @@ bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t size = size64.get32();
|
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
|
jlong jsize = size; // the VM wants longs for the size
|
||||||
bool r = env->CallBooleanMethod(gVMRuntime_singleton,
|
if (reportSizeToVM) {
|
||||||
gVMRuntime_trackExternalAllocationMethodID,
|
// SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
|
||||||
jsize);
|
bool r = env->CallBooleanMethod(gVMRuntime_singleton,
|
||||||
if (GraphicsJNI::hasException(env)) {
|
gVMRuntime_trackExternalAllocationMethodID,
|
||||||
return false;
|
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
|
// 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) {
|
||||||
// SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size);
|
if (reportSizeToVM) {
|
||||||
// we didn't actually allocate it, so inform the VM
|
// SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size);
|
||||||
env->CallVoidMethod(gVMRuntime_singleton,
|
// we didn't actually allocate it, so inform the VM
|
||||||
gVMRuntime_trackExternalFreeMethodID,
|
env->CallVoidMethod(gVMRuntime_singleton,
|
||||||
jsize);
|
gVMRuntime_trackExternalFreeMethodID,
|
||||||
if (!GraphicsJNI::hasException(env)) {
|
jsize);
|
||||||
doThrowOOME(env, "bitmap size too large for malloc");
|
if (!GraphicsJNI::hasException(env)) {
|
||||||
|
doThrowOOME(env, "bitmap size too large for malloc");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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
|
// since we're already allocated, we lockPixels right away
|
||||||
// HeapAllocator behaves this way too
|
// HeapAllocator behaves this way too
|
||||||
bitmap->lockPixels();
|
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) {
|
bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
|
||||||
return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable);
|
return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -59,7 +59,8 @@ public:
|
|||||||
Returns true on success. If it returns false, then it failed, and the
|
Returns true on success. If it returns false, then it failed, and the
|
||||||
appropriate exception will have been raised.
|
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
|
/** Copy the colors in colors[] to the bitmap, convert to the correct
|
||||||
format along the way.
|
format along the way.
|
||||||
@ -71,12 +72,13 @@ public:
|
|||||||
|
|
||||||
class JavaPixelAllocator : public SkBitmap::Allocator {
|
class JavaPixelAllocator : public SkBitmap::Allocator {
|
||||||
public:
|
public:
|
||||||
JavaPixelAllocator(JNIEnv* env);
|
JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM);
|
||||||
// overrides
|
// overrides
|
||||||
virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
|
virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JNIEnv* fEnv;
|
JNIEnv* fEnv;
|
||||||
|
bool fReportSizeToVM;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AutoJavaFloatArray {
|
class AutoJavaFloatArray {
|
||||||
|
@ -128,6 +128,19 @@ public class BitmapFactory {
|
|||||||
*/
|
*/
|
||||||
public boolean inInputShareable;
|
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
|
* The resulting width of the bitmap, set independent of the state of
|
||||||
* inJustDecodeBounds. However, if there is an error trying to decode,
|
* inJustDecodeBounds. However, if there is an error trying to decode,
|
||||||
|
Reference in New Issue
Block a user