summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/HardwareLayer.java49
-rw-r--r--core/java/android/view/HardwareRenderer.java10
-rw-r--r--core/java/android/view/RenderNode.java14
-rw-r--r--core/java/android/view/TextureView.java10
-rw-r--r--core/java/android/view/ThreadedRenderer.java6
-rw-r--r--core/java/android/view/View.java192
-rw-r--r--core/java/android/view/ViewGroup.java16
-rw-r--r--core/java/android/view/ViewRootImpl.java119
-rw-r--r--core/jni/android_view_HardwareLayer.cpp9
-rw-r--r--core/jni/android_view_RenderNode.cpp16
-rw-r--r--libs/hwui/DamageAccumulator.cpp20
-rw-r--r--libs/hwui/DamageAccumulator.h10
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp30
-rw-r--r--libs/hwui/DeferredLayerUpdater.h8
-rw-r--r--libs/hwui/RenderNode.cpp148
-rw-r--r--libs/hwui/RenderNode.h10
-rw-r--r--libs/hwui/RenderProperties.cpp51
-rw-r--r--libs/hwui/RenderProperties.h103
-rw-r--r--libs/hwui/TreeInfo.h5
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp1
-rw-r--r--libs/hwui/renderthread/DrawFrameTask.cpp3
21 files changed, 428 insertions, 402 deletions
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index b5b9199..266a6fe 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -19,7 +19,6 @@ package android.view;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import com.android.internal.util.VirtualRefBasePtr;
@@ -34,34 +33,18 @@ import com.android.internal.util.VirtualRefBasePtr;
* @hide
*/
final class HardwareLayer {
- private static final int LAYER_TYPE_TEXTURE = 1;
- private static final int LAYER_TYPE_DISPLAY_LIST = 2;
-
private HardwareRenderer mRenderer;
private VirtualRefBasePtr mFinalizer;
- private RenderNode mDisplayList;
- private final int mLayerType;
- private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
+ private HardwareLayer(HardwareRenderer renderer, long deferredUpdater) {
if (renderer == null || deferredUpdater == 0) {
throw new IllegalArgumentException("Either hardware renderer: " + renderer
+ " or deferredUpdater: " + deferredUpdater + " is invalid");
}
mRenderer = renderer;
- mLayerType = type;
mFinalizer = new VirtualRefBasePtr(deferredUpdater);
}
- private void assertType(int type) {
- if (mLayerType != type) {
- throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
- }
- }
-
- boolean hasDisplayList() {
- return mDisplayList != null;
- }
-
/**
* Update the paint used when drawing this layer.
*
@@ -90,11 +73,6 @@ final class HardwareLayer {
// Already destroyed
return;
}
-
- if (mDisplayList != null) {
- mDisplayList.destroyDisplayListData();
- mDisplayList = null;
- }
mRenderer.onLayerDestroyed(this);
mRenderer = null;
mFinalizer.release();
@@ -105,21 +83,6 @@ final class HardwareLayer {
return mFinalizer.get();
}
- public RenderNode startRecording() {
- assertType(LAYER_TYPE_DISPLAY_LIST);
-
- if (mDisplayList == null) {
- mDisplayList = RenderNode.create("HardwareLayer");
- }
- return mDisplayList;
- }
-
- public void endRecording(Rect dirtyRect) {
- nUpdateRenderLayer(mFinalizer.get(), mDisplayList.getNativeDisplayList(),
- dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
- mRenderer.pushLayerUpdate(this);
- }
-
/**
* Copies this layer into the specified bitmap.
*
@@ -160,7 +123,6 @@ final class HardwareLayer {
* Indicates that this layer has lost its texture.
*/
public void detachSurfaceTexture(final SurfaceTexture surface) {
- assertType(LAYER_TYPE_TEXTURE);
mRenderer.safelyRun(new Runnable() {
@Override
public void run() {
@@ -177,13 +139,11 @@ final class HardwareLayer {
}
public void setSurfaceTexture(SurfaceTexture surface) {
- assertType(LAYER_TYPE_TEXTURE);
nSetSurfaceTexture(mFinalizer.get(), surface, false);
mRenderer.pushLayerUpdate(this);
}
public void updateSurfaceTexture() {
- assertType(LAYER_TYPE_TEXTURE);
nUpdateSurfaceTexture(mFinalizer.get());
mRenderer.pushLayerUpdate(this);
}
@@ -192,18 +152,13 @@ final class HardwareLayer {
* This should only be used by HardwareRenderer! Do not call directly
*/
SurfaceTexture createSurfaceTexture() {
- assertType(LAYER_TYPE_TEXTURE);
SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.get()));
nSetSurfaceTexture(mFinalizer.get(), st, true);
return st;
}
static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
- return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
- }
-
- static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
- return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
+ return new HardwareLayer(renderer, layer);
}
private static native void nOnTextureDestroyed(long layerUpdater);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 592dec8..3de8144 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -374,16 +374,6 @@ public abstract class HardwareRenderer {
abstract HardwareLayer createTextureLayer();
/**
- * Creates a new hardware layer.
- *
- * @param width The minimum width of the layer
- * @param height The minimum height of the layer
- *
- * @return A hardware layer
- */
- abstract HardwareLayer createDisplayListLayer(int width, int height);
-
- /**
* Creates a new {@link SurfaceTexture} that can be used to render into the
* specified hardware layer.
*
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index c165475..d86b699 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -19,6 +19,7 @@ package android.view;
import android.annotation.NonNull;
import android.graphics.Matrix;
import android.graphics.Outline;
+import android.graphics.Paint;
import java.util.ArrayList;
import java.util.List;
@@ -322,11 +323,13 @@ public class RenderNode {
* handled in the drawLayer operation directly (and more efficiently).
*
* @param caching true if the display list represents a hardware layer, false otherwise.
- *
- * @hide
*/
- public boolean setCaching(boolean caching) {
- return nSetCaching(mNativeRenderNode, caching);
+ public boolean setLayerType(int layerType) {
+ return nSetLayerType(mNativeRenderNode, layerType);
+ }
+
+ public boolean setLayerPaint(Paint paint) {
+ return nSetLayerPaint(mNativeRenderNode, paint != null ? paint.mNativePaint : 0);
}
/**
@@ -902,7 +905,8 @@ public class RenderNode {
private static native boolean nSetCameraDistance(long renderNode, float distance);
private static native boolean nSetPivotY(long renderNode, float pivotY);
private static native boolean nSetPivotX(long renderNode, float pivotX);
- private static native boolean nSetCaching(long renderNode, boolean caching);
+ private static native boolean nSetLayerType(long renderNode, int layerType);
+ private static native boolean nSetLayerPaint(long renderNode, long paint);
private static native boolean nSetClipToBounds(long renderNode, boolean clipToBounds);
private static native boolean nSetProjectBackwards(long renderNode, boolean shouldProject);
private static native boolean nSetProjectionReceiver(long renderNode, boolean shouldRecieve);
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 2a9f7d5..1f7eaa2 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -275,6 +275,11 @@ public class TextureView extends View {
}
}
+ @Override
+ public void setLayerPaint(Paint paint) {
+ setLayerType(/* ignored */ 0, paint);
+ }
+
/**
* Always returns {@link #LAYER_TYPE_HARDWARE}.
*/
@@ -332,11 +337,6 @@ public class TextureView extends View {
}
}
- @Override
- boolean destroyLayer(boolean valid) {
- return false;
- }
-
/**
* @hide
*/
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 7bbe84e..2bfbd65 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -257,12 +257,6 @@ public class ThreadedRenderer extends HardwareRenderer {
}
@Override
- HardwareLayer createDisplayListLayer(int width, int height) {
- long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
- return HardwareLayer.adoptDisplayListLayer(this, layer);
- }
-
- @Override
HardwareLayer createTextureLayer() {
long layer = nCreateTextureLayer(mNativeProxy);
return HardwareLayer.adoptTextureLayer(this, layer);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 434f853..f3996fb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3465,8 +3465,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
})
int mLayerType = LAYER_TYPE_NONE;
Paint mLayerPaint;
- Rect mLocalDirtyRect;
- private HardwareLayer mHardwareLayer;
/**
* Set to true when drawing cache is enabled and cannot be created.
@@ -12931,7 +12929,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
stopNestedScroll();
destroyDrawingCache();
- destroyLayer(false);
cleanupDraw();
mCurrentAnimation = null;
@@ -13409,30 +13406,32 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
+ "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE");
}
- if (layerType == mLayerType) {
+ boolean typeChanged = mRenderNode.setLayerType(layerType);
+
+ if (!typeChanged) {
setLayerPaint(paint);
return;
}
// Destroy any previous software drawing cache if needed
- switch (mLayerType) {
- case LAYER_TYPE_HARDWARE:
- destroyLayer(false);
- // fall through - non-accelerated views may use software layer mechanism instead
- case LAYER_TYPE_SOFTWARE:
- destroyDrawingCache();
- break;
- default:
- break;
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
+ destroyDrawingCache();
+ invalidateParentCaches();
+ invalidate(true);
}
mLayerType = layerType;
- final boolean layerDisabled = mLayerType == LAYER_TYPE_NONE;
+ final boolean layerDisabled = (mLayerType == LAYER_TYPE_NONE);
mLayerPaint = layerDisabled ? null : (paint == null ? new Paint() : paint);
- mLocalDirtyRect = layerDisabled ? null : new Rect();
+ mRenderNode.setLayerPaint(mLayerPaint);
- invalidateParentCaches();
- invalidate(true);
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
+ // LAYER_TYPE_SOFTWARE is handled by View:draw(), so need to invalidate()
+ invalidateParentCaches();
+ invalidate(true);
+ } else {
+ invalidateViewProperty(false, false);
+ }
}
/**
@@ -13465,11 +13464,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (layerType != LAYER_TYPE_NONE) {
mLayerPaint = paint == null ? new Paint() : paint;
if (layerType == LAYER_TYPE_HARDWARE) {
- HardwareLayer layer = getHardwareLayer();
- if (layer != null) {
- layer.setLayerPaint(mLayerPaint);
+ if (mRenderNode.setLayerPaint(mLayerPaint)) {
+ invalidateViewProperty(false, false);
}
- invalidateViewProperty(false, false);
} else {
invalidate();
}
@@ -13527,16 +13524,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
- getHardwareLayer();
- // TODO: We need a better way to handle this case
- // If views have registered pre-draw listeners they need
- // to be notified before we build the layer. Those listeners
- // may however rely on other events to happen first so we
- // cannot just invoke them here until they don't cancel the
- // current frame
- if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
- attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
- }
+ // The only part of a hardware layer we can build in response to
+ // this call is to ensure the display list is up to date.
+ // The actual rendering of the display list into the layer must
+ // be done at playback time
+ updateDisplayListIfDirty();
break;
case LAYER_TYPE_SOFTWARE:
buildDrawingCache(true);
@@ -13545,70 +13537,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * <p>Returns a hardware layer that can be used to draw this view again
- * without executing its draw method.</p>
+ * If this View draws with a HardwareLayer, returns it.
+ * Otherwise returns null
*
- * @return A HardwareLayer ready to render, or null if an error occurred.
+ * TODO: Only TextureView uses this, can we eliminate it?
*/
HardwareLayer getHardwareLayer() {
- if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null ||
- !mAttachInfo.mHardwareRenderer.isEnabled()) {
- return null;
- }
-
- final int width = mRight - mLeft;
- final int height = mBottom - mTop;
-
- if (width == 0 || height == 0) {
- return null;
- }
-
- if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
- if (mHardwareLayer == null) {
- mHardwareLayer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
- width, height);
- mLocalDirtyRect.set(0, 0, width, height);
- } else if (mHardwareLayer.isValid()) {
- // This should not be necessary but applications that change
- // the parameters of their background drawable without calling
- // this.setBackground(Drawable) can leave the view in a bad state
- // (for instance isOpaque() returns true, but the background is
- // not opaque.)
- computeOpaqueFlags();
-
- if (mHardwareLayer.prepare(width, height, isOpaque())) {
- mLocalDirtyRect.set(0, 0, width, height);
- }
- }
-
- mHardwareLayer.setLayerPaint(mLayerPaint);
- RenderNode displayList = mHardwareLayer.startRecording();
- updateDisplayListIfDirty(displayList, true);
- mHardwareLayer.endRecording(mLocalDirtyRect);
- mLocalDirtyRect.setEmpty();
- }
-
- return mHardwareLayer;
- }
-
- /**
- * Destroys this View's hardware layer if possible.
- *
- * @return True if the layer was destroyed, false otherwise.
- *
- * @see #setLayerType(int, android.graphics.Paint)
- * @see #LAYER_TYPE_HARDWARE
- */
- boolean destroyLayer(boolean valid) {
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
-
- invalidate(true);
- invalidateParentCaches();
- return true;
- }
- return false;
+ return null;
}
/**
@@ -13624,7 +13559,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
protected void destroyHardwareResources() {
resetDisplayList();
- destroyLayer(true);
}
/**
@@ -13719,20 +13653,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null);
}
- /**
- * Returns a DisplayList. If the incoming displayList is null, one will be created.
- * Otherwise, the same display list will be returned (after having been rendered into
- * along the way, depending on the invalidation state of the view).
- *
- * @param renderNode The previous version of this displayList, could be null.
- * @param isLayer Whether the requester of the display list is a layer. If so,
- * the view will avoid creating a layer inside the resulting display list.
- * @return A new or reused DisplayList object.
- */
- private void updateDisplayListIfDirty(@NonNull RenderNode renderNode, boolean isLayer) {
- if (renderNode == null) {
- throw new IllegalArgumentException("RenderNode must not be null");
- }
+ private void updateDisplayListIfDirty() {
+ final RenderNode renderNode = mRenderNode;
if (!canHaveDisplayList()) {
// can't populate RenderNode, don't try
return;
@@ -13740,11 +13662,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
|| !renderNode.isValid()
- || (!isLayer && mRecreateDisplayList)) {
+ || (mRecreateDisplayList)) {
// Don't need to recreate the display list, just need to tell our
// children to restore/recreate theirs
if (renderNode.isValid()
- && !isLayer
&& !mRecreateDisplayList) {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
@@ -13753,13 +13674,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return; // no work needed
}
- if (!isLayer) {
- // If we got here, we're recreating it. Mark it as such to ensure that
- // we copy in child display lists into ours in drawChild()
- mRecreateDisplayList = true;
- }
+ // If we got here, we're recreating it. Mark it as such to ensure that
+ // we copy in child display lists into ours in drawChild()
+ mRecreateDisplayList = true;
- boolean caching = false;
int width = mRight - mLeft;
int height = mBottom - mTop;
int layerType = getLayerType();
@@ -13767,34 +13685,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
final HardwareCanvas canvas = renderNode.start(width, height);
try {
- if (!isLayer && layerType != LAYER_TYPE_NONE) {
- if (layerType == LAYER_TYPE_HARDWARE) {
- final HardwareLayer layer = getHardwareLayer();
- if (layer != null && layer.isValid()) {
- canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
- } else {
- canvas.saveLayer(0, 0, mRight - mLeft, mBottom - mTop, mLayerPaint,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
- Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- }
- caching = true;
- } else {
- buildDrawingCache(true);
- Bitmap cache = getDrawingCache(true);
- if (cache != null) {
- canvas.drawBitmap(cache, 0, 0, mLayerPaint);
- caching = true;
- }
+ final HardwareLayer layer = getHardwareLayer();
+ if (layer != null && layer.isValid()) {
+ canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
+ } else if (layerType == LAYER_TYPE_SOFTWARE) {
+ buildDrawingCache(true);
+ Bitmap cache = getDrawingCache(true);
+ if (cache != null) {
+ canvas.drawBitmap(cache, 0, 0, mLayerPaint);
}
} else {
-
computeScroll();
canvas.translate(-mScrollX, -mScrollY);
- if (!isLayer) {
- mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- }
+ mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+ mPrivateFlags &= ~PFLAG_DIRTY_MASK;
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
@@ -13808,14 +13713,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
} finally {
renderNode.end(canvas);
- renderNode.setCaching(caching);
- if (isLayer) {
- renderNode.setLeftTopRightBottom(0, 0, width, height);
- } else {
- setDisplayListProperties(renderNode);
- }
+ setDisplayListProperties(renderNode);
}
- } else if (!isLayer) {
+ } else {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
}
@@ -13830,7 +13730,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public RenderNode getDisplayList() {
- updateDisplayListIfDirty(mRenderNode, false);
+ updateDisplayListIfDirty();
return mRenderNode;
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2905851..21b266e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4386,10 +4386,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Make sure we do not set both flags at the same time
int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
- if (child.mLayerType != LAYER_TYPE_NONE) {
+ if (child.mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- child.mLocalDirtyRect.union(dirty);
}
final int[] location = attachInfo.mInvalidateChildLocation;
@@ -4498,9 +4497,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
location[CHILD_LEFT_INDEX] = left;
location[CHILD_TOP_INDEX] = top;
- if (mLayerType != LAYER_TYPE_NONE) {
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
- mLocalDirtyRect.union(dirty);
}
return mParent;
@@ -4517,9 +4515,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
}
- if (mLayerType != LAYER_TYPE_NONE) {
+ if (mLayerType == LAYER_TYPE_SOFTWARE) {
mPrivateFlags |= PFLAG_INVALIDATED;
- mLocalDirtyRect.union(dirty);
}
return mParent;
@@ -4567,10 +4564,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
- if (child.mLayerType != LAYER_TYPE_NONE) {
- child.mLocalDirtyRect.union(dirty);
- }
-
int left = child.mLeft;
int top = child.mTop;
if (!child.getMatrix().isIdentity()) {
@@ -4618,9 +4611,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
- if (mLayerType != LAYER_TYPE_NONE) {
- mLocalDirtyRect.union(dirty);
- }
if (!getMatrix().isIdentity()) {
transformRect(dirty);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 76d5038..fc48497 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -631,27 +631,7 @@ public final class ViewRootImpl implements ViewParent,
}
void destroyHardwareLayers() {
- if (mThread != Thread.currentThread()) {
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled()) {
- HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
- }
- } else {
- destroyHardwareLayer(mView);
- }
- }
-
- private static void destroyHardwareLayer(View view) {
- view.destroyLayer(true);
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyHardwareLayer(group.getChildAt(i));
- }
- }
+ // TODO Implement
}
void flushHardwareLayerUpdates() {
@@ -1520,54 +1500,55 @@ public final class ViewRootImpl implements ViewParent,
disposeResizeBuffer();
- if (mResizeBuffer == null) {
- mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
- mWidth, mHeight);
- }
- mResizeBuffer.prepare(mWidth, mHeight, false);
- RenderNode layerRenderNode = mResizeBuffer.startRecording();
- HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
- try {
- final int restoreCount = layerCanvas.save();
-
- int yoff;
- final boolean scrolling = mScroller != null
- && mScroller.computeScrollOffset();
- if (scrolling) {
- yoff = mScroller.getCurrY();
- mScroller.abortAnimation();
- } else {
- yoff = mScrollY;
- }
-
- layerCanvas.translate(0, -yoff);
- if (mTranslator != null) {
- mTranslator.translateCanvas(layerCanvas);
- }
-
- RenderNode renderNode = mView.mRenderNode;
- if (renderNode != null && renderNode.isValid()) {
- layerCanvas.drawDisplayList(renderNode, null,
- RenderNode.FLAG_CLIP_CHILDREN);
- } else {
- mView.draw(layerCanvas);
- }
-
- drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
-
- mResizeBufferStartTime = SystemClock.uptimeMillis();
- mResizeBufferDuration = mView.getResources().getInteger(
- com.android.internal.R.integer.config_mediumAnimTime);
-
- layerCanvas.restoreToCount(restoreCount);
- layerRenderNode.end(layerCanvas);
- layerRenderNode.setCaching(true);
- layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
- mTempRect.set(0, 0, mWidth, mHeight);
- } finally {
- mResizeBuffer.endRecording(mTempRect);
- }
- mAttachInfo.mHardwareRenderer.flushLayerUpdates();
+// TODO: Again....
+// if (mResizeBuffer == null) {
+// mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
+// mWidth, mHeight);
+// }
+// mResizeBuffer.prepare(mWidth, mHeight, false);
+// RenderNode layerRenderNode = mResizeBuffer.startRecording();
+// HardwareCanvas layerCanvas = layerRenderNode.start(mWidth, mHeight);
+// try {
+// final int restoreCount = layerCanvas.save();
+//
+// int yoff;
+// final boolean scrolling = mScroller != null
+// && mScroller.computeScrollOffset();
+// if (scrolling) {
+// yoff = mScroller.getCurrY();
+// mScroller.abortAnimation();
+// } else {
+// yoff = mScrollY;
+// }
+//
+// layerCanvas.translate(0, -yoff);
+// if (mTranslator != null) {
+// mTranslator.translateCanvas(layerCanvas);
+// }
+//
+// RenderNode renderNode = mView.mRenderNode;
+// if (renderNode != null && renderNode.isValid()) {
+// layerCanvas.drawDisplayList(renderNode, null,
+// RenderNode.FLAG_CLIP_CHILDREN);
+// } else {
+// mView.draw(layerCanvas);
+// }
+//
+// drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
+//
+// mResizeBufferStartTime = SystemClock.uptimeMillis();
+// mResizeBufferDuration = mView.getResources().getInteger(
+// com.android.internal.R.integer.config_mediumAnimTime);
+//
+// layerCanvas.restoreToCount(restoreCount);
+// layerRenderNode.end(layerCanvas);
+// layerRenderNode.setCaching(true);
+// layerRenderNode.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+// mTempRect.set(0, 0, mWidth, mHeight);
+// } finally {
+// mResizeBuffer.endRecording(mTempRect);
+// }
+// mAttachInfo.mHardwareRenderer.flushLayerUpdates();
}
mAttachInfo.mContentInsets.set(mPendingContentInsets);
if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 64b077b..ace17ec 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -87,14 +87,6 @@ static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject
layer->updateTexImage();
}
-static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr, jlong displayListPtr,
- jint left, jint top, jint right, jint bottom) {
- DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
- RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr);
- layer->setDisplayList(displayList, left, top, right, bottom);
-}
-
static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
jlong layerUpdaterPtr) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
@@ -126,7 +118,6 @@ static JNINativeMethod gMethods[] = {
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
(void*) android_view_HardwareLayer_setSurfaceTexture },
{ "nUpdateSurfaceTexture", "(J)V", (void*) android_view_HardwareLayer_updateSurfaceTexture },
- { "nUpdateRenderLayer", "(JJIIII)V", (void*) android_view_HardwareLayer_updateRenderLayer },
{ "nGetLayer", "(J)J", (void*) android_view_HardwareLayer_getLayer },
{ "nGetTexName", "(J)I", (void*) android_view_HardwareLayer_getTexName },
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 26f8993..3ffde2d 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -87,9 +87,16 @@ static void android_view_RenderNode_setDisplayListData(JNIEnv* env,
// RenderProperties - setters
// ----------------------------------------------------------------------------
-static jboolean android_view_RenderNode_setCaching(JNIEnv* env,
- jobject clazz, jlong renderNodePtr, jboolean caching) {
- return SET_AND_DIRTY(setCaching, caching, RenderNode::GENERIC);
+static jboolean android_view_RenderNode_setLayerType(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jint jlayerType) {
+ LayerType layerType = static_cast<LayerType>(jlayerType);
+ return SET_AND_DIRTY(mutateLayerProperties().setType, layerType, RenderNode::GENERIC);
+}
+
+static jboolean android_view_RenderNode_setLayerPaint(JNIEnv* env,
+ jobject clazz, jlong renderNodePtr, jlong paintPtr) {
+ SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+ return SET_AND_DIRTY(mutateLayerProperties().setFromPaint, paint, RenderNode::GENERIC);
}
static jboolean android_view_RenderNode_setStaticMatrix(JNIEnv* env,
@@ -475,7 +482,8 @@ static JNINativeMethod gMethods[] = {
{ "nOutput", "(J)V", (void*) android_view_RenderNode_output },
{ "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize },
- { "nSetCaching", "(JZ)Z", (void*) android_view_RenderNode_setCaching },
+ { "nSetLayerType", "(JI)Z", (void*) android_view_RenderNode_setLayerType },
+ { "nSetLayerPaint", "(JJ)Z", (void*) android_view_RenderNode_setLayerPaint },
{ "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix },
{ "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix },
{ "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds },
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 898e81a..1cb87f2 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -35,6 +35,7 @@ NullDamageAccumulator* NullDamageAccumulator::instance() {
enum TransformType {
TransformRenderNode,
TransformMatrix4,
+ TransformNone,
};
struct DirtyStack {
@@ -80,14 +81,25 @@ void DamageAccumulator::pushTransform(const Matrix4* transform) {
mHead->matrix4 = transform;
}
+void DamageAccumulator::pushNullTransform() {
+ pushCommon();
+ mHead->type = TransformNone;
+}
+
void DamageAccumulator::popTransform() {
LOG_ALWAYS_FATAL_IF(mHead->prev == mHead, "Cannot pop the root frame!");
DirtyStack* dirtyFrame = mHead;
mHead = mHead->prev;
- if (dirtyFrame->type == TransformRenderNode) {
+ switch (dirtyFrame->type) {
+ case TransformRenderNode:
applyRenderNodeTransform(dirtyFrame);
- } else {
+ break;
+ case TransformMatrix4:
applyMatrix4Transform(dirtyFrame);
+ break;
+ case TransformNone:
+ mHead->pendingDirty.join(dirtyFrame->pendingDirty);
+ break;
}
}
@@ -186,6 +198,10 @@ void DamageAccumulator::dirty(float left, float top, float right, float bottom)
mHead->pendingDirty.join(left, top, right, bottom);
}
+void DamageAccumulator::peekAtDirty(SkRect* dest) {
+ *dest = mHead->pendingDirty;
+}
+
void DamageAccumulator::finish(SkRect* totalDirty) {
LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
// Root node never has a transform, so this is the fully mapped dirty rect
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index 2ca30d4..fc9b41b 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -35,8 +35,10 @@ class IDamageAccumulator {
public:
virtual void pushTransform(const RenderNode* transform) = 0;
virtual void pushTransform(const Matrix4* transform) = 0;
+ virtual void pushNullTransform() = 0;
virtual void popTransform() = 0;
virtual void dirty(float left, float top, float right, float bottom) = 0;
+ virtual void peekAtDirty(SkRect* dest) = 0;
protected:
virtual ~IDamageAccumulator() {}
};
@@ -52,6 +54,9 @@ public:
// will be affected by the transform when popTransform() is called.
virtual void pushTransform(const RenderNode* transform);
virtual void pushTransform(const Matrix4* transform);
+ // This is used in combination with peekAtDirty to inspect the damage
+ // area of a subtree
+ virtual void pushNullTransform();
// Pops a transform node from the stack, propagating the dirty rect
// up to the parent node. Returns the IDamageTransform that was just applied
@@ -59,6 +64,9 @@ public:
virtual void dirty(float left, float top, float right, float bottom);
+ // Returns the current dirty area, *NOT* transformed by pushed transforms
+ virtual void peekAtDirty(SkRect* dest);
+
void finish(SkRect* totalDirty);
private:
@@ -75,8 +83,10 @@ class NullDamageAccumulator : public IDamageAccumulator {
public:
virtual void pushTransform(const RenderNode* transform) { }
virtual void pushTransform(const Matrix4* transform) { }
+ virtual void pushNullTransform() { }
virtual void popTransform() { }
virtual void dirty(float left, float top, float right, float bottom) { }
+ virtual void peekAtDirty(SkRect* dest) { dest->setEmpty(); }
ANDROID_API static NullDamageAccumulator* instance();
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index d494c4c..8e99b9a 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -27,8 +27,7 @@ static void defaultLayerDestroyer(Layer* layer) {
}
DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroyer)
- : mDisplayList(0)
- , mSurfaceTexture(0)
+ : mSurfaceTexture(0)
, mTransform(0)
, mNeedsGLContextAttach(false)
, mUpdateTexImage(false)
@@ -41,7 +40,6 @@ DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, LayerDestroyer destroye
mColorFilter = SkSafeRef(mLayer->getColorFilter());
mAlpha = mLayer->getAlpha();
mMode = mLayer->getMode();
- mDirtyRect.setEmpty();
if (!mDestroyer) {
mDestroyer = defaultLayerDestroyer;
@@ -60,37 +58,13 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
-void DeferredLayerUpdater::setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom) {
- mDisplayList = displayList;
- if (mDirtyRect.isEmpty()) {
- mDirtyRect.set(left, top, right, bottom);
- } else {
- mDirtyRect.unionWith(Rect(left, top, right, bottom));
- }
-}
-
bool DeferredLayerUpdater::apply(TreeInfo& info) {
bool success = true;
// These properties are applied the same to both layer types
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
- if (mDisplayList.get()) {
- if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
- success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
- }
- mLayer->setBlend(mBlend);
- // TODO: Use DamageAccumulator to get the damage area for the layer's
- // subtree to only update that part of the layer. Do this as part of
- // reworking layers to be a RenderProperty instead of a View-managed object
- mDirtyRect.set(0, 0, mWidth, mHeight);
- mDisplayList->prepareTree(info);
- mLayer->updateDeferred(mDisplayList.get(),
- mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
- mDirtyRect.setEmpty();
- mDisplayList = 0;
- } else if (mSurfaceTexture.get()) {
+ if (mSurfaceTexture.get()) {
if (mNeedsGLContextAttach) {
mNeedsGLContextAttach = false;
mSurfaceTexture->attachToContext(mLayer->getTexture());
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index b7cfe80..5082271 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -74,9 +74,6 @@ public:
mTransform = matrix ? new SkMatrix(*matrix) : 0;
}
- ANDROID_API void setDisplayList(RenderNode* displayList,
- int left, int top, int right, int bottom);
-
ANDROID_API void setPaint(const SkPaint* paint);
ANDROID_API bool apply(TreeInfo& info);
@@ -94,11 +91,6 @@ private:
int mAlpha;
SkXfermode::Mode mMode;
- // Layer type specific properties
- // displayList and surfaceTexture are mutually exclusive, only 1 may be set
- // dirtyRect is only valid if displayList is set
- sp<RenderNode> mDisplayList;
- Rect mDirtyRect;
sp<GLConsumer> mSurfaceTexture;
SkMatrix* mTransform;
bool mNeedsGLContextAttach;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 83ad76f..378183a 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -30,6 +30,8 @@
#include "Debug.h"
#include "DisplayListOp.h"
#include "DisplayListLogBuffer.h"
+#include "LayerRenderer.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
@@ -59,12 +61,14 @@ RenderNode::RenderNode()
, mNeedsDisplayListDataSync(false)
, mDisplayListData(0)
, mStagingDisplayListData(0)
- , mNeedsAnimatorsSync(false) {
+ , mNeedsAnimatorsSync(false)
+ , mLayer(0) {
}
RenderNode::~RenderNode() {
delete mDisplayListData;
delete mStagingDisplayListData;
+ LayerRenderer::destroyLayerDeferred(mLayer);
}
void RenderNode::setStagingDisplayList(DisplayListData* data) {
@@ -124,17 +128,72 @@ void RenderNode::damageSelf(TreeInfo& info) {
}
}
+void RenderNode::prepareLayer(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) {
+ // We push a null transform here as we don't care what the existing dirty
+ // area is, only what our display list dirty is as well as our children's
+ // dirty area
+ info.damageAccumulator->pushNullTransform();
+ }
+}
+
+void RenderNode::pushLayerUpdate(TreeInfo& info) {
+ LayerType layerType = properties().layerProperties().type();
+ // If we are not a layer OR we cannot be rendered (eg, view was detached)
+ // we need to destroy any Layers we may have had previously
+ if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) {
+ if (layerType == kLayerTypeRenderLayer) {
+ info.damageAccumulator->popTransform();
+ }
+ if (CC_UNLIKELY(mLayer)) {
+ LayerRenderer::destroyLayer(mLayer);
+ mLayer = NULL;
+ }
+ return;
+ }
+
+ if (!mLayer) {
+ mLayer = LayerRenderer::createRenderLayer(getWidth(), getHeight());
+ applyLayerPropertiesToLayer(info);
+ damageSelf(info);
+ } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
+ LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight());
+ damageSelf(info);
+ }
+
+ SkRect dirty;
+ info.damageAccumulator->peekAtDirty(&dirty);
+ info.damageAccumulator->popTransform();
+
+ if (!dirty.isEmpty()) {
+ mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
+ }
+ // This is not inside the above if because we may have called
+ // updateDeferred on a previous prepare pass that didn't have a renderer
+ if (info.renderer && mLayer->deferredUpdateScheduled) {
+ info.renderer->pushLayerUpdate(mLayer);
+ }
+}
+
void RenderNode::prepareTreeImpl(TreeInfo& info) {
info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
evaluateAnimations(info);
} else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) {
- pushStagingChanges(info);
+ pushStagingPropertiesChanges(info);
} else if (info.mode == TreeInfo::MODE_RT_ONLY) {
evaluateAnimations(info);
}
+
+ prepareLayer(info);
+ if (info.mode == TreeInfo::MODE_FULL) {
+ pushStagingDisplayListChanges(info);
+ }
prepareSubTree(info, mDisplayListData);
+ pushLayerUpdate(info);
+
info.damageAccumulator->popTransform();
}
@@ -152,7 +211,7 @@ private:
TreeInfo& mInfo;
};
-void RenderNode::pushStagingChanges(TreeInfo& info) {
+void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) {
// Push the animators first so that setupStartValueIfNecessary() is called
// before properties() is trampled by stagingProperties(), as they are
// required by some animators.
@@ -170,6 +229,7 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
damageSelf(info);
info.damageAccumulator->popTransform();
mProperties = mStagingProperties;
+ applyLayerPropertiesToLayer(info);
// We could try to be clever and only re-damage if the matrix changed.
// However, we don't need to worry about that. The cost of over-damaging
// here is only going to be a single additional map rect of this node
@@ -178,6 +238,18 @@ void RenderNode::pushStagingChanges(TreeInfo& info) {
info.damageAccumulator->pushTransform(this);
damageSelf(info);
}
+}
+
+void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) {
+ if (CC_LIKELY(!mLayer)) return;
+
+ const LayerProperties& props = properties().layerProperties();
+ mLayer->setAlpha(props.alpha(), props.xferMode());
+ mLayer->setColorFilter(props.colorFilter());
+ mLayer->setBlend(props.needsBlending());
+}
+
+void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {
if (mNeedsDisplayListDataSync) {
mNeedsDisplayListDataSync = false;
// Do a push pass on the old tree to handle freeing DisplayListData
@@ -274,9 +346,10 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
renderer.concatMatrix(*properties().getTransformMatrix());
}
}
- bool clipToBoundsNeeded = properties().getCaching() ? false : properties().getClipToBounds();
+ const bool isLayer = properties().layerProperties().type() != kLayerTypeNone;
+ bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds();
if (properties().getAlpha() < 1) {
- if (properties().getCaching()) {
+ if (isLayer) {
renderer.setOverrideLayerAlpha(properties().getAlpha());
} else if (!properties().getHasOverlappingRendering()) {
renderer.scaleAlpha(properties().getAlpha());
@@ -691,8 +764,14 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T&
*/
template <class T>
void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
+ const bool drawLayer = (mLayer && (&renderer != mLayer->renderer));
+ // If we are updating the contents of mLayer, we don't want to apply any of
+ // the RenderNode's properties to this issueOperations pass. Those will all
+ // be applied when the layer is drawn, aka when this is true.
+ const bool useViewProperties = (!mLayer || drawLayer);
+
const int level = handler.level();
- if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) {
+ if (mDisplayListData->isEmpty() || (useViewProperties && properties().getAlpha() <= 0)) {
DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName());
return;
}
@@ -714,7 +793,9 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo);
- setViewProperties<T>(renderer, handler);
+ if (useViewProperties) {
+ setViewProperties<T>(renderer, handler);
+ }
bool quickRejected = properties().getClipToBounds()
&& renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
@@ -723,31 +804,36 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
}
- Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
- buildZSortedChildList(zTranslatedNodes);
-
- // for 3d root, draw children with negative z values
- issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
-
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- DisplayListOp *op = mDisplayListData->displayListOps[i];
-
-#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
-#endif
- logBuffer.writeCommand(level, op->name());
- handler(op, saveCountOffset, properties().getClipToBounds());
-
- if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
- issueOperationsOfProjectedChildren(renderer, handler);
+ if (drawLayer) {
+ handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+ renderer.getSaveCount() - 1, properties().getClipToBounds());
+ } else {
+ Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
+ buildZSortedChildList(zTranslatedNodes);
+
+ // for 3d root, draw children with negative z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler);
+
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ const int saveCountOffset = renderer.getSaveCount() - 1;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ DisplayListOp *op = mDisplayListData->displayListOps[i];
+
+ #if DEBUG_DISPLAY_LIST
+ op->output(level + 1);
+ #endif
+ logBuffer.writeCommand(level, op->name());
+ handler(op, saveCountOffset, properties().getClipToBounds());
+
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
+ issueOperationsOfProjectedChildren(renderer, handler);
+ }
}
- }
- // for 3d root, draw children with positive z values
- issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ // for 3d root, draw children with positive z values
+ issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler);
+ }
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index f0f6e7c..b2fe849 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -254,9 +254,13 @@ private:
};
void prepareTreeImpl(TreeInfo& info);
- void pushStagingChanges(TreeInfo& info);
+ void pushStagingPropertiesChanges(TreeInfo& info);
+ void pushStagingDisplayListChanges(TreeInfo& info);
void evaluateAnimations(TreeInfo& info);
void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
+ void applyLayerPropertiesToLayer(TreeInfo& info);
+ void prepareLayer(TreeInfo& info);
+ void pushLayerUpdate(TreeInfo& info);
String8 mName;
@@ -272,6 +276,10 @@ private:
std::set< sp<BaseRenderNodeAnimator> > mStagingAnimators;
std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+ // Owned by RT. Lifecycle is managed by prepareTree(), with the exception
+ // being in ~RenderNode() which may happen on any thread.
+ Layer* mLayer;
+
/**
* Draw time state - these properties are only set and used during rendering
*/
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 5f7d4e3..8848b2f 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -21,16 +21,59 @@
#include <utils/Trace.h>
#include <SkCanvas.h>
+#include <SkColorFilter.h>
#include <SkMatrix.h>
#include <SkPath.h>
#include <SkPathOps.h>
#include "Matrix.h"
+#include "OpenGLRenderer.h"
#include "utils/MathUtils.h"
namespace android {
namespace uirenderer {
+LayerProperties::LayerProperties()
+ : mType(kLayerTypeNone)
+ , mColorFilter(NULL) {
+ reset();
+}
+
+LayerProperties::~LayerProperties() {
+ setType(kLayerTypeNone);
+}
+
+void LayerProperties::reset() {
+ mOpaque = false;
+ setFromPaint(NULL);
+}
+
+bool LayerProperties::setColorFilter(SkColorFilter* filter) {
+ if (mColorFilter == filter) return false;
+ SkRefCnt_SafeAssign(mColorFilter, filter);
+ return true;
+}
+
+bool LayerProperties::setFromPaint(const SkPaint* paint) {
+ bool changed = false;
+ SkXfermode::Mode mode;
+ int alpha;
+ OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+ changed |= setAlpha(static_cast<uint8_t>(alpha));
+ changed |= setXferMode(mode);
+ changed |= setColorFilter(paint ? paint->getColorFilter() : NULL);
+ return changed;
+}
+
+LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
+ setType(other.type());
+ setOpaque(other.opaque());
+ setAlpha(other.alpha());
+ setXferMode(other.xferMode());
+ setColorFilter(other.colorFilter());
+ return *this;
+}
+
RenderProperties::PrimitiveFields::PrimitiveFields()
: mClipToBounds(true)
, mProjectBackwards(false)
@@ -45,8 +88,7 @@ RenderProperties::PrimitiveFields::PrimitiveFields()
, mLeft(0), mTop(0), mRight(0), mBottom(0)
, mWidth(0), mHeight(0)
, mPivotExplicitlySet(false)
- , mMatrixOrPivotDirty(false)
- , mCaching(false) {
+ , mMatrixOrPivotDirty(false) {
}
RenderProperties::ComputedFields::ComputedFields()
@@ -73,6 +115,7 @@ RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
setStaticMatrix(other.getStaticMatrix());
setAnimationMatrix(other.getAnimationMatrix());
setCameraDistance(other.getCameraDistance());
+ mLayerProperties = other.layerProperties();
// Force recalculation of the matrix, since other's dirty bit may be clear
mPrimitiveFields.mMatrixOrPivotDirty = true;
@@ -103,9 +146,9 @@ void RenderProperties::debugOutputProperties(const int level) const {
}
}
- bool clipToBoundsNeeded = mPrimitiveFields.mCaching ? false : mPrimitiveFields.mClipToBounds;
+ bool clipToBoundsNeeded = layerProperties().type() != kLayerTypeNone ? false : mPrimitiveFields.mClipToBounds;
if (mPrimitiveFields.mAlpha < 1) {
- if (mPrimitiveFields.mCaching) {
+ if (layerProperties().type() != kLayerTypeNone) {
ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
} else if (!mPrimitiveFields.mHasOverlappingRendering) {
ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index b012fc5..8c6cc9e 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -32,6 +32,7 @@
#include "Outline.h"
class SkBitmap;
+class SkColorFilter;
class SkPaint;
namespace android {
@@ -39,15 +40,95 @@ namespace uirenderer {
class Matrix4;
class RenderNode;
+class RenderProperties;
// The __VA_ARGS__ will be executed if a & b are not equal
#define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false)
#define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true)
+// Keep in sync with View.java:LAYER_TYPE_*
+enum LayerType {
+ kLayerTypeNone = 0,
+ // Although we cannot build the software layer directly (must be done at
+ // record time), this information is used when applying alpha.
+ kLayerTypeSoftware = 1,
+ kLayerTypeRenderLayer = 2,
+ // TODO: LayerTypeSurfaceTexture? Maybe?
+};
+
+class ANDROID_API LayerProperties {
+public:
+ bool setType(LayerType type) {
+ if (RP_SET(mType, type)) {
+ reset();
+ return true;
+ }
+ return false;
+ }
+
+ LayerType type() const {
+ return mType;
+ }
+
+ bool setOpaque(bool opaque) {
+ return RP_SET(mOpaque, opaque);
+ }
+
+ bool opaque() const {
+ return mOpaque;
+ }
+
+ bool setAlpha(uint8_t alpha) {
+ return RP_SET(mAlpha, alpha);
+ }
+
+ uint8_t alpha() const {
+ return mAlpha;
+ }
+
+ bool setXferMode(SkXfermode::Mode mode) {
+ return RP_SET(mMode, mode);
+ }
+
+ SkXfermode::Mode xferMode() const {
+ return mMode;
+ }
+
+ bool setColorFilter(SkColorFilter* filter);
+
+ SkColorFilter* colorFilter() const {
+ return mColorFilter;
+ }
+
+ // Sets alpha, xfermode, and colorfilter from an SkPaint
+ // paint may be NULL, in which case defaults will be set
+ bool setFromPaint(const SkPaint* paint);
+
+ bool needsBlending() const {
+ return !opaque() || alpha() < 255;
+ }
+
+ LayerProperties& operator=(const LayerProperties& other);
+
+private:
+ LayerProperties();
+ ~LayerProperties();
+ void reset();
+
+ friend class RenderProperties;
+
+ LayerType mType;
+ // Whether or not that Layer's content is opaque, doesn't include alpha
+ bool mOpaque;
+ uint8_t mAlpha;
+ SkXfermode::Mode mMode;
+ SkColorFilter* mColorFilter;
+};
+
/*
* Data structure that holds the properties for a RenderNode
*/
-class RenderProperties {
+class ANDROID_API RenderProperties {
public:
RenderProperties();
virtual ~RenderProperties();
@@ -366,10 +447,6 @@ public:
return false;
}
- bool setCaching(bool caching) {
- return RP_SET(mPrimitiveFields.mCaching, caching);
- }
-
int getWidth() const {
return mPrimitiveFields.mWidth;
}
@@ -396,10 +473,6 @@ public:
return mComputedFields.mTransformMatrix;
}
- bool getCaching() const {
- return mPrimitiveFields.mCaching;
- }
-
bool getClipToBounds() const {
return mPrimitiveFields.mClipToBounds;
}
@@ -422,7 +495,7 @@ public:
void debugOutputProperties(const int level) const;
- ANDROID_API void updateMatrix();
+ void updateMatrix();
bool hasClippingPath() const {
return mPrimitiveFields.mRevealClip.willClip();
@@ -445,6 +518,14 @@ public:
return mPrimitiveFields.mRevealClip;
}
+ const LayerProperties& layerProperties() const {
+ return mLayerProperties;
+ }
+
+ LayerProperties& mutateLayerProperties() {
+ return mLayerProperties;
+ }
+
private:
// Rendering properties
@@ -467,11 +548,11 @@ private:
int mWidth, mHeight;
bool mPivotExplicitlySet;
bool mMatrixOrPivotDirty;
- bool mCaching;
} mPrimitiveFields;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
+ LayerProperties mLayerProperties;
/**
* These fields are all generated from other properties and are not set directly.
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index fd78f8e..0fc0cef 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -26,6 +26,7 @@ namespace uirenderer {
class BaseRenderNodeAnimator;
class AnimationListener;
+class OpenGLRenderer;
class AnimationHook {
public:
@@ -63,6 +64,7 @@ public:
, animationHook(NULL)
, prepareTextures(mode == MODE_FULL)
, damageAccumulator(NullDamageAccumulator::instance())
+ , renderer(0)
{}
const TraversalMode mode;
@@ -73,6 +75,9 @@ public:
bool prepareTextures;
// Must not be null
IDamageAccumulator* damageAccumulator;
+ // The renderer that will be drawing the next frame. Use this to push any
+ // layer updates or similar. May be NULL.
+ OpenGLRenderer* renderer;
struct Out {
Out()
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 8a5c857..440f965 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -440,6 +440,7 @@ void CanvasContext::prepareTree(TreeInfo& info) {
info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
info.damageAccumulator = &mDamageAccumulator;
+ info.renderer = mCanvas;
mRootRenderNode->prepareTree(info);
int runningBehind = 0;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index bdfdd21..797566f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -130,9 +130,6 @@ bool DrawFrameTask::syncFrameState(TreeInfo& info) {
mContext->processLayerUpdate(mLayers[i].get(), info);
}
mLayers.clear();
- if (info.out.hasAnimations) {
- // TODO: Uh... crap?
- }
mContext->prepareTree(info);
if (info.out.hasAnimations) {