diff options
| author | 2014-03-03 11:38:22 -0800 | |
|---|---|---|
| committer | 2014-03-05 16:25:50 -0800 | |
| commit | 8b6f2df48e10de35d43621ce174eb3dde394725c (patch) | |
| tree | 4badc91b0241c272ef13d24d32ca6b0428ab1ba8 | |
| parent | 322f7d6e4abf8d0098ae322fe328b2510383baf5 (diff) | |
Draw shadows from casters together if the Z values are similar
Change-Id: Ib5d00c83e81d9d4c384685a84988a681da8b4490
| -rw-r--r-- | libs/hwui/DisplayList.cpp | 70 | ||||
| -rw-r--r-- | libs/hwui/DisplayList.h | 7 |
2 files changed, 59 insertions, 18 deletions
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index 112f8d3f5deb..8d52b4ee7765 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -488,6 +488,8 @@ void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { replayStruct.mDrawGlStatus); } +#define SHADOW_DELTA 2.0f + template <class T> void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler, const int level) { @@ -501,34 +503,66 @@ void DisplayList::iterate3dChildren(ChildrenSelectMode mode, OpenGLRenderer& ren 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 + SkRegion::kIntersect_Op); // clip to 3d root bounds handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); - for (size_t i = 0; i < m3dNodes.size(); i++) { - const float zValue = m3dNodes[i].key; - DrawDisplayListOp* childOp = m3dNodes[i].value; + /** + * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters + * with very similar Z heights to draw together. + * + * 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); + size_t drawIndex, shadowIndex, endIndex; + if (mode == kNegativeZChildren) { + drawIndex = 0; + endIndex = nonNegativeIndex; + shadowIndex = endIndex; // draw no shadows + } else { + drawIndex = nonNegativeIndex; + endIndex = m3dNodes.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; + DisplayList* caster = casterOp->mDisplayList; + const float casterZ = m3dNodes[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); + + DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, + caster->mAlpha, &(caster->mOutline), caster->mWidth, caster->mHeight); + handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); + } + + lastCasterZ = casterZ; // must do this even if current caster not casting a shadow + shadowIndex++; + continue; + } + } - if (mode == kPositiveZChildren && zValue < 0.0f) continue; - if (mode == kNegativeZChildren && zValue > 0.0f) break; + // only the actual child DL draw needs to be in save/restore, + // since it modifies the renderer's matrix + int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); + DrawDisplayListOp* childOp = m3dNodes[drawIndex].value; DisplayList* child = childOp->mDisplayList; - if (mode == kPositiveZChildren && zValue > 0.0f - && child->mCastsShadow && child->mAlpha > 0.0f) { - /* draw shadow with parent matrix applied, passing in the child's total matrix - * TODO: consider depth in more complex scenarios (neg z, added shadow depth) - */ - mat4 shadowMatrix(childOp->mTransformFromCompositingAncestor); - child->applyViewPropertyTransforms(shadowMatrix); - - DisplayListOp* shadowOp = new (alloc) DrawShadowOp(shadowMatrix, - child->mAlpha, &(child->mOutline), child->mWidth, child->mHeight); - handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); - } 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); + drawIndex++; } handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); } diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index aba40b662533..a3577d411198 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -550,6 +550,13 @@ public: private: typedef key_value_pair_t<float, DrawDisplayListOp*> ZDrawDisplayListOpPair; + static size_t findNonNegativeIndex(const Vector<ZDrawDisplayListOpPair>& nodes) { + for (size_t i = 0; i < nodes.size(); i++) { + if (nodes[i].key >= 0.0f) return i; + } + return nodes.size(); + } + enum ChildrenSelectMode { kNegativeZChildren, kPositiveZChildren |