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
This commit is contained in:
Stan Iliev
2016-10-13 17:07:09 -04:00
parent 5d2f4b7643
commit c0e7a90f1f
7 changed files with 43 additions and 19 deletions

View File

@@ -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

View File

@@ -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<jlong>(Canvas::create_recording_canvas(width, height));
jlong renderNodePtr, jint width, jint height) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
return reinterpret_cast<jlong>(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<Canvas*>(canvasPtr);
canvas->resetRecording(width, height);
RenderNode* renderNode = reinterpret_cast<RenderNode*>(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 },

View File

@@ -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();

View File

@@ -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

View File

@@ -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");
}

View File

@@ -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);
}

View File

@@ -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;