Merge "Count native allocation for VD against Java heap" into nyc-dev
am: 6543533f29
* commit '6543533f29d869d5cbbc1c403e4e0ed219fcc300':
Count native allocation for VD against Java heap
Change-Id: I2bc21681d07d759f7fd668ec286f719b7ea6707a
This commit is contained in:
@@ -92,14 +92,14 @@ static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCachi
|
|||||||
/**
|
/**
|
||||||
* Draw
|
* Draw
|
||||||
*/
|
*/
|
||||||
static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
|
static int draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
|
||||||
jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
|
jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
|
||||||
VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
|
VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
|
||||||
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
|
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
|
||||||
SkRect rect;
|
SkRect rect;
|
||||||
GraphicsJNI::jrect_to_rect(env, jrect, &rect);
|
GraphicsJNI::jrect_to_rect(env, jrect, &rect);
|
||||||
SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
|
SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
|
||||||
tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
|
return tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -349,7 +349,7 @@ static const JNINativeMethod gMethods[] = {
|
|||||||
{"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
|
{"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
|
||||||
{"nSetAllowCaching", "!(JZ)V", (void*)setAllowCaching},
|
{"nSetAllowCaching", "!(JZ)V", (void*)setAllowCaching},
|
||||||
|
|
||||||
{"nDraw", "(JJJLandroid/graphics/Rect;ZZ)V", (void*)draw},
|
{"nDraw", "(JJJLandroid/graphics/Rect;ZZ)I", (void*)draw},
|
||||||
{"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
|
{"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
|
||||||
{"nCreateFullPath", "!(J)J", (void*)createFullPath},
|
{"nCreateFullPath", "!(J)J", (void*)createFullPath},
|
||||||
{"nUpdateFullPathProperties", "!(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
|
{"nUpdateFullPathProperties", "!(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This lets you create a drawable based on an XML vector graphic.
|
* This lets you create a drawable based on an XML vector graphic.
|
||||||
* <p/>
|
* <p/>
|
||||||
@@ -299,9 +301,33 @@ public class VectorDrawable extends Drawable {
|
|||||||
final long colorFilterNativeInstance = colorFilter == null ? 0 :
|
final long colorFilterNativeInstance = colorFilter == null ? 0 :
|
||||||
colorFilter.native_instance;
|
colorFilter.native_instance;
|
||||||
boolean canReuseCache = mVectorState.canReuseCache();
|
boolean canReuseCache = mVectorState.canReuseCache();
|
||||||
nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
|
int pixelCount = nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
|
||||||
colorFilterNativeInstance, mTmpBounds, needMirroring(),
|
colorFilterNativeInstance, mTmpBounds, needMirroring(),
|
||||||
canReuseCache);
|
canReuseCache);
|
||||||
|
if (pixelCount == 0) {
|
||||||
|
// Invalid canvas matrix or drawable bounds. This would not affect existing bitmap
|
||||||
|
// cache, if any.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deltaInBytes;
|
||||||
|
// Track different bitmap cache based whether the canvas is hw accelerated. By doing so,
|
||||||
|
// we don't over count bitmap cache allocation: if the input canvas is always of the same
|
||||||
|
// type, only one bitmap cache is allocated.
|
||||||
|
if (canvas.isHardwareAccelerated()) {
|
||||||
|
// Each pixel takes 4 bytes.
|
||||||
|
deltaInBytes = (pixelCount - mVectorState.mLastHWCachePixelCount) * 4;
|
||||||
|
mVectorState.mLastHWCachePixelCount = pixelCount;
|
||||||
|
} else {
|
||||||
|
// Each pixel takes 4 bytes.
|
||||||
|
deltaInBytes = (pixelCount - mVectorState.mLastSWCachePixelCount) * 4;
|
||||||
|
mVectorState.mLastSWCachePixelCount = pixelCount;
|
||||||
|
}
|
||||||
|
if (deltaInBytes > 0) {
|
||||||
|
VMRuntime.getRuntime().registerNativeAllocation(deltaInBytes);
|
||||||
|
} else if (deltaInBytes < 0) {
|
||||||
|
VMRuntime.getRuntime().registerNativeFree(-deltaInBytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -537,11 +563,16 @@ public class VectorDrawable extends Drawable {
|
|||||||
if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) {
|
if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) {
|
||||||
// This VD has been used to display other VD resource content, clean up.
|
// This VD has been used to display other VD resource content, clean up.
|
||||||
if (mVectorState.mRootGroup != null) {
|
if (mVectorState.mRootGroup != null) {
|
||||||
|
// Subtract the native allocation for all the nodes.
|
||||||
|
VMRuntime.getRuntime().registerNativeFree(mVectorState.mRootGroup.getNativeSize());
|
||||||
// Remove child nodes' reference to tree
|
// Remove child nodes' reference to tree
|
||||||
mVectorState.mRootGroup.setTree(null);
|
mVectorState.mRootGroup.setTree(null);
|
||||||
}
|
}
|
||||||
mVectorState.mRootGroup = new VGroup();
|
mVectorState.mRootGroup = new VGroup();
|
||||||
if (mVectorState.mNativeTree != null) {
|
if (mVectorState.mNativeTree != null) {
|
||||||
|
// Subtract the native allocation for the tree wrapper, which contains root node
|
||||||
|
// as well as rendering related data.
|
||||||
|
VMRuntime.getRuntime().registerNativeFree(mVectorState.NATIVE_ALLOCATION_SIZE);
|
||||||
mVectorState.mNativeTree.release();
|
mVectorState.mNativeTree.release();
|
||||||
}
|
}
|
||||||
mVectorState.createNativeTree(mVectorState.mRootGroup);
|
mVectorState.createNativeTree(mVectorState.mRootGroup);
|
||||||
@@ -558,6 +589,7 @@ public class VectorDrawable extends Drawable {
|
|||||||
state.mCacheDirty = true;
|
state.mCacheDirty = true;
|
||||||
inflateChildElements(r, parser, attrs, theme);
|
inflateChildElements(r, parser, attrs, theme);
|
||||||
|
|
||||||
|
state.onTreeConstructionFinished();
|
||||||
// Update local properties.
|
// Update local properties.
|
||||||
updateLocalState(r);
|
updateLocalState(r);
|
||||||
}
|
}
|
||||||
@@ -750,6 +782,16 @@ public class VectorDrawable extends Drawable {
|
|||||||
boolean mCachedAutoMirrored;
|
boolean mCachedAutoMirrored;
|
||||||
boolean mCacheDirty;
|
boolean mCacheDirty;
|
||||||
|
|
||||||
|
// Since sw canvas and hw canvas uses different bitmap caches, we track the allocation of
|
||||||
|
// these bitmaps separately.
|
||||||
|
int mLastSWCachePixelCount = 0;
|
||||||
|
int mLastHWCachePixelCount = 0;
|
||||||
|
|
||||||
|
// This tracks the total native allocation for all the nodes.
|
||||||
|
private int mAllocationOfAllNodes = 0;
|
||||||
|
|
||||||
|
private static final int NATIVE_ALLOCATION_SIZE = 316;
|
||||||
|
|
||||||
// Deep copy for mutate() or implicitly mutate.
|
// Deep copy for mutate() or implicitly mutate.
|
||||||
public VectorDrawableState(VectorDrawableState copy) {
|
public VectorDrawableState(VectorDrawableState copy) {
|
||||||
if (copy != null) {
|
if (copy != null) {
|
||||||
@@ -771,12 +813,20 @@ public class VectorDrawable extends Drawable {
|
|||||||
if (copy.mRootName != null) {
|
if (copy.mRootName != null) {
|
||||||
mVGTargetsMap.put(copy.mRootName, this);
|
mVGTargetsMap.put(copy.mRootName, this);
|
||||||
}
|
}
|
||||||
|
onTreeConstructionFinished();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createNativeTree(VGroup rootGroup) {
|
private void createNativeTree(VGroup rootGroup) {
|
||||||
mNativeTree = new VirtualRefBasePtr(nCreateTree(rootGroup.mNativePtr));
|
mNativeTree = new VirtualRefBasePtr(nCreateTree(rootGroup.mNativePtr));
|
||||||
|
// Register tree size
|
||||||
|
VMRuntime.getRuntime().registerNativeAllocation(NATIVE_ALLOCATION_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTreeConstructionFinished() {
|
||||||
mRootGroup.setTree(mNativeTree);
|
mRootGroup.setTree(mNativeTree);
|
||||||
|
mAllocationOfAllNodes = mRootGroup.getNativeSize();
|
||||||
|
VMRuntime.getRuntime().registerNativeAllocation(mAllocationOfAllNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
long getNativeRenderer() {
|
long getNativeRenderer() {
|
||||||
@@ -881,6 +931,14 @@ public class VectorDrawable extends Drawable {
|
|||||||
return mRootGroup.onStateChange(stateSet);
|
return mRootGroup.onStateChange(stateSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finalize() throws Throwable {
|
||||||
|
super.finalize();
|
||||||
|
int bitmapCacheSize = mLastHWCachePixelCount * 4 + mLastSWCachePixelCount * 4;
|
||||||
|
VMRuntime.getRuntime().registerNativeFree(NATIVE_ALLOCATION_SIZE
|
||||||
|
+ mAllocationOfAllNodes + bitmapCacheSize);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setAlpha() and getAlpha() are used mostly for animation purpose. Return true if alpha
|
* setAlpha() and getAlpha() are used mostly for animation purpose. Return true if alpha
|
||||||
* has changed.
|
* has changed.
|
||||||
@@ -905,6 +963,8 @@ public class VectorDrawable extends Drawable {
|
|||||||
private static final int TRANSLATE_Y_INDEX = 6;
|
private static final int TRANSLATE_Y_INDEX = 6;
|
||||||
private static final int TRANSFORM_PROPERTY_COUNT = 7;
|
private static final int TRANSFORM_PROPERTY_COUNT = 7;
|
||||||
|
|
||||||
|
private static final int NATIVE_ALLOCATION_SIZE = 100;
|
||||||
|
|
||||||
private static final HashMap<String, Integer> sPropertyMap =
|
private static final HashMap<String, Integer> sPropertyMap =
|
||||||
new HashMap<String, Integer>() {
|
new HashMap<String, Integer>() {
|
||||||
{
|
{
|
||||||
@@ -1072,6 +1132,16 @@ public class VectorDrawable extends Drawable {
|
|||||||
return mIsStateful;
|
return mIsStateful;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int getNativeSize() {
|
||||||
|
// Return the native allocation needed for the subtree.
|
||||||
|
int size = NATIVE_ALLOCATION_SIZE;
|
||||||
|
for (int i = 0; i < mChildren.size(); i++) {
|
||||||
|
size += mChildren.get(i).getNativeSize();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canApplyTheme() {
|
public boolean canApplyTheme() {
|
||||||
if (mThemeAttrs != null) {
|
if (mThemeAttrs != null) {
|
||||||
@@ -1240,6 +1310,7 @@ public class VectorDrawable extends Drawable {
|
|||||||
*/
|
*/
|
||||||
private static class VClipPath extends VPath {
|
private static class VClipPath extends VPath {
|
||||||
private final long mNativePtr;
|
private final long mNativePtr;
|
||||||
|
private static final int NATIVE_ALLOCATION_SIZE = 120;
|
||||||
|
|
||||||
public VClipPath() {
|
public VClipPath() {
|
||||||
mNativePtr = nCreateClipPath();
|
mNativePtr = nCreateClipPath();
|
||||||
@@ -1283,6 +1354,11 @@ public class VectorDrawable extends Drawable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int getNativeSize() {
|
||||||
|
return NATIVE_ALLOCATION_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateStateFromTypedArray(TypedArray a) {
|
private void updateStateFromTypedArray(TypedArray a) {
|
||||||
// Account for any configuration changes.
|
// Account for any configuration changes.
|
||||||
mChangingConfigurations |= a.getChangingConfigurations();
|
mChangingConfigurations |= a.getChangingConfigurations();
|
||||||
@@ -1319,6 +1395,7 @@ public class VectorDrawable extends Drawable {
|
|||||||
private static final int FILL_TYPE_INDEX = 11;
|
private static final int FILL_TYPE_INDEX = 11;
|
||||||
private static final int TOTAL_PROPERTY_COUNT = 12;
|
private static final int TOTAL_PROPERTY_COUNT = 12;
|
||||||
|
|
||||||
|
private static final int NATIVE_ALLOCATION_SIZE = 264;
|
||||||
// Property map for animatable attributes.
|
// Property map for animatable attributes.
|
||||||
private final static HashMap<String, Integer> sPropertyMap
|
private final static HashMap<String, Integer> sPropertyMap
|
||||||
= new HashMap<String, Integer> () {
|
= new HashMap<String, Integer> () {
|
||||||
@@ -1395,6 +1472,11 @@ public class VectorDrawable extends Drawable {
|
|||||||
return mStrokeColors != null || mFillColors != null;
|
return mStrokeColors != null || mFillColors != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int getNativeSize() {
|
||||||
|
return NATIVE_ALLOCATION_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getNativePtr() {
|
public long getNativePtr() {
|
||||||
return mNativePtr;
|
return mNativePtr;
|
||||||
@@ -1688,6 +1770,7 @@ public class VectorDrawable extends Drawable {
|
|||||||
abstract void applyTheme(Theme t);
|
abstract void applyTheme(Theme t);
|
||||||
abstract boolean onStateChange(int[] state);
|
abstract boolean onStateChange(int[] state);
|
||||||
abstract boolean isStateful();
|
abstract boolean isStateful();
|
||||||
|
abstract int getNativeSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long nCreateTree(long rootGroupPtr);
|
private static native long nCreateTree(long rootGroupPtr);
|
||||||
@@ -1697,7 +1780,7 @@ public class VectorDrawable extends Drawable {
|
|||||||
private static native float nGetRootAlpha(long rendererPtr);
|
private static native float nGetRootAlpha(long rendererPtr);
|
||||||
private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
|
private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
|
||||||
|
|
||||||
private static native void nDraw(long rendererPtr, long canvasWrapperPtr,
|
private static native int nDraw(long rendererPtr, long canvasWrapperPtr,
|
||||||
long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
|
long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
|
||||||
private static native long nCreateFullPath();
|
private static native long nCreateFullPath();
|
||||||
private static native long nCreateFullPath(long nativeFullPathPtr);
|
private static native long nCreateFullPath(long nativeFullPathPtr);
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ bool Group::GroupProperties::isValidProperty(int propertyId) {
|
|||||||
return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
|
return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
|
int Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
|
||||||
const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
|
const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
|
||||||
// The imageView can scale the canvas in different ways, in order to
|
// The imageView can scale the canvas in different ways, in order to
|
||||||
// avoid blurry scaling, we have to draw into a bitmap with exact pixel
|
// avoid blurry scaling, we have to draw into a bitmap with exact pixel
|
||||||
@@ -478,7 +478,7 @@ void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
|
|||||||
scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
|
scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
|
||||||
|
|
||||||
if (scaledWidth <= 0 || scaledHeight <= 0) {
|
if (scaledWidth <= 0 || scaledHeight <= 0) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mStagingProperties.setScaledSize(scaledWidth, scaledHeight);
|
mStagingProperties.setScaledSize(scaledWidth, scaledHeight);
|
||||||
@@ -500,6 +500,7 @@ void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
|
|||||||
mStagingProperties.setBounds(tmpBounds);
|
mStagingProperties.setBounds(tmpBounds);
|
||||||
outCanvas->drawVectorDrawable(this);
|
outCanvas->drawVectorDrawable(this);
|
||||||
outCanvas->restoreToCount(saveCount);
|
outCanvas->restoreToCount(saveCount);
|
||||||
|
return scaledWidth * scaledHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tree::drawStaging(Canvas* outCanvas) {
|
void Tree::drawStaging(Canvas* outCanvas) {
|
||||||
|
|||||||
@@ -542,7 +542,9 @@ public:
|
|||||||
Tree(Group* rootNode) : mRootNode(rootNode) {
|
Tree(Group* rootNode) : mRootNode(rootNode) {
|
||||||
mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
|
mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
|
||||||
}
|
}
|
||||||
void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
|
// Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
|
||||||
|
// canvas. Returns the number of pixels needed for the bitmap cache.
|
||||||
|
int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
|
||||||
const SkRect& bounds, bool needsMirroring, bool canReuseCache);
|
const SkRect& bounds, bool needsMirroring, bool canReuseCache);
|
||||||
void drawStaging(Canvas* canvas);
|
void drawStaging(Canvas* canvas);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user