diff options
-rw-r--r-- | core/java/android/view/HardwareLayer.java | 49 | ||||
-rw-r--r-- | core/java/android/view/HardwareRenderer.java | 10 | ||||
-rw-r--r-- | core/java/android/view/RenderNode.java | 14 | ||||
-rw-r--r-- | core/java/android/view/TextureView.java | 10 | ||||
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 6 | ||||
-rw-r--r-- | core/java/android/view/View.java | 192 | ||||
-rw-r--r-- | core/java/android/view/ViewGroup.java | 16 | ||||
-rw-r--r-- | core/java/android/view/ViewRootImpl.java | 119 | ||||
-rw-r--r-- | core/jni/android_view_HardwareLayer.cpp | 9 | ||||
-rw-r--r-- | core/jni/android_view_RenderNode.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/DamageAccumulator.cpp | 20 | ||||
-rw-r--r-- | libs/hwui/DamageAccumulator.h | 10 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.cpp | 30 | ||||
-rw-r--r-- | libs/hwui/DeferredLayerUpdater.h | 8 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 148 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 10 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.cpp | 51 | ||||
-rw-r--r-- | libs/hwui/RenderProperties.h | 103 | ||||
-rw-r--r-- | libs/hwui/TreeInfo.h | 5 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 3 |
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) { |