diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 9ed15881355b6..6e3fbf7ccbbef 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -548,7 +548,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, GraphicsJNI::defaultColorSpace())); - PixelRef* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL); + sk_sp nativeBitmap = PixelRef::allocateHeapPixelRef(&bitmap, NULL); if (!nativeBitmap) { return NULL; } @@ -558,8 +558,7 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, 0, 0, width, height, bitmap); } - return createBitmap(env, nativeBitmap, - getPremulBitmapCreateFlags(isMutable)); + return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable)); } static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle, @@ -832,7 +831,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } // Map the bitmap in place from the ashmem region if possible otherwise copy. - PixelRef* nativeBitmap; + sk_sp nativeBitmap; if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { #if DEBUG_PARCEL ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " @@ -853,8 +852,8 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } // Map the pixels in place and take ownership of the ashmem region. - nativeBitmap = GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), - ctable, dupFd, const_cast(blob.data()), size, !isMutable); + nativeBitmap = sk_sp(GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(), + ctable, dupFd, const_cast(blob.data()), size, !isMutable)); SkSafeUnref(ctable); if (!nativeBitmap) { close(dupFd); @@ -880,7 +879,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { #endif // Copy the pixels into a new buffer. - nativeBitmap = GraphicsJNI::allocateHeapPixelRef(bitmap.get(), ctable); + nativeBitmap = PixelRef::allocateHeapPixelRef(bitmap.get(), ctable); SkSafeUnref(ctable); if (!nativeBitmap) { blob.release(); @@ -895,7 +894,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { blob.release(); } - return createBitmap(env, nativeBitmap, + return createBitmap(env, nativeBitmap.release(), getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); } diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 82b70fc683dc0..a866bae84bdd1 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -399,160 +399,8 @@ jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region) return obj; } -static JNIEnv* vm2env(JavaVM* vm) -{ - JNIEnv* env = NULL; - if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env) - { - SkDebugf("------- [%p] vm->GetEnv() failed\n", vm); - sk_throw(); - } - return env; -} - /////////////////////////////////////////////////////////////////////////////// -static bool computeAllocationSize(const SkBitmap& bitmap, size_t* size) { - int32_t rowBytes32 = SkToS32(bitmap.rowBytes()); - int64_t bigSize = (int64_t)bitmap.height() * rowBytes32; - if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) { - return false; // allocation will be too large - } - - *size = sk_64_asS32(bigSize); - return true; -} - -android::PixelRef* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { - const SkImageInfo& info = bitmap->info(); - if (info.colorType() == kUnknown_SkColorType) { - LOG_ALWAYS_FATAL("unknown bitmap configuration"); - return nullptr; - } - - size_t size; - if (!computeAllocationSize(*bitmap, &size)) { - return nullptr; - } - - // we must respect the rowBytes value already set on the bitmap instead of - // attempting to compute our own. - const size_t rowBytes = bitmap->rowBytes(); - - void* addr = calloc(size, 1); - if (!addr) { - return nullptr; - } - - auto wrapper = new android::PixelRef(addr, size, info, rowBytes, ctable); - wrapper->getSkBitmap(bitmap); - // since we're already allocated, we lockPixels right away - // HeapAllocator behaves this way too - bitmap->lockPixels(); - - return wrapper; -} - -struct AndroidPixelRefContext { - int32_t stableID; -}; - -static void allocatePixelsReleaseProc(void* ptr, void* ctx) { - AndroidPixelRefContext* context = (AndroidPixelRefContext*)ctx; - if (android::uirenderer::Caches::hasInstance()) { - android::uirenderer::Caches::getInstance().textureCache.releaseTexture(context->stableID); - } - - sk_free(ptr); - delete context; -} - -bool GraphicsJNI::allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) { - const SkImageInfo& info = bitmap->info(); - if (info.colorType() == kUnknown_SkColorType) { - doThrowIAE(env, "unknown bitmap configuration"); - return NULL; - } - - size_t size; - if (!computeAllocationSize(*bitmap, &size)) { - return false; - } - - // we must respect the rowBytes value already set on the bitmap instead of - // attempting to compute our own. - const size_t rowBytes = bitmap->rowBytes(); - - void* addr = sk_malloc_flags(size, 0); - if (NULL == addr) { - return false; - } - - AndroidPixelRefContext* context = new AndroidPixelRefContext; - SkMallocPixelRef* pr = SkMallocPixelRef::NewWithProc(info, rowBytes, ctable, addr, - &allocatePixelsReleaseProc, context); - if (!pr) { - delete context; - return false; - } - - // set the stableID in the context so that it can be used later in - // allocatePixelsReleaseProc to remove the texture from the cache. - context->stableID = pr->getStableID(); - - bitmap->setPixelRef(pr)->unref(); - // since we're already allocated, we can lockPixels right away - bitmap->lockPixels(); - - return true; -} - -android::PixelRef* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, - SkColorTable* ctable) { - int fd; - - const SkImageInfo& info = bitmap->info(); - if (info.colorType() == kUnknown_SkColorType) { - doThrowIAE(env, "unknown bitmap configuration"); - return nullptr; - } - - size_t size; - if (!computeAllocationSize(*bitmap, &size)) { - return nullptr; - } - - // we must respect the rowBytes value already set on the bitmap instead of - // attempting to compute our own. - const size_t rowBytes = bitmap->rowBytes(); - - // Create new ashmem region with read/write priv - fd = ashmem_create_region("bitmap", size); - if (fd < 0) { - return nullptr; - } - - void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (addr == MAP_FAILED) { - close(fd); - return nullptr; - } - - if (ashmem_set_prot_region(fd, PROT_READ) < 0) { - munmap(addr, size); - close(fd); - return nullptr; - } - - auto wrapper = new android::PixelRef(addr, fd, size, info, rowBytes, ctable); - wrapper->getSkBitmap(bitmap); - // since we're already allocated, we lockPixels right away - // HeapAllocator behaves this way too - bitmap->lockPixels(); - - return wrapper; -} - android::PixelRef* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly) { const SkImageInfo& info = bitmap->info(); @@ -597,7 +445,7 @@ sk_sp GraphicsJNI::defaultColorSpace() { /////////////////////////////////////////////////////////////////////////////// bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { - mStorage.reset(GraphicsJNI::allocateHeapPixelRef(bitmap, ctable)); + mStorage = android::PixelRef::allocateHeapPixelRef(bitmap, ctable); return !!mStorage; } @@ -702,8 +550,7 @@ AshmemPixelAllocator::AshmemPixelAllocator(JNIEnv *env) { } bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { - JNIEnv* env = vm2env(mJavaVM); - mStorage.reset(GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable)); + mStorage = android::PixelRef::allocateAshmemPixelRef(bitmap, ctable); return !!mStorage; } diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index e5af52512abcc..1c11998028c39 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -72,11 +72,6 @@ public: static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap); - static android::PixelRef* allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable); - - static android::PixelRef* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, - SkColorTable* ctable); - static android::PixelRef* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly); diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp index 43f7ca5c12371..d7ab111720936 100644 --- a/core/jni/android_graphics_Canvas.cpp +++ b/core/jni/android_graphics_Canvas.cpp @@ -446,7 +446,8 @@ static void drawBitmapArray(JNIEnv* env, jobject, jlong canvasHandle, GraphicsJNI::defaultColorSpace()); SkBitmap bitmap; bitmap.setInfo(info); - if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) { + sk_sp pixelRef = PixelRef::allocateHeapPixelRef(&bitmap, NULL); + if (!pixelRef) { return; } diff --git a/libs/hwui/hwui/PixelRef.cpp b/libs/hwui/hwui/PixelRef.cpp index 795de6be1d6f2..949ee65ad6846 100644 --- a/libs/hwui/hwui/PixelRef.cpp +++ b/libs/hwui/hwui/PixelRef.cpp @@ -23,6 +23,84 @@ namespace android { +static bool computeAllocationSize(const SkBitmap& bitmap, size_t* size) { + int32_t rowBytes32 = SkToS32(bitmap.rowBytes()); + int64_t bigSize = (int64_t)bitmap.height() * rowBytes32; + if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) { + return false; // allocation will be too large + } + + *size = sk_64_asS32(bigSize); + return true; +} + +typedef sk_sp (*AllocPixeRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes, + SkColorTable* ctable); + +static sk_sp allocatePixelRef(SkBitmap* bitmap, SkColorTable* ctable, AllocPixeRef alloc) { + const SkImageInfo& info = bitmap->info(); + if (info.colorType() == kUnknown_SkColorType) { + LOG_ALWAYS_FATAL("unknown bitmap configuration"); + return nullptr; + } + + size_t size; + if (!computeAllocationSize(*bitmap, &size)) { + return nullptr; + } + + // we must respect the rowBytes value already set on the bitmap instead of + // attempting to compute our own. + const size_t rowBytes = bitmap->rowBytes(); + auto wrapper = alloc(size, info, rowBytes, ctable); + if (wrapper) { + wrapper->getSkBitmap(bitmap); + // since we're already allocated, we lockPixels right away + // HeapAllocator behaves this way too + bitmap->lockPixels(); + } + return wrapper; +} + +sk_sp PixelRef::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { + return allocatePixelRef(bitmap, ctable, &PixelRef::allocateHeapPixelRef); +} + +sk_sp PixelRef::allocateAshmemPixelRef(SkBitmap* bitmap, SkColorTable* ctable) { + return allocatePixelRef(bitmap, ctable, &PixelRef::allocateAshmemPixelRef); +} + +sk_sp PixelRef::allocateHeapPixelRef(size_t size, const SkImageInfo& info, size_t rowBytes, + SkColorTable* ctable) { + void* addr = calloc(size, 1); + if (!addr) { + return nullptr; + } + return sk_sp(new PixelRef(addr, size, info, rowBytes, ctable)); +} + +sk_sp PixelRef::allocateAshmemPixelRef(size_t size, const SkImageInfo& info, + size_t rowBytes, SkColorTable* ctable) { + // Create new ashmem region with read/write priv + int fd = ashmem_create_region("bitmap", size); + if (fd < 0) { + return nullptr; + } + + void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + close(fd); + return nullptr; + } + + if (ashmem_set_prot_region(fd, PROT_READ) < 0) { + munmap(addr, size); + close(fd); + return nullptr; + } + return sk_sp(new PixelRef(addr, fd, size, info, rowBytes, ctable)); +} + void PixelRef::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) { if (kIndex_8_SkColorType != newInfo.colorType()) { ctable = nullptr; diff --git a/libs/hwui/hwui/PixelRef.h b/libs/hwui/hwui/PixelRef.h index 3f8aea6ebf4af..0baf4b86eed0a 100644 --- a/libs/hwui/hwui/PixelRef.h +++ b/libs/hwui/hwui/PixelRef.h @@ -33,6 +33,14 @@ typedef void (*FreeFunc)(void* addr, void* context); class ANDROID_API PixelRef : public SkPixelRef { public: + static sk_sp allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable); + static sk_sp allocateHeapPixelRef(size_t allocSize, const SkImageInfo& info, + size_t rowBytes, SkColorTable* ctable); + + static sk_sp allocateAshmemPixelRef(SkBitmap* bitmap, SkColorTable* ctable); + static sk_sp allocateAshmemPixelRef(size_t allocSize, const SkImageInfo& info, + size_t rowBytes, SkColorTable* ctable); + PixelRef(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable); PixelRef(void* address, void* context, FreeFunc freeFunc, diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 51c0a05fb6d74..168c23d51f697 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -128,7 +129,7 @@ public: SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType, colorSpace); bitmap.setInfo(info); - bitmap.allocPixels(info); + PixelRef::allocateHeapPixelRef(&bitmap, nullptr); return bitmap; } diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp index 5cab04d26c2a7..8e595ab2393a4 100644 --- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp +++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp @@ -25,12 +25,20 @@ using namespace android; using namespace android::uirenderer; +SkBitmap createSkBitmap(int width, int height) { + SkBitmap bitmap; + SkImageInfo info = SkImageInfo::Make(width, height, kN32_SkColorType, kPremul_SkAlphaType); + bitmap.setInfo(info); + bitmap.allocPixels(info); + return bitmap; +} + /** * 1x1 bitmaps must not be optimized into solid color shaders, since HWUI can't * compose/render color shaders */ TEST(SkiaBehavior, CreateBitmapShader1x1) { - SkBitmap origBitmap = TestUtils::createSkBitmap(1, 1); + SkBitmap origBitmap = createSkBitmap(1, 1); sk_sp s = SkMakeBitmapShader( origBitmap, SkShader::kClamp_TileMode, @@ -49,7 +57,7 @@ TEST(SkiaBehavior, CreateBitmapShader1x1) { } TEST(SkiaBehavior, genIds) { - SkBitmap bitmap = TestUtils::createSkBitmap(100, 100); + SkBitmap bitmap = createSkBitmap(100, 100); uint32_t genId = bitmap.getGenerationID(); bitmap.notifyPixelsChanged(); EXPECT_NE(genId, bitmap.getGenerationID());