OSDN Git Service

Rework and clean up DisplayList projection
authorChris Craik <ccraik@google.com>
Thu, 6 Feb 2014 00:50:41 +0000 (16:50 -0800)
committerChris Craik <ccraik@google.com>
Fri, 7 Feb 2014 00:07:37 +0000 (16:07 -0800)
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

core/java/android/view/DisplayList.java
core/java/android/view/View.java
core/jni/android_view_DisplayList.cpp
libs/hwui/DisplayList.cpp
libs/hwui/DisplayList.h
libs/hwui/DisplayListRenderer.cpp
libs/hwui/DisplayListRenderer.h
libs/hwui/Snapshot.cpp
libs/hwui/Snapshot.h
tests/HwAccelerationTest/res/layout/projection.xml
tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java

index 8b63359..418aec3 100644 (file)
@@ -431,6 +431,17 @@ public class DisplayList {
     }
 
     /**
+     * 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 @@ public class DisplayList {
     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);
index 2710fdf..93459d2 100644 (file)
@@ -2335,7 +2335,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      *                               1   PFLAG3_IS_LAID_OUT
      *                              1    PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT
      *                             1     PFLAG3_CALLED_SUPER
-     *                            1      PFLAG3_PROJECT_BACKGROUND
      * |-------|-------|-------|-------|
      */
 
@@ -2371,12 +2370,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      */
     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 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         // 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;
     }
index 9379375..4bacdde 100644 (file)
@@ -117,6 +117,12 @@ static void android_view_DisplayList_setProjectBackwards(JNIEnv* env,
     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 @@ static JNINativeMethod gMethods[] = {
     { "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",
index fd3dae7..ae8c189 100644 (file)
@@ -240,6 +240,7 @@ void DisplayList::init() {
     mClipToBounds = true;
     mIsolatedZVolume = true;
     mProjectBackwards = false;
+    mProjectionReceiver = false;
     mOutline.rewind();
     mAlpha = 1;
     mHasOverlappingRendering = true;
@@ -524,6 +525,7 @@ void DisplayList::computeOrderingImpl(
         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 @@ void DisplayList::computeOrderingImpl(
         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 != 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->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->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 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren
         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 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren
 
 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 @@ 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;
+        const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex;
         for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
             DisplayListOp *op = mDisplayListData->displayListOps[i];
 
@@ -751,7 +771,7 @@ 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)) {
+            if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) {
                 iterateProjectedChildren(renderer, handler, level);
             }
         }
index 8622d61..935282e 100644 (file)
@@ -112,7 +112,7 @@ public:
  */
 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 @@ public:
     Vector<DrawDisplayListOp*> children;
 
     // index of DisplayListOp restore, after which projected descendents should be drawn
-    int projectionIndex;
-    Matrix4 projectionTransform;
+    int projectionReceiveIndex;
 };
 
 /**
@@ -198,6 +197,14 @@ public:
         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 @@ private:
     bool mClipToBounds;
     bool mIsolatedZVolume;
     bool mProjectBackwards;
+    bool mProjectionReceiver;
     SkPath mOutline;
     float mAlpha;
     bool mHasOverlappingRendering;
index c8a6c2d..f7d7b3d 100644 (file)
@@ -173,14 +173,6 @@ 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));
@@ -254,6 +246,9 @@ status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
             flags, *currentTransform());
     addDrawOp(op);
     mDisplayListData->children.push(op);
+    if (displayList->isProjectionReceiver()) {
+        mDisplayListData->projectionReceiveIndex = mDisplayListData->displayListOps.size() - 1;
+    }
 
     return DrawGlInfo::kStatusDone;
 }
index 1360808..f129c10 100644 (file)
@@ -221,8 +221,6 @@ public:
     uint32_t getFunctorCount() const {
         return mFunctorCount;
     }
-protected:
-    virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored);
 
 private:
     void insertRestoreToCount();
index a6ec183..d26ee38 100644 (file)
@@ -70,10 +70,6 @@ Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
     } else {
         region = NULL;
     }
-
-    if (saveFlags & Snapshot::kFlagProjectionTarget) {
-        flags |= Snapshot::kFlagProjectionTarget;
-    }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
index d61d972..cc6d0cd 100644 (file)
@@ -75,13 +75,7 @@ public:
          * 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
     };
 
     /**
index 564201a..b6e4c5e 100644 (file)
@@ -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
index f27652d..208c387 100644 (file)
@@ -72,33 +72,6 @@ public class ProjectionActivity extends Activity {
         }
     }
 
-    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