Make bitmap backed by native memory instead of java byte array
Test: refactoring CL. Existing unit tests still pass.
bug:27762775
Change-Id: Ic4e914b3a941c3d545f8ce9e320e638973df0e91
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 18c4ee3..6acb76d 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -127,12 +127,10 @@
}
};
-Bitmap::Bitmap(JNIEnv* env, jbyteArray storageObj, void* address,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
- : mPixelStorageType(PixelStorageType::Java) {
- env->GetJavaVM(&mPixelStorage.java.jvm);
- mPixelStorage.java.jweakRef = env->NewWeakGlobalRef(storageObj);
- mPixelStorage.java.jstrongRef = nullptr;
+Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+ : mPixelStorageType(PixelStorageType::Heap) {
+ mPixelStorage.heap.address = address;
+ mPixelStorage.heap.size = size;
mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
// Note: this will trigger a call to onStrongRefDestroyed(), but
// we want the pixel ref to have a ref count of 0 at this point
@@ -187,12 +185,8 @@
munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
close(mPixelStorage.ashmem.fd);
break;
- case PixelStorageType::Java:
- JNIEnv* env = jniEnv();
- LOG_ALWAYS_FATAL_IF(mPixelStorage.java.jstrongRef,
- "Deleting a bitmap wrapper while there are outstanding strong "
- "references! mPinnedRefCount = %d", mPinnedRefCount);
- env->DeleteWeakGlobalRef(mPixelStorage.java.jweakRef);
+ case PixelStorageType::Heap:
+ free(mPixelStorage.heap.address);
break;
}
@@ -219,6 +213,15 @@
}
}
+size_t Bitmap::getAllocationByteCount() const {
+ switch (mPixelStorageType) {
+ case PixelStorageType::Heap:
+ return mPixelStorage.heap.size;
+ default:
+ return rowBytes() * height();
+ }
+}
+
const SkImageInfo& Bitmap::info() const {
return mPixelRef->info();
}
@@ -244,7 +247,6 @@
// We just restored this from 0, pin the pixels and inc the strong count
// Note that there *might be* an incoming onStrongRefDestroyed from whatever
// last unref'd
- pinPixelsLocked();
mPinnedRefCount++;
}
return mPixelRef.get();
@@ -283,13 +285,6 @@
return mPinnedRefCount == 0 && !mAttachedToJava;
}
-JNIEnv* Bitmap::jniEnv() {
- JNIEnv* env;
- auto success = mPixelStorage.java.jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
- LOG_ALWAYS_FATAL_IF(success != JNI_OK,
- "Failed to get JNIEnv* from JVM: %p", mPixelStorage.java.jvm);
- return env;
-}
void Bitmap::onStrongRefDestroyed() {
bool disposeSelf = false;
@@ -298,7 +293,6 @@
if (mPinnedRefCount > 0) {
mPinnedRefCount--;
if (mPinnedRefCount == 0) {
- unpinPixelsLocked();
disposeSelf = shouldDisposeSelfLocked();
}
}
@@ -308,49 +302,6 @@
}
}
-void Bitmap::pinPixelsLocked() {
- switch (mPixelStorageType) {
- case PixelStorageType::Invalid:
- LOG_ALWAYS_FATAL("Cannot pin invalid pixels!");
- break;
- case PixelStorageType::External:
- case PixelStorageType::Ashmem:
- // Nothing to do
- break;
- case PixelStorageType::Java: {
- JNIEnv* env = jniEnv();
- if (!mPixelStorage.java.jstrongRef) {
- mPixelStorage.java.jstrongRef = reinterpret_cast<jbyteArray>(
- env->NewGlobalRef(mPixelStorage.java.jweakRef));
- if (!mPixelStorage.java.jstrongRef) {
- LOG_ALWAYS_FATAL("Failed to acquire strong reference to pixels");
- }
- }
- break;
- }
- }
-}
-
-void Bitmap::unpinPixelsLocked() {
- switch (mPixelStorageType) {
- case PixelStorageType::Invalid:
- LOG_ALWAYS_FATAL("Cannot unpin invalid pixels!");
- break;
- case PixelStorageType::External:
- case PixelStorageType::Ashmem:
- // Don't need to do anything
- break;
- case PixelStorageType::Java: {
- JNIEnv* env = jniEnv();
- if (mPixelStorage.java.jstrongRef) {
- env->DeleteGlobalRef(mPixelStorage.java.jstrongRef);
- mPixelStorage.java.jstrongRef = nullptr;
- }
- break;
- }
- }
-}
-
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
assertValid();
android::AutoMutex _lock(mLock);
@@ -723,7 +674,7 @@
SkBitmap bitmap;
bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
- Bitmap* nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
+ Bitmap* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
if (!nativeBitmap) {
return NULL;
}
@@ -742,8 +693,8 @@
SkBitmap src;
reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
- SkBitmap result;
- JavaPixelAllocator allocator(env);
+ SkBitmap result;
+ HeapAllocator allocator;
if (!src.copyTo(&result, dstCT, &allocator)) {
return NULL;
@@ -798,8 +749,7 @@
}
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint width, jint height, jint configHandle, jint allocSize,
- jboolean requestPremul) {
+ jint width, jint height, jint configHandle, jboolean requestPremul) {
LocalScopedBitmap bitmap(bitmapHandle);
SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
@@ -807,8 +757,8 @@
if (colorType == kARGB_4444_SkColorType) {
colorType = kN32_SkColorType;
}
-
- if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
+ size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
+ if (requestedSize > bitmap->getAllocationByteCount()) {
// done in native as there's no way to get BytesPerPixel in Java
doThrowIAE(env, "Bitmap not large enough to support new configuration");
return;
@@ -1053,7 +1003,7 @@
#endif
// Copy the pixels into a new buffer.
- nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable);
+ nativeBitmap = GraphicsJNI::allocateHeapPixelRef(bitmap.get(), ctable);
SkSafeUnref(ctable);
if (!nativeBitmap) {
blob.release();
@@ -1165,7 +1115,7 @@
const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
SkIPoint offset;
SkBitmap dst;
- JavaPixelAllocator allocator(env);
+ HeapAllocator allocator;
src.extractAlpha(&dst, paint, &allocator, &offset);
// If Skia can't allocate pixels for destination bitmap, it resets
@@ -1370,6 +1320,11 @@
android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
}
+static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
+ LocalScopedBitmap bitmapHandle(bitmapPtr);
+ return static_cast<jint>(bitmapHandle->getAllocationByteCount());
+}
+
///////////////////////////////////////////////////////////////////////////////
static const JNINativeMethod gBitmapMethods[] = {
@@ -1383,7 +1338,7 @@
(void*)Bitmap_copyAshmemConfig },
{ "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
{ "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
- { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure },
+ { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
{ "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(JI)V", (void*)Bitmap_erase },
@@ -1414,6 +1369,7 @@
{ "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
{ "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef },
{ "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
+ { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
};
int register_android_graphics_Bitmap(JNIEnv* env)