summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ThreadedRenderer.java28
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp8
-rw-r--r--graphics/java/android/graphics/Bitmap.java10
-rw-r--r--libs/hwui/AssetAtlas.cpp22
-rw-r--r--libs/hwui/AssetAtlas.h62
-rw-r--r--services/core/java/com/android/server/AssetAtlasService.java98
6 files changed, 125 insertions, 103 deletions
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 25c51279fc06..5017a38fdb4e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -460,6 +460,8 @@ public class ThreadedRenderer extends HardwareRenderer {
if (buffer != null) {
long[] map = atlas.getMap();
if (map != null) {
+ // TODO Remove after fixing b/15425820
+ validateMap(context, map);
nSetAtlas(renderProxy, buffer, map);
}
// If IAssetAtlas is not the same class as the IBinder
@@ -474,6 +476,32 @@ public class ThreadedRenderer extends HardwareRenderer {
Log.w(LOG_TAG, "Could not acquire atlas", e);
}
}
+
+ private static void validateMap(Context context, long[] map) {
+ Log.d("Atlas", "Validating map...");
+ HashSet<Long> preloadedPointers = new HashSet<Long>();
+
+ // We only care about drawables that hold bitmaps
+ final Resources resources = context.getResources();
+ final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
+
+ final int count = drawables.size();
+ ArrayList<Bitmap> tmpList = new ArrayList<Bitmap>();
+ for (int i = 0; i < count; i++) {
+ drawables.valueAt(i).addAtlasableBitmaps(tmpList);
+ for (int j = 0; j < tmpList.size(); j++) {
+ preloadedPointers.add(tmpList.get(j).getSkBitmap());
+ }
+ tmpList.clear();
+ }
+
+ for (int i = 0; i < map.length; i += 4) {
+ if (!preloadedPointers.contains(map[i])) {
+ Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
+ map[i] = 0;
+ }
+ }
+ }
}
static native void setupShadersDiskCache(String cacheFile);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 5c95f8a9a9ae..7a934bde7834 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -857,13 +857,6 @@ static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
bitmap->unlockPixels();
}
-static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkPixelRef* pixelRef = bitmap ? bitmap->pixelRef() : nullptr;
- SkSafeRef(pixelRef);
- return reinterpret_cast<jlong>(pixelRef);
-}
-
///////////////////////////////////////////////////////////////////////////////
static JNINativeMethod gBitmapMethods[] = {
@@ -903,7 +896,6 @@ static JNINativeMethod gBitmapMethods[] = {
(void*)Bitmap_copyPixelsFromBuffer },
{ "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
{ "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
- { "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef },
};
int register_android_graphics_Bitmap(JNIEnv* env)
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 76d6edfdd579..e2f7799786a0 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1573,15 +1573,6 @@ public final class Bitmap implements Parcelable {
return mSkBitmapPtr;
}
- /**
- * Refs the underlying SkPixelRef and returns a pointer to it.
- *
- * @hide
- * */
- public final long refSkPixelRef() {
- return nativeRefPixelRef(mSkBitmapPtr);
- }
-
private static class BitmapFinalizer {
private long mNativeBitmap;
@@ -1670,5 +1661,4 @@ public final class Bitmap implements Parcelable {
private static native boolean nativeHasMipMap(long nativeBitmap);
private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
- private static native long nativeRefPixelRef(long nativeBitmap);
}
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index 882826ead10e..4d2e3a097b55 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -82,12 +82,12 @@ void AssetAtlas::updateTextureId() {
///////////////////////////////////////////////////////////////////////////////
AssetAtlas::Entry* AssetAtlas::getEntry(const SkBitmap* bitmap) const {
- ssize_t index = mEntries.indexOfKey(bitmap->pixelRef());
+ ssize_t index = mEntries.indexOfKey(bitmap);
return index >= 0 ? mEntries.valueAt(index) : nullptr;
}
Texture* AssetAtlas::getEntryTexture(const SkBitmap* bitmap) const {
- ssize_t index = mEntries.indexOfKey(bitmap->pixelRef());
+ ssize_t index = mEntries.indexOfKey(bitmap);
return index >= 0 ? mEntries.valueAt(index)->texture : nullptr;
}
@@ -120,7 +120,7 @@ void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) {
const float height = float(mTexture->height);
for (int i = 0; i < count; ) {
- SkPixelRef* pixelRef = reinterpret_cast<SkPixelRef*>(map[i++]);
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(map[i++]);
// NOTE: We're converting from 64 bit signed values to 32 bit
// signed values. This is guaranteed to be safe because the "x"
// and "y" coordinate values are guaranteed to be representable
@@ -131,21 +131,21 @@ void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) {
bool rotated = map[i++] > 0;
// Bitmaps should never be null, we're just extra paranoid
- if (!pixelRef) continue;
+ if (!bitmap) continue;
const UvMapper mapper(
- x / width, (x + pixelRef->info().width()) / width,
- y / height, (y + pixelRef->info().height()) / height);
+ x / width, (x + bitmap->width()) / width,
+ y / height, (y + bitmap->height()) / height);
Texture* texture = new DelegateTexture(caches, mTexture);
- texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType());
- texture->width = pixelRef->info().width();
- texture->height = pixelRef->info().height();
+ texture->blend = !bitmap->isOpaque();
+ texture->width = bitmap->width();
+ texture->height = bitmap->height();
- Entry* entry = new Entry(pixelRef, x, y, rotated, texture, mapper, *this);
+ Entry* entry = new Entry(bitmap, x, y, rotated, texture, mapper, *this);
texture->uvMapper = &entry->uvMapper;
- mEntries.add(entry->pixelRef, entry);
+ mEntries.add(entry->bitmap, entry);
}
}
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index 17c5281cb3de..1772effb911b 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -48,8 +48,24 @@ public:
* Entry representing the position and rotation of a
* bitmap inside the atlas.
*/
- class Entry {
- public:
+ struct Entry {
+ /**
+ * The bitmap that generated this atlas entry.
+ */
+ SkBitmap* bitmap;
+
+ /**
+ * Location of the bitmap inside the atlas, in pixels.
+ */
+ int x;
+ int y;
+
+ /**
+ * If set, the bitmap is rotated 90 degrees (clockwise)
+ * inside the atlas.
+ */
+ bool rotated;
+
/*
* A "virtual texture" object that represents the texture
* this entry belongs to. This texture should never be
@@ -64,6 +80,11 @@ public:
const UvMapper uvMapper;
/**
+ * Atlas this entry belongs to.
+ */
+ const AssetAtlas& atlas;
+
+ /**
* Unique identifier used to merge bitmaps and 9-patches stored
* in the atlas.
*/
@@ -72,37 +93,10 @@ public:
}
private:
- /**
- * The pixel ref that generated this atlas entry.
- */
- SkPixelRef* pixelRef;
-
- /**
- * Location of the bitmap inside the atlas, in pixels.
- */
- int x;
- int y;
-
- /**
- * If set, the bitmap is rotated 90 degrees (clockwise)
- * inside the atlas.
- */
- bool rotated;
-
- /**
- * Atlas this entry belongs to.
- */
- const AssetAtlas& atlas;
-
- Entry(SkPixelRef* pixelRef, int x, int y, bool rotated,
- Texture* texture, const UvMapper& mapper, const AssetAtlas& atlas)
- : texture(texture)
- , uvMapper(mapper)
- , pixelRef(pixelRef)
- , x(x)
- , y(y)
- , rotated(rotated)
- , atlas(atlas) {
+ Entry(SkBitmap* bitmap, int x, int y, bool rotated,
+ Texture* texture, const UvMapper& mapper, const AssetAtlas& atlas):
+ bitmap(bitmap), x(x), y(y), rotated(rotated),
+ texture(texture), uvMapper(mapper), atlas(atlas) {
}
~Entry() {
@@ -184,7 +178,7 @@ private:
const bool mBlendKey;
const bool mOpaqueKey;
- KeyedVector<const SkPixelRef*, Entry*> mEntries;
+ KeyedVector<const SkBitmap*, Entry*> mEntries;
}; // class AssetAtlas
}; // namespace uirenderer
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index 26f4232ff835..9e28b64ff8f4 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -199,6 +199,8 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
private final ArrayList<Bitmap> mBitmaps;
private final int mPixelCount;
+ private Bitmap mAtlasBitmap;
+
Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) {
mBitmaps = bitmaps;
mPixelCount = pixelCount;
@@ -253,9 +255,8 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
// We always render the atlas into a bitmap. This bitmap is then
// uploaded into the GraphicBuffer using OpenGL to swizzle the content
- final Bitmap atlasBitmap = Bitmap.createBitmap(
- buffer.getWidth(), buffer.getHeight(), Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(atlasBitmap);
+ final Canvas canvas = acquireCanvas(buffer.getWidth(), buffer.getHeight());
+ if (canvas == null) return false;
final Atlas.Entry entry = new Atlas.Entry();
@@ -264,58 +265,73 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
int mapIndex = 0;
boolean result = false;
- final long startRender = System.nanoTime();
- final int count = mBitmaps.size();
+ try {
+ final long startRender = System.nanoTime();
+ final int count = mBitmaps.size();
+
+ for (int i = 0; i < count; i++) {
+ final Bitmap bitmap = mBitmaps.get(i);
+ if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
+ // We have more bitmaps to pack than the current configuration
+ // says, we were most likely not able to detect a change in the
+ // list of preloaded drawables, abort and delete the configuration
+ if (mapIndex >= mAtlasMap.length) {
+ deleteDataFile();
+ break;
+ }
- for (int i = 0; i < count; i++) {
- final Bitmap bitmap = mBitmaps.get(i);
- if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
- // We have more bitmaps to pack than the current configuration
- // says, we were most likely not able to detect a change in the
- // list of preloaded drawables, abort and delete the configuration
- if (mapIndex >= mAtlasMap.length) {
- deleteDataFile();
- break;
+ canvas.save();
+ canvas.translate(entry.x, entry.y);
+ if (entry.rotated) {
+ canvas.translate(bitmap.getHeight(), 0.0f);
+ canvas.rotate(90.0f);
+ }
+ canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
+ canvas.restore();
+ atlasMap[mapIndex++] = bitmap.getSkBitmap();
+ atlasMap[mapIndex++] = entry.x;
+ atlasMap[mapIndex++] = entry.y;
+ atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
}
+ }
- canvas.save();
- canvas.translate(entry.x, entry.y);
- if (entry.rotated) {
- canvas.translate(bitmap.getHeight(), 0.0f);
- canvas.rotate(90.0f);
- }
- canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
- canvas.restore();
- atlasMap[mapIndex++] = bitmap.refSkPixelRef();
- atlasMap[mapIndex++] = entry.x;
- atlasMap[mapIndex++] = entry.y;
- atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
+ final long endRender = System.nanoTime();
+ result = nUploadAtlas(buffer, mAtlasBitmap);
+
+ final long endUpload = System.nanoTime();
+ if (DEBUG_ATLAS) {
+ float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
+ float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
+ Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
+ renderDuration + uploadDuration, renderDuration, uploadDuration));
}
- }
- final long endRender = System.nanoTime();
- releaseCanvas(canvas, atlasBitmap);
- result = nUploadAtlas(buffer, atlasBitmap);
- atlasBitmap.recycle();
- final long endUpload = System.nanoTime();
-
- if (DEBUG_ATLAS) {
- float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
- float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
- Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
- renderDuration + uploadDuration, renderDuration, uploadDuration));
+ } finally {
+ releaseCanvas(canvas);
}
return result;
}
/**
+ * Returns a Canvas for the specified buffer. If {@link #DEBUG_ATLAS_TEXTURE}
+ * is turned on, the returned Canvas will render into a local bitmap that
+ * will then be saved out to disk for debugging purposes.
+ * @param width
+ * @param height
+ */
+ private Canvas acquireCanvas(int width, int height) {
+ mAtlasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ return new Canvas(mAtlasBitmap);
+ }
+
+ /**
* Releases the canvas used to render into the buffer. Calling this method
* will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE}
* is turend on, calling this method will write the content of the atlas
* to disk in /data/system/atlas.png for debugging.
*/
- private void releaseCanvas(Canvas canvas, Bitmap atlasBitmap) {
+ private void releaseCanvas(Canvas canvas) {
canvas.setBitmap(null);
if (DEBUG_ATLAS_TEXTURE) {
@@ -324,7 +340,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
try {
FileOutputStream out = new FileOutputStream(dataFile);
- atlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
+ mAtlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (FileNotFoundException e) {
// Ignore
@@ -332,6 +348,8 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
// Ignore
}
}
+ mAtlasBitmap.recycle();
+ mAtlasBitmap = null;
}
}