summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/jni/android_graphics_drawable_VectorDrawable.cpp6
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java87
-rw-r--r--libs/hwui/VectorDrawable.cpp5
-rw-r--r--libs/hwui/VectorDrawable.h4
4 files changed, 94 insertions, 8 deletions
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 0de6549ec134..9e69f79e4ffc 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -92,14 +92,14 @@ static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCachi
/**
* 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) {
VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
SkRect rect;
GraphicsJNI::jrect_to_rect(env, jrect, &rect);
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},
{"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)J", (void*)createFullPath},
{"nUpdateFullPathProperties", "!(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 0e457800aac9..ef669715b139 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -52,6 +52,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
+import dalvik.system.VMRuntime;
+
/**
* This lets you create a drawable based on an XML vector graphic.
* <p/>
@@ -299,9 +301,33 @@ public class VectorDrawable extends Drawable {
final long colorFilterNativeInstance = colorFilter == null ? 0 :
colorFilter.native_instance;
boolean canReuseCache = mVectorState.canReuseCache();
- nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
+ int pixelCount = nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
colorFilterNativeInstance, mTmpBounds, needMirroring(),
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) {
// This VD has been used to display other VD resource content, clean up.
if (mVectorState.mRootGroup != null) {
+ // Subtract the native allocation for all the nodes.
+ VMRuntime.getRuntime().registerNativeFree(mVectorState.mRootGroup.getNativeSize());
// Remove child nodes' reference to tree
mVectorState.mRootGroup.setTree(null);
}
mVectorState.mRootGroup = new VGroup();
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.createNativeTree(mVectorState.mRootGroup);
@@ -558,6 +589,7 @@ public class VectorDrawable extends Drawable {
state.mCacheDirty = true;
inflateChildElements(r, parser, attrs, theme);
+ state.onTreeConstructionFinished();
// Update local properties.
updateLocalState(r);
}
@@ -750,6 +782,16 @@ public class VectorDrawable extends Drawable {
boolean mCachedAutoMirrored;
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.
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
@@ -771,12 +813,20 @@ public class VectorDrawable extends Drawable {
if (copy.mRootName != null) {
mVGTargetsMap.put(copy.mRootName, this);
}
+ onTreeConstructionFinished();
}
}
private void createNativeTree(VGroup rootGroup) {
mNativeTree = new VirtualRefBasePtr(nCreateTree(rootGroup.mNativePtr));
+ // Register tree size
+ VMRuntime.getRuntime().registerNativeAllocation(NATIVE_ALLOCATION_SIZE);
+ }
+
+ void onTreeConstructionFinished() {
mRootGroup.setTree(mNativeTree);
+ mAllocationOfAllNodes = mRootGroup.getNativeSize();
+ VMRuntime.getRuntime().registerNativeAllocation(mAllocationOfAllNodes);
}
long getNativeRenderer() {
@@ -881,6 +931,14 @@ public class VectorDrawable extends Drawable {
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
* has changed.
@@ -905,6 +963,8 @@ public class VectorDrawable extends Drawable {
private static final int TRANSLATE_Y_INDEX = 6;
private static final int TRANSFORM_PROPERTY_COUNT = 7;
+ private static final int NATIVE_ALLOCATION_SIZE = 100;
+
private static final HashMap<String, Integer> sPropertyMap =
new HashMap<String, Integer>() {
{
@@ -1073,6 +1133,16 @@ public class VectorDrawable extends Drawable {
}
@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
public boolean canApplyTheme() {
if (mThemeAttrs != null) {
return true;
@@ -1240,6 +1310,7 @@ public class VectorDrawable extends Drawable {
*/
private static class VClipPath extends VPath {
private final long mNativePtr;
+ private static final int NATIVE_ALLOCATION_SIZE = 120;
public VClipPath() {
mNativePtr = nCreateClipPath();
@@ -1283,6 +1354,11 @@ public class VectorDrawable extends Drawable {
return false;
}
+ @Override
+ int getNativeSize() {
+ return NATIVE_ALLOCATION_SIZE;
+ }
+
private void updateStateFromTypedArray(TypedArray a) {
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
@@ -1319,6 +1395,7 @@ public class VectorDrawable extends Drawable {
private static final int FILL_TYPE_INDEX = 11;
private static final int TOTAL_PROPERTY_COUNT = 12;
+ private static final int NATIVE_ALLOCATION_SIZE = 264;
// Property map for animatable attributes.
private final static HashMap<String, Integer> sPropertyMap
= new HashMap<String, Integer> () {
@@ -1396,6 +1473,11 @@ public class VectorDrawable extends Drawable {
}
@Override
+ int getNativeSize() {
+ return NATIVE_ALLOCATION_SIZE;
+ }
+
+ @Override
public long getNativePtr() {
return mNativePtr;
}
@@ -1688,6 +1770,7 @@ public class VectorDrawable extends Drawable {
abstract void applyTheme(Theme t);
abstract boolean onStateChange(int[] state);
abstract boolean isStateful();
+ abstract int getNativeSize();
}
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 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);
private static native long nCreateFullPath();
private static native long nCreateFullPath(long nativeFullPathPtr);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index ac17ed2eb735..f0348e4977ae 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -456,7 +456,7 @@ bool Group::GroupProperties::isValidProperty(int propertyId) {
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) {
// 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
@@ -478,7 +478,7 @@ void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
if (scaledWidth <= 0 || scaledHeight <= 0) {
- return;
+ return 0;
}
mStagingProperties.setScaledSize(scaledWidth, scaledHeight);
@@ -500,6 +500,7 @@ void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
mStagingProperties.setBounds(tmpBounds);
outCanvas->drawVectorDrawable(this);
outCanvas->restoreToCount(saveCount);
+ return scaledWidth * scaledHeight;
}
void Tree::drawStaging(Canvas* outCanvas) {
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 1c6f48e7276b..b33f26c1a79d 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -542,7 +542,9 @@ public:
Tree(Group* rootNode) : mRootNode(rootNode) {
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);
void drawStaging(Canvas* canvas);