summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libs/hwui/DisplayList.cpp96
-rw-r--r--libs/hwui/DisplayList.h17
-rw-r--r--libs/hwui/DisplayListOp.h10
-rw-r--r--libs/hwui/DisplayListRenderer.cpp8
-rw-r--r--libs/hwui/DisplayListRenderer.h2
-rw-r--r--libs/hwui/Snapshot.cpp4
-rw-r--r--libs/hwui/Snapshot.h8
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml9
-rw-r--r--tests/HwAccelerationTest/res/layout/projection.xml36
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java110
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);
+ }
+}