summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/DisplayList.java18
-rw-r--r--core/java/android/view/GLES20DisplayList.java27
-rw-r--r--core/java/android/view/View.java33
-rw-r--r--core/java/android/view/ViewPropertyAnimator.java27
-rw-r--r--core/jni/android_view_GLES20DisplayList.cpp13
-rw-r--r--libs/hwui/Debug.h3
-rw-r--r--libs/hwui/DeferredDisplayList.h4
-rw-r--r--libs/hwui/DisplayList.cpp264
-rw-r--r--libs/hwui/DisplayList.h131
-rw-r--r--libs/hwui/DisplayListOp.h66
-rw-r--r--libs/hwui/DisplayListRenderer.cpp9
-rw-r--r--libs/hwui/DisplayListRenderer.h1
-rw-r--r--libs/hwui/Layer.cpp9
-rw-r--r--libs/hwui/Matrix.cpp95
-rw-r--r--libs/hwui/Matrix.h14
-rw-r--r--libs/hwui/OpenGLRenderer.cpp67
-rw-r--r--libs/hwui/OpenGLRenderer.h13
-rw-r--r--libs/hwui/Vector.h15
18 files changed, 667 insertions, 142 deletions
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 623472a..daa7537 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -438,6 +438,21 @@ public abstract class DisplayList {
public abstract float getTranslationY();
/**
+ * Sets the translation value for the display list on the Z axis
+ *
+ * @see View#setTranslationZ(float)
+ * @see #getTranslationZ()
+ */
+ public abstract void setTranslationZ(float translationZ);
+
+ /**
+ * Returns the translation value for this display list on the Z axis.
+ *
+ * @see #setTranslationZ(float)
+ */
+ public abstract float getTranslationZ();
+
+ /**
* Sets the rotation value for the display list around the Z axis
*
* @param rotation The rotation value of the display list, in degrees
@@ -536,7 +551,8 @@ public abstract class DisplayList {
*
* @hide
*/
- public abstract void setTransformationInfo(float alpha, float translationX, float translationY,
+ public abstract void setTransformationInfo(float alpha,
+ float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
/**
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index c652bac..911fc34 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -231,6 +231,21 @@ class GLES20DisplayList extends DisplayList {
}
@Override
+ public void setTranslationZ(float translationZ) {
+ if (hasNativeDisplayList()) {
+ nSetTranslationZ(mFinalizer.mNativeDisplayList, translationZ);
+ }
+ }
+
+ @Override
+ public float getTranslationZ() {
+ if (hasNativeDisplayList()) {
+ return nGetTranslationZ(mFinalizer.mNativeDisplayList);
+ }
+ return 0.0f;
+ }
+
+ @Override
public void setRotation(float rotation) {
if (hasNativeDisplayList()) {
nSetRotation(mFinalizer.mNativeDisplayList, rotation);
@@ -306,10 +321,12 @@ class GLES20DisplayList extends DisplayList {
}
@Override
- public void setTransformationInfo(float alpha, float translationX, float translationY,
+ public void setTransformationInfo(float alpha,
+ float translationX, float translationY, float translationZ,
float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
if (hasNativeDisplayList()) {
- nSetTransformationInfo(mFinalizer.mNativeDisplayList, alpha, translationX, translationY,
+ nSetTransformationInfo(mFinalizer.mNativeDisplayList, alpha,
+ translationX, translationY, translationZ,
rotation, rotationX, rotationY, scaleX, scaleY);
}
}
@@ -459,14 +476,15 @@ class GLES20DisplayList extends DisplayList {
boolean hasOverlappingRendering);
private static native void nSetTranslationX(int displayList, float translationX);
private static native void nSetTranslationY(int displayList, float translationY);
+ private static native void nSetTranslationZ(int displayList, float translationZ);
private static native void nSetRotation(int displayList, float rotation);
private static native void nSetRotationX(int displayList, float rotationX);
private static native void nSetRotationY(int displayList, float rotationY);
private static native void nSetScaleX(int displayList, float scaleX);
private static native void nSetScaleY(int displayList, float scaleY);
private static native void nSetTransformationInfo(int displayList, float alpha,
- float translationX, float translationY, float rotation, float rotationX,
- float rotationY, float scaleX, float scaleY);
+ float translationX, float translationY, float translationZ,
+ float rotation, float rotationX, float rotationY, float scaleX, float scaleY);
private static native void nSetStaticMatrix(int displayList, int nativeMatrix);
private static native void nSetAnimationMatrix(int displayList, int animationMatrix);
@@ -482,6 +500,7 @@ class GLES20DisplayList extends DisplayList {
private static native float nGetScaleY(int displayList);
private static native float nGetTranslationX(int displayList);
private static native float nGetTranslationY(int displayList);
+ private static native float nGetTranslationZ(int displayList);
private static native float nGetRotation(int displayList);
private static native float nGetRotationX(int displayList);
private static native float nGetRotationY(int displayList);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5d264b6..4b97c40 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2981,6 +2981,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@ViewDebug.ExportedProperty
float mTranslationY = 0f;
+ @ViewDebug.ExportedProperty
+ float mTranslationZ = 0f;
+
/**
* The amount of scale in the x direction around the pivot point. A
* value of 1 means no scaling is applied.
@@ -10484,6 +10487,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * @hide
+ */
+ @ViewDebug.ExportedProperty(category = "drawing")
+ public float getTranslationZ() {
+ return mTransformationInfo != null ? mTransformationInfo.mTranslationZ : 0;
+ }
+
+ /**
+ * @hide
+ */
+ public void setTranslationZ(float translationZ) {
+ ensureTransformationInfo();
+ final TransformationInfo info = mTransformationInfo;
+ if (info.mTranslationZ != translationZ) {
+ invalidateViewProperty(true, false);
+ info.mTranslationZ = translationZ;
+ info.mMatrixDirty = true;
+ invalidateViewProperty(false, true);
+ if (mDisplayList != null) {
+ mDisplayList.setTranslationZ(translationZ);
+ }
+ if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
+ // View was rejected last time it was drawn by its parent; this may have changed
+ invalidateParentIfNeeded();
+ }
+ }
+ }
+
+ /**
* Hit rectangle in parent's coordinates
*
* @param outRect The hit rectangle of the view.
@@ -14142,6 +14174,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
displayList.setTransformationInfo(alpha,
mTransformationInfo.mTranslationX, mTransformationInfo.mTranslationY,
+ mTransformationInfo.mTranslationZ,
mTransformationInfo.mRotation, mTransformationInfo.mRotationX,
mTransformationInfo.mRotationY, mTransformationInfo.mScaleX,
mTransformationInfo.mScaleY);
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 67a94be..391b345 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -144,9 +144,10 @@ public class ViewPropertyAnimator {
private static final int X = 0x0080;
private static final int Y = 0x0100;
private static final int ALPHA = 0x0200;
+ private static final int TRANSLATION_Z = 0x0400;
- private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
- ROTATION | ROTATION_X | ROTATION_Y | X | Y;
+ private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
+ SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y;
/**
* The mechanism by which the user can request several properties that are then animated
@@ -573,6 +574,22 @@ public class ViewPropertyAnimator {
}
/**
+ * @hide
+ */
+ public ViewPropertyAnimator translationZ(float value) {
+ animateProperty(TRANSLATION_Z, value);
+ return this;
+ }
+
+ /**
+ * @hide
+ */
+ public ViewPropertyAnimator translationZBy(float value) {
+ animatePropertyBy(TRANSLATION_Z, value);
+ return this;
+ }
+
+ /**
* This method will cause the View's <code>translationY</code> property to be animated to the
* specified value. Animations already running on the property will be canceled.
*
@@ -909,6 +926,10 @@ public class ViewPropertyAnimator {
info.mTranslationY = value;
if (displayList != null) displayList.setTranslationY(value);
break;
+ case TRANSLATION_Z:
+ info.mTranslationZ = value;
+ if (displayList != null) displayList.setTranslationZ(value);
+ break;
case ROTATION:
info.mRotation = value;
if (displayList != null) displayList.setRotation(value);
@@ -957,6 +978,8 @@ public class ViewPropertyAnimator {
return info.mTranslationX;
case TRANSLATION_Y:
return info.mTranslationY;
+ case TRANSLATION_Z:
+ return info.mTranslationZ;
case ROTATION:
return info.mRotation;
case ROTATION_X:
diff --git a/core/jni/android_view_GLES20DisplayList.cpp b/core/jni/android_view_GLES20DisplayList.cpp
index 4ce2e24..24b411a7 100644
--- a/core/jni/android_view_GLES20DisplayList.cpp
+++ b/core/jni/android_view_GLES20DisplayList.cpp
@@ -109,6 +109,11 @@ static void android_view_GLES20DisplayList_setTranslationY(JNIEnv* env,
displayList->setTranslationY(ty);
}
+static void android_view_GLES20DisplayList_setTranslationZ(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, float tz) {
+ displayList->setTranslationZ(tz);
+}
+
static void android_view_GLES20DisplayList_setRotation(JNIEnv* env,
jobject clazz, DisplayList* displayList, float rotation) {
displayList->setRotation(rotation);
@@ -136,11 +141,12 @@ static void android_view_GLES20DisplayList_setScaleY(JNIEnv* env,
static void android_view_GLES20DisplayList_setTransformationInfo(JNIEnv* env,
jobject clazz, DisplayList* displayList, float alpha,
- float translationX, float translationY, float rotation, float rotationX, float rotationY,
- float scaleX, float scaleY) {
+ float translationX, float translationY, float translationZ,
+ float rotation, float rotationX, float rotationY, float scaleX, float scaleY) {
displayList->setAlpha(alpha);
displayList->setTranslationX(translationX);
displayList->setTranslationY(translationY);
+ displayList->setTranslationZ(translationZ);
displayList->setRotation(rotation);
displayList->setRotationX(rotationX);
displayList->setRotationY(rotationY);
@@ -314,12 +320,13 @@ static JNINativeMethod gMethods[] = {
(void*) android_view_GLES20DisplayList_setHasOverlappingRendering },
{ "nSetTranslationX", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationX },
{ "nSetTranslationY", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationY },
+ { "nSetTranslationZ", "(IF)V", (void*) android_view_GLES20DisplayList_setTranslationZ },
{ "nSetRotation", "(IF)V", (void*) android_view_GLES20DisplayList_setRotation },
{ "nSetRotationX", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationX },
{ "nSetRotationY", "(IF)V", (void*) android_view_GLES20DisplayList_setRotationY },
{ "nSetScaleX", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleX },
{ "nSetScaleY", "(IF)V", (void*) android_view_GLES20DisplayList_setScaleY },
- { "nSetTransformationInfo","(IFFFFFFFF)V",
+ { "nSetTransformationInfo","(IFFFFFFFFF)V",
(void*) android_view_GLES20DisplayList_setTransformationInfo },
{ "nSetPivotX", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotX },
{ "nSetPivotY", "(IF)V", (void*) android_view_GLES20DisplayList_setPivotY },
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 786f12a..79afad1 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -85,6 +85,9 @@
// Turn on to highlight drawing batches and merged batches with different colors
#define DEBUG_MERGE_BEHAVIOR 0
+// Turn on to enable 3D support in the renderer (off by default until API for control exists)
+#define DEBUG_ENABLE_3D 0
+
#if DEBUG_INIT
#define INIT_LOGD(...) ALOGD(__VA_ARGS__)
#else
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 3dcbd0b..fca3588 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -79,13 +79,13 @@ public:
};
class DeferredDisplayList {
+ friend class DeferStateStruct; // used to give access to allocator
public:
DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
mBounds(bounds), mAvoidOverdraw(avoidOverdraw) {
clear();
}
~DeferredDisplayList() { clear(); }
- void reset(const Rect& bounds) { mBounds.set(bounds); }
enum OpBatchId {
kOpBatch_None = 0, // Don't batch
@@ -120,6 +120,8 @@ public:
void addDrawOp(OpenGLRenderer& renderer, DrawOp* op);
private:
+ DeferredDisplayList(const DeferredDisplayList& other); // disallow copy
+
DeferredDisplayState* createState() {
return new (mAllocator) DeferredDisplayState();
}
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a3e4bb4..c616cd8 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -14,8 +14,12 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_VIEW
+
#include <SkCanvas.h>
+#include <utils/Trace.h>
+
#include "Debug.h"
#include "DisplayList.h"
#include "DisplayListOp.h"
@@ -65,11 +69,6 @@ void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) {
void DisplayList::clearResources() {
mDisplayListData = NULL;
- mClipRectOp = NULL;
- mSaveLayerOp = NULL;
- mSaveOp = NULL;
- mRestoreToCountOp = NULL;
-
delete mTransformMatrix;
delete mTransformCamera;
delete mTransformMatrix3D;
@@ -168,17 +167,6 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
return;
}
- // allocate reusable ops for state-deferral
- LinearAllocator& alloc = mDisplayListData->allocator;
- mClipRectOp = new (alloc) ClipRectOp();
- mSaveLayerOp = new (alloc) SaveLayerOp();
- mSaveOp = new (alloc) SaveOp();
- mRestoreToCountOp = new (alloc) RestoreToCountOp();
- if (CC_UNLIKELY(!mSaveOp)) { // temporary debug logging
- ALOGW("Error: %s's SaveOp not allocated, size %d", getName(), mSize);
- CRASH();
- }
-
mFunctorCount = recorder.getFunctorCount();
Caches& caches = Caches::getInstance();
@@ -253,6 +241,7 @@ void DisplayList::init() {
mHasOverlappingRendering = true;
mTranslationX = 0;
mTranslationY = 0;
+ mTranslationZ = 0;
mRotation = 0;
mRotationX = 0;
mRotationY= 0;
@@ -269,6 +258,7 @@ void DisplayList::init() {
mHeight = 0;
mPivotExplicitlySet = false;
mCaching = false;
+ mIs3dRoot = true; // TODO: setter, java side impl
}
size_t DisplayList::getSize() {
@@ -320,27 +310,38 @@ void DisplayList::updateMatrix() {
mPivotY = mPrevHeight / 2.0f;
}
}
- if ((mMatrixFlags & ROTATION_3D) == 0) {
+ if (!DEBUG_ENABLE_3D && (mMatrixFlags & ROTATION_3D) == 0) {
mTransformMatrix->setTranslate(mTranslationX, mTranslationY);
mTransformMatrix->preRotate(mRotation, mPivotX, mPivotY);
mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
} else {
- if (!mTransformCamera) {
- mTransformCamera = new Sk3DView();
- mTransformMatrix3D = new SkMatrix();
+ if (DEBUG_ENABLE_3D) {
+ mTransform.loadTranslate(mPivotX + mTranslationX, mPivotY + mTranslationY,
+ mTranslationZ);
+ mTransform.rotate(mRotationX, 1, 0, 0);
+ mTransform.rotate(mRotationY, 0, 1, 0);
+ mTransform.rotate(mRotation, 0, 0, 1);
+ mTransform.scale(mScaleX, mScaleY, 1);
+ mTransform.translate(-mPivotX, -mPivotY);
+ } else {
+ /* TODO: support this old transform approach, based on API level */
+ if (!mTransformCamera) {
+ mTransformCamera = new Sk3DView();
+ mTransformMatrix3D = new SkMatrix();
+ }
+ mTransformMatrix->reset();
+ mTransformCamera->save();
+ mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
+ mTransformCamera->rotateX(mRotationX);
+ mTransformCamera->rotateY(mRotationY);
+ mTransformCamera->rotateZ(-mRotation);
+ mTransformCamera->getMatrix(mTransformMatrix3D);
+ mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
+ mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
+ mPivotY + mTranslationY);
+ mTransformMatrix->postConcat(*mTransformMatrix3D);
+ mTransformCamera->restore();
}
- mTransformMatrix->reset();
- mTransformCamera->save();
- mTransformMatrix->preScale(mScaleX, mScaleY, mPivotX, mPivotY);
- mTransformCamera->rotateX(mRotationX);
- mTransformCamera->rotateY(mRotationY);
- mTransformCamera->rotateZ(-mRotation);
- mTransformCamera->getMatrix(mTransformMatrix3D);
- mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY);
- mTransformMatrix3D->postTranslate(mPivotX + mTranslationX,
- mPivotY + mTranslationY);
- mTransformMatrix->postConcat(*mTransformMatrix3D);
- mTransformCamera->restore();
}
}
mMatrixDirty = false;
@@ -417,8 +418,13 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
if (mMatrixFlags != 0) {
if (mMatrixFlags == TRANSLATION) {
renderer.translate(mTranslationX, mTranslationY);
+ renderer.translateZ(mTranslationZ);
} else {
+#if DEBUG_ENABLE_3D
+ renderer.concatMatrix(mTransform);
+#else
renderer.concatMatrix(mTransformMatrix);
+#endif
}
}
bool clipToBoundsNeeded = mCaching ? false : mClipToBounds;
@@ -436,14 +442,107 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
clipToBoundsNeeded = false; // clipping done by saveLayer
}
- handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
- mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
- mClipToBounds);
+
+ SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
+ 0, 0, mRight - mLeft, mBottom - mTop,
+ mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags);
+ handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
}
}
if (clipToBoundsNeeded) {
- handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
- PROPERTY_SAVECOUNT, mClipToBounds);
+ ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0,
+ mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op);
+ handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
+ }
+}
+
+/**
+ * Apply property-based transformations to input matrix
+ */
+void DisplayList::applyViewPropertyTransforms(mat4& matrix) {
+ if (mLeft != 0 || mTop != 0) {
+ matrix.translate(mLeft, mTop);
+ }
+ if (mStaticMatrix) {
+ mat4 stat(*mStaticMatrix);
+ matrix.multiply(stat);
+ } else if (mAnimationMatrix) {
+ mat4 anim(*mAnimationMatrix);
+ matrix.multiply(anim);
+ }
+ if (mMatrixFlags != 0) {
+ if (mMatrixFlags == TRANSLATION) {
+ matrix.translate(mTranslationX, mTranslationY, mTranslationZ);
+ } else {
+#if DEBUG_ENABLE_3D
+ matrix.multiply(mTransform);
+#else
+ mat4 temp(*mTransformMatrix);
+ matrix.multiply(temp);
+#endif
+ }
+ }
+}
+
+/**
+ * Organizes the DisplayList hierarchy to prepare for Z-based draw order.
+ *
+ * This should be called before a call to defer() or drawDisplayList()
+ *
+ * Each DisplayList that serves as a 3d root builds its list of composited children,
+ * which are flagged to not draw in the standard draw loop.
+ */
+void DisplayList::computeOrdering() {
+ ATRACE_CALL();
+ mat4::identity();
+ for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) {
+ DrawDisplayListOp* childOp = mDisplayListData->children[i];
+ childOp->mDisplayList->computeOrderingImpl(childOp, &m3dNodes, &mat4::identity());
+ }
+}
+
+void DisplayList::computeOrderingImpl(
+ DrawDisplayListOp* opState,
+ KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot,
+ const mat4* transformFrom3dRoot) {
+ // 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, insert into current 3d root and flag for out of order draw
+ opState->mSkipInOrderDraw = true;
+
+ Vector3 pivot(mPivotX, mPivotY, 0.0f);
+ mat4 totalTransform(opState->mTransformFrom3dRoot);
+ applyViewPropertyTransforms(totalTransform);
+ totalTransform.mapPoint3d(pivot);
+ const float key = pivot.z;
+
+ if (compositedChildrenOf3dRoot->indexOfKey(key) < 0) {
+ compositedChildrenOf3dRoot->add(key, Vector<DrawDisplayListOp*>());
+ }
+ compositedChildrenOf3dRoot->editValueFor(key).push(opState);
+ } else {
+ // standard in order draw
+ opState->mSkipInOrderDraw = false;
+ }
+
+ m3dNodes.clear();
+ if (mIs3dRoot) {
+ // create a new 3d space for children by separating their ordering
+ compositedChildrenOf3dRoot = &m3dNodes;
+ transformFrom3dRoot = &mat4::identity();
+ } else {
+ transformFrom3dRoot = &(opState->mTransformFrom3dRoot);
+ }
+
+ if (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);
+ }
}
}
@@ -454,6 +553,8 @@ public:
inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) {
operation->defer(mDeferStruct, saveCount, mLevel, clipToBounds);
}
+ inline LinearAllocator& allocator() { return *(mDeferStruct.mAllocator); }
+
private:
DeferStateStruct& mDeferStruct;
const int mLevel;
@@ -474,6 +575,8 @@ public:
#endif
operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds);
}
+ inline LinearAllocator& allocator() { return *(mReplayStruct.mAllocator); }
+
private:
ReplayStateStruct& mReplayStruct;
const int mLevel;
@@ -490,11 +593,60 @@ void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
replayStruct.mDrawGlStatus);
}
+template <class T>
+void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
+ T& handler, const int level) {
+ if (m3dNodes.size() == 0 ||
+ (mode == kNegativeZChildren && m3dNodes.keyAt(0) > 0.0f) ||
+ (mode == kPositiveZChildren && m3dNodes.keyAt(m3dNodes.size() - 1) < 0.0f)) {
+ // nothing to draw
+ return;
+ }
+
+ LinearAllocator& alloc = handler.allocator();
+ ClipRectOp* op = new (alloc) ClipRectOp(0, 0, mWidth, mHeight,
+ SkRegion::kIntersect_Op); // clip to 3d root bounds for now
+ handler(op, PROPERTY_SAVECOUNT, mClipToBounds);
+ int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+
+ for (int i = 0; i < m3dNodes.size(); i++) {
+ const float zValue = m3dNodes.keyAt(i);
+
+ if (mode == kPositiveZChildren && zValue < 0.0f) continue;
+ if (mode == kNegativeZChildren && zValue > 0.0f) break;
+
+ const Vector<DrawDisplayListOp*>& nodesAtZ = m3dNodes[i];
+ for (int j = 0; j < nodesAtZ.size(); j++) {
+ DrawDisplayListOp* op = nodesAtZ[j];
+ if (mode == kPositiveZChildren) {
+ /* draw shadow on renderer with parent matrix applied, passing in the child's total matrix
+ *
+ * TODO:
+ * -determine and pass background shape (and possibly drawable alpha)
+ * -view must opt-in to shadows
+ * -consider shadows for other content
+ */
+ mat4 shadowMatrix(op->mTransformFrom3dRoot);
+ op->mDisplayList->applyViewPropertyTransforms(shadowMatrix);
+ DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, op->mDisplayList->mAlpha,
+ op->mDisplayList->getWidth(), op->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;
+ }
+ }
+ handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
+}
+
/**
* This function serves both defer and replay modes, and will organize the displayList's component
* operations for a single frame:
*
- * Every 'simple' operation that affects just the matrix and alpha (or other factors of
+ * Every 'simple' state operation that affects just the matrix and alpha (or other factors of
* DeferredDisplayState) may be issued directly to the renderer, but complex operations (with custom
* defer logic) and operations in displayListOps are issued through the 'handler' which handles the
* defer vs replay logic, per operation
@@ -517,8 +669,9 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level)
clipRect->right, clipRect->bottom);
#endif
+ LinearAllocator& alloc = handler.allocator();
int restoreTo = renderer.getSaveCount();
- handler(mSaveOp->reinit(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
+ handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag),
PROPERTY_SAVECOUNT, mClipToBounds);
DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "",
@@ -526,30 +679,31 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level)
setViewProperties<T>(renderer, handler, level + 1);
- if (mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight)) {
- DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
- handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
- renderer.restoreToCount(restoreTo);
- renderer.setOverrideLayerAlpha(1.0f);
- return;
- }
+ bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight);
+ if (!quickRejected) {
+ // for 3d root, draw children with negative z values
+ iterate3dChildren(kNegativeZChildren, renderer, handler, level);
- DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
- int saveCount = renderer.getSaveCount() - 1;
- for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
- DisplayListOp *op = mDisplayListData->displayListOps[i];
+ DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
+ const int saveCountOffset = renderer.getSaveCount() - 1;
+ for (unsigned int i = 0; i < mDisplayListData->displayListOps.size(); i++) {
+ DisplayListOp *op = mDisplayListData->displayListOps[i];
#if DEBUG_DISPLAY_LIST
- op->output(level + 1);
+ op->output(level + 1);
#endif
- logBuffer.writeCommand(level, op->name());
- handler(op, saveCount, mClipToBounds);
+ logBuffer.writeCommand(level, op->name());
+ handler(op, saveCountOffset, mClipToBounds);
+ }
+
+ // for 3d root, draw children with positive z values
+ iterate3dChildren(kPositiveZChildren, renderer, handler, level);
}
DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
- handler(mRestoreToCountOp->reinit(restoreTo), PROPERTY_SAVECOUNT, mClipToBounds);
- renderer.restoreToCount(restoreTo);
+ handler(new (alloc) RestoreToCountOp(restoreTo),
+ PROPERTY_SAVECOUNT, mClipToBounds);
renderer.setOverrideLayerAlpha(1.0f);
}
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 1cd5f1c..983cc02 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -26,6 +26,7 @@
#include <private/hwui/DrawGlInfo.h>
+#include <utils/KeyedVector.h>
#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
#include <utils/SortedVector.h>
@@ -37,6 +38,8 @@
#include <androidfw/ResourceTypes.h>
#include "Debug.h"
+#include "Matrix.h"
+#include "DeferredDisplayList.h"
#define TRANSLATION 0x0001
#define ROTATION 0x0002
@@ -65,36 +68,70 @@ class ClipRectOp;
class SaveLayerOp;
class SaveOp;
class RestoreToCountOp;
+class DrawDisplayListOp;
-struct DeferStateStruct {
- DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
- : mDeferredList(deferredList), mRenderer(renderer), mReplayFlags(replayFlags) {}
- DeferredDisplayList& mDeferredList;
+/**
+ * Holds data used in the playback a tree of DisplayLists.
+ */
+class PlaybackStateStruct {
+protected:
+ PlaybackStateStruct(OpenGLRenderer& renderer, int replayFlags, LinearAllocator* allocator)
+ : mRenderer(renderer), mReplayFlags(replayFlags), mAllocator(allocator){}
+
+public:
OpenGLRenderer& mRenderer;
const int mReplayFlags;
+
+ // Allocator with the lifetime of a single frame.
+ // replay uses an Allocator owned by the struct, while defer shares the DeferredDisplayList's Allocator
+ LinearAllocator * const mAllocator;
};
-struct ReplayStateStruct {
+class DeferStateStruct : public PlaybackStateStruct {
+public:
+ DeferStateStruct(DeferredDisplayList& deferredList, OpenGLRenderer& renderer, int replayFlags)
+ : PlaybackStateStruct(renderer, replayFlags, &(deferredList.mAllocator)), mDeferredList(deferredList) {}
+
+ DeferredDisplayList& mDeferredList;
+};
+
+class ReplayStateStruct : public PlaybackStateStruct {
+public:
ReplayStateStruct(OpenGLRenderer& renderer, Rect& dirty, int replayFlags)
- : mRenderer(renderer), mDirty(dirty), mReplayFlags(replayFlags),
- mDrawGlStatus(DrawGlInfo::kStatusDone) {}
- OpenGLRenderer& mRenderer;
+ : PlaybackStateStruct(renderer, replayFlags, &mReplayAllocator),
+ mDirty(dirty), mDrawGlStatus(DrawGlInfo::kStatusDone) {}
+
Rect& mDirty;
- const int mReplayFlags;
status_t mDrawGlStatus;
+ LinearAllocator mReplayAllocator;
};
/**
- * Refcounted structure that holds data used in display list stream
+ * Refcounted structure that holds the list of commands used in display list stream.
*/
class DisplayListData : public LightRefBase<DisplayListData> {
public:
+ // allocator into which all ops were allocated
LinearAllocator allocator;
+
+ // pointers to all ops within display list, pointing into allocator data
Vector<DisplayListOp*> displayListOps;
+
+ // list of children display lists for quick, non-drawing traversal
+ Vector<DrawDisplayListOp*> children;
};
/**
- * Replays recorded drawing commands.
+ * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
+ *
+ * Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
+ * functionality is split between DisplayListRenderer (which manages the recording), DisplayListData
+ * (which holds the actual data), and DisplayList (which holds properties and performs playback onto
+ * a renderer).
+ *
+ * Note that DisplayListData is swapped out from beneath an individual DisplayList when a view's
+ * recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay
+ * attached.
*/
class DisplayList {
public:
@@ -113,6 +150,7 @@ public:
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
+ void computeOrdering();
void defer(DeferStateStruct& deferStruct, const int level);
void replay(ReplayStateStruct& replayStruct, const int level);
@@ -188,12 +226,7 @@ public:
void setTranslationX(float translationX) {
if (translationX != mTranslationX) {
mTranslationX = translationX;
- mMatrixDirty = true;
- if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
- mMatrixFlags &= ~TRANSLATION;
- } else {
- mMatrixFlags |= TRANSLATION;
- }
+ onTranslationUpdate();
}
}
@@ -204,12 +237,7 @@ public:
void setTranslationY(float translationY) {
if (translationY != mTranslationY) {
mTranslationY = translationY;
- mMatrixDirty = true;
- if (mTranslationX == 0.0f && mTranslationY == 0.0f) {
- mMatrixFlags &= ~TRANSLATION;
- } else {
- mMatrixFlags |= TRANSLATION;
- }
+ onTranslationUpdate();
}
}
@@ -217,6 +245,17 @@ public:
return mTranslationY;
}
+ void setTranslationZ(float translationZ) {
+ if (translationZ != mTranslationZ) {
+ mTranslationZ = translationZ;
+ onTranslationUpdate();
+ }
+ }
+
+ float getTranslationZ() const {
+ return mTranslationZ;
+ }
+
void setRotation(float rotation) {
if (rotation != mRotation) {
mRotation = rotation;
@@ -454,12 +493,36 @@ public:
}
private:
+ enum ChildrenSelectMode {
+ kNegativeZChildren,
+ kPositiveZChildren
+ };
+
+ void onTranslationUpdate() {
+ mMatrixDirty = true;
+ if (mTranslationX == 0.0f && mTranslationY == 0.0f && mTranslationZ == 0.0f) {
+ mMatrixFlags &= ~TRANSLATION;
+ } else {
+ mMatrixFlags |= TRANSLATION;
+ }
+ }
+
void outputViewProperties(const int level);
+ void applyViewPropertyTransforms(mat4& matrix);
+
+ void computeOrderingImpl(DrawDisplayListOp* opState,
+ KeyedVector<float, Vector<DrawDisplayListOp*> >* compositedChildrenOf3dRoot,
+ const mat4* transformFromRoot);
+
template <class T>
inline void setViewProperties(OpenGLRenderer& renderer, T& handler, const int level);
template <class T>
+ inline void iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer,
+ T& handler, const int level);
+
+ template <class T>
inline void iterate(OpenGLRenderer& renderer, T& handler, const int level);
void init();
@@ -509,7 +572,7 @@ private:
bool mClipToBounds;
float mAlpha;
bool mHasOverlappingRendering;
- float mTranslationX, mTranslationY;
+ float mTranslationX, mTranslationY, mTranslationZ;
float mRotation, mRotationX, mRotationY;
float mScaleX, mScaleY;
float mPivotX, mPivotY;
@@ -526,23 +589,17 @@ private:
SkMatrix* mTransformMatrix3D;
SkMatrix* mStaticMatrix;
SkMatrix* mAnimationMatrix;
+ Matrix4 mTransform;
bool mCaching;
+ bool mIs3dRoot;
+
/**
- * State operations - needed to defer displayList property operations (for example, when setting
- * an alpha causes a SaveLayerAlpha to occur). These operations point into mDisplayListData's
- * allocation, or null if uninitialized.
- *
- * These are initialized (via friend re-constructors) when a displayList is issued in either
- * replay or deferred mode. If replaying, the ops are not used until the next frame. If
- * deferring, the ops may be stored in the DeferredDisplayList to be played back a second time.
- *
- * They should be used at most once per frame (one call to 'iterate') to avoid overwriting data
+ * Draw time state - these properties are only set and used during rendering
*/
- ClipRectOp* mClipRectOp;
- SaveLayerOp* mSaveLayerOp;
- SaveOp* mSaveOp;
- RestoreToCountOp* mRestoreToCountOp;
+
+ // for 3d roots, contains a z sorted list of all children items
+ KeyedVector<float, Vector<DrawDisplayListOp*> > m3dNodes; // TODO: good data structure
}; // class DisplayList
}; // namespace uirenderer
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 88077d4..1980b03 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -262,7 +262,6 @@ protected:
///////////////////////////////////////////////////////////////////////////////
class SaveOp : public StateOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveOp(int flags)
: mFlags(flags) {}
@@ -295,7 +294,6 @@ private:
};
class RestoreToCountOp : public StateOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
RestoreToCountOp(int count)
: mCount(count) {}
@@ -328,7 +326,6 @@ private:
};
class SaveLayerOp : public StateOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
SaveLayerOp(float left, float top, float right, float bottom,
int alpha, SkXfermode::Mode mode, int flags)
@@ -524,7 +521,6 @@ protected:
};
class ClipRectOp : public ClipOp {
- friend class DisplayList; // give DisplayList private constructor/reinit access
public:
ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
: ClipOp(op), mArea(left, top, right, bottom) {}
@@ -1100,7 +1096,7 @@ private:
class DrawColorOp : public DrawOp {
public:
DrawColorOp(int color, SkXfermode::Mode mode)
- : DrawOp(0), mColor(color), mMode(mode) {};
+ : DrawOp(NULL), mColor(color), mMode(mode) {};
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawColor(mColor, mMode);
@@ -1505,7 +1501,7 @@ private:
class DrawFunctorOp : public DrawOp {
public:
DrawFunctorOp(Functor* functor)
- : DrawOp(0), mFunctor(functor) {}
+ : DrawOp(NULL), mFunctor(functor) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
renderer.startMark("GL functor");
@@ -1525,20 +1521,21 @@ private:
};
class DrawDisplayListOp : public DrawBoundedOp {
+ friend class DisplayList; // grant DisplayList access to info of child
public:
- DrawDisplayListOp(DisplayList* displayList, int flags)
+ DrawDisplayListOp(DisplayList* displayList, int flags, const mat4& transformFromParent)
: DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
- mDisplayList(displayList), mFlags(flags) {}
+ mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {}
virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
bool useQuickReject) {
- if (mDisplayList && mDisplayList->isRenderable()) {
+ if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
mDisplayList->defer(deferStruct, level + 1);
}
}
virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
bool useQuickReject) {
- if (mDisplayList && mDisplayList->isRenderable()) {
+ if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
mDisplayList->replay(replayStruct, level + 1);
}
}
@@ -1559,13 +1556,58 @@ public:
private:
DisplayList* mDisplayList;
- int mFlags;
+ const int mFlags;
+
+ ///////////////////////////
+ // Properties below are used by DisplayList::computeOrderingImpl() and iterate()
+ ///////////////////////////
+ /**
+ * Records transform vs parent, used for computing total transform without rerunning DL contents
+ */
+ 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.
+ *
+ * Note: doesn't include any transformation recorded within the DisplayList and its properties.
+ */
+ mat4 mTransformFrom3dRoot;
+ bool mSkipInOrderDraw;
+};
+
+/**
+ * Not a canvas operation, used only by 3d / z ordering logic in DisplayList::iterate()
+ */
+class DrawShadowOp : public DrawOp {
+public:
+ DrawShadowOp(const mat4& casterTransform, float casterAlpha, float width, float height)
+ : DrawOp(NULL), mCasterTransform(casterTransform), mCasterAlpha(casterAlpha),
+ mWidth(width), mHeight(height) {}
+
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
+ return renderer.drawShadow(mCasterTransform, mCasterAlpha, mWidth, mHeight);
+ }
+
+ virtual void output(int level, uint32_t logFlags) const {
+ OP_LOG("DrawShadow of width %.2f, height %.2f", mWidth, mHeight);
+ }
+
+ virtual const char* name() { return "DrawShadow"; }
+
+private:
+ const mat4 mCasterTransform;
+ const float mCasterAlpha;
+ const float mWidth;
+ const float mHeight;
};
class DrawLayerOp : public DrawOp {
public:
DrawLayerOp(Layer* layer, float x, float y)
- : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
+ : DrawOp(NULL), mLayer(layer), mX(x), mY(y) {}
virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
return renderer.drawLayer(mLayer, mX, mY);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index d024923..19a027d 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -111,6 +111,7 @@ DisplayList* DisplayListRenderer::getDisplayList(DisplayList* displayList) {
} else {
displayList->initFromDisplayListRenderer(*this, true);
}
+ // TODO: should just avoid setting the DisplayList's DisplayListData
displayList->setRenderable(mHasDrawOps);
return displayList;
}
@@ -120,7 +121,8 @@ bool DisplayListRenderer::isDeferred() {
}
void DisplayListRenderer::setViewport(int width, int height) {
- mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
+ // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
+ mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
mWidth = width;
mHeight = height;
@@ -248,7 +250,10 @@ status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
// resources cache, but we rely on the caller (UI toolkit) to
// do the right thing for now
- addDrawOp(new (alloc()) DrawDisplayListOp(displayList, flags));
+ DrawDisplayListOp* op = new (alloc()) DrawDisplayListOp(displayList, flags, currentTransform());
+ addDrawOp(op);
+ mDisplayListData->children.push(op);
+
return DrawGlInfo::kStatusDone;
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index d233150..7269378 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -328,6 +328,7 @@ private:
return patch;
}
+ // TODO: move these to DisplayListData
Vector<SkBitmap*> mBitmapResources;
Vector<SkBitmap*> mOwnedBitmapResources;
Vector<SkiaColorFilter*> mFilterResources;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index bd371a3..742ffd4 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -194,11 +194,9 @@ void Layer::defer() {
dirtyRect.set(0, 0, width, height);
}
- if (deferredList) {
- deferredList->reset(dirtyRect);
- } else {
- deferredList = new DeferredDisplayList(dirtyRect);
- }
+ delete deferredList;
+ deferredList = new DeferredDisplayList(dirtyRect);
+
DeferStateStruct deferredState(*deferredList, *renderer,
DisplayList::kReplayFlag_ClipChildren);
@@ -206,6 +204,7 @@ void Layer::defer() {
renderer->setupFrameState(dirtyRect.left, dirtyRect.top,
dirtyRect.right, dirtyRect.bottom, !isBlend());
+ displayList->computeOrdering();
displayList->defer(deferredState, 0);
deferredUpdateScheduled = false;
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index ba22071..4f5cd26 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -89,8 +89,9 @@ uint8_t Matrix4::getType() const {
float m01 = data[kSkewX];
float m10 = data[kSkewY];
float m11 = data[kScaleY];
+ float m32 = data[kTranslateZ];
- if (m01 != 0.0f || m10 != 0.0f) {
+ if (m01 != 0.0f || m10 != 0.0f || m32 != 0.0f) {
mType |= kTypeAffine;
}
@@ -131,11 +132,13 @@ bool Matrix4::changesBounds() const {
}
bool Matrix4::isPureTranslate() const {
- return getGeometryType() <= kTypeTranslate;
+ // NOTE: temporary hack to workaround ignoreTransform behavior with Z values
+ // TODO: separate this into isPure2dTranslate vs isPure3dTranslate
+ return getGeometryType() <= kTypeTranslate && (data[kTranslateZ] == 0.0f);
}
bool Matrix4::isSimple() const {
- return getGeometryType() <= (kTypeScale | kTypeTranslate);
+ return getGeometryType() <= (kTypeScale | kTypeTranslate) && (data[kTranslateZ] == 0.0f);
}
bool Matrix4::isIdentity() const {
@@ -369,6 +372,84 @@ void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
mType = kTypeUnknown;
}
+// translated from android.opengl.Matrix#frustumM()
+void Matrix4::loadFrustum(float left, float top, float right, float bottom, float near, float far) {
+ float r_width = 1.0f / (right - left);
+ float r_height = 1.0f / (top - bottom);
+ float r_depth = 1.0f / (near - far);
+ float x = 2.0f * (near * r_width);
+ float y = 2.0f * (near * r_height);
+ float A = (right + left) * r_width;
+ float B = (top + bottom) * r_height;
+ float C = (far + near) * r_depth;
+ float D = 2.0f * (far * near * r_depth);
+
+ memset(&data, 0, sizeof(data));
+ mType = kTypeUnknown;
+
+ data[kScaleX] = x;
+ data[kScaleY] = y;
+ data[8] = A;
+ data[9] = B;
+ data[kScaleZ] = C;
+ data[kTranslateZ] = D;
+ data[11] = -1.0f;
+}
+
+// translated from android.opengl.Matrix#setLookAtM()
+void Matrix4::loadLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ) {
+ float fx = centerX - eyeX;
+ float fy = centerY - eyeY;
+ float fz = centerZ - eyeZ;
+
+ // Normalize f
+ float rlf = 1.0f / sqrt(fx*fx + fy*fy + fz*fz);
+ fx *= rlf;
+ fy *= rlf;
+ fz *= rlf;
+
+ // compute s = f x up (x means "cross product")
+ float sx = fy * upZ - fz * upY;
+ float sy = fz * upX - fx * upZ;
+ float sz = fx * upY - fy * upX;
+
+ // and normalize s
+ float rls = 1.0f / sqrt(sx*sx + sy*sy + sz*sz);
+ sx *= rls;
+ sy *= rls;
+ sz *= rls;
+
+ // compute u = s x f
+ float ux = sy * fz - sz * fy;
+ float uy = sz * fx - sx * fz;
+ float uz = sx * fy - sy * fx;
+
+ mType = kTypeUnknown;
+ data[0] = sx;
+ data[1] = ux;
+ data[2] = -fx;
+ data[3] = 0.0f;
+
+ data[4] = sy;
+ data[5] = uy;
+ data[6] = -fy;
+ data[7] = 0.0f;
+
+ data[8] = sz;
+ data[9] = uz;
+ data[10] = -fz;
+ data[11] = 0.0f;
+
+ data[12] = 0.0f;
+ data[13] = 0.0f;
+ data[14] = 0.0f;
+ data[15] = 1.0f;
+
+ translate(-eyeX, -eyeY, -eyeZ);
+}
+
void Matrix4::loadOrtho(float left, float right, float bottom, float top, float near, float far) {
loadIdentity();
@@ -382,6 +463,14 @@ void Matrix4::loadOrtho(float left, float right, float bottom, float top, float
mType = kTypeTranslate | kTypeScale | kTypeRectToRect;
}
+void Matrix4::mapPoint3d(Vector3& vec) const {
+ //TODO: optimize simple case
+ Vector3 orig(vec);
+ vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX];
+ vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY];
+ vec.z = orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ];
+}
+
#define MUL_ADD_STORE(a, b, c) a = (a) * (b) + (c)
void Matrix4::mapPoint(float& x, float& y) const {
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index b861ba4..00ca050 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -121,6 +121,10 @@ public:
void loadRotate(float angle);
void loadRotate(float angle, float x, float y, float z);
void loadMultiply(const Matrix4& u, const Matrix4& v);
+ void loadFrustum(float left, float top, float right, float bottom, float near, float far);
+ void loadLookAt(float eyeX, float eyeY, float eyeZ,
+ float centerX, float centerY, float centerZ,
+ float upX, float upY, float upZ);
void loadOrtho(float left, float right, float bottom, float top, float near, float far);
@@ -134,17 +138,18 @@ public:
void multiply(float v);
- void translate(float x, float y) {
+ void translate(float x, float y, float z = 0) {
if ((getType() & sGeometryMask) <= kTypeTranslate) {
data[kTranslateX] += x;
data[kTranslateY] += y;
+ data[kTranslateZ] += z;
} else {
// Doing a translation will only affect the translate bit of the type
// Save the type
uint8_t type = mType;
Matrix4 u;
- u.loadTranslate(x, y, 0.0f);
+ u.loadTranslate(x, y, z);
multiply(u);
// Restore the type and fix the translate bit
@@ -190,8 +195,9 @@ public:
void copyTo(float* v) const;
void copyTo(SkMatrix& v) const;
- void mapRect(Rect& r) const;
- void mapPoint(float& x, float& y) const;
+ void mapPoint3d(Vector3& vec) const;
+ void mapPoint(float& x, float& y) const; // 2d only
+ void mapRect(Rect& r) const; // 2d only
float getTranslateX() const;
float getTranslateY() const;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e256ec2..6599b20 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -180,7 +180,21 @@ void OpenGLRenderer::setViewport(int width, int height) {
}
void OpenGLRenderer::initViewport(int width, int height) {
- mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
+ float dist = std::max(width, height) * 1.5;
+
+ if (DEBUG_ENABLE_3D) {
+ // TODO: make view proj app configurable
+ Matrix4 projection;
+ projection.loadFrustum(-width / 2, -height / 2, width / 2, height / 2, dist, 0);
+ Matrix4 view;
+ view.loadLookAt(0, 0, dist,
+ 0, 0, 0,
+ 0, 1, 0);
+ mViewProjMatrix.loadMultiply(projection, view);
+ mViewProjMatrix.translate(-width/2, -height/2);
+ } else {
+ mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
+ }
mWidth = width;
mHeight = height;
@@ -753,7 +767,7 @@ bool OpenGLRenderer::restoreSnapshot() {
if (restoreOrtho) {
Rect& r = previous->viewport;
glViewport(r.left, r.top, r.right, r.bottom);
- mOrthoMatrix.load(current->orthoMatrix);
+ mViewProjMatrix.load(current->orthoMatrix);
}
mSaveCount--;
@@ -984,7 +998,7 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
mSnapshot->height = bounds.getHeight();
- mSnapshot->orthoMatrix.load(mOrthoMatrix);
+ mSnapshot->orthoMatrix.load(mViewProjMatrix);
endTiling();
debugOverdraw(false, false);
@@ -1013,7 +1027,9 @@ bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
// Change the ortho projection
glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
- mOrthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+
+ // TODO: determine best way to support 3d drawing within HW layers
+ mViewProjMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
return true;
}
@@ -1539,10 +1555,8 @@ void OpenGLRenderer::getMatrix(SkMatrix* matrix) {
}
void OpenGLRenderer::concatMatrix(SkMatrix* matrix) {
- SkMatrix transform;
- currentTransform().copyTo(transform);
- transform.preConcat(*matrix);
- currentTransform().load(transform);
+ mat4 transform(*matrix);
+ currentTransform().multiply(transform);
}
///////////////////////////////////////////////////////////////////////////////
@@ -1927,10 +1941,10 @@ void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
bool dirty = right - left > 0.0f && bottom - top > 0.0f;
if (!ignoreTransform) {
- mCaches.currentProgram->set(mOrthoMatrix, mModelView, currentTransform(), offset);
+ mCaches.currentProgram->set(mViewProjMatrix, mModelView, currentTransform(), offset);
if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, currentTransform());
} else {
- mCaches.currentProgram->set(mOrthoMatrix, mModelView, mat4::identity(), offset);
+ mCaches.currentProgram->set(mViewProjMatrix, mModelView, mat4::identity(), offset);
if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
}
}
@@ -2064,9 +2078,12 @@ void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
int32_t replayFlags) {
status_t status;
+
// All the usual checks and setup operations (quickReject, setupDraw, etc.)
// will be performed by the display list itself
if (displayList && displayList->isRenderable()) {
+ // compute 3d ordering
+ displayList->computeOrdering();
if (CC_UNLIKELY(mCaches.drawDeferDisabled)) {
status = startFrame();
ReplayStateStruct replayStruct(*this, dirty, replayFlags);
@@ -2082,7 +2099,7 @@ status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty,
flushLayers();
status = startFrame();
- return status | deferredList.flush(*this, dirty);
+ return deferredList.flush(*this, dirty) | status;
}
return DrawGlInfo::kStatusDone;
@@ -3372,6 +3389,34 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, SkPaint* paint
return drawColorRects(rects, count, color, mode);
}
+status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha,
+ float width, float height) {
+ if (mSnapshot->isIgnored()) return DrawGlInfo::kStatusDone;
+
+ // For now, always and scissor
+ // TODO: use quickReject
+ mCaches.enableScissor();
+
+ SkPaint paint;
+ paint.setColor(0x3f000000);
+ paint.setAntiAlias(true);
+ VertexBuffer vertexBuffer;
+ {
+ //TODO: populate vertex buffer with better shadow geometry.
+ Vector3 pivot(width/2, height/2, 0.0f);
+ casterTransform.mapPoint3d(pivot);
+
+ float zScaleFactor = 0.5 + 0.0005f * pivot.z;
+
+ SkPath path;
+ path.addRect(pivot.x - width * zScaleFactor, pivot.y - height * zScaleFactor,
+ pivot.x + width * zScaleFactor, pivot.y + height * zScaleFactor);
+ PathTessellator::tessellatePath(path, &paint, mSnapshot->transform, vertexBuffer);
+ }
+
+ return drawVertexBuffer(vertexBuffer, &paint);
+}
+
status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
SkXfermode::Mode mode, bool ignoreTransform, bool dirty, bool clip) {
if (count == 0) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index cfc5931..185e247 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -265,6 +265,12 @@ public:
ANDROID_API void getMatrix(SkMatrix* matrix);
virtual void setMatrix(SkMatrix* matrix);
virtual void concatMatrix(SkMatrix* matrix);
+ virtual void concatMatrix(Matrix4& matrix) {
+ currentTransform().multiply(matrix);
+ }
+ void translateZ(float z) {
+ currentTransform().translate(0,0,z);
+ }
ANDROID_API const Rect& getClipBounds();
@@ -315,6 +321,9 @@ public:
DrawOpMode drawOpMode = kDrawOpMode_Immediate);
virtual status_t drawRects(const float* rects, int count, SkPaint* paint);
+ status_t drawShadow(const mat4& casterTransform, float casterAlpha,
+ float width, float height);
+
virtual void resetShader();
virtual void setupShader(SkiaShader* shader);
@@ -1070,8 +1079,8 @@ private:
// Dimensions of the drawing surface
int mWidth, mHeight;
- // Matrix used for ortho projection in shaders
- mat4 mOrthoMatrix;
+ // Matrix used for view/projection in shaders
+ mat4 mViewProjMatrix;
/**
* Model-view matrix used to position/size objects
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index 497924e..5110272 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -107,6 +107,21 @@ struct Vector2 {
}
}; // class Vector2
+class Vector3 {
+public:
+ float x;
+ float y;
+ float z;
+
+ Vector3() :
+ x(0.0f), y(0.0f), z(0.0f) {
+ }
+
+ Vector3(float px, float py, float pz) :
+ x(px), y(py), z(pz) {
+ }
+};
+
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////