Merge "Move AssetAtlas off of SkBitmap*" into mnc-dev
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user