Fix root RenderNode damage calculation
Bug: 15888445
Change-Id: I281ec9271c9889673dcdfcb6d31e341a7b47b7de
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f2f363a..8c9b819 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -327,6 +327,12 @@
}
/**
+ * Indicates that the content drawn by HardwareDrawCallbacks needs to
+ * be updated, which will be done by the next call to draw()
+ */
+ abstract void invalidateRoot();
+
+ /**
* Draws the specified view.
*
* @param view The view to draw.
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index fb8ce15..120c036 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -93,6 +93,7 @@
private RenderNode mRootNode;
private Choreographer mChoreographer;
private boolean mProfilingEnabled;
+ private boolean mRootNodeNeedsUpdate;
ThreadedRenderer(Context context, boolean translucent) {
final TypedArray a = context.obtainStyledAttributes(
@@ -247,30 +248,41 @@
return changed;
}
- private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
+ private void updateViewTreeDisplayList(View view) {
view.mPrivateFlags |= View.PFLAG_DRAWN;
-
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
== View.PFLAG_INVALIDATED;
view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
-
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
- HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
- try {
- canvas.save();
- canvas.translate(mInsetLeft, mInsetTop);
- callbacks.onHardwarePreDraw(canvas);
- canvas.drawRenderNode(view.getDisplayList());
- callbacks.onHardwarePostDraw(canvas);
- canvas.restore();
- } finally {
- mRootNode.end(canvas);
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
-
+ view.getDisplayList();
view.mRecreateDisplayList = false;
}
+ private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
+ updateViewTreeDisplayList(view);
+
+ if (mRootNodeNeedsUpdate || !mRootNode.isValid()) {
+ HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight);
+ try {
+ canvas.save();
+ canvas.translate(mInsetLeft, mInsetTop);
+ callbacks.onHardwarePreDraw(canvas);
+ canvas.drawRenderNode(view.getDisplayList());
+ callbacks.onHardwarePostDraw(canvas);
+ canvas.restore();
+ mRootNodeNeedsUpdate = false;
+ } finally {
+ mRootNode.end(canvas);
+ }
+ }
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+
+ @Override
+ void invalidateRoot() {
+ mRootNodeNeedsUpdate = true;
+ }
+
@Override
void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
attachInfo.mIgnoreDirtyState = true;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b554548..341419c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2440,8 +2440,11 @@
if (attachInfo.mHardwareRenderer != null && attachInfo.mHardwareRenderer.isEnabled()) {
// Draw with hardware renderer.
mIsAnimating = false;
- mHardwareYOffset = yOffset;
- mHardwareXOffset = xOffset;
+ if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {
+ mHardwareYOffset = yOffset;
+ mHardwareXOffset = xOffset;
+ mAttachInfo.mHardwareRenderer.invalidateRoot();
+ }
mResizeAlpha = resizeAlpha;
dirty.setEmpty();
@@ -2827,6 +2830,10 @@
// Set the new focus host and node.
mAccessibilityFocusedHost = view;
mAccessibilityFocusedVirtualView = node;
+
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.invalidateRoot();
+ }
}
@Override
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index aab48b3..988d461 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -138,13 +138,6 @@
}
}
-protected:
- virtual void damageSelf(TreeInfo& info) {
- // Intentionally a no-op. As RootRenderNode gets a new DisplayListData
- // every frame this would result in every draw push being a full inval,
- // which is wrong. Only RootRenderNode has this issue.
- }
-
private:
sp<Looper> mLooper;
std::vector<OnFinishedEvent> mOnFinishedEvents;
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 54fa143..8cc65b2 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -173,9 +173,6 @@
// UI thread only!
ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
-protected:
- virtual void damageSelf(TreeInfo& info);
-
private:
typedef key_value_pair_t<float, DrawRenderNodeOp*> ZDrawRenderNodeOpPair;
@@ -250,6 +247,7 @@
void prepareLayer(TreeInfo& info);
void pushLayerUpdate(TreeInfo& info);
void deleteDisplayListData();
+ void damageSelf(TreeInfo& info);
void incParentRefCount() { mParentCount++; }
void decParentRefCount();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 57279b7..a4ac262 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -185,6 +185,11 @@
} else if (!mDirtyRegionsEnabled || mHaveNewSurface) {
dirty.setEmpty();
} else {
+ if (!dirty.intersect(0, 0, width, height)) {
+ ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
+ SK_RECT_ARGS(dirty), width, height);
+ dirty.setEmpty();
+ }
profiler().unionDirty(&dirty);
}