Add warning if an in-use Bitmap is reconfigured
Bug: 18928352 Also fix an issue around re-configure not properly handling mPinnedCount in android::Bitmap Change-Id: I1815b121f1474ad931060771bb1d52ef31d2aac7
This commit is contained in:
@@ -188,18 +188,43 @@ size_t Bitmap::rowBytes() const {
|
||||
return mPixelRef->rowBytes();
|
||||
}
|
||||
|
||||
SkPixelRef* Bitmap::pixelRef() const {
|
||||
SkPixelRef* Bitmap::peekAtPixelRef() const {
|
||||
assertValid();
|
||||
return mPixelRef.get();
|
||||
}
|
||||
|
||||
SkPixelRef* Bitmap::refPixelRef() {
|
||||
assertValid();
|
||||
android::AutoMutex _lock(mLock);
|
||||
return refPixelRefLocked();
|
||||
}
|
||||
|
||||
SkPixelRef* Bitmap::refPixelRefLocked() {
|
||||
mPixelRef->ref();
|
||||
if (mPixelRef->unique()) {
|
||||
// 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();
|
||||
}
|
||||
|
||||
void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
|
||||
SkColorTable* ctable) {
|
||||
{
|
||||
android::AutoMutex _lock(mLock);
|
||||
if (mPinnedRefCount) {
|
||||
ALOGW("Called reconfigure on a bitmap that is in use! This may"
|
||||
" cause graphical corruption!");
|
||||
}
|
||||
}
|
||||
mPixelRef->reconfigure(info, rowBytes, ctable);
|
||||
}
|
||||
|
||||
void Bitmap::reconfigure(const SkImageInfo& info) {
|
||||
mPixelRef->reconfigure(info, mPixelRef->rowBytes(), mPixelRef->colorTable());
|
||||
reconfigure(info, mPixelRef->rowBytes(), mPixelRef->colorTable());
|
||||
}
|
||||
|
||||
void Bitmap::detachFromJava() {
|
||||
@@ -287,18 +312,10 @@ void Bitmap::unpinPixelsLocked() {
|
||||
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
|
||||
assertValid();
|
||||
android::AutoMutex _lock(mLock);
|
||||
mPixelRef->ref();
|
||||
if (mPixelRef->unique()) {
|
||||
// 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++;
|
||||
}
|
||||
// Safe because mPixelRef is a WrappedPixelRef type, otherwise rowBytes()
|
||||
// would require locking the pixels first.
|
||||
outBitmap->setInfo(mPixelRef->info(), mPixelRef->rowBytes());
|
||||
outBitmap->setPixelRef(mPixelRef.get())->unref();
|
||||
outBitmap->setPixelRef(refPixelRefLocked())->unref();
|
||||
outBitmap->setHasHardwareMipMap(hasHardwareMipMap());
|
||||
}
|
||||
|
||||
@@ -323,7 +340,7 @@ public:
|
||||
}
|
||||
|
||||
void* pixels() {
|
||||
return mBitmap->pixelRef()->pixels();
|
||||
return mBitmap->peekAtPixelRef()->pixels();
|
||||
}
|
||||
|
||||
bool valid() {
|
||||
@@ -780,7 +797,7 @@ static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
|
||||
|
||||
static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
|
||||
LocalScopedBitmap bitmap(bitmapHandle);
|
||||
return static_cast<jint>(bitmap->pixelRef()->getGenerationID());
|
||||
return static_cast<jint>(bitmap->peekAtPixelRef()->getGenerationID());
|
||||
}
|
||||
|
||||
static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
|
||||
@@ -800,10 +817,10 @@ static void Bitmap_setHasAlpha(JNIEnv* env, jobject, jlong bitmapHandle,
|
||||
jboolean hasAlpha, jboolean requestPremul) {
|
||||
LocalScopedBitmap bitmap(bitmapHandle);
|
||||
if (hasAlpha) {
|
||||
bitmap->pixelRef()->changeAlphaType(
|
||||
bitmap->peekAtPixelRef()->changeAlphaType(
|
||||
requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
|
||||
} else {
|
||||
bitmap->pixelRef()->changeAlphaType(kOpaque_SkAlphaType);
|
||||
bitmap->peekAtPixelRef()->changeAlphaType(kOpaque_SkAlphaType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,9 +829,9 @@ static void Bitmap_setPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
|
||||
LocalScopedBitmap bitmap(bitmapHandle);
|
||||
if (!bitmap->info().isOpaque()) {
|
||||
if (isPremul) {
|
||||
bitmap->pixelRef()->changeAlphaType(kPremul_SkAlphaType);
|
||||
bitmap->peekAtPixelRef()->changeAlphaType(kPremul_SkAlphaType);
|
||||
} else {
|
||||
bitmap->pixelRef()->changeAlphaType(kUnpremul_SkAlphaType);
|
||||
bitmap->peekAtPixelRef()->changeAlphaType(kUnpremul_SkAlphaType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1164,7 +1181,7 @@ static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
|
||||
|
||||
static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
|
||||
LocalScopedBitmap bitmap(bitmapHandle);
|
||||
SkPixelRef* pixelRef = bitmap.valid() ? bitmap->pixelRef() : nullptr;
|
||||
SkPixelRef* pixelRef = bitmap.valid() ? bitmap->peekAtPixelRef() : nullptr;
|
||||
SkSafeRef(pixelRef);
|
||||
return reinterpret_cast<jlong>(pixelRef);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,8 @@ public:
|
||||
int width() const { return info().width(); }
|
||||
int height() const { return info().height(); }
|
||||
size_t rowBytes() const;
|
||||
SkPixelRef* pixelRef() const;
|
||||
SkPixelRef* peekAtPixelRef() const;
|
||||
SkPixelRef* refPixelRef();
|
||||
bool valid() const { return mPixelStorageType != PixelStorageType::Invalid; }
|
||||
|
||||
void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
|
||||
@@ -88,6 +89,7 @@ private:
|
||||
JNIEnv* jniEnv();
|
||||
bool shouldDisposeSelfLocked();
|
||||
void assertValid() const;
|
||||
SkPixelRef* refPixelRefLocked();
|
||||
|
||||
android::Mutex mLock;
|
||||
int mPinnedRefCount = 0;
|
||||
|
||||
@@ -184,7 +184,7 @@ public:
|
||||
}
|
||||
|
||||
mBitmap->reconfigure(info, bitmap->rowBytes(), ctable);
|
||||
bitmap->setPixelRef(mBitmap->pixelRef());
|
||||
bitmap->setPixelRef(mBitmap->refPixelRef())->unref();
|
||||
|
||||
// since we're already allocated, we lockPixels right away
|
||||
// HeapAllocator/JavaPixelAllocator behaves this way too
|
||||
@@ -258,7 +258,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
|
||||
unsigned int existingBufferSize = 0;
|
||||
if (javaBitmap != NULL) {
|
||||
reuseBitmap = GraphicsJNI::getBitmap(env, javaBitmap);
|
||||
if (reuseBitmap->pixelRef()->isImmutable()) {
|
||||
if (reuseBitmap->peekAtPixelRef()->isImmutable()) {
|
||||
ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
|
||||
javaBitmap = NULL;
|
||||
reuseBitmap = nullptr;
|
||||
|
||||
@@ -352,8 +352,8 @@ void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap)
|
||||
getBitmap(env, bitmap)->getSkBitmap(outBitmap);
|
||||
}
|
||||
|
||||
SkPixelRef* GraphicsJNI::getSkPixelRef(JNIEnv* env, jobject bitmap) {
|
||||
return getBitmap(env, bitmap)->pixelRef();
|
||||
SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject bitmap) {
|
||||
return getBitmap(env, bitmap)->refPixelRef();
|
||||
}
|
||||
|
||||
SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
|
||||
static android::Bitmap* getBitmap(JNIEnv*, jobject bitmap);
|
||||
static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap);
|
||||
static SkPixelRef* getSkPixelRef(JNIEnv*, jobject bitmap);
|
||||
static SkPixelRef* refSkPixelRef(JNIEnv*, jobject bitmap);
|
||||
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
|
||||
|
||||
// Given the 'native' long held by the Rasterizer.java object, return a
|
||||
|
||||
@@ -180,7 +180,7 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
|
||||
(void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot,
|
||||
screenshotInfo, rowBytes, nullptr);
|
||||
screenshot.detach();
|
||||
bitmap->pixelRef()->setImmutable();
|
||||
bitmap->peekAtPixelRef()->setImmutable();
|
||||
|
||||
return GraphicsJNI::createBitmap(env, bitmap,
|
||||
GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
|
||||
|
||||
@@ -62,7 +62,7 @@ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
|
||||
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap);
|
||||
SkPixelRef* pixelRef = GraphicsJNI::refSkPixelRef(env, jbitmap);
|
||||
if (!pixelRef) {
|
||||
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
|
||||
}
|
||||
@@ -71,9 +71,9 @@ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
|
||||
void* addr = pixelRef->pixels();
|
||||
if (NULL == addr) {
|
||||
pixelRef->unlockPixels();
|
||||
pixelRef->unref();
|
||||
return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED;
|
||||
}
|
||||
pixelRef->ref();
|
||||
|
||||
if (addrPtr) {
|
||||
*addrPtr = addr;
|
||||
@@ -86,7 +86,7 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) {
|
||||
return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
SkPixelRef* pixelRef = GraphicsJNI::getSkPixelRef(env, jbitmap);
|
||||
SkPixelRef* pixelRef = GraphicsJNI::refSkPixelRef(env, jbitmap);
|
||||
if (!pixelRef) {
|
||||
return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
|
||||
}
|
||||
@@ -98,6 +98,12 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) {
|
||||
pixelRef->notifyPixelsChanged();
|
||||
|
||||
pixelRef->unlockPixels();
|
||||
// Awkward in that we need to double-unref as the call to get the SkPixelRef
|
||||
// did a ref(), so we need to unref() for the local ref and for the previous
|
||||
// AndroidBitmap_lockPixels(). However this keeps GraphicsJNI a bit safer
|
||||
// if others start using it without knowing about android::Bitmap's "fun"
|
||||
// ref counting mechanism(s).
|
||||
pixelRef->unref();
|
||||
pixelRef->unref();
|
||||
|
||||
return ANDROID_BITMAP_RESULT_SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user