Merge "Add display lists caching."
This commit is contained in:
55
core/java/android/view/DisplayList.java
Normal file
55
core/java/android/view/DisplayList.java
Normal file
@@ -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();
|
||||
}
|
||||
@@ -35,14 +35,10 @@ import android.text.SpannableString;
|
||||
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 @@ class GLES20Canvas extends Canvas {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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 @@ class GLES20Canvas extends Canvas {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
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 @@ class GLES20Canvas extends Canvas {
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
74
core/java/android/view/GLES20DisplayList.java
Normal file
74
core/java/android/view/GLES20DisplayList.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
60
core/java/android/view/HardwareCanvas.java
Normal file
60
core/java/android/view/HardwareCanvas.java
Normal file
@@ -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);
|
||||
}
|
||||
@@ -102,6 +102,14 @@ public abstract class HardwareRenderer {
|
||||
*/
|
||||
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
|
||||
@@ -577,7 +585,7 @@ public abstract class HardwareRenderer {
|
||||
|
||||
@Override
|
||||
GLES20Canvas createCanvas() {
|
||||
return mGlCanvas = new GLES20Canvas(mGl, true);
|
||||
return mGlCanvas = new GLES20Canvas(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -590,6 +598,11 @@ public abstract class HardwareRenderer {
|
||||
mGlCanvas.onPostDraw();
|
||||
}
|
||||
|
||||
@Override
|
||||
DisplayList createDisplayList() {
|
||||
return new GLES20DisplayList();
|
||||
}
|
||||
|
||||
static HardwareRenderer create(boolean translucent) {
|
||||
if (GLES20Canvas.isAvailable()) {
|
||||
return new Gl20Renderer(translucent);
|
||||
|
||||
@@ -1250,12 +1250,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
*/
|
||||
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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
|
||||
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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
|
||||
private Bitmap mDrawingCache;
|
||||
private Bitmap mUnscaledDrawingCache;
|
||||
private DisplayList mDisplayList;
|
||||
|
||||
/**
|
||||
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
|
||||
@@ -7316,6 +7312,64 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* <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>
|
||||
*
|
||||
@@ -7383,6 +7437,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
mUnscaledDrawingCache.recycle();
|
||||
mUnscaledDrawingCache = null;
|
||||
}
|
||||
if (mDisplayList != null) {
|
||||
mDisplayList.destroy();
|
||||
mDisplayList = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -10167,7 +10225,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
|
||||
IBinder mPanelParentWindowToken;
|
||||
Surface mSurface;
|
||||
|
||||
boolean mHardwareAccelerated;
|
||||
boolean mHardwareAccelerated;
|
||||
HardwareRenderer mHardwareRenderer;
|
||||
|
||||
/**
|
||||
* Scale factor used by the compatibility mode
|
||||
|
||||
@@ -1830,8 +1830,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
|
||||
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 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
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 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
@@ -196,8 +196,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
int mCurScrollY;
|
||||
Scroller mScroller;
|
||||
|
||||
HardwareRenderer mHwRenderer;
|
||||
|
||||
final ViewConfiguration mViewConfiguration;
|
||||
|
||||
/**
|
||||
@@ -451,10 +449,10 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
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 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
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 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
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 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
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 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
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 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 @@ static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject canvas,
|
||||
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 @@ static JNINativeMethod gMethods[] = {
|
||||
|
||||
{ "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
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,229 @@
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Display list
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DisplayList::DisplayList(const DisplayListRenderer& recorder) {
|
||||
const SkWriter32& writer = recorder.writeStream();
|
||||
init();
|
||||
|
||||
if (writer.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = writer.size();
|
||||
void* buffer = sk_malloc_throw(size);
|
||||
writer.flatten(buffer);
|
||||
mReader.setMemory(buffer, size);
|
||||
|
||||
mRCPlayback.reset(&recorder.mRCRecorder);
|
||||
mRCPlayback.setupBuffer(mReader);
|
||||
|
||||
mTFPlayback.reset(&recorder.mTFRecorder);
|
||||
mTFPlayback.setupBuffer(mReader);
|
||||
|
||||
const SkTDArray<const SkFlatBitmap*>& bitmaps = recorder.getBitmaps();
|
||||
mBitmapCount = bitmaps.count();
|
||||
if (mBitmapCount > 0) {
|
||||
mBitmaps = new SkBitmap[mBitmapCount];
|
||||
for (const SkFlatBitmap** flatBitmapPtr = bitmaps.begin();
|
||||
flatBitmapPtr != bitmaps.end(); flatBitmapPtr++) {
|
||||
const SkFlatBitmap* flatBitmap = *flatBitmapPtr;
|
||||
int index = flatBitmap->index() - 1;
|
||||
flatBitmap->unflatten(&mBitmaps[index], &mRCPlayback);
|
||||
}
|
||||
}
|
||||
|
||||
const SkTDArray<const SkFlatMatrix*>& matrices = recorder.getMatrices();
|
||||
mMatrixCount = matrices.count();
|
||||
if (mMatrixCount > 0) {
|
||||
mMatrices = new SkMatrix[mMatrixCount];
|
||||
for (const SkFlatMatrix** matrixPtr = matrices.begin();
|
||||
matrixPtr != matrices.end(); matrixPtr++) {
|
||||
const SkFlatMatrix* flatMatrix = *matrixPtr;
|
||||
flatMatrix->unflatten(&mMatrices[flatMatrix->index() - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
const SkTDArray<const SkFlatPaint*>& paints = recorder.getPaints();
|
||||
mPaintCount = paints.count();
|
||||
if (mPaintCount > 0) {
|
||||
mPaints = new SkPaint[mPaintCount];
|
||||
for (const SkFlatPaint** flatPaintPtr = paints.begin();
|
||||
flatPaintPtr != paints.end(); flatPaintPtr++) {
|
||||
const SkFlatPaint* flatPaint = *flatPaintPtr;
|
||||
int index = flatPaint->index() - 1;
|
||||
flatPaint->unflatten(&mPaints[index], &mRCPlayback, &mTFPlayback);
|
||||
}
|
||||
}
|
||||
|
||||
mPathHeap = recorder.mPathHeap;
|
||||
mPathHeap->safeRef();
|
||||
}
|
||||
|
||||
DisplayList::~DisplayList() {
|
||||
sk_free((void*) mReader.base());
|
||||
|
||||
Caches& caches = Caches::getInstance();
|
||||
for (int i = 0; i < mBitmapCount; i++) {
|
||||
caches.textureCache.remove(&mBitmaps[i]);
|
||||
}
|
||||
|
||||
delete[] mBitmaps;
|
||||
delete[] mMatrices;
|
||||
delete[] mPaints;
|
||||
|
||||
mPathHeap->safeUnref();
|
||||
}
|
||||
|
||||
void DisplayList::init() {
|
||||
mBitmaps = NULL;
|
||||
mMatrices = NULL;
|
||||
mPaints = NULL;
|
||||
mPathHeap = NULL;
|
||||
mBitmapCount = mMatrixCount = mPaintCount = 0;
|
||||
}
|
||||
|
||||
void DisplayList::replay(OpenGLRenderer& renderer) {
|
||||
TextContainer text;
|
||||
mReader.rewind();
|
||||
|
||||
int saveCount = renderer.getSaveCount() - 1;
|
||||
|
||||
while (!mReader.eof()) {
|
||||
switch (mReader.readInt()) {
|
||||
case AcquireContext: {
|
||||
renderer.acquireContext();
|
||||
}
|
||||
break;
|
||||
case ReleaseContext: {
|
||||
renderer.releaseContext();
|
||||
}
|
||||
break;
|
||||
case Save: {
|
||||
renderer.save(getInt());
|
||||
}
|
||||
break;
|
||||
case Restore: {
|
||||
renderer.restore();
|
||||
}
|
||||
break;
|
||||
case RestoreToCount: {
|
||||
renderer.restoreToCount(saveCount + getInt());
|
||||
}
|
||||
break;
|
||||
case SaveLayer: {
|
||||
renderer.saveLayer(getFloat(), getFloat(), getFloat(), getFloat(),
|
||||
getPaint(), getInt());
|
||||
}
|
||||
break;
|
||||
case Translate: {
|
||||
renderer.translate(getFloat(), getFloat());
|
||||
}
|
||||
break;
|
||||
case Rotate: {
|
||||
renderer.rotate(getFloat());
|
||||
}
|
||||
break;
|
||||
case Scale: {
|
||||
renderer.scale(getFloat(), getFloat());
|
||||
}
|
||||
break;
|
||||
case SetMatrix: {
|
||||
renderer.setMatrix(getMatrix());
|
||||
}
|
||||
break;
|
||||
case ConcatMatrix: {
|
||||
renderer.concatMatrix(getMatrix());
|
||||
}
|
||||
break;
|
||||
case ClipRect: {
|
||||
renderer.clipRect(getFloat(), getFloat(), getFloat(), getFloat(),
|
||||
(SkRegion::Op) getInt());
|
||||
}
|
||||
break;
|
||||
case DrawBitmap: {
|
||||
renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getPaint());
|
||||
}
|
||||
break;
|
||||
case DrawBitmapMatrix: {
|
||||
renderer.drawBitmap(getBitmap(), getMatrix(), getPaint());
|
||||
}
|
||||
break;
|
||||
case DrawBitmapRect: {
|
||||
renderer.drawBitmap(getBitmap(), getFloat(), getFloat(), getFloat(), getFloat(),
|
||||
getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
|
||||
}
|
||||
break;
|
||||
case DrawPatch: {
|
||||
int32_t* xDivs = NULL;
|
||||
int32_t* yDivs = NULL;
|
||||
uint32_t xDivsCount = 0;
|
||||
uint32_t yDivsCount = 0;
|
||||
|
||||
SkBitmap* bitmap = getBitmap();
|
||||
|
||||
xDivs = getInts(xDivsCount);
|
||||
yDivs = getInts(yDivsCount);
|
||||
|
||||
renderer.drawPatch(bitmap, xDivs, yDivs, xDivsCount, yDivsCount,
|
||||
getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
|
||||
}
|
||||
break;
|
||||
case DrawColor: {
|
||||
renderer.drawColor(getInt(), (SkXfermode::Mode) getInt());
|
||||
}
|
||||
break;
|
||||
case DrawRect: {
|
||||
renderer.drawRect(getFloat(), getFloat(), getFloat(), getFloat(), getPaint());
|
||||
}
|
||||
break;
|
||||
case DrawPath: {
|
||||
renderer.drawPath(getPath(), getPaint());
|
||||
}
|
||||
break;
|
||||
case DrawLines: {
|
||||
int count = 0;
|
||||
float* points = getFloats(count);
|
||||
renderer.drawLines(points, count, getPaint());
|
||||
}
|
||||
break;
|
||||
case DrawText: {
|
||||
getText(&text);
|
||||
renderer.drawText(text.text(), text.length(), getInt(),
|
||||
getFloat(), getFloat(), getPaint());
|
||||
}
|
||||
break;
|
||||
case ResetShader: {
|
||||
renderer.resetShader();
|
||||
}
|
||||
break;
|
||||
case SetupShader: {
|
||||
// TODO: Implement
|
||||
}
|
||||
break;
|
||||
case ResetColorFilter: {
|
||||
renderer.resetColorFilter();
|
||||
}
|
||||
break;
|
||||
case SetupColorFilter: {
|
||||
// TODO: Implement
|
||||
}
|
||||
break;
|
||||
case ResetShadow: {
|
||||
renderer.resetShadow();
|
||||
}
|
||||
break;
|
||||
case SetupShadow: {
|
||||
renderer.setupShadow(getFloat(), getFloat(), getFloat(), getInt());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Base structure
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -56,75 +279,89 @@ void DisplayListRenderer::reset() {
|
||||
// Operations
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DisplayListRenderer::setViewport(int width, int height) {
|
||||
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
void DisplayListRenderer::prepare() {
|
||||
mSnapshot = new Snapshot(mFirstSnapshot,
|
||||
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
|
||||
mSaveCount = 1;
|
||||
mSnapshot->setClip(0.0f, 0.0f, mWidth, mHeight);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::acquireContext() {
|
||||
addOp(AcquireContext);
|
||||
addOp(DisplayList::AcquireContext);
|
||||
OpenGLRenderer::acquireContext();
|
||||
}
|
||||
|
||||
void DisplayListRenderer::releaseContext() {
|
||||
addOp(ReleaseContext);
|
||||
addOp(DisplayList::ReleaseContext);
|
||||
OpenGLRenderer::releaseContext();
|
||||
}
|
||||
|
||||
int DisplayListRenderer::save(int flags) {
|
||||
addOp(Save);
|
||||
addOp(DisplayList::Save);
|
||||
addInt(flags);
|
||||
return OpenGLRenderer::save(flags);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::restore() {
|
||||
addOp(Restore);
|
||||
addOp(DisplayList::Restore);
|
||||
OpenGLRenderer::restore();
|
||||
}
|
||||
|
||||
void DisplayListRenderer::restoreToCount(int saveCount) {
|
||||
addOp(RestoreToCount);
|
||||
addOp(DisplayList::RestoreToCount);
|
||||
addInt(saveCount);
|
||||
OpenGLRenderer::restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
|
||||
const SkPaint* p, int flags) {
|
||||
addOp(SaveLayer);
|
||||
addOp(DisplayList::SaveLayer);
|
||||
addBounds(left, top, right, bottom);
|
||||
addPaint(p);
|
||||
addInt(flags);
|
||||
return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags);
|
||||
return OpenGLRenderer::save(flags);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::translate(float dx, float dy) {
|
||||
addOp(Translate);
|
||||
addOp(DisplayList::Translate);
|
||||
addPoint(dx, dy);
|
||||
OpenGLRenderer::translate(dx, dy);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::rotate(float degrees) {
|
||||
addOp(Rotate);
|
||||
addOp(DisplayList::Rotate);
|
||||
addFloat(degrees);
|
||||
OpenGLRenderer::rotate(degrees);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::scale(float sx, float sy) {
|
||||
addOp(Scale);
|
||||
addOp(DisplayList::Scale);
|
||||
addPoint(sx, sy);
|
||||
OpenGLRenderer::scale(sx, sy);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::setMatrix(SkMatrix* matrix) {
|
||||
addOp(SetMatrix);
|
||||
addOp(DisplayList::SetMatrix);
|
||||
addMatrix(matrix);
|
||||
OpenGLRenderer::setMatrix(matrix);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::concatMatrix(SkMatrix* matrix) {
|
||||
addOp(ConcatMatrix);
|
||||
addOp(DisplayList::ConcatMatrix);
|
||||
addMatrix(matrix);
|
||||
OpenGLRenderer::concatMatrix(matrix);
|
||||
}
|
||||
|
||||
bool DisplayListRenderer::clipRect(float left, float top, float right, float bottom,
|
||||
SkRegion::Op op) {
|
||||
addOp(ClipRect);
|
||||
addOp(DisplayList::ClipRect);
|
||||
addBounds(left, top, right, bottom);
|
||||
addInt(op);
|
||||
return OpenGLRenderer::clipRect(left, top, right, bottom, op);
|
||||
@@ -132,88 +369,77 @@ bool DisplayListRenderer::clipRect(float left, float top, float right, float bot
|
||||
|
||||
void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
|
||||
const SkPaint* paint) {
|
||||
addOp(DrawBitmap);
|
||||
addOp(DisplayList::DrawBitmap);
|
||||
addBitmap(bitmap);
|
||||
addPoint(left, top);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawBitmap(bitmap, left, top, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix,
|
||||
const SkPaint* paint) {
|
||||
addOp(DrawBitmapMatrix);
|
||||
addOp(DisplayList::DrawBitmapMatrix);
|
||||
addBitmap(bitmap);
|
||||
addMatrix(matrix);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawBitmap(bitmap, matrix, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
|
||||
float srcRight, float srcBottom, float dstLeft, float dstTop,
|
||||
float dstRight, float dstBottom, const SkPaint* paint) {
|
||||
addOp(DrawBitmapRect);
|
||||
addOp(DisplayList::DrawBitmapRect);
|
||||
addBitmap(bitmap);
|
||||
addBounds(srcLeft, srcTop, srcRight, srcBottom);
|
||||
addBounds(dstLeft, dstTop, dstRight, dstBottom);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
|
||||
dstLeft, dstTop, dstRight, dstBottom, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
|
||||
uint32_t width, uint32_t height, float left, float top, float right, float bottom,
|
||||
const SkPaint* paint) {
|
||||
addOp(DrawPatch);
|
||||
addOp(DisplayList::DrawPatch);
|
||||
addBitmap(bitmap);
|
||||
addInts(xDivs, width);
|
||||
addInts(yDivs, height);
|
||||
addBounds(left, top, right, bottom);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, width, height,
|
||||
left, top, right, bottom, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
|
||||
addOp(DrawColor);
|
||||
addOp(DisplayList::DrawColor);
|
||||
addInt(color);
|
||||
addInt(mode);
|
||||
OpenGLRenderer::drawColor(color, mode);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
|
||||
const SkPaint* paint) {
|
||||
addOp(DrawRect);
|
||||
addOp(DisplayList::DrawRect);
|
||||
addBounds(left, top, right, bottom);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawRect(left, top, right, bottom, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
|
||||
addOp(DrawPath);
|
||||
addOp(DisplayList::DrawPath);
|
||||
addPath(path);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawPath(path, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawLines(float* points, int count, const SkPaint* paint) {
|
||||
addOp(DrawLines);
|
||||
addOp(DisplayList::DrawLines);
|
||||
addFloats(points, count);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawLines(points, count, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
|
||||
float x, float y, SkPaint* paint) {
|
||||
addOp(DrawText);
|
||||
addOp(DisplayList::DrawText);
|
||||
addText(text, bytesCount);
|
||||
addInt(count);
|
||||
addPoint(x, y);
|
||||
addPaint(paint);
|
||||
OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint);
|
||||
}
|
||||
|
||||
void DisplayListRenderer::resetShader() {
|
||||
addOp(ResetShader);
|
||||
addOp(DisplayList::ResetShader);
|
||||
OpenGLRenderer::resetShader();
|
||||
}
|
||||
|
||||
@@ -223,7 +449,7 @@ void DisplayListRenderer::setupShader(SkiaShader* shader) {
|
||||
}
|
||||
|
||||
void DisplayListRenderer::resetColorFilter() {
|
||||
addOp(ResetColorFilter);
|
||||
addOp(DisplayList::ResetColorFilter);
|
||||
OpenGLRenderer::resetColorFilter();
|
||||
}
|
||||
|
||||
@@ -233,12 +459,12 @@ void DisplayListRenderer::setupColorFilter(SkiaColorFilter* filter) {
|
||||
}
|
||||
|
||||
void DisplayListRenderer::resetShadow() {
|
||||
addOp(ResetShadow);
|
||||
addOp(DisplayList::ResetShadow);
|
||||
OpenGLRenderer::resetShadow();
|
||||
}
|
||||
|
||||
void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
|
||||
addOp(SetupShadow);
|
||||
addOp(DisplayList::SetupShadow);
|
||||
addFloat(radius);
|
||||
addPoint(dx, dy);
|
||||
addInt(color);
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
|
||||
int count() const { return mPaths.count(); }
|
||||
|
||||
const SkPath& operator[](int index) const {
|
||||
SkPath& operator[](int index) const {
|
||||
return *mPaths[index];
|
||||
}
|
||||
|
||||
@@ -103,16 +103,18 @@ private:
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Renderer
|
||||
// Display list
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DisplayListRenderer;
|
||||
|
||||
/**
|
||||
* Records drawing commands in a display list for latter playback.
|
||||
* Replays recorded drawing commands.
|
||||
*/
|
||||
class DisplayListRenderer: public OpenGLRenderer {
|
||||
class DisplayList {
|
||||
public:
|
||||
DisplayListRenderer();
|
||||
~DisplayListRenderer();
|
||||
DisplayList(const DisplayListRenderer& recorder);
|
||||
~DisplayList();
|
||||
|
||||
enum Op {
|
||||
AcquireContext,
|
||||
@@ -121,7 +123,6 @@ public:
|
||||
Restore,
|
||||
RestoreToCount,
|
||||
SaveLayer,
|
||||
SaveLayerAlpha,
|
||||
Translate,
|
||||
Rotate,
|
||||
Scale,
|
||||
@@ -145,6 +146,109 @@ public:
|
||||
SetupShadow
|
||||
};
|
||||
|
||||
void replay(OpenGLRenderer& renderer);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
class TextContainer {
|
||||
public:
|
||||
size_t length() const {
|
||||
return mByteLength;
|
||||
}
|
||||
|
||||
const char* text() const {
|
||||
return (const char*) mText;
|
||||
}
|
||||
|
||||
size_t mByteLength;
|
||||
const char* mText;
|
||||
};
|
||||
|
||||
SkBitmap* getBitmap() {
|
||||
int index = getInt();
|
||||
return &mBitmaps[index - 1];
|
||||
}
|
||||
|
||||
inline int getIndex() {
|
||||
return mReader.readInt();
|
||||
}
|
||||
|
||||
inline int getInt() {
|
||||
return mReader.readInt();
|
||||
}
|
||||
|
||||
SkMatrix* getMatrix() {
|
||||
int index = getInt();
|
||||
if (index == 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &mMatrices[index - 1];
|
||||
}
|
||||
|
||||
SkPath* getPath() {
|
||||
return &(*mPathHeap)[getInt() - 1];
|
||||
}
|
||||
|
||||
SkPaint* getPaint() {
|
||||
int index = getInt();
|
||||
if (index == 0) {
|
||||
return NULL;
|
||||
}
|
||||
return &mPaints[index - 1];
|
||||
}
|
||||
|
||||
inline float getFloat() {
|
||||
return mReader.readScalar();
|
||||
}
|
||||
|
||||
int32_t* getInts(uint32_t& count) {
|
||||
count = getInt();
|
||||
return (int32_t*) mReader.skip(count * sizeof(int32_t));
|
||||
}
|
||||
|
||||
float* getFloats(int& count) {
|
||||
count = getInt();
|
||||
return (float*) mReader.skip(count * sizeof(float));
|
||||
}
|
||||
|
||||
void getText(TextContainer* text) {
|
||||
size_t length = text->mByteLength = getInt();
|
||||
text->mText = (const char*) mReader.skip(length);
|
||||
}
|
||||
|
||||
PathHeap* mPathHeap;
|
||||
|
||||
SkBitmap* mBitmaps;
|
||||
int mBitmapCount;
|
||||
|
||||
SkMatrix* mMatrices;
|
||||
int mMatrixCount;
|
||||
|
||||
SkPaint* mPaints;
|
||||
int mPaintCount;
|
||||
|
||||
mutable SkFlattenableReadBuffer mReader;
|
||||
|
||||
SkRefCntPlayback mRCPlayback;
|
||||
SkTypefacePlayback mTFPlayback;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Renderer
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Records drawing commands in a display list for latter playback.
|
||||
*/
|
||||
class DisplayListRenderer: public OpenGLRenderer {
|
||||
public:
|
||||
DisplayListRenderer();
|
||||
~DisplayListRenderer();
|
||||
|
||||
void setViewport(int width, int height);
|
||||
void prepare();
|
||||
|
||||
void acquireContext();
|
||||
void releaseContext();
|
||||
|
||||
@@ -189,8 +293,28 @@ public:
|
||||
|
||||
void reset();
|
||||
|
||||
DisplayList* getDisplayList() const {
|
||||
return new DisplayList(*this);
|
||||
}
|
||||
|
||||
const SkWriter32& writeStream() const {
|
||||
return mWriter;
|
||||
}
|
||||
|
||||
const SkTDArray<const SkFlatBitmap*>& getBitmaps() const {
|
||||
return mBitmaps;
|
||||
}
|
||||
|
||||
const SkTDArray<const SkFlatMatrix*>& getMatrices() const {
|
||||
return mMatrices;
|
||||
}
|
||||
|
||||
const SkTDArray<const SkFlatPaint*>& getPaints() const {
|
||||
return mPaints;
|
||||
}
|
||||
|
||||
private:
|
||||
inline void addOp(Op drawOp) {
|
||||
inline void addOp(DisplayList::Op drawOp) {
|
||||
mWriter.writeInt(drawOp);
|
||||
}
|
||||
|
||||
@@ -199,6 +323,7 @@ private:
|
||||
}
|
||||
|
||||
void addInts(const int32_t* values, uint32_t count) {
|
||||
mWriter.writeInt(count);
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
mWriter.writeInt(values[i]);
|
||||
}
|
||||
@@ -209,6 +334,7 @@ private:
|
||||
}
|
||||
|
||||
void addFloats(const float* values, int count) {
|
||||
mWriter.writeInt(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
mWriter.writeScalar(values[i]);
|
||||
}
|
||||
@@ -273,6 +399,8 @@ private:
|
||||
SkRefCntRecorder mRCRecorder;
|
||||
SkRefCntRecorder mTFRecorder;
|
||||
|
||||
friend class DisplayList;
|
||||
|
||||
}; // class DisplayListRenderer
|
||||
|
||||
}; // namespace uirenderer
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace uirenderer {
|
||||
// Renderer
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class DisplayListRenderer;
|
||||
|
||||
/**
|
||||
* OpenGL renderer used to draw accelerated 2D graphics. The API is a
|
||||
* simplified version of Skia's Canvas API.
|
||||
@@ -63,7 +65,7 @@ public:
|
||||
OpenGLRenderer();
|
||||
virtual ~OpenGLRenderer();
|
||||
|
||||
void setViewport(int width, int height);
|
||||
virtual void setViewport(int width, int height);
|
||||
|
||||
virtual void prepare();
|
||||
virtual void finish();
|
||||
@@ -428,6 +430,8 @@ private:
|
||||
// Misc
|
||||
GLint mMaxTextureSize;
|
||||
|
||||
friend class DisplayListRenderer;
|
||||
|
||||
}; // class OpenGLRenderer
|
||||
|
||||
}; // namespace uirenderer
|
||||
|
||||
Reference in New Issue
Block a user