am 1641c0cb: Merge "Move AssetAtlas off of SkBitmap*" into mnc-dev

* commit '1641c0cb0b6baf313c82846fe4f64007078c604f':
  Move AssetAtlas off of SkBitmap*
This commit is contained in:
John Reck
2015-05-04 14:40:41 +00:00
committed by Android Git Automerger
6 changed files with 103 additions and 125 deletions

View File

@@ -460,8 +460,6 @@ 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
@@ -476,32 +474,6 @@ 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);

View File

@@ -857,6 +857,13 @@ 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[] = {
@@ -896,6 +903,7 @@ 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)

View File

@@ -1573,6 +1573,15 @@ 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;
@@ -1661,4 +1670,5 @@ 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);
}

View File

@@ -82,12 +82,12 @@ void AssetAtlas::updateTextureId() {
///////////////////////////////////////////////////////////////////////////////
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;
}
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;
}
@@ -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; ) {
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
// 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 (!bitmap) continue;
if (!pixelRef) continue;
const UvMapper mapper(
x / width, (x + bitmap->width()) / width,
y / height, (y + bitmap->height()) / height);
x / width, (x + pixelRef->info().width()) / width,
y / height, (y + pixelRef->info().height()) / height);
Texture* texture = new DelegateTexture(caches, mTexture);
texture->blend = !bitmap->isOpaque();
texture->width = bitmap->width();
texture->height = bitmap->height();
texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType());
texture->width = pixelRef->info().width();
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;
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
* bitmap inside the atlas.
*/
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;
class Entry {
public:
/*
* A "virtual texture" object that represents the texture
* this entry belongs to. This texture should never be
@@ -79,11 +63,6 @@ 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.
@@ -93,10 +72,37 @@ public:
}
private:
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) {
/**
* 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() {
@@ -178,7 +184,7 @@ private:
const bool mBlendKey;
const bool mOpaqueKey;
KeyedVector<const SkBitmap*, Entry*> mEntries;
KeyedVector<const SkPixelRef*, Entry*> mEntries;
}; // class AssetAtlas
}; // namespace uirenderer

View File

@@ -199,8 +199,6 @@ 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;
@@ -255,8 +253,9 @@ 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 Canvas canvas = acquireCanvas(buffer.getWidth(), buffer.getHeight());
if (canvas == null) return false;
final Bitmap atlasBitmap = Bitmap.createBitmap(
buffer.getWidth(), buffer.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(atlasBitmap);
final Atlas.Entry entry = new Atlas.Entry();
@@ -265,73 +264,58 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
int mapIndex = 0;
boolean result = false;
try {
final long startRender = System.nanoTime();
final int count = mBitmaps.size();
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;
}
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;
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.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 endRender = System.nanoTime();
releaseCanvas(canvas, atlasBitmap);
result = nUploadAtlas(buffer, atlasBitmap);
atlasBitmap.recycle();
final long endUpload = System.nanoTime();
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);
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));
}
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) {
private void releaseCanvas(Canvas canvas, Bitmap atlasBitmap) {
canvas.setBitmap(null);
if (DEBUG_ATLAS_TEXTURE) {
@@ -340,7 +324,7 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
try {
FileOutputStream out = new FileOutputStream(dataFile);
mAtlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
atlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
} catch (FileNotFoundException e) {
// Ignore
@@ -348,8 +332,6 @@ public class AssetAtlasService extends IAssetAtlas.Stub {
// Ignore
}
}
mAtlasBitmap.recycle();
mAtlasBitmap = null;
}
}