Move allocatePixelRef methods to hwui.

This patch also makes tests to use SkBitmap backed by hwui/PixelRef,
Test: refactoring cl.
bug:27762775

Change-Id: Ib936e81877790849118420f5e565fc8f4466c1be
This commit is contained in:
sergeyv
2016-10-11 15:49:16 -07:00
parent 01421d760a
commit c36bd6c16d
8 changed files with 109 additions and 172 deletions

View File

@@ -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<PixelRef> 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<PixelRef> 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<void*>(blob.data()), size, !isMutable);
nativeBitmap = sk_sp<PixelRef>(GraphicsJNI::mapAshmemPixelRef(env, bitmap.get(),
ctable, dupFd, const_cast<void*>(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);
}

View File

@@ -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<SkColorSpace> 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;
}

View File

@@ -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);

View File

@@ -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 = PixelRef::allocateHeapPixelRef(&bitmap, NULL);
if (!pixelRef) {
return;
}

View File

@@ -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<PixelRef> (*AllocPixeRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes,
SkColorTable* ctable);
static sk_sp<PixelRef> 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> PixelRef::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
return allocatePixelRef(bitmap, ctable, &PixelRef::allocateHeapPixelRef);
}
sk_sp<PixelRef> PixelRef::allocateAshmemPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
return allocatePixelRef(bitmap, ctable, &PixelRef::allocateAshmemPixelRef);
}
sk_sp<PixelRef> 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<PixelRef>(new PixelRef(addr, size, info, rowBytes, ctable));
}
sk_sp<PixelRef> 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<PixelRef>(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;

View File

@@ -33,6 +33,14 @@ typedef void (*FreeFunc)(void* addr, void* context);
class ANDROID_API PixelRef : public SkPixelRef {
public:
static sk_sp<PixelRef> allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
static sk_sp<PixelRef> allocateHeapPixelRef(size_t allocSize, const SkImageInfo& info,
size_t rowBytes, SkColorTable* ctable);
static sk_sp<PixelRef> allocateAshmemPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
static sk_sp<PixelRef> 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,

View File

@@ -21,6 +21,7 @@
#include <Matrix.h>
#include <Rect.h>
#include <RenderNode.h>
#include <hwui/PixelRef.h>
#include <renderstate/RenderState.h>
#include <renderthread/RenderThread.h>
#include <Snapshot.h>
@@ -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;
}

View File

@@ -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<SkShader> 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());