summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chet Haase <chet@google.com> 2012-09-30 12:14:13 -0700
committer Chet Haase <chet@google.com> 2012-09-30 15:35:08 -0700
commit6a2d17f71342f981c9df1dc5beff33e30eb3ae2b (patch)
treeaaf68defc949273eccdd48aa40927fe8895ad37d
parent933a7546c857dba7704a15b7f7f7847934f14912 (diff)
Fix texture corruption
When memory gets low on a device, activities flush everything they can. Hardware-accelerated activites, such as Launcher, flush GL resources and destroy the GL context. However, some resources were still hanging around, due to deferred destruction policies (we don't delete layers until the DisplayLists they are in are finalized, to ensure we don't deref deleted objects). This meant that we were referring to obsolete GL data in these objects. in particular, it meant that we might come around later, after a new GL context was created, and delete a texture object that was incorrect. We use the layer's "texture id" to refer to the texture underlying the layer. But if there's a new GL context, then this texture ID is no longer valid, and we may be deleting the texture that a different object (layer, icon, whatever) is referring to, because the driver may return that same ID under the new GL context. The fix is to more aggressively delete things that we know will not be used again when the GL context is destroyed. In particular, we delete all resources being used by all DisplayLists at GL context destruction time. Issue #7195815 Textures corruption on all devices, in many apps Change-Id: I52d2d208173690dbb794a83402d38f14ea4c6c22
-rw-r--r--core/java/android/view/DisplayList.java7
-rw-r--r--core/java/android/view/GLES20DisplayList.java8
-rw-r--r--core/java/android/view/HardwareRenderer.java6
-rw-r--r--core/java/android/view/View.java3
-rw-r--r--core/jni/android/graphics/Canvas.cpp3
-rw-r--r--core/jni/android_view_GLES20DisplayList.cpp6
-rw-r--r--libs/hwui/Caches.cpp4
-rw-r--r--libs/hwui/DisplayListRenderer.cpp63
-rw-r--r--libs/hwui/DisplayListRenderer.h3
9 files changed, 69 insertions, 34 deletions
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index a42e15677c39..5e34a36bb52d 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -332,4 +332,11 @@ public abstract class DisplayList {
* @see View#offsetTopAndBottom(int)
*/
public abstract void offsetTopBottom(int offset);
+
+ /**
+ * Reset native resources. This is called when cleaning up the state of DisplayLists
+ * during destruction of hardware resources, to ensure that we do not hold onto
+ * obsolete resources after related resources are gone.
+ */
+ public abstract void reset();
}
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 3bdd5c054c3c..e9bd0c43976d 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -87,6 +87,13 @@ class GLES20DisplayList extends DisplayList {
}
@Override
+ public void reset() {
+ if (hasNativeDisplayList()) {
+ nReset(mFinalizer.mNativeDisplayList);
+ }
+ }
+
+ @Override
public boolean isValid() {
return mValid;
}
@@ -294,6 +301,7 @@ class GLES20DisplayList extends DisplayList {
}
}
+ private static native void nReset(int displayList);
private static native void nOffsetTopBottom(int displayList, int offset);
private static native void nOffsetLeftRight(int displayList, int offset);
private static native void nSetLeftTopRightBottom(int displayList, int left, int top,
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 28763b3c949d..99987bfd2793 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1508,6 +1508,9 @@ public abstract class HardwareRenderer {
@Override
void destroyLayers(View view) {
if (view != null && isEnabled() && checkCurrent() != SURFACE_STATE_ERROR) {
+ if (mCanvas != null) {
+ mCanvas.clearLayerUpdates();
+ }
destroyHardwareLayer(view);
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
}
@@ -1556,6 +1559,9 @@ public abstract class HardwareRenderer {
safelyRun(new Runnable() {
@Override
public void run() {
+ if (mCanvas != null) {
+ mCanvas.clearLayerUpdates();
+ }
destroyResources(view);
GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6eca8fd93ca7..4b6f4ead0e34 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12394,6 +12394,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mHardwareLayer.destroy();
mHardwareLayer = null;
+ if (mDisplayList != null) {
+ mDisplayList.reset();
+ }
invalidate(true);
invalidateParentCaches();
}
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 5c276024fcf2..2a02f7c82eba 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -931,6 +931,9 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l
SkIRect ir;
bool result = canvas->getClipBounds(&r, SkCanvas::kBW_EdgeType);
+ if (!result) {
+ r.setEmpty();
+ }
r.round(&ir);
(void)GraphicsJNI::irect_to_jrect(ir, env, bounds);
return result;
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
index b307a2f9d8f9..c5f52df5ad4e 100644
--- a/core/jni/android_view_GLES20DisplayList.cpp
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -36,6 +36,11 @@ using namespace uirenderer;
*/
#ifdef USE_OPENGL_RENDERER
+static void android_view_GLES20DisplayList_reset(JNIEnv* env,
+ jobject clazz, DisplayList* displayList) {
+ displayList->reset();
+}
+
// ----------------------------------------------------------------------------
// DisplayList view properties
// ----------------------------------------------------------------------------
@@ -185,6 +190,7 @@ const char* const kClassPathName = "android/view/GLES20DisplayList";
static JNINativeMethod gMethods[] = {
#ifdef USE_OPENGL_RENDERER
+ { "nReset", "(I)V", (void*) android_view_GLES20DisplayList_reset },
{ "nSetCaching", "(IZ)V", (void*) android_view_GLES20DisplayList_setCaching },
{ "nSetStaticMatrix", "(II)V", (void*) android_view_GLES20DisplayList_setStaticMatrix },
{ "nSetAnimationMatrix", "(II)V", (void*) android_view_GLES20DisplayList_setAnimationMatrix },
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index e44329404190..7853ae4168b9 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -268,8 +268,6 @@ void Caches::deleteDisplayListDeferred(DisplayList* displayList) {
void Caches::flush(FlushMode mode) {
FLUSH_LOGD("Flushing caches (mode %d)", mode);
- clearGarbage();
-
switch (mode) {
case kFlushMode_Full:
textureCache.clear();
@@ -293,6 +291,8 @@ void Caches::flush(FlushMode mode) {
layerCache.clear();
break;
}
+
+ clearGarbage();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index f84c84735daf..589d5c2eb985 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -105,35 +105,6 @@ DisplayList::~DisplayList() {
clearResources();
}
-void DisplayList::initProperties() {
- mLeft = 0;
- mTop = 0;
- mRight = 0;
- mBottom = 0;
- mClipChildren = true;
- mAlpha = 1;
- mMultipliedAlpha = 255;
- mHasOverlappingRendering = true;
- mTranslationX = 0;
- mTranslationY = 0;
- mRotation = 0;
- mRotationX = 0;
- mRotationY= 0;
- mScaleX = 1;
- mScaleY = 1;
- mPivotX = 0;
- mPivotY = 0;
- mCameraDistance = 0;
- mMatrixDirty = false;
- mMatrixFlags = 0;
- mPrevWidth = -1;
- mPrevHeight = -1;
- mWidth = 0;
- mHeight = 0;
- mPivotExplicitlySet = false;
- mCaching = false;
-}
-
void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
if (displayList) {
DISPLAY_LIST_LOGD("Deferring display list destruction");
@@ -215,8 +186,12 @@ void DisplayList::clearResources() {
mLayers.clear();
}
+void DisplayList::reset() {
+ clearResources();
+ init();
+}
+
void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing) {
- const SkWriter32& writer = recorder.writeStream();
if (reusing) {
// re-using display list - clear out previous allocations
@@ -224,8 +199,8 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
}
init();
- initProperties();
+ const SkWriter32& writer = recorder.writeStream();
if (writer.size() == 0) {
return;
}
@@ -303,6 +278,32 @@ void DisplayList::init() {
mSize = 0;
mIsRenderable = true;
mFunctorCount = 0;
+ mLeft = 0;
+ mTop = 0;
+ mRight = 0;
+ mBottom = 0;
+ mClipChildren = true;
+ mAlpha = 1;
+ mMultipliedAlpha = 255;
+ mHasOverlappingRendering = true;
+ mTranslationX = 0;
+ mTranslationY = 0;
+ mRotation = 0;
+ mRotationX = 0;
+ mRotationY= 0;
+ mScaleX = 1;
+ mScaleY = 1;
+ mPivotX = 0;
+ mPivotY = 0;
+ mCameraDistance = 0;
+ mMatrixDirty = false;
+ mMatrixFlags = 0;
+ mPrevWidth = -1;
+ mPrevHeight = -1;
+ mWidth = 0;
+ mHeight = 0;
+ mPivotExplicitlySet = false;
+ mCaching = false;
}
size_t DisplayList::getSize() {
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 39061f4c6c71..2610055ecd06 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -137,6 +137,8 @@ public:
void output(OpenGLRenderer& renderer, uint32_t level = 0);
+ ANDROID_API void reset();
+
void setRenderable(bool renderable) {
mIsRenderable = renderable;
}
@@ -399,7 +401,6 @@ public:
private:
void init();
- void initProperties();
void clearResources();