Merge "Destroy layers and flush layers cache when a window is destroyed."
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index d561484..ac0abc3 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -277,14 +277,25 @@
///////////////////////////////////////////////////////////////////////////
/**
+ * Must match Caches::FlushMode values
+ *
* @see #flushCaches(int)
*/
- public static final int FLUSH_CACHES_MODERATE = 0;
+ public static final int FLUSH_CACHES_LAYERS = 0;
+
+ /**
+ * Must match Caches::FlushMode values
+ *
+ * @see #flushCaches(int)
+ */
+ public static final int FLUSH_CACHES_MODERATE = 1;
/**
+ * Must match Caches::FlushMode values
+ *
* @see #flushCaches(int)
*/
- public static final int FLUSH_CACHES_FULL = 1;
+ public static final int FLUSH_CACHES_FULL = 2;
/**
* Flush caches to reclaim as much memory as possible. The amount of memory
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 078222b..c987f48 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -38,7 +38,7 @@
class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> {
// The recording canvas pool should be large enough to handle a deeply nested
// view hierarchy because display lists are generated recursively.
- private static final int POOL_LIMIT = 50;
+ private static final int POOL_LIMIT = 25;
private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool(
Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d2476af..5404e3a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -140,6 +140,13 @@
abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
/**
+ * Destoys the layers used by the specified view hierarchy.
+ *
+ * @param view The root of the view hierarchy
+ */
+ abstract void destroyLayers(View view);
+
+ /**
* This method should be invoked whenever the current hardware renderer
* context should be reset.
*/
@@ -622,18 +629,8 @@
+ "from multiple threads");
}
- /*
- * The window size has changed, so we need to create a new
- * surface.
- */
- if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
- /*
- * Unbind and destroy the old EGL surface, if
- * there is one.
- */
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
- }
+ // In case we need to destroy an existing surface
+ destroySurface();
// Create an EGL surface we can render into.
mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
@@ -693,15 +690,21 @@
mDestroyed = true;
- sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+ destroySurface();
- mEglSurface = null;
mGl = null;
setEnabled(false);
}
+ void destroySurface() {
+ if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+ mEglSurface = null;
+ }
+ }
+
@Override
void invalidate() {
// Cancels any existing buffer to ensure we'll get a buffer
@@ -921,6 +924,34 @@
return ((GLES20TextureLayer) layer).getSurfaceTexture();
}
+ @Override
+ void destroyLayers(View view) {
+ if (view != null && isEnabled()) {
+ checkCurrent();
+ destroyHardwareLayer(view);
+ GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+ }
+ }
+
+ private void destroyHardwareLayer(View view) {
+ view.destroyLayer();
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+
+ int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ destroyHardwareLayer(group.getChildAt(i));
+ }
+ }
+ }
+
+ static HardwareRenderer create(boolean translucent) {
+ if (GLES20Canvas.isAvailable()) {
+ return new Gl20Renderer(translucent);
+ }
+ return null;
+ }
+
static void trimMemory(int level) {
if (sEgl == null || sEglConfig == null) return;
@@ -950,12 +981,5 @@
break;
}
}
-
- static HardwareRenderer create(boolean translucent) {
- if (GLES20Canvas.isAvailable()) {
- return new Gl20Renderer(translucent);
- }
- return null;
- }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8c41b9f..5dcb84f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9230,10 +9230,7 @@
destroyDrawingCache();
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
- }
+ destroyLayer();
if (mDisplayList != null) {
mDisplayList.invalidate();
@@ -9605,21 +9602,10 @@
// Destroy any previous software drawing cache if needed
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
- }
+ destroyLayer();
// fall through - unaccelerated views may use software layer mechanism instead
case LAYER_TYPE_SOFTWARE:
- if (mDrawingCache != null) {
- mDrawingCache.recycle();
- mDrawingCache = null;
- }
-
- if (mUnscaledDrawingCache != null) {
- mUnscaledDrawingCache.recycle();
- mUnscaledDrawingCache = null;
- }
+ destroyDrawingCache();
break;
default:
break;
@@ -9745,6 +9731,13 @@
return mHardwareLayer;
}
+ void destroyLayer() {
+ if (mHardwareLayer != null) {
+ mHardwareLayer.destroy();
+ mHardwareLayer = null;
+ }
+ }
+
/**
* <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call
* to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 54e02a7..76e16a9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -541,6 +541,13 @@
}
}
+ private void destroyHardwareResources() {
+ if (mAttachInfo.mHardwareRenderer.isEnabled()) {
+ mAttachInfo.mHardwareRenderer.destroyLayers(mView);
+ }
+ mAttachInfo.mHardwareRenderer.destroy(false);
+ }
+
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -872,7 +879,7 @@
host.dispatchWindowVisibilityChanged(viewVisibility);
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
if (mAttachInfo.mHardwareRenderer != null) {
- mAttachInfo.mHardwareRenderer.destroy(false);
+ destroyHardwareResources();
}
}
if (viewVisibility == View.GONE) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 7114b6a..c5858e9 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -173,13 +173,15 @@
gradientCache.clear();
// fall through
case kFlushMode_Moderate:
- layerCache.clear();
pathCache.clear();
roundRectShapeCache.clear();
circleShapeCache.clear();
ovalShapeCache.clear();
rectShapeCache.clear();
arcShapeCache.clear();
+ // fall through
+ case kFlushMode_Layers:
+ layerCache.clear();
break;
}
}
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 76dff4b..cdcbf21 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -101,7 +101,8 @@
public:
enum FlushMode {
- kFlushMode_Moderate = 0,
+ kFlushMode_Layers = 0,
+ kFlushMode_Moderate,
kFlushMode_Full
};
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 8157631..a3d346d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -37,7 +37,7 @@
// Defines
///////////////////////////////////////////////////////////////////////////////
-#define MIN_WRITER_SIZE 16384
+#define MIN_WRITER_SIZE 4096
// Debug
#if DEBUG_DISPLAY_LIST