Add display lists caching.
Change-Id: Iac3a248a81ed8cb076a83ef9d186b8ebba685b4c
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
new file mode 100644
index 0000000..b1160f0
--- /dev/null
+++ b/core/java/android/view/DisplayList.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * A display lists records a series of graphics related operation and can replay
+ * them later. Display lists are usually built by recording operations on a
+ * {@link android.graphics.Canvas}. Replaying the operations from a display list
+ * avoids executing views drawing code on every frame, and is thus much more
+ * efficient.
+ */
+abstract class DisplayList {
+ /**
+ * Starts recording the display list. All operations performed on the
+ * returned canvas are recorded and stored in this display list.
+ *
+ * @return A canvas to record drawing operations.
+ */
+ abstract HardwareCanvas start();
+
+ /**
+ * Ends the recording for this display list. A display list cannot be
+ * replayed if recording is not finished.
+ */
+ abstract void end();
+
+ /**
+ * Frees resources taken by this display list. This method must be called
+ * before releasing all references.
+ */
+ abstract void destroy();
+
+ /**
+ * Indicates whether this display list can be replayed or not.
+ *
+ * @return True if the display list can be replayed, false otherwise.
+ *
+ * @see android.view.HardwareCanvas#drawDisplayList(DisplayList)
+ */
+ abstract boolean isReady();
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index f917001..f0b00dd 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -35,14 +35,10 @@
import android.text.SpannedString;
import android.text.TextUtils;
-import javax.microedition.khronos.opengles.GL;
-
/**
* An implementation of Canvas on top of OpenGL ES 2.0.
*/
-class GLES20Canvas extends Canvas {
- @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
- private final GL mGl;
+class GLES20Canvas extends HardwareCanvas {
private final boolean mOpaque;
private int mRenderer;
@@ -72,27 +68,29 @@
///////////////////////////////////////////////////////////////////////////
// Constructors
///////////////////////////////////////////////////////////////////////////
+
+ GLES20Canvas(boolean translucent) {
+ this(false, translucent);
+ }
- GLES20Canvas(GL gl, boolean translucent) {
- mGl = gl;
+ GLES20Canvas(boolean record, boolean translucent) {
mOpaque = !translucent;
- mRenderer = nCreateRenderer();
+ if (record) {
+ mRenderer = nCreateDisplayListRenderer();
+ } else {
+ mRenderer = nCreateRenderer();
+ }
+
if (mRenderer == 0) {
throw new IllegalStateException("Could not create GLES20Canvas renderer");
}
}
-
- private native int nCreateRenderer();
- /**
- * This method <strong>must</strong> be called before releasing a
- * reference to a GLES20Canvas. This method is responsible for freeing
- * native resources associated with the hardware. Not invoking this
- * method properly can result in memory leaks.
- *
- * @hide
- */
+ private native int nCreateRenderer();
+ private native int nCreateDisplayListRenderer();
+
+ @Override
public synchronized void destroy() {
if (mRenderer != 0) {
nDestroyRenderer(mRenderer);
@@ -105,16 +103,6 @@
///////////////////////////////////////////////////////////////////////////
// Canvas management
///////////////////////////////////////////////////////////////////////////
-
- @Override
- public boolean isHardwareAccelerated() {
- return true;
- }
-
- @Override
- public void setBitmap(Bitmap bitmap) {
- throw new UnsupportedOperationException();
- }
@Override
public boolean isOpaque() {
@@ -145,12 +133,14 @@
private native void nSetViewport(int renderer, int width, int height);
+ @Override
void onPreDraw() {
nPrepare(mRenderer);
}
private native void nPrepare(int renderer);
+ @Override
void onPostDraw() {
nFinish(mRenderer);
}
@@ -177,6 +167,29 @@
}
private native void nReleaseContext(int renderer);
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Display list
+ ///////////////////////////////////////////////////////////////////////////
+
+ int getDisplayList() {
+ return nCreateDisplayList(mRenderer);
+ }
+
+ private native int nCreateDisplayList(int renderer);
+
+ void destroyDisplayList(int displayList) {
+ nDestroyDisplayList(displayList);
+ }
+
+ private native void nDestroyDisplayList(int displayList);
+
+ @Override
+ public void drawDisplayList(DisplayList displayList) {
+ nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+ }
+
+ private native void nDrawDisplayList(int renderer, int displayList);
///////////////////////////////////////////////////////////////////////////
// Clipping
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
new file mode 100644
index 0000000..2886bf3
--- /dev/null
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * An implementation of display list for OpenGL ES 2.0.
+ */
+class GLES20DisplayList extends DisplayList {
+ private GLES20Canvas mCanvas;
+
+ private boolean mStarted = false;
+ private boolean mRecorded = false;
+
+ int mNativeDisplayList;
+
+ @Override
+ HardwareCanvas start() {
+ if (mStarted) {
+ throw new IllegalStateException("Recording has already started");
+ }
+
+ destroyCanvas();
+
+ mCanvas = new GLES20Canvas(true, true);
+ mStarted = true;
+ mRecorded = false;
+
+ return mCanvas;
+ }
+
+ private void destroyCanvas() {
+ if (mCanvas != null) {
+ mCanvas.destroyDisplayList(mNativeDisplayList);
+ mCanvas.destroy();
+
+ mCanvas = null;
+ mNativeDisplayList = 0;
+ }
+ }
+
+ @Override
+ void end() {
+ if (mCanvas != null) {
+ mStarted = false;
+ mRecorded = true;
+
+ mNativeDisplayList = mCanvas.getDisplayList();
+ }
+ }
+
+ @Override
+ void destroy() {
+ destroyCanvas();
+ }
+
+ @Override
+ boolean isReady() {
+ return !mStarted && mRecorded;
+ }
+}
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
new file mode 100644
index 0000000..22d2fe6
--- /dev/null
+++ b/core/java/android/view/HardwareCanvas.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+
+/**
+ * Hardware accelerated canvas.
+ */
+abstract class HardwareCanvas extends Canvas {
+ @Override
+ public boolean isHardwareAccelerated() {
+ return true;
+ }
+
+ @Override
+ public void setBitmap(Bitmap bitmap) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * This method <strong>must</strong> be called before releasing a
+ * reference to a hardware canvas. This method is responsible for
+ * freeing native resources associated with the hardware. Not
+ * invoking this method properly can result in memory leaks.
+ */
+ public abstract void destroy();
+
+ /**
+ * Invoked before any drawing operation is performed in this canvas.
+ */
+ abstract void onPreDraw();
+
+ /**
+ * Invoked after all drawing operation have been performed.
+ */
+ abstract void onPostDraw();
+
+ /**
+ * Draws the specified display list onto this canvas.
+ *
+ * @param displayList The display list to replay.
+ */
+ public abstract void drawDisplayList(DisplayList displayList);
+}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index fbb13af..2cc4052 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -103,6 +103,14 @@
abstract void draw(View view, View.AttachInfo attachInfo, int yOffset);
/**
+ * Creates a new canvas that can be used to record drawing operations
+ * in the specified display list.
+ *
+ * @return A new recording canvas.
+ */
+ abstract DisplayList createDisplayList();
+
+ /**
* Initializes the hardware renderer for the specified surface and setup the
* renderer for drawing, if needed. This is invoked when the ViewRoot has
* potentially lost the hardware renderer. The hardware renderer should be
@@ -577,7 +585,7 @@
@Override
GLES20Canvas createCanvas() {
- return mGlCanvas = new GLES20Canvas(mGl, true);
+ return mGlCanvas = new GLES20Canvas(true);
}
@Override
@@ -590,6 +598,11 @@
mGlCanvas.onPostDraw();
}
+ @Override
+ DisplayList createDisplayList() {
+ return new GLES20DisplayList();
+ }
+
static HardwareRenderer create(boolean translucent) {
if (GLES20Canvas.isAvailable()) {
return new Gl20Renderer(translucent);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 96066b7..3b10437 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1250,12 +1250,12 @@
*/
private static final int[][] VIEW_STATE_SETS;
- static final int VIEW_STATE_WINDOW_FOCUSED = 1<<0;
- static final int VIEW_STATE_SELECTED = 1<<1;
- static final int VIEW_STATE_FOCUSED = 1<<2;
- static final int VIEW_STATE_ENABLED = 1<<3;
- static final int VIEW_STATE_PRESSED = 1<<4;
- static final int VIEW_STATE_ACTIVATED = 1<<5;
+ static final int VIEW_STATE_WINDOW_FOCUSED = 1;
+ static final int VIEW_STATE_SELECTED = 1 << 1;
+ static final int VIEW_STATE_FOCUSED = 1 << 2;
+ static final int VIEW_STATE_ENABLED = 1 << 3;
+ static final int VIEW_STATE_PRESSED = 1 << 4;
+ static final int VIEW_STATE_ACTIVATED = 1 << 5;
static final int[] VIEW_STATE_IDS = new int[] {
R.attr.state_window_focused, VIEW_STATE_WINDOW_FOCUSED,
@@ -1268,28 +1268,23 @@
static {
int[] orderedIds = new int[VIEW_STATE_IDS.length];
- for (int i=0; i<R.styleable.ViewDrawableStates.length; i++) {
+ for (int i = 0; i < R.styleable.ViewDrawableStates.length; i++) {
int viewState = R.styleable.ViewDrawableStates[i];
- for (int j=0; j<VIEW_STATE_IDS.length; j+=2) {
+ for (int j = 0; j<VIEW_STATE_IDS.length; j += 2) {
if (VIEW_STATE_IDS[j] == viewState) {
- orderedIds[i*2] = viewState;
- orderedIds[i*2+1] = VIEW_STATE_IDS[j+1];
+ orderedIds[i * 2] = viewState;
+ orderedIds[i * 2 + 1] = VIEW_STATE_IDS[j + 1];
}
}
}
- final int NUM_BITS = VIEW_STATE_IDS.length/2;
- VIEW_STATE_SETS = new int[1<<NUM_BITS][];
- for (int i=0; i<VIEW_STATE_SETS.length; i++) {
+ final int NUM_BITS = VIEW_STATE_IDS.length / 2;
+ VIEW_STATE_SETS = new int[1 << NUM_BITS][];
+ for (int i = 0; i < VIEW_STATE_SETS.length; i++) {
int numBits = Integer.bitCount(i);
int[] set = new int[numBits];
int pos = 0;
- for (int j=0; j<orderedIds.length; j+=2) {
- if ((i&orderedIds[j+1]) != 0) {
- if (false) {
- Log.i("View", "Index #" + i + " @ ordered #" + j
- + " resid=0x" + Integer.toHexString(orderedIds[j])
- + " mask " + orderedIds[j+1]);
- }
+ for (int j = 0; j < orderedIds.length; j += 2) {
+ if ((i & orderedIds[j+1]) != 0) {
set[pos++] = orderedIds[j];
}
}
@@ -1958,6 +1953,7 @@
private Bitmap mDrawingCache;
private Bitmap mUnscaledDrawingCache;
+ private DisplayList mDisplayList;
/**
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
@@ -7317,6 +7313,64 @@
}
/**
+ * <p>Returns a display list that can be used to draw this view again
+ * without executing its draw method.</p>
+ *
+ * @return A DisplayList ready to replay, or null if caching is not enabled.
+ */
+ DisplayList getDisplayList() {
+ if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
+ return null;
+ }
+
+ if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
+ return null;
+ }
+
+ if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED &&
+ ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDisplayList == null)) {
+
+ if (mDisplayList != null) {
+ mDisplayList.destroy();
+ }
+
+ mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
+
+ final HardwareCanvas canvas = mDisplayList.start();
+ try {
+ int width = mRight - mLeft;
+ int height = mBottom - mTop;
+
+ canvas.setViewport(width, height);
+ canvas.onPreDraw();
+
+ final int restoreCount = canvas.save();
+
+ mPrivateFlags |= DRAWN;
+ mPrivateFlags |= DRAWING_CACHE_VALID;
+
+ // Fast path for layouts with no backgrounds
+ if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+ mPrivateFlags &= ~DIRTY_MASK;
+ dispatchDraw(canvas);
+ } else {
+ draw(canvas);
+ }
+
+ canvas.restoreToCount(restoreCount);
+ } finally {
+ canvas.onPostDraw();
+
+ mDisplayList.end();
+
+ canvas.destroy();
+ }
+ }
+
+ return mDisplayList;
+ }
+
+ /**
* <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
*
* @return A non-scaled bitmap representing this view or null if cache is disabled.
@@ -7383,6 +7437,10 @@
mUnscaledDrawingCache.recycle();
mUnscaledDrawingCache = null;
}
+ if (mDisplayList != null) {
+ mDisplayList.destroy();
+ mDisplayList = null;
+ }
}
/**
@@ -10167,7 +10225,8 @@
IBinder mPanelParentWindowToken;
Surface mSurface;
- boolean mHardwareAccelerated;
+ boolean mHardwareAccelerated;
+ HardwareRenderer mHardwareRenderer;
/**
* Scale factor used by the compatibility mode
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 12c49c4..570e288 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1830,8 +1830,7 @@
boolean scalingRequired = false;
boolean caching = false;
- if (!canvas.isHardwareAccelerated() &&
- (flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
+ if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
(flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
caching = true;
if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
@@ -1914,12 +1913,18 @@
final int sx = child.mScrollX;
final int sy = child.mScrollY;
+ DisplayList displayList = null;
Bitmap cache = null;
if (caching) {
- cache = child.getDrawingCache(true);
+ if (!canvas.isHardwareAccelerated()) {
+ cache = child.getDrawingCache(true);
+ } else {
+ displayList = child.getDisplayList();
+ }
}
- final boolean hasNoCache = cache == null;
+ final boolean hasDisplayList = displayList != null && displayList.isReady();
+ final boolean hasNoCache = cache == null || hasDisplayList;
final int restoreTo = canvas.save();
if (hasNoCache) {
@@ -2002,17 +2007,21 @@
}
if (hasNoCache) {
- // Fast path for layouts with no backgrounds
- if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
+ if (!hasDisplayList) {
+ // Fast path for layouts with no backgrounds
+ if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+ if (ViewDebug.TRACE_HIERARCHY) {
+ ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
+ }
+ child.mPrivateFlags &= ~DIRTY_MASK;
+ child.dispatchDraw(canvas);
+ } else {
+ child.draw(canvas);
}
- child.mPrivateFlags &= ~DIRTY_MASK;
- child.dispatchDraw(canvas);
} else {
- child.draw(canvas);
+ ((HardwareCanvas) canvas).drawDisplayList(displayList);
}
- } else {
+ } else if (cache != null) {
final Paint cachePaint = mCachePaint;
if (alpha < 1.0f) {
cachePaint.setAlpha((int) (alpha * 255));
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index f6a06ce..77ba6fe 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -196,8 +196,6 @@
int mCurScrollY;
Scroller mScroller;
- HardwareRenderer mHwRenderer;
-
final ViewConfiguration mViewConfiguration;
/**
@@ -451,10 +449,10 @@
if (attrs != null &&
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0) {
final boolean translucent = attrs.format != PixelFormat.OPAQUE;
- if (mHwRenderer != null) {
- mHwRenderer.destroy(true);
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.destroy(true);
}
- mHwRenderer = HardwareRenderer.createGlRenderer(2, translucent);
+ mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
mAttachInfo.mHardwareAccelerated = true;
}
}
@@ -663,8 +661,8 @@
attachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
- if (mHwRenderer != null) {
- mHwRenderer.destroy(false);
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.destroy(false);
}
}
if (viewVisibility == View.GONE) {
@@ -869,8 +867,8 @@
fullRedrawNeeded = true;
mPreviousTransparentRegion.setEmpty();
- if (mHwRenderer != null) {
- hwIntialized = mHwRenderer.initialize(mHolder);
+ if (mAttachInfo.mHardwareRenderer != null) {
+ hwIntialized = mAttachInfo.mHardwareRenderer.initialize(mHolder);
}
}
} else if (!mSurface.isValid()) {
@@ -948,8 +946,8 @@
}
}
- if (hwIntialized || (windowShouldResize && mHwRenderer != null)) {
- mHwRenderer.setup(mWidth, mHeight);
+ if (hwIntialized || (windowShouldResize && mAttachInfo.mHardwareRenderer != null)) {
+ mAttachInfo.mHardwareRenderer.setup(mWidth, mHeight);
}
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@@ -1262,9 +1260,9 @@
dirty.union(0, 0, (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
}
- if (mHwRenderer != null && mHwRenderer.isEnabled()) {
+ if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
if (!dirty.isEmpty()) {
- mHwRenderer.draw(mView, mAttachInfo, yoff);
+ mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, yoff);
}
if (scrolling) {
@@ -1774,8 +1772,9 @@
boolean inTouchMode = msg.arg2 != 0;
ensureTouchModeLocally(inTouchMode);
- if (mHwRenderer != null) {
- mHwRenderer.initializeIfNeeded(mWidth, mHeight, mAttachInfo, mHolder);
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
+ mAttachInfo, mHolder);
}
}
@@ -2582,9 +2581,9 @@
}
private void destroyHardwareRenderer() {
- if (mHwRenderer != null) {
- mHwRenderer.destroy(true);
- mHwRenderer = null;
+ if (mAttachInfo.mHardwareRenderer != null) {
+ mAttachInfo.mHardwareRenderer.destroy(true);
+ mAttachInfo.mHardwareRenderer = null;
mAttachInfo.mHardwareAccelerated = false;
}
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index bbf3509..cb1556b1 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -30,6 +30,7 @@
#include <SkTemplates.h>
#include <SkXfermode.h>
+#include <DisplayListRenderer.h>
#include <OpenGLDebugRenderer.h>
#include <OpenGLRenderer.h>
#include <SkiaShader.h>
@@ -378,6 +379,30 @@
env->ReleaseStringChars(text, textArray);
}
+// ----------------------------------------------------------------------------
+// Display lists
+// ----------------------------------------------------------------------------
+
+static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(
+ JNIEnv* env, jobject canvas) {
+ return new DisplayListRenderer;
+}
+
+static DisplayList* android_view_GLES20Canvas_createDisplayList(JNIEnv* env,
+ jobject canvas, DisplayListRenderer* renderer) {
+ return renderer->getDisplayList();
+}
+
+static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
+ jobject canvas, DisplayList* displayList) {
+ delete displayList;
+}
+
+static void android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
+ jobject canvas, OpenGLRenderer* renderer, DisplayList* displayList) {
+ displayList->replay(*renderer);
+}
+
#endif // USE_OPENGL_RENDERER
// ----------------------------------------------------------------------------
@@ -455,6 +480,12 @@
{ "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_getClipBounds },
+
+ { "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+ { "nCreateDisplayList", "(I)I", (void*) android_view_GLES20Canvas_createDisplayList },
+ { "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList },
+ { "nDrawDisplayList", "(II)V", (void*) android_view_GLES20Canvas_drawDisplayList },
+
#endif
};