diff options
-rw-r--r-- | libs/hwui/DisplayList.cpp | 96 | ||||
-rw-r--r-- | libs/hwui/DisplayList.h | 17 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 10 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/DisplayListRenderer.h | 2 | ||||
-rw-r--r-- | libs/hwui/Snapshot.cpp | 4 | ||||
-rw-r--r-- | libs/hwui/Snapshot.h | 8 | ||||
-rw-r--r-- | tests/HwAccelerationTest/AndroidManifest.xml | 9 | ||||
-rw-r--r-- | tests/HwAccelerationTest/res/layout/projection.xml | 36 | ||||
-rw-r--r-- | tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java | 110 |
10 files changed, 269 insertions, 31 deletions
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 4e811ec..d3d2613 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -472,6 +472,7 @@ void DisplayList::applyViewPropertyTransforms(mat4& matrix) { matrix.multiply(anim); } if (mMatrixFlags != 0) { + updateMatrix(); if (mMatrixFlags == TRANSLATION) { matrix.translate(mTranslationX, mTranslationY, mTranslationZ); } else { @@ -499,29 +500,42 @@ void DisplayList::computeOrdering() { for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; - childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity()); + childOp->mDisplayList->computeOrderingImpl(childOp, + &m3dNodes, &mat4::identity(), + &mProjectedNodes, &mat4::identity()); } } void DisplayList::computeOrderingImpl( DrawDisplayListOp* opState, Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot, - const mat4* transformFrom3dRoot) { + const mat4* transformFrom3dRoot, + Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, + const mat4* transformFromProjectionSurface) { // TODO: should avoid this calculation in most cases - opState->mTransformFrom3dRoot.load(*transformFrom3dRoot); - opState->mTransformFrom3dRoot.multiply(opState->mTransformFromParent); - - if (mTranslationZ != 0.0f) { // TODO: other signals, such as custom 4x4 matrix - // composited layer, flag for out of order draw... + // TODO: just calculate single matrix, down to all leaf composited elements + Matrix4 localTransformFrom3dRoot(*transformFrom3dRoot); + localTransformFrom3dRoot.multiply(opState->mTransformFromParent); + Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface); + localTransformFromProjectionSurface.multiply(opState->mTransformFromParent); + + if (mTranslationZ != 0.0f) { // TODO: other signals for 3d compositing, such as custom matrix4 + // composited 3d layer, flag for out of order draw and save matrix... opState->mSkipInOrderDraw = true; + opState->mTransformFromCompositingAncestor.load(localTransformFrom3dRoot); // ... and insert into current 3d root, keyed with pivot z for later sorting Vector3 pivot(mPivotX, mPivotY, 0.0f); - mat4 totalTransform(opState->mTransformFrom3dRoot); + mat4 totalTransform(localTransformFrom3dRoot); applyViewPropertyTransforms(totalTransform); totalTransform.mapPoint3d(pivot); compositedChildrenOf3dRoot->add(ZDrawDisplayListOpPair(pivot.z, opState)); + } else if (mProjectToContainedVolume) { + // composited projectee, flag for out of order draw, save matrix, and store in proj surface + opState->mSkipInOrderDraw = true; + opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface); + compositedChildrenOfProjectionSurface->add(opState); } else { // standard in order draw opState->mSkipInOrderDraw = false; @@ -529,18 +543,30 @@ void DisplayList::computeOrderingImpl( m3dNodes.clear(); if (mIsContainedVolume) { - // create a new 3d space for children by separating their ordering + // create a new 3d space for descendents by collecting them compositedChildrenOf3dRoot = &m3dNodes; transformFrom3dRoot = &mat4::identity(); } else { - transformFrom3dRoot = &(opState->mTransformFrom3dRoot); + applyViewPropertyTransforms(localTransformFrom3dRoot); + transformFrom3dRoot = &localTransformFrom3dRoot; + } + + mProjectedNodes.clear(); + if (mDisplayListData != NULL && mDisplayListData->projectionIndex >= 0) { + // create a new projection surface for descendents by collecting them + compositedChildrenOfProjectionSurface = &mProjectedNodes; + transformFromProjectionSurface = &mat4::identity(); + } else { + applyViewPropertyTransforms(localTransformFromProjectionSurface); + transformFromProjectionSurface = &localTransformFromProjectionSurface; } if (mDisplayListData != NULL && mDisplayListData->children.size() > 0) { for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; childOp->mDisplayList->computeOrderingImpl(childOp, - compositedChildrenOf3dRoot, transformFrom3dRoot); + compositedChildrenOf3dRoot, transformFrom3dRoot, + compositedChildrenOfProjectionSurface, transformFromProjectionSurface); } } } @@ -598,19 +624,19 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren if (m3dNodes.size() == 0 || (mode == kNegativeZChildren && m3dNodes[0].key > 0.0f) || (mode == kPositiveZChildren && m3dNodes[m3dNodes.size() - 1].key < 0.0f)) { - // nothing to draw + // no 3d children to draw return; } LinearAllocator& alloc = handler.allocator(); - ClipRectOp* op = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, + ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, SkRegion::kIntersect_Op); // clip to 3d root bounds for now - handler(op, PROPERTY_SAVECOUNT, mClipToBounds); + handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); for (size_t i = 0; i < m3dNodes.size(); i++) { const float zValue = m3dNodes[i].key; - DrawDisplayListOp* op = m3dNodes[i].value; + DrawDisplayListOp* childOp = m3dNodes[i].value; if (mode == kPositiveZChildren && zValue < 0.0f) continue; if (mode == kNegativeZChildren && zValue > 0.0f) break; @@ -622,19 +648,38 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren * -determine and pass background shape (and possibly drawable alpha) * -view must opt-in to shadows * -consider shadows for other content + * -inform shadow system of ancestor transform (for use in lighting) */ - mat4 shadowMatrix(op->mTransformFrom3dRoot); - op->mDisplayList->applyViewPropertyTransforms(shadowMatrix); + mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor); + childOp->mDisplayList->applyViewPropertyTransforms(shadowMatrix); DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, - op->mDisplayList->mAlpha, - op->mDisplayList->getWidth(), op->mDisplayList->getHeight()); + childOp->mDisplayList->mAlpha, + childOp->mDisplayList->getWidth(), childOp->mDisplayList->getHeight()); handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); } - renderer.concatMatrix(op->mTransformFrom3dRoot); - op->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone - handler(op, renderer.getSaveCount() - 1, mClipToBounds); - op->mSkipInOrderDraw = true; + renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); + childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone + handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); + childOp->mSkipInOrderDraw = true; + } + handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); +} + +template <class T> +void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) { + LinearAllocator& alloc = handler.allocator(); + ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, + SkRegion::kReplace_Op); // clip to projection surface root bounds + handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); + int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); + + for (size_t i = 0; i < mProjectedNodes.size(); i++) { + DrawDisplayListOp* childOp = mProjectedNodes[i]; + renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); + childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone + handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); + childOp->mSkipInOrderDraw = true; } handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); } @@ -686,6 +731,7 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); const int saveCountOffset = renderer.getSaveCount() - 1; + const int projectionIndex = mDisplayListData->projectionIndex; for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) { DisplayListOp *op = mDisplayListData->displayListOps[i]; @@ -695,6 +741,10 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) logBuffer.writeCommand(level, op->name()); handler(op, saveCountOffset, mClipToBounds); + + if (CC_UNLIKELY(i == projectionIndex && mProjectedNodes.size() > 0)) { + iterateProjectedChildren(renderer, handler, level); + } } // for 3d root, draw children with positive z values diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index d3113a3..5399185 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -112,6 +112,7 @@ public: */ class DisplayListData : public LightRefBase<DisplayListData> { public: + DisplayListData() : projectionIndex(-1) {} // allocator into which all ops were allocated LinearAllocator allocator; @@ -120,6 +121,10 @@ public: // list of children display lists for quick, non-drawing traversal Vector<DrawDisplayListOp*> children; + + // index of DisplayListOp restore, after which projected descendents should be drawn + int projectionIndex; + Matrix4 projectionTransform; }; /** @@ -522,8 +527,10 @@ private: void applyViewPropertyTransforms(mat4& matrix); void computeOrderingImpl(DrawDisplayListOp* opState, - Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot, - const mat4* transformFromRoot); + Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot, + const mat4* transformFrom3dRoot, + Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, + const mat4* transformFromProjectionSurface); template <class T> inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level); @@ -533,6 +540,9 @@ private: T& handler, const int level); template <class T> + inline void iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level); + + template <class T> inline void iterate(OpenGLRenderer& renderer, T& handler, const int level); void init(); @@ -610,6 +620,9 @@ private: // for 3d roots, contains a z sorted list of all children items Vector<ZDrawDisplayListOpPair> m3dNodes; + + // for projection surfaces, contains a list of all children items + Vector<DrawDisplayListOp*> mProjectedNodes; }; // class DisplayList }; // namespace uirenderer diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index c375bfa..e3d4e2d 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1568,14 +1568,14 @@ private: const mat4 mTransformFromParent; /** - * Holds the transformation between the 3d root ViewGroup and this DisplayList drawing - * instance. Represents any translations / transformations done within the drawing of the 3d - * root ViewGroup's draw, before the draw of the View represented by this DisplayList draw - * instance. + * Holds the transformation between the 3d root OR projection surface ViewGroup and this + * DisplayList drawing instance. Represents any translations / transformations done within the + * drawing of the compositing ancestor ViewGroup's draw, before the draw of the View represented + * by this DisplayList draw instance. * * Note: doesn't include any transformation recorded within the DisplayList and its properties. */ - mat4 mTransformFrom3dRoot; + mat4 mTransformFromCompositingAncestor; bool mSkipInOrderDraw; }; diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 051ccfe..c8a6c2d 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -173,6 +173,14 @@ void DisplayListRenderer::restoreToCount(int saveCount) { StatefulBaseRenderer::restoreToCount(saveCount); } +void DisplayListRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { + bool restoreProjection = removed.flags & Snapshot::kFlagProjectionTarget; + if (restoreProjection) { + mDisplayListData->projectionIndex = mDisplayListData->displayListOps.size() - 1; + mDisplayListData->projectionTransform.load(*currentTransform()); + } +} + int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode, int flags) { addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, alpha, mode, flags)); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index f129c10..1360808 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -221,6 +221,8 @@ public: uint32_t getFunctorCount() const { return mFunctorCount; } +protected: + virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored); private: void insertRestoreToCount(); diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp index d26ee38..a6ec183 100644 --- a/libs/hwui/Snapshot.cpp +++ b/libs/hwui/Snapshot.cpp @@ -70,6 +70,10 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags): } else { region = NULL; } + + if (saveFlags & Snapshot::kFlagProjectionTarget) { + flags |= Snapshot::kFlagProjectionTarget; + } } /////////////////////////////////////////////////////////////////////////////// diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index cc6d0cd..d61d972 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -75,7 +75,13 @@ public: * Indicates that this snapshot or an ancestor snapshot is * an FBO layer. */ - kFlagFboTarget = 0x10 + kFlagFboTarget = 0x10, + /** + * Indicates that the save/restore pair encapsulates a + * projection target, and that after the restore any projected + * descendents should be drawn. + */ + kFlagProjectionTarget = 0x20 }; /** diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index 6f774f8..0ad3456 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -858,5 +858,14 @@ </intent-filter> </activity> + <activity + android:name="ProjectionActivity" + android:label="Reordering/Projection"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + </application> </manifest> diff --git a/tests/HwAccelerationTest/res/layout/projection.xml b/tests/HwAccelerationTest/res/layout/projection.xml new file mode 100644 index 0000000..564201a --- /dev/null +++ b/tests/HwAccelerationTest/res/layout/projection.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<view class="com.android.test.hwui.ProjectionActivity$ProjecteeLayout" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + tools:context="com.example.projection.ProjectionActivity" + tools:ignore="MergeRootFrame"> + <TextView + android:layout_width="match_parent" + android:layout_height="100dp" + android:textSize="50sp" + android:text="TextView"/> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="100dp" + android:clipChildren="false"> + <view class="com.android.test.hwui.ProjectionActivity$ProjectedView" + android:id="@+id/projection" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + <TextView + android:layout_width="match_parent" + android:layout_height="match_parent" + android:textSize="50sp" + android:text="TextView"/> + </FrameLayout> + + <TextView + android:layout_width="match_parent" + android:layout_height="100dp" + android:textSize="50sp" + android:text="TextView"/> +</view>
\ No newline at end of file diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java new file mode 100644 index 0000000..51a6803 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java @@ -0,0 +1,110 @@ +package com.android.test.hwui; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.os.Bundle; + +import android.app.Activity; +import android.util.AttributeSet; +import android.view.DisplayList; +import android.view.View; +import android.widget.LinearLayout; + +public class ProjectionActivity extends Activity { + /** + * The content from this view should be projected in between the background of the + * ProjecteeLayout and its children, unclipped. + * + * This view doesn't clip to its bounds (because its parent has clipChildren=false) so that + * when it is projected onto the ProjecteeLayout, it draws outside its view bounds. + */ + public static class ProjectedView extends View { + private final Paint mPaint = new Paint(); + private final RectF mRectF = new RectF(); + + public ProjectedView(Context context) { + this(context, null); + } + + public ProjectedView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ProjectedView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + setOnClickListener(new OnClickListener() { + boolean toggle = false; + @Override + public void onClick(View v) { + toggle = !toggle; + setProject(toggle); + } + }); + } + + private void setProject(boolean value) { + DisplayList displayList = getDisplayList(); + if (displayList != null) { + displayList.setProjectToContainedVolume(value); + } + // NOTE: we can't invalidate ProjectedView for the redraw because: + // 1) the view won't preserve displayList properties that it doesn't know about + // 2) the damage rect won't be big enough + + // instead, twiddle properties on the container, so that enough area of the screen is + // redrawn without rerecording any DisplayLists. + container.setTranslationX(100f); + container.setTranslationX(0.0f); + } + + @Override + protected void onDraw(Canvas canvas) { + // TODO: set projection flag + final int w = getWidth(); + final int h = getHeight(); + mRectF.set(0, -h, w, 2 * h); + mPaint.setAntiAlias(true); + mPaint.setColor(0x5f00ff00); + canvas.drawOval(mRectF, mPaint); + } + } + + public static class ProjecteeLayout extends LinearLayout { + private final Paint mPaint = new Paint(); + private final RectF mRectF = new RectF(); + + public ProjecteeLayout(Context context) { + this(context, null); + } + + public ProjecteeLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ProjecteeLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void dispatchDraw(Canvas canvas) { + canvas.save(0x20); // secret save flag + mRectF.set(0, 0, getWidth(), getHeight()); + mPaint.setColor(0x5f000000); + canvas.drawOval(mRectF, mPaint); + canvas.restore(); + super.dispatchDraw(canvas); + } + } + + static View container; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.projection); + container = findViewById(R.id.container); + } +} |