Fix damage tracking for RenderNode drawn twice
Bug: 127866048 Test: CustomRenderer demo Change-Id: I431a7284b1d0a026e06500a78f41830a268235a5
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -255,6 +255,8 @@ private:
|
||||
DisplayList* mDisplayList;
|
||||
DisplayList* mStagingDisplayList;
|
||||
|
||||
int64_t mDamageGenerationId;
|
||||
|
||||
friend class AnimatorManager;
|
||||
AnimatorManager mAnimatorManager;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
setupRoot(width, height);
|
||||
|
||||
mRenderer.setContentRoot(mContent);
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user