Merge "Move AssetAtlas off of SkBitmap*" into mnc-dev

This commit is contained in:
John Reck
2015-05-04 14:34:38 +00:00
committed by Android (Google) Code Review
6 changed files with 103 additions and 125 deletions

View File

@@ -460,8 +460,6 @@ public class ThreadedRenderer extends HardwareRenderer {
if (buffer != null) { if (buffer != null) {
long[] map = atlas.getMap(); long[] map = atlas.getMap();
if (map != null) { if (map != null) {
// TODO Remove after fixing b/15425820
validateMap(context, map);
nSetAtlas(renderProxy, buffer, map); nSetAtlas(renderProxy, buffer, map);
} }
// If IAssetAtlas is not the same class as the IBinder // If IAssetAtlas is not the same class as the IBinder
@@ -476,32 +474,6 @@ public class ThreadedRenderer extends HardwareRenderer {
Log.w(LOG_TAG, "Could not acquire atlas", e); 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); static native void setupShadersDiskCache(String cacheFile);

View File

@@ -857,6 +857,13 @@ static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
bitmap->unlockPixels(); 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[] = { static JNINativeMethod gBitmapMethods[] = {
@@ -896,6 +903,7 @@ static JNINativeMethod gBitmapMethods[] = {
(void*)Bitmap_copyPixelsFromBuffer }, (void*)Bitmap_copyPixelsFromBuffer },
{ "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs }, { "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
{ "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw }, { "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
{ "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef },
}; };
int register_android_graphics_Bitmap(JNIEnv* env) int register_android_graphics_Bitmap(JNIEnv* env)

View File

@@ -1573,6 +1573,15 @@ public final class Bitmap implements Parcelable {
return mSkBitmapPtr; 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 static class BitmapFinalizer {
private long mNativeBitmap; private long mNativeBitmap;
@@ -1661,4 +1670,5 @@ public final class Bitmap implements Parcelable {
private static native boolean nativeHasMipMap(long nativeBitmap); private static native boolean nativeHasMipMap(long nativeBitmap);
private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap); private static native void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap);
private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1); private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
private static native long nativeRefPixelRef(long nativeBitmap);
} }

View File

@@ -82,12 +82,12 @@ void AssetAtlas::updateTextureId() {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
AssetAtlas::Entry* AssetAtlas::getEntry(const SkBitmap* bitmap) const { AssetAtlas::Entry* AssetAtlas::getEntry(const SkBitmap* bitmap) const {
ssize_t index = mEntries.indexOfKey(bitmap); ssize_t index = mEntries.indexOfKey(bitmap->pixelRef());
return index >= 0 ? mEntries.valueAt(index) : nullptr; return index >= 0 ? mEntries.valueAt(index) : nullptr;
} }
Texture* AssetAtlas::getEntryTexture(const SkBitmap* bitmap) const { Texture* AssetAtlas::getEntryTexture(const SkBitmap* bitmap) const {
ssize_t index = mEntries.indexOfKey(bitmap); ssize_t index = mEntries.indexOfKey(bitmap->pixelRef());
return index >= 0 ? mEntries.valueAt(index)->texture : nullptr; 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); const float height = float(mTexture->height);
for (int i = 0; i < count; ) { for (int i = 0; i < count; ) {
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(map[i++]); SkPixelRef* pixelRef = reinterpret_cast<SkPixelRef*>(map[i++]);
// NOTE: We're converting from 64 bit signed values to 32 bit // NOTE: We're converting from 64 bit signed values to 32 bit
// signed values. This is guaranteed to be safe because the "x" // signed values. This is guaranteed to be safe because the "x"
// and "y" coordinate values are guaranteed to be representable // 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; bool rotated = map[i++] > 0;
// Bitmaps should never be null, we're just extra paranoid // Bitmaps should never be null, we're just extra paranoid
if (!bitmap) continue; if (!pixelRef) continue;
const UvMapper mapper( const UvMapper mapper(
x / width, (x + bitmap->width()) / width, x / width, (x + pixelRef->info().width()) / width,
y / height, (y + bitmap->height()) / height); y / height, (y + pixelRef->info().height()) / height);
Texture* texture = new DelegateTexture(caches, mTexture); Texture* texture = new DelegateTexture(caches, mTexture);
texture->blend = !bitmap->isOpaque(); texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType());
texture->width = bitmap->width(); texture->width = pixelRef->info().width();
texture->height = bitmap->height(); texture->height = pixelRef->info().height();
Entry* entry = new Entry(bitmap, x, y, rotated, texture, mapper, *this); Entry* entry = new Entry(pixelRef, x, y, rotated, texture, mapper, *this);
texture->uvMapper = &entry->uvMapper; texture->uvMapper = &entry->uvMapper;
mEntries.add(entry->bitmap, entry); mEntries.add(entry->pixelRef, entry);
} }
} }

View File

@@ -48,24 +48,8 @@ public:
* Entry representing the position and rotation of a * Entry representing the position and rotation of a
* bitmap inside the atlas. * bitmap inside the atlas.
*/ */
struct Entry { class Entry {
/** public:
* 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 * A "virtual texture" object that represents the texture
* this entry belongs to. This texture should never be * this entry belongs to. This texture should never be
@@ -79,11 +63,6 @@ public:
*/ */
const UvMapper uvMapper; const UvMapper uvMapper;
/**
* Atlas this entry belongs to.
*/
const AssetAtlas& atlas;
/** /**
* Unique identifier used to merge bitmaps and 9-patches stored * Unique identifier used to merge bitmaps and 9-patches stored
* in the atlas. * in the atlas.
@@ -93,10 +72,37 @@ public:
} }
private: private:
Entry(SkBitmap* bitmap, int x, int y, bool rotated, /**
Texture* texture, const UvMapper& mapper, const AssetAtlas& atlas): * The pixel ref that generated this atlas entry.
bitmap(bitmap), x(x), y(y), rotated(rotated), */
texture(texture), uvMapper(mapper), atlas(atlas) { 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() { ~Entry() {
@@ -178,7 +184,7 @@ private:
const bool mBlendKey; const bool mBlendKey;
const bool mOpaqueKey; const bool mOpaqueKey;
KeyedVector<const SkBitmap*, Entry*> mEntries; KeyedVector<const SkPixelRef*, Entry*> mEntries;
}; // class AssetAtlas }; // class AssetAtlas
}; // namespace uirenderer }; // namespace uirenderer

View File

@@ -199,8 +199,6 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
private final ArrayList<Bitmap> mBitmaps; private final ArrayList<Bitmap> mBitmaps;
private final int mPixelCount; private final int mPixelCount;
private Bitmap mAtlasBitmap;
Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) { Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) {
mBitmaps = bitmaps; mBitmaps = bitmaps;
mPixelCount = pixelCount; mPixelCount = pixelCount;
@@ -255,8 +253,9 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
// We always render the atlas into a bitmap. This bitmap is then // We always render the atlas into a bitmap. This bitmap is then
// uploaded into the GraphicBuffer using OpenGL to swizzle the content // uploaded into the GraphicBuffer using OpenGL to swizzle the content
final Canvas canvas = acquireCanvas(buffer.getWidth(), buffer.getHeight()); final Bitmap atlasBitmap = Bitmap.createBitmap(
if (canvas == null) return false; buffer.getWidth(), buffer.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(atlasBitmap);
final Atlas.Entry entry = new Atlas.Entry(); final Atlas.Entry entry = new Atlas.Entry();
@@ -265,73 +264,58 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
int mapIndex = 0; int mapIndex = 0;
boolean result = false; boolean result = false;
try { final long startRender = System.nanoTime();
final long startRender = System.nanoTime(); final int count = mBitmaps.size();
final int count = mBitmaps.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
final Bitmap bitmap = mBitmaps.get(i); final Bitmap bitmap = mBitmaps.get(i);
if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) { if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
// We have more bitmaps to pack than the current configuration // We have more bitmaps to pack than the current configuration
// says, we were most likely not able to detect a change in the // says, we were most likely not able to detect a change in the
// list of preloaded drawables, abort and delete the configuration // list of preloaded drawables, abort and delete the configuration
if (mapIndex >= mAtlasMap.length) { if (mapIndex >= mAtlasMap.length) {
deleteDataFile(); deleteDataFile();
break; 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(); final long endRender = System.nanoTime();
result = nUploadAtlas(buffer, mAtlasBitmap); releaseCanvas(canvas, atlasBitmap);
result = nUploadAtlas(buffer, atlasBitmap);
atlasBitmap.recycle();
final long endUpload = System.nanoTime();
final long endUpload = System.nanoTime(); if (DEBUG_ATLAS) {
if (DEBUG_ATLAS) { float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f; float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f; Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)", renderDuration + uploadDuration, renderDuration, uploadDuration));
renderDuration + uploadDuration, renderDuration, uploadDuration));
}
} finally {
releaseCanvas(canvas);
} }
return result; 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 * Releases the canvas used to render into the buffer. Calling this method
* will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE} * will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE}
* is turend on, calling this method will write the content of the atlas * is turend on, calling this method will write the content of the atlas
* to disk in /data/system/atlas.png for debugging. * to disk in /data/system/atlas.png for debugging.
*/ */
private void releaseCanvas(Canvas canvas) { private void releaseCanvas(Canvas canvas, Bitmap atlasBitmap) {
canvas.setBitmap(null); canvas.setBitmap(null);
if (DEBUG_ATLAS_TEXTURE) { if (DEBUG_ATLAS_TEXTURE) {
@@ -340,7 +324,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
try { try {
FileOutputStream out = new FileOutputStream(dataFile); FileOutputStream out = new FileOutputStream(dataFile);
mAtlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); atlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close(); out.close();
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// Ignore // Ignore
@@ -348,8 +332,6 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
// Ignore // Ignore
} }
} }
mAtlasBitmap.recycle();
mAtlasBitmap = null;
} }
} }