From c0e7a90f1f5f98e85dbeda021fac0dff79725933 Mon Sep 17 00:00:00 2001 From: Stan Iliev Date: Thu, 13 Oct 2016 17:07:09 -0400 Subject: [PATCH] Initial refactoring to enable reuse of SkiaDisplayList on a per RenderNode basis. With Skia renderer we see 30% speed improvement in Invalidate Tree UI Jank test, when SkiaDisplayList objects are reused. Test: manually built and run on angler-eng. Change-Id: Ie4ec50ddb2015150e3ec678dde7ebed0c8d90067 --- core/java/android/view/DisplayListCanvas.java | 14 ++++++----- core/jni/android_view_DisplayListCanvas.cpp | 14 ++++++----- libs/hwui/RecordingCanvas.cpp | 2 +- libs/hwui/RecordingCanvas.h | 2 +- libs/hwui/SkiaCanvas.h | 3 ++- libs/hwui/hwui/Canvas.cpp | 3 ++- libs/hwui/hwui/Canvas.h | 24 ++++++++++++++++--- 7 files changed, 43 insertions(+), 19 deletions(-) diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java index 872303a69a506..f88a9b5e17086 100644 --- a/core/java/android/view/DisplayListCanvas.java +++ b/core/java/android/view/DisplayListCanvas.java @@ -52,9 +52,10 @@ public class DisplayListCanvas extends Canvas { if (node == null) throw new IllegalArgumentException("node cannot be null"); DisplayListCanvas canvas = sPool.acquire(); if (canvas == null) { - canvas = new DisplayListCanvas(width, height); + canvas = new DisplayListCanvas(node, width, height); } else { - nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, width, height); + nResetDisplayListCanvas(canvas.mNativeCanvasWrapper, node.mNativeRenderNode, + width, height); } canvas.mNode = node; canvas.mWidth = width; @@ -80,8 +81,8 @@ public class DisplayListCanvas extends Canvas { // Constructors /////////////////////////////////////////////////////////////////////////// - private DisplayListCanvas(int width, int height) { - super(nCreateDisplayListCanvas(width, height)); + private DisplayListCanvas(@NonNull RenderNode node, int width, int height) { + super(nCreateDisplayListCanvas(node.mNativeRenderNode, width, height)); mDensity = 0; // disable bitmap density scaling } @@ -231,9 +232,10 @@ public class DisplayListCanvas extends Canvas { } @FastNative - private static native long nCreateDisplayListCanvas(int width, int height); + private static native long nCreateDisplayListCanvas(long node, int width, int height); @FastNative - private static native void nResetDisplayListCanvas(long canvas, int width, int height); + private static native void nResetDisplayListCanvas(long canvas, long node, + int width, int height); @FastNative private static native int nGetMaximumTextureWidth(); @FastNative diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp index 8d2a058ecc58b..74c073f84165c 100644 --- a/core/jni/android_view_DisplayListCanvas.cpp +++ b/core/jni/android_view_DisplayListCanvas.cpp @@ -169,14 +169,16 @@ static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env, } static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz, - jint width, jint height) { - return reinterpret_cast(Canvas::create_recording_canvas(width, height)); + jlong renderNodePtr, jint width, jint height) { + RenderNode* renderNode = reinterpret_cast(renderNodePtr); + return reinterpret_cast(Canvas::create_recording_canvas(width, height, renderNode)); } static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz, - jlong canvasPtr, jint width, jint height) { + jlong canvasPtr, jlong renderNodePtr, jint width, jint height) { Canvas* canvas = reinterpret_cast(canvasPtr); - canvas->resetRecording(width, height); + RenderNode* renderNode = reinterpret_cast(renderNodePtr); + canvas->resetRecording(width, height, renderNode); } @@ -229,8 +231,8 @@ static JNINativeMethod gMethods[] = { { "nFinishRecording", "(J)J", (void*) android_view_DisplayListCanvas_finishRecording }, { "nDrawRenderNode", "(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode }, - { "nCreateDisplayListCanvas", "(II)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas }, - { "nResetDisplayListCanvas", "(JII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas }, + { "nCreateDisplayListCanvas", "(JII)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas }, + { "nResetDisplayListCanvas", "(JJII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas }, { "nDrawLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawLayer }, diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 27e6a12fb59e8..826194e0eee78 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -36,7 +36,7 @@ RecordingCanvas::~RecordingCanvas() { "Destroyed a RecordingCanvas during a record!"); } -void RecordingCanvas::resetRecording(int width, int height) { +void RecordingCanvas::resetRecording(int width, int height, RenderNode* node) { LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!"); mDisplayList = new DisplayList(); diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index efa6b915ac7a4..1742232190818 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -50,7 +50,7 @@ public: RecordingCanvas(size_t width, size_t height); virtual ~RecordingCanvas(); - virtual void resetRecording(int width, int height) override; + virtual void resetRecording(int width, int height, RenderNode* node = nullptr) override; virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override; // ---------------------------------------------------------------------------- // MISC HWUI OPERATIONS - TODO: CATEGORIZE diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h index 0e506f4d9412d..a97e7a87a3ed9 100644 --- a/libs/hwui/SkiaCanvas.h +++ b/libs/hwui/SkiaCanvas.h @@ -48,7 +48,8 @@ public: return mCanvas.get(); } - virtual void resetRecording(int width, int height) override { + virtual void resetRecording(int width, int height, + uirenderer::RenderNode* renderNode) override { LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas"); } diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index b18e7942d142f..1ea8bd2fcdbfe 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -17,6 +17,7 @@ #include "Canvas.h" #include "RecordingCanvas.h" +#include "RenderNode.h" #include "MinikinUtils.h" #include "Paint.h" #include "Typeface.h" @@ -25,7 +26,7 @@ namespace android { -Canvas* Canvas::create_recording_canvas(int width, int height) { +Canvas* Canvas::create_recording_canvas(int width, int height, uirenderer::RenderNode* renderNode) { return new uirenderer::RecordingCanvas(width, height); } diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index d76143bf999c3..74bf1822d17c9 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -74,7 +74,23 @@ public: static Canvas* create_canvas(const SkBitmap& bitmap); - static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height); + /** + * Create a new Canvas object that records view system drawing operations for deferred + * rendering. A canvas returned by this call supports calls to the resetRecording(...) and + * finishRecording() calls. The latter call returns a DisplayList that is specific to the + * RenderPipeline defined by Properties::getRenderPipelineType(). + * + * @param width of the requested Canvas. + * @param height of the requested Canvas. + * @param renderNode is an optional parameter that specifies the node that will consume the + * DisplayList produced by the returned Canvas. This enables the reuse of select C++ + * objects as a speed optimization. + * @return new non-null Canvas Object. The type of DisplayList produced by this canvas is + determined based on Properties::getRenderPipelineType(). + * + */ + static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height, + uirenderer::RenderNode* renderNode = nullptr); /** * Create a new Canvas object which delegates to an SkCanvas. @@ -83,7 +99,8 @@ public: * delegated to this object. This function will call ref() on the * SkCanvas, and the returned Canvas will unref() it upon * destruction. - * @return new Canvas object. Will not return NULL. + * @return new non-null Canvas Object. The type of DisplayList produced by this canvas is + * determined based on Properties::getRenderPipelineType(). */ static Canvas* create_canvas(SkCanvas* skiaCanvas); @@ -112,7 +129,8 @@ public: // View System operations (not exposed in public Canvas API) // ---------------------------------------------------------------------------- - virtual void resetRecording(int width, int height) = 0; + virtual void resetRecording(int width, int height, + uirenderer::RenderNode* renderNode = nullptr) = 0; virtual uirenderer::DisplayList* finishRecording() = 0; virtual void insertReorderBarrier(bool enableReorder) = 0;