Rework and clean up DisplayList projection
Move the projection surface to be a property of a DisplayList,
set to true for every background drawable.
Additionally, handle a projecting view background such that it doesn't
try to project onto itself (which is undesirable).
Change-Id: Ic70b17474bd87340e80767f8518f73b233419c7a
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 8b63359..418aec3 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -431,6 +431,17 @@
}
/**
+ * Sets whether the display list is a projection receiver - that its parent
+ * DisplayList should draw any descendent DisplayLists with
+ * ProjectBackwards=true directly on top of it. Default value is false.
+ */
+ public void setProjectionReceiver(boolean shouldRecieve) {
+ if (hasNativeDisplayList()) {
+ nSetProjectionReceiver(mFinalizer.mNativeDisplayList, shouldRecieve);
+ }
+ }
+
+ /**
* Sets the outline, defining the shape that casts a shadow.
*
* Deep copies the native path to simplify reference ownership.
@@ -1065,6 +1076,7 @@
private static native void nSetCaching(long displayList, boolean caching);
private static native void nSetClipToBounds(long displayList, boolean clipToBounds);
private static native void nSetProjectBackwards(long displayList, boolean shouldProject);
+ private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve);
private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume);
private static native void nSetOutline(long displayList, long nativePath);
private static native void nSetAlpha(long displayList, float alpha);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2710fdf..93459d2 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2335,7 +2335,6 @@
* 1 PFLAG3_IS_LAID_OUT
* 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
* 1 PFLAG3_CALLED_SUPER
- * 1 PFLAG3_PROJECT_BACKGROUND
* |-------|-------|-------|-------|
*/
@@ -2371,12 +2370,6 @@
*/
static final int PFLAG3_CALLED_SUPER = 0x10;
- /**
- * Flag indicating that the background of this view will be drawn into a
- * display list and projected onto the closest parent projection surface.
- */
- static final int PFLAG3_PROJECT_BACKGROUND = 0x20;
-
/* End of masks for mPrivateFlags3 */
static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
@@ -15014,6 +15007,7 @@
// Set up drawable properties that are view-independent.
displayList.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom);
displayList.setProjectBackwards(drawable.isProjected());
+ displayList.setProjectionReceiver(true);
displayList.setClipToBounds(false);
return displayList;
}
diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp
index 9379375..4bacdde 100644
--- a/core/jni/android_view_DisplayList.cpp
+++ b/core/jni/android_view_DisplayList.cpp
@@ -117,6 +117,12 @@
displayList->setProjectBackwards(shouldProject);
}
+static void android_view_DisplayList_setProjectionReceiver(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean shouldRecieve) {
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+ displayList->setProjectionReceiver(shouldRecieve);
+}
+
static void android_view_DisplayList_setOutline(JNIEnv* env,
jobject clazz, jlong displayListPtr, jlong outlinePathPtr) {
DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
@@ -391,7 +397,8 @@
{ "nSetAnimationMatrix", "(JJ)V", (void*) android_view_DisplayList_setAnimationMatrix },
{ "nSetClipToBounds", "(JZ)V", (void*) android_view_DisplayList_setClipToBounds },
{ "nSetIsolatedZVolume", "(JZ)V", (void*) android_view_DisplayList_setIsolatedZVolume },
- { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards },
+ { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards },
+ { "nSetProjectionReceiver","(JZ)V", (void*) android_view_DisplayList_setProjectionReceiver },
{ "nSetOutline", "(JJ)V", (void*) android_view_DisplayList_setOutline },
{ "nSetAlpha", "(JF)V", (void*) android_view_DisplayList_setAlpha },
{ "nSetHasOverlappingRendering", "(JZ)V",
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index fd3dae7..ae8c189 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -240,6 +240,7 @@
mClipToBounds = true;
mIsolatedZVolume = true;
mProjectBackwards = false;
+ mProjectionReceiver = false;
mOutline.rewind();
mAlpha = 1;
mHasOverlappingRendering = true;
@@ -524,6 +525,7 @@
const mat4* transformFromProjectionSurface) {
m3dNodes.clear();
mProjectedNodes.clear();
+ if (mDisplayListData == NULL || mSize == 0) return;
// TODO: should avoid this calculation in most cases
// TODO: just calculate single matrix, down to all leaf composited elements
@@ -553,32 +555,46 @@
opState->mSkipInOrderDraw = false;
}
- if (mIsolatedZVolume) {
- // create a new 3d space for descendents by collecting them
- compositedChildrenOf3dRoot = &m3dNodes;
- transformFrom3dRoot = &mat4::identity();
- } else {
- applyViewPropertyTransforms(localTransformFrom3dRoot);
- transformFrom3dRoot = &localTransformFrom3dRoot;
- }
+ if (mDisplayListData->children.size() > 0) {
+ if (mIsolatedZVolume) {
+ // create a new 3d space for descendents by collecting them
+ compositedChildrenOf3dRoot = &m3dNodes;
+ transformFrom3dRoot = &mat4::identity();
+ } else {
+ applyViewPropertyTransforms(localTransformFrom3dRoot);
+ transformFrom3dRoot = &localTransformFrom3dRoot;
+ }
- 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) {
+ const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0;
+ bool haveAppliedPropertiesToProjection = false;
for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
DrawDisplayListOp* childOp = mDisplayListData->children[i];
- childOp->mDisplayList->computeOrderingImpl(childOp,
+ DisplayList* child = childOp->mDisplayList;
+
+ Vector<DrawDisplayListOp*>* projectionChildren = NULL;
+ const mat4* projectionTransform = NULL;
+ if (isProjectionReceiver && !child->mProjectBackwards) {
+ // if receiving projections, collect projecting descendent
+
+ // Note that if a direct descendent is projecting backwards, we pass it's
+ // grandparent projection collection, since it shouldn't project onto it's
+ // parent, where it will already be drawing.
+ projectionChildren = &mProjectedNodes;
+ projectionTransform = &mat4::identity();
+ } else {
+ if (!haveAppliedPropertiesToProjection) {
+ applyViewPropertyTransforms(localTransformFromProjectionSurface);
+ haveAppliedPropertiesToProjection = true;
+ }
+ projectionChildren = compositedChildrenOfProjectionSurface;
+ projectionTransform = &localTransformFromProjectionSurface;
+ }
+ child->computeOrderingImpl(childOp,
compositedChildrenOf3dRoot, transformFrom3dRoot,
- compositedChildrenOfProjectionSurface, transformFromProjectionSurface);
+ projectionChildren, projectionTransform);
}
}
+
}
class DeferOperationHandler {
@@ -638,11 +654,11 @@
return;
}
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
LinearAllocator& alloc = handler.allocator();
ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
SkRegion::kIntersect_Op); // clip to 3d root bounds for now
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;
@@ -677,18 +693,22 @@
template <class T>
void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) {
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
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];
+
+ // matrix save, concat, and restore can be done safely without allocating operations
+ int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag);
renderer.concatMatrix(childOp->mTransformFromCompositingAncestor);
childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone
handler(childOp, renderer.getSaveCount() - 1, mClipToBounds);
childOp->mSkipInOrderDraw = true;
+ renderer.restoreToCount(restoreTo);
}
handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
}
@@ -740,7 +760,7 @@
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
const int saveCountOffset = renderer.getSaveCount() - 1;
- const int projectionIndex = mDisplayListData->projectionIndex;
+ const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
DisplayListOp *op = mDisplayListData->displayListOps[i];
@@ -751,7 +771,7 @@
logBuffer.writeCommand(level, op->name());
handler(op, saveCountOffset, mClipToBounds);
- if (CC_UNLIKELY(i == projectionIndex && mProjectedNodes.size() > 0)) {
+ if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
iterateProjectedChildren(renderer, handler, level);
}
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 8622d61..935282e 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -112,7 +112,7 @@
*/
class DisplayListData : public LightRefBase<DisplayListData> {
public:
- DisplayListData() : projectionIndex(-1) {}
+ DisplayListData() : projectionReceiveIndex(-1) {}
// allocator into which all ops were allocated
LinearAllocator allocator;
@@ -123,8 +123,7 @@
Vector<DrawDisplayListOp*> children;
// index of DisplayListOp restore, after which projected descendents should be drawn
- int projectionIndex;
- Matrix4 projectionTransform;
+ int projectionReceiveIndex;
};
/**
@@ -198,6 +197,14 @@
mProjectBackwards = shouldProject;
}
+ void setProjectionReceiver(bool shouldRecieve) {
+ mProjectionReceiver = shouldRecieve;
+ }
+
+ bool isProjectionReceiver() {
+ return mProjectionReceiver;
+ }
+
void setOutline(const SkPath* outline) {
if (!outline) {
mOutline.reset();
@@ -600,6 +607,7 @@
bool mClipToBounds;
bool mIsolatedZVolume;
bool mProjectBackwards;
+ bool mProjectionReceiver;
SkPath mOutline;
float mAlpha;
bool mHasOverlappingRendering;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index c8a6c2d..f7d7b3d 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -173,14 +173,6 @@
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));
@@ -254,6 +246,9 @@
flags, *currentTransform());
addDrawOp(op);
mDisplayListData->children.push(op);
+ if (displayList->isProjectionReceiver()) {
+ mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
+ }
return DrawGlInfo::kStatusDone;
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 1360808..f129c10 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -221,8 +221,6 @@
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 a6ec183..d26ee38 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -70,10 +70,6 @@
} else {
region = NULL;
}
-
- if (saveFlags & Snapshot::kFlagProjectionTarget) {
- flags |= Snapshot::kFlagProjectionTarget;
- }
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index d61d972..cc6d0cd 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -75,13 +75,7 @@
* Indicates that this snapshot or an ancestor snapshot is
* an FBO layer.
*/
- 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
+ kFlagFboTarget = 0x10
};
/**
diff --git a/tests/HwAccelerationTest/res/layout/projection.xml b/tests/HwAccelerationTest/res/layout/projection.xml
index 564201a..b6e4c5e 100644
--- a/tests/HwAccelerationTest/res/layout/projection.xml
+++ b/tests/HwAccelerationTest/res/layout/projection.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<view class="com.android.test.hwui.ProjectionActivity$ProjecteeLayout"
+<LinearLayout
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"
+ android:background="#66ff0000"
tools:context="com.example.projection.ProjectionActivity"
tools:ignore="MergeRootFrame">
<TextView
@@ -33,4 +34,4 @@
android:layout_height="100dp"
android:textSize="50sp"
android:text="TextView"/>
-</view>
\ No newline at end of file
+</LinearLayout>
\ 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
index f27652d..208c387 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
@@ -72,33 +72,6 @@
}
}
- 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