Loading libs/hwui/RenderNode.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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) { Loading libs/hwui/RenderNode.h +2 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,8 @@ private: DisplayList* mDisplayList; DisplayList* mStagingDisplayList; int64_t mDamageGenerationId; friend class AnimatorManager; AnimatorManager mAnimatorManager; Loading libs/hwui/TreeInfo.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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 libs/hwui/TreeInfo.h +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java +71 −19 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading @@ -36,38 +40,86 @@ public class CustomRenderer extends Activity { getWindow().takeSurface(mSurfaceCallbacks); } private SurfaceHolder.Callback2 mSurfaceCallbacks = new SurfaceHolder.Callback2() { @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { 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 public void surfaceCreated(SurfaceHolder holder) { protected void onStop() { super.onStop(); mAnimator.end(); mAnimator = null; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mContent.setLeftTopRightBottom(0, 0, width, height); RecordingCanvas canvas = mContent.beginRecording(); 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); paint.setTextSize(Math.min(width, height) * .05f); canvas.drawText("Hello custom renderer!", width / 2, height / 2, paint); mContent.endRecording(); float textSize = Math.min(width, height) * .05f; paint.setTextSize(textSize); canvas.drawText("Hello custom renderer!", width / 2, textSize * 2, paint); mRenderer.setContentRoot(mContent); mRenderer.setSurface(holder.getSurface()); 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()) .setFrameCommitCallback(Runnable::run, () -> { Log.d("CustomRenderer", "Frame committed!"); }) .syncAndDraw(); } private SurfaceHolder.Callback2 mSurfaceCallbacks = new SurfaceHolder.Callback2() { @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { } @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { setupRoot(width, height); mRenderer.setContentRoot(mRootNode); mRenderer.setSurface(holder.getSurface()); draw(); if (!mAnimator.isStarted()) { mAnimator.start(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { mRenderer.destroy(); Loading Loading
libs/hwui/RenderNode.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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) { Loading
libs/hwui/RenderNode.h +2 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,8 @@ private: DisplayList* mDisplayList; DisplayList* mStagingDisplayList; int64_t mDamageGenerationId; friend class AnimatorManager; AnimatorManager mAnimatorManager; Loading
libs/hwui/TreeInfo.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -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
libs/hwui/TreeInfo.h +1 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
tests/HwAccelerationTest/src/com/android/test/hwui/CustomRenderer.java +71 −19 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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) { Loading @@ -36,38 +40,86 @@ public class CustomRenderer extends Activity { getWindow().takeSurface(mSurfaceCallbacks); } private SurfaceHolder.Callback2 mSurfaceCallbacks = new SurfaceHolder.Callback2() { @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { 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 public void surfaceCreated(SurfaceHolder holder) { protected void onStop() { super.onStop(); mAnimator.end(); mAnimator = null; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mContent.setLeftTopRightBottom(0, 0, width, height); RecordingCanvas canvas = mContent.beginRecording(); 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); paint.setTextSize(Math.min(width, height) * .05f); canvas.drawText("Hello custom renderer!", width / 2, height / 2, paint); mContent.endRecording(); float textSize = Math.min(width, height) * .05f; paint.setTextSize(textSize); canvas.drawText("Hello custom renderer!", width / 2, textSize * 2, paint); mRenderer.setContentRoot(mContent); mRenderer.setSurface(holder.getSurface()); 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()) .setFrameCommitCallback(Runnable::run, () -> { Log.d("CustomRenderer", "Frame committed!"); }) .syncAndDraw(); } private SurfaceHolder.Callback2 mSurfaceCallbacks = new SurfaceHolder.Callback2() { @Override public void surfaceRedrawNeeded(SurfaceHolder holder) { } @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { setupRoot(width, height); mRenderer.setContentRoot(mRootNode); mRenderer.setSurface(holder.getSurface()); draw(); if (!mAnimator.isStarted()) { mAnimator.start(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { mRenderer.destroy(); Loading