diff options
-rw-r--r-- | libs/hwui/DisplayList.cpp | 123 | ||||
-rw-r--r-- | libs/hwui/DisplayList.h | 13 | ||||
-rw-r--r-- | libs/hwui/DisplayListOp.h | 26 | ||||
-rw-r--r-- | libs/hwui/Matrix.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/Matrix.h | 1 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 17 | ||||
-rw-r--r-- | libs/hwui/OpenGLRenderer.h | 4 | ||||
-rw-r--r-- | libs/hwui/SpotShadow.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/Vector.h | 4 |
9 files changed, 118 insertions, 85 deletions
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 5c5a04259258..b954c1fa7ba8 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -304,8 +304,11 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, /** * Apply property-based transformations to input matrix + * + * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4 + * matrix computation instead of the Skia 3x3 matrix + camera hackery. */ -void DisplayList::applyViewPropertyTransforms(mat4& matrix) { +void DisplayList::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) { if (mLeft != 0 || mTop != 0) { matrix.translate(mLeft, mTop); } @@ -319,15 +322,31 @@ void DisplayList::applyViewPropertyTransforms(mat4& matrix) { if (mMatrixFlags != 0) { updateMatrix(); if (mMatrixFlags == TRANSLATION) { - matrix.translate(mTranslationX, mTranslationY, mTranslationZ); + matrix.translate(mTranslationX, mTranslationY, + true3dTransform ? mTranslationZ : 0.0f); } else { - matrix.multiply(*mTransformMatrix); + if (!true3dTransform) { + matrix.multiply(*mTransformMatrix); + } else { + mat4 true3dMat; + true3dMat.loadTranslate( + mPivotX + mTranslationX, + mPivotY + mTranslationY, + mTranslationZ); + true3dMat.rotate(mRotationX, 1, 0, 0); + true3dMat.rotate(mRotationY, 0, 1, 0); + true3dMat.rotate(mRotation, 0, 0, 1); + true3dMat.scale(mScaleX, mScaleY, 1); + true3dMat.translate(-mPivotX, -mPivotY); + + matrix.multiply(true3dMat); + } } } } /** - * Organizes the DisplayList hierarchy to prepare for Z-based draw order. + * Organizes the DisplayList hierarchy to prepare for background projection reordering. * * This should be called before a call to defer() or drawDisplayList() * @@ -336,7 +355,6 @@ void DisplayList::applyViewPropertyTransforms(mat4& matrix) { */ void DisplayList::computeOrdering() { ATRACE_CALL(); - m3dNodes.clear(); mProjectedNodes.clear(); // TODO: create temporary DDLOp and call computeOrderingImpl on top DisplayList so that @@ -345,40 +363,23 @@ 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(), &mProjectedNodes, &mat4::identity()); } } void DisplayList::computeOrderingImpl( DrawDisplayListOp* opState, - Vector<ZDrawDisplayListOpPair>* compositedChildrenOf3dRoot, - const mat4* transformFrom3dRoot, Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface) { - m3dNodes.clear(); mProjectedNodes.clear(); if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return; // TODO: should avoid this calculation in most cases // 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(localTransformFrom3dRoot); - applyViewPropertyTransforms(totalTransform); - totalTransform.mapPoint3d(pivot); - compositedChildrenOf3dRoot->add(ZDrawDisplayListOpPair(pivot.z, opState)); - } else if (mProjectBackwards) { + if (mProjectBackwards) { // composited projectee, flag for out of order draw, save matrix, and store in proj surface opState->mSkipInOrderDraw = true; opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface); @@ -389,15 +390,6 @@ void DisplayList::computeOrderingImpl( } 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; - } - const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0; bool haveAppliedPropertiesToProjection = false; for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { @@ -422,9 +414,7 @@ void DisplayList::computeOrderingImpl( projectionChildren = compositedChildrenOfProjectionSurface; projectionTransform = &localTransformFromProjectionSurface; } - child->computeOrderingImpl(childOp, - compositedChildrenOf3dRoot, transformFrom3dRoot, - projectionChildren, projectionTransform); + child->computeOrderingImpl(childOp, projectionChildren, projectionTransform); } } @@ -477,14 +467,36 @@ void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { replayStruct.mDrawGlStatus); } +void DisplayList::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) { + if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return; + + for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { + DrawDisplayListOp* childOp = mDisplayListData->children[i]; + DisplayList* child = childOp->mDisplayList; + float childZ = child->mTranslationZ; + + if (childZ != 0.0f) { + zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp)); + childOp->mSkipInOrderDraw = true; + } else if (!child->mProjectBackwards) { + // regular, in order drawing DisplayList + childOp->mSkipInOrderDraw = false; + } + } + + // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order) + std::stable_sort(zTranslatedNodes.begin(), zTranslatedNodes.end()); +} + #define SHADOW_DELTA 0.1f template <class T> -void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer, - T& handler, const int level) { - if (m3dNodes.size() == 0 || - (mode == kNegativeZChildren && m3dNodes[0].key > 0.0f) || - (mode == kPositiveZChildren && m3dNodes[m3dNodes.size() - 1].key < 0.0f)) { +void DisplayList::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, + ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) { + const int size = zTranslatedNodes.size(); + if (size == 0 + || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f) + || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) { // no 3d children to draw return; } @@ -502,7 +514,7 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren * This way, if Views A & B have the same Z height and are both casting shadows, the shadows are * underneath both, and neither's shadow is drawn on top of the other. */ - const size_t nonNegativeIndex = findNonNegativeIndex(m3dNodes); + const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes); size_t drawIndex, shadowIndex, endIndex; if (mode == kNegativeZChildren) { drawIndex = 0; @@ -510,24 +522,29 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren shadowIndex = endIndex; // draw no shadows } else { drawIndex = nonNegativeIndex; - endIndex = m3dNodes.size(); + endIndex = size; shadowIndex = drawIndex; // potentially draw shadow for each pos Z child } float lastCasterZ = 0.0f; while (shadowIndex < endIndex || drawIndex < endIndex) { if (shadowIndex < endIndex) { - DrawDisplayListOp* casterOp = m3dNodes[shadowIndex].value; + DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value; DisplayList* caster = casterOp->mDisplayList; - const float casterZ = m3dNodes[shadowIndex].key; + const float casterZ = zTranslatedNodes[shadowIndex].key; // attempt to render the shadow if the caster about to be drawn is its caster, // OR if its caster's Z value is similar to the previous potential caster if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { if (caster->mCastsShadow && caster->mAlpha > 0.0f) { - mat4 shadowMatrix(casterOp->mTransformFromCompositingAncestor); - caster->applyViewPropertyTransforms(shadowMatrix); + mat4 shadowMatrixXY(casterOp->mTransformFromParent); + caster->applyViewPropertyTransforms(shadowMatrixXY); - DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, + // Z matrix needs actual 3d transformation, so mapped z values will be correct + mat4 shadowMatrixZ(casterOp->mTransformFromParent); + caster->applyViewPropertyTransforms(shadowMatrixZ, true); + + DisplayListOp* shadowOp = new (alloc) DrawShadowOp( + shadowMatrixXY, shadowMatrixZ, caster->mAlpha, &(caster->mOutline), caster->mWidth, caster->mHeight); handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); } @@ -542,10 +559,10 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren // since it modifies the renderer's matrix int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); - DrawDisplayListOp* childOp = m3dNodes[drawIndex].value; + DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value; DisplayList* child = childOp->mDisplayList; - renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); + renderer.concatMatrix(childOp->mTransformFromParent); childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); childOp->mSkipInOrderDraw = true; @@ -617,11 +634,11 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight); if (!quickRejected) { - // Z sort 3d children (stable-ness makes z compare fall back to standard drawing order) - std::stable_sort(m3dNodes.begin(), m3dNodes.end()); + Vector<ZDrawDisplayListOpPair> zTranslatedNodes; + buildZSortedChildList(zTranslatedNodes); // for 3d root, draw children with negative z values - iterate3dChildren(kNegativeZChildren, renderer, handler, level); + iterate3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler); DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); const int saveCountOffset = renderer.getSaveCount() - 1; @@ -642,7 +659,7 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) } // for 3d root, draw children with positive z values - iterate3dChildren(kPositiveZChildren, renderer, handler, level); + iterate3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler); } DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index a3577d411198..189b544a2203 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -573,20 +573,20 @@ private: void outputViewProperties(const int level); - void applyViewPropertyTransforms(mat4& matrix); + void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false); void computeOrderingImpl(DrawDisplayListOp* opState, - 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); + void buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes); + template <class T> - inline void iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer, - T& handler, const int level); + inline void iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, + ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler); template <class T> inline void iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level); @@ -657,9 +657,6 @@ private: * Draw time state - these properties are only set and used during rendering */ - // 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 diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 65eda29c9d81..6ce83174c48f 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1534,10 +1534,10 @@ private: const mat4 mTransformFromParent; /** - * 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. + * Holds the transformation between the 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. */ @@ -1550,19 +1550,20 @@ private: */ class DrawShadowOp : public DrawOp { public: - DrawShadowOp(const mat4& transform, float alpha, const SkPath* outline, + DrawShadowOp(const mat4& transformXY, const mat4& transformZ, float alpha, const SkPath* outline, float fallbackWidth, float fallbackHeight) - : DrawOp(NULL), mTransform(transform), mAlpha(alpha), mOutline(outline), + : DrawOp(NULL), mTransformXY(transformXY), mTransformZ(transformZ), + mAlpha(alpha), mOutline(outline), mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight) {} virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) { - if (!mOutline->isEmpty()) { - return renderer.drawShadow(mTransform, mAlpha, mOutline); + if (mOutline->isEmpty()) { + SkPath fakeOutline; + fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight); + return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, &fakeOutline); } - SkPath fakeOutline; - fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight); - return renderer.drawShadow(mTransform, mAlpha, &fakeOutline); + return renderer.drawShadow(mTransformXY, mTransformZ, mAlpha, mOutline); } virtual void output(int level, uint32_t logFlags) const { @@ -1572,7 +1573,8 @@ public: virtual const char* name() { return "DrawShadow"; } private: - const mat4 mTransform; + const mat4 mTransformXY; + const mat4 mTransformZ; const float mAlpha; const SkPath* mOutline; const float mFallbackWidth; diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp index 3d6188a0ddfa..f06106b14ee7 100644 --- a/libs/hwui/Matrix.cpp +++ b/libs/hwui/Matrix.cpp @@ -385,9 +385,14 @@ void Matrix4::loadOrtho(float left, float right, float bottom, float top, float mType = kTypeTranslate | kTypeScale | kTypeRectToRect; } +float Matrix4::mapZ(const Vector3& orig) const { + // duplicates logic for mapPoint3d's z coordinate + return orig.x * data[2] + orig.y * data[6] + orig.z * data[kScaleZ] + data[kTranslateZ]; +} + void Matrix4::mapPoint3d(Vector3& vec) const { //TODO: optimize simple case - Vector3 orig(vec); + const 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]; diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h index 8b586f04c026..26cb05fe686e 100644 --- a/libs/hwui/Matrix.h +++ b/libs/hwui/Matrix.h @@ -199,6 +199,7 @@ public: void copyTo(float* v) const; void copyTo(SkMatrix& v) const; + float mapZ(const Vector3& orig) const; void mapPoint3d(Vector3& vec) const; void mapPoint(float& x, float& y) const; // 2d only void mapRect(Rect& r) const; // 2d only diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 7002e2674af7..83de77219881 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -3190,8 +3190,16 @@ status_t OpenGLRenderer::drawRects(const float* rects, int count, const SkPaint* return drawColorRects(rects, count, paint, false, true, true); } -status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlpha, - const SkPath* casterOutline) { +static void mapPointFakeZ(Vector3& point, const mat4& transformXY, const mat4& transformZ) { + // map z coordinate with true 3d matrix + point.z = transformZ.mapZ(point); + + // map x,y coordinates with draw/Skia matrix + transformXY.mapPoint(point.x, point.y); +} + +status_t OpenGLRenderer::drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ, + float casterAlpha, const SkPath* casterOutline) { if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone; // TODO: use quickRejectWithScissor. For now, always force enable scissor. @@ -3217,7 +3225,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp for (int i = 0; i < casterVertexCount; i++) { const Vertex& point2d = casterVertices2d[i]; casterPolygon[i] = Vector3(point2d.x, point2d.y, 0); - casterTransform.mapPoint3d(casterPolygon[i]); + mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ); } // map the centroid of the caster into 3d @@ -3225,7 +3233,7 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp reinterpret_cast<const Vector2*>(casterVertices2d.array()), casterVertexCount); Vector3 centroid3d(centroid.x, centroid.y, 0); - casterTransform.mapPoint3d(centroid3d); + mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ); // draw caster's shadows if (mCaches.propertyAmbientShadowStrength > 0) { @@ -3244,7 +3252,6 @@ status_t OpenGLRenderer::drawShadow(const mat4& casterTransform, float casterAlp ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount, lightPosScale, *currentTransform(), getWidth(), getHeight(), spotShadowVertexBuffer); - drawVertexBuffer(kVertexBufferMode_Shadow, spotShadowVertexBuffer, &paint); } diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 03beae3eb4e9..76dd014f479f 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -208,8 +208,8 @@ public: DrawOpMode drawOpMode = kDrawOpMode_Immediate); virtual status_t drawRects(const float* rects, int count, const SkPaint* paint); - status_t drawShadow(const mat4& casterTransform, float casterAlpha, - const SkPath* casterOutline); + status_t drawShadow(const mat4& casterTransformXY, const mat4& casterTransformZ, + float casterAlpha, const SkPath* casterOutline); virtual void resetShader(); virtual void setupShader(SkiaShader* shader); diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index 54039c017f53..4e52555feff3 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -35,7 +35,7 @@ static const double EPSILON = 1e-7; * Calculate the angle between and x and a y coordinate. * The atan2 range from -PI to PI. */ -float angle(const Vector2& point, const Vector2& center) { +static float angle(const Vector2& point, const Vector2& center) { return atan2(point.y - center.y, point.x - center.x); } @@ -51,7 +51,7 @@ float angle(const Vector2& point, const Vector2& center) { * @param p2 The second point defining the line segment * @return The distance along the ray if it intersects with the line segment, negative if otherwise */ -float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy, +static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy, const Vector2& p1, const Vector2& p2) { // The math below is derived from solving this formula, basically the // intersection point should stay on both the ray and the edge of (p1, p2). @@ -550,12 +550,12 @@ void SpotShadow::computeSpotShadow(const Vector3* lightPoly, int lightPolyLength for (int i = 0; i < polyLength; i++) { if (poly[i].z <= 0.00001) { inputPolyPositionValid = false; - ALOGE("polygon below the surface"); + ALOGW("polygon below the surface"); break; } if (poly[i].z >= lightPoly[0].z) { inputPolyPositionValid = false; - ALOGE("polygon above the light"); + ALOGW("polygon above the light"); break; } } diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h index 15b9d6b8374e..c61cb6183807 100644 --- a/libs/hwui/Vector.h +++ b/libs/hwui/Vector.h @@ -124,6 +124,10 @@ public: Vector3(float px, float py, float pz) : x(px), y(py), z(pz) { } + + void dump() { + ALOGD("Vector3[%.2f, %.2f, %.2f]", x, y, z); + } }; /////////////////////////////////////////////////////////////////////////////// |