diff options
| -rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 28 | ||||
| -rwxr-xr-x | core/jni/android/graphics/Bitmap.cpp | 8 | ||||
| -rw-r--r-- | graphics/java/android/graphics/Bitmap.java | 10 | ||||
| -rw-r--r-- | libs/hwui/AssetAtlas.cpp | 22 | ||||
| -rw-r--r-- | libs/hwui/AssetAtlas.h | 62 | ||||
| -rw-r--r-- | services/core/java/com/android/server/AssetAtlasService.java | 98 |
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; } } |