summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2019-03-07 17:01:08 -0800
committerJohn Reck <jreck@google.com>2019-03-07 17:03:48 -0800
commitf1aa7909e6496da4a1ae9ccfcbab5db843d329c3 (patch)
tree95a611c7a0055078596c206835d426db22a4f5ee
parent4348a4d7078dd4a2d786464db170f817ee19f6b1 (diff)
Fix damage tracking for RenderNode drawn twice
Bug: 127866048 Test: CustomRenderer demo Change-Id: I431a7284b1d0a026e06500a78f41830a268235a5
-rw-r--r--libs/hwui/RenderNode.cpp7
-rw-r--r--libs/hwui/RenderNode.h2
-rw-r--r--libs/hwui/TreeInfo.cpp1
-rw-r--r--libs/hwui/TreeInfo.h1
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java90
5 files changed, 82 insertions, 19 deletions
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 1ff7ffe6bf87..e0ed3e4940a8 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -134,6 +134,7 @@ void RenderNode::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
void RenderNode::damageSelf(TreeInfo& info) {
if (isRenderable()) {
+ mDamageGenerationId = info.damageGenerationId;
if (properties().getClipDamageToBounds()) {
info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight());
} else {
@@ -199,6 +200,12 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
* stencil buffer may be needed. Views that use a functor to draw will be forced onto a layer.
*/
void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
+ if (mDamageGenerationId == info.damageGenerationId) {
+ // We hit the same node a second time in the same tree. We don't know the minimal
+ // damage rect anymore, so just push the biggest we can onto our parent's transform
+ // We push directly onto parent in case we are clipped to bounds but have moved position.
+ info.damageAccumulator->dirty(DIRTY_MIN, DIRTY_MIN, DIRTY_MAX, DIRTY_MAX);
+ }
info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 6060123ed759..23e7a0e60554 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -255,6 +255,8 @@ private:
DisplayList* mDisplayList;
DisplayList* mStagingDisplayList;
+ int64_t mDamageGenerationId;
+
friend class AnimatorManager;
AnimatorManager mAnimatorManager;
diff --git a/libs/hwui/TreeInfo.cpp b/libs/hwui/TreeInfo.cpp
index 808a12a311e2..cdad20ec6caa 100644
--- a/libs/hwui/TreeInfo.cpp
+++ b/libs/hwui/TreeInfo.cpp
@@ -24,6 +24,7 @@ TreeInfo::TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContex
: mode(mode)
, prepareTextures(mode == MODE_FULL)
, canvasContext(canvasContext)
+ , damageGenerationId(canvasContext.getFrameNumber())
, disableForceDark(canvasContext.useForceDark() ? 0 : 1) {}
} // namespace android::uirenderer
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index a0d960527ca6..04eabac395f0 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -87,6 +87,7 @@ public:
// Must not be null during actual usage
DamageAccumulator* damageAccumulator = nullptr;
+ int64_t damageGenerationId = 0;
LayerUpdateQueue* layerUpdateQueue = nullptr;
ErrorHandler* errorHandler = nullptr;
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
index fece8babb400..5ad7fb9027a2 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java
@@ -16,6 +16,7 @@
package com.android.test.hwui;
+import android.animation.ObjectAnimator;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.HardwareRenderer;
@@ -23,12 +24,15 @@ import android.graphics.Paint;
import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
import android.os.Bundle;
-import android.util.Log;
+import android.os.Handler;
import android.view.SurfaceHolder;
public class CustomRenderer extends Activity {
- private RenderNode mContent = new RenderNode("CustomRenderer");
+ private RenderNode mRootNode = new RenderNode("CustomRenderer");
+ private RenderNode mChildNode = new RenderNode("RedBox");
private HardwareRenderer mRenderer = new HardwareRenderer();
+ private ObjectAnimator mAnimator;
+ private Handler mRedrawHandler = new Handler(true);
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -36,6 +40,64 @@ public class CustomRenderer extends Activity {
getWindow().takeSurface(mSurfaceCallbacks);
}
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mAnimator = ObjectAnimator.ofFloat(mChildNode, "translationY", 0, 300);
+ mAnimator.setRepeatMode(ObjectAnimator.REVERSE);
+ mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
+ final Runnable redraw = this::draw;
+ mAnimator.addUpdateListener(animation -> {
+ mRedrawHandler.post(redraw);
+ });
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mAnimator.end();
+ mAnimator = null;
+ }
+
+ private void setupRoot(int width, int height) {
+ mRootNode.setPosition(0, 0, width, height);
+
+ RecordingCanvas canvas = mRootNode.beginRecording();
+ canvas.drawColor(Color.WHITE);
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setColor(Color.BLACK);
+ paint.setTextAlign(Paint.Align.CENTER);
+ float textSize = Math.min(width, height) * .05f;
+ paint.setTextSize(textSize);
+ canvas.drawText("Hello custom renderer!", width / 2, textSize * 2, paint);
+
+ canvas.translate(0, height / 4);
+ canvas.drawRenderNode(mChildNode);
+ canvas.translate(width / 2, 0);
+ canvas.drawRenderNode(mChildNode);
+ mRootNode.endRecording();
+
+ setupChild(width / 2, height / 2);
+ }
+
+ private void setupChild(int width, int height) {
+ mChildNode.setPosition(0, 0, width, height);
+ mChildNode.setScaleX(.5f);
+ mChildNode.setScaleY(.5f);
+
+ RecordingCanvas canvas = mChildNode.beginRecording();
+ canvas.drawColor(Color.RED);
+ mChildNode.endRecording();
+ }
+
+ private void draw() {
+ // Since we are constantly pumping frames between onStart & onStop we don't really
+ // care about any errors that may happen. They will self-correct.
+ mRenderer.createRenderRequest()
+ .setVsyncTime(System.nanoTime())
+ .syncAndDraw();
+ }
+
private SurfaceHolder.Callback2 mSurfaceCallbacks = new SurfaceHolder.Callback2() {
@Override
@@ -48,24 +110,14 @@ public class CustomRenderer extends Activity {
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- mContent.setLeftTopRightBottom(0, 0, width, height);
- RecordingCanvas canvas = mContent.beginRecording();
- canvas.drawColor(Color.WHITE);
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setColor(Color.BLACK);
- paint.setTextAlign(Paint.Align.CENTER);
- paint.setTextSize(Math.min(width, height) * .05f);
- canvas.drawText("Hello custom renderer!", width / 2, height / 2, paint);
- mContent.endRecording();
-
- mRenderer.setContentRoot(mContent);
+ setupRoot(width, height);
+
+ mRenderer.setContentRoot(mRootNode);
mRenderer.setSurface(holder.getSurface());
- mRenderer.createRenderRequest()
- .setVsyncTime(System.nanoTime())
- .setFrameCommitCallback(Runnable::run, () -> {
- Log.d("CustomRenderer", "Frame committed!");
- })
- .syncAndDraw();
+ draw();
+ if (!mAnimator.isStarted()) {
+ mAnimator.start();
+ }
}
@Override