From 0a97330b98dd633b58dcfff405d94476c89e867d Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 16 Jul 2014 13:29:45 -0700 Subject: [PATCH] Fix root RenderNode damage calculation Bug: 15888445 Change-Id: I281ec9271c9889673dcdfcb6d31e341a7b47b7de --- core/java/android/view/HardwareRenderer.java | 6 +++ core/java/android/view/ThreadedRenderer.java | 46 ++++++++++++-------- core/java/android/view/ViewRootImpl.java | 11 ++++- core/jni/android_view_ThreadedRenderer.cpp | 7 --- libs/hwui/RenderNode.h | 4 +- libs/hwui/renderthread/CanvasContext.cpp | 5 +++ 6 files changed, 50 insertions(+), 29 deletions(-) diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index f2f363a0353f4..8c9b819f64501 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -326,6 +326,12 @@ public abstract class HardwareRenderer { void onHardwarePostDraw(HardwareCanvas canvas); } + /** + * 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. * diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index fb8ce15393891..120c036e7b67b 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -93,6 +93,7 @@ public class ThreadedRenderer extends HardwareRenderer { 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 @@ public class ThreadedRenderer extends HardwareRenderer { 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 b554548e0232f..341419c050a37 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2440,8 +2440,11 @@ public final class ViewRootImpl implements ViewParent, 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 @@ public final class ViewRootImpl implements ViewParent, // 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 aab48b3155f4b..988d461d0598d 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -138,13 +138,6 @@ public: } } -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 mLooper; std::vector mOnFinishedEvents; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 54fa143f9aa8d..8cc65b27f4ce0 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -173,9 +173,6 @@ public: // UI thread only! ANDROID_API void addAnimator(const sp& animator); -protected: - virtual void damageSelf(TreeInfo& info); - private: typedef key_value_pair_t ZDrawRenderNodeOpPair; @@ -250,6 +247,7 @@ private: 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 57279b778d92b..a4ac2620fdf0a 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -185,6 +185,11 @@ void CanvasContext::draw() { } 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); }