diff options
Diffstat (limited to 'libs/hwui/RenderNode.cpp')
-rw-r--r-- | libs/hwui/RenderNode.cpp | 291 |
1 files changed, 221 insertions, 70 deletions
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index d964efc..131384a 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -15,19 +15,24 @@ */ #define ATRACE_TAG ATRACE_TAG_VIEW +#define LOG_TAG "OpenGLRenderer" #include "RenderNode.h" #include <algorithm> +#include <string> #include <SkCanvas.h> #include <algorithm> #include <utils/Trace.h> +#include "DamageAccumulator.h" #include "Debug.h" #include "DisplayListOp.h" #include "DisplayListLogBuffer.h" +#include "LayerRenderer.h" +#include "OpenGLRenderer.h" #include "utils/MathUtils.h" namespace android { @@ -57,12 +62,14 @@ RenderNode::RenderNode() , mNeedsDisplayListDataSync(false) , mDisplayListData(0) , mStagingDisplayListData(0) - , mNeedsAnimatorsSync(false) { + , mNeedsAnimatorsSync(false) + , mLayer(0) { } RenderNode::~RenderNode() { delete mDisplayListData; delete mStagingDisplayListData; + LayerRenderer::destroyLayerDeferred(mLayer); } void RenderNode::setStagingDisplayList(DisplayListData* data) { @@ -110,14 +117,97 @@ void RenderNode::prepareTree(TreeInfo& info) { prepareTreeImpl(info); } -void RenderNode::prepareTreeImpl(TreeInfo& info) { - if (info.performStagingPush) { - pushStagingChanges(info); +void RenderNode::damageSelf(TreeInfo& info) { + if (isRenderable()) { + if (properties().getClipDamageToBounds()) { + info.damageAccumulator->dirty(0, 0, properties().getWidth(), properties().getHeight()); + } else { + // Hope this is big enough? + // TODO: Get this from the display list ops or something + info.damageAccumulator->dirty(INT_MIN, INT_MIN, INT_MAX, INT_MAX); + } + } +} + +void RenderNode::prepareLayer(TreeInfo& info) { + LayerType layerType = properties().layerProperties().type(); + if (CC_UNLIKELY(layerType == kLayerTypeRenderLayer)) { + // We push a null transform here as we don't care what the existing dirty + // area is, only what our display list dirty is as well as our children's + // dirty area + info.damageAccumulator->pushNullTransform(); + } +} + +void RenderNode::pushLayerUpdate(TreeInfo& info) { + LayerType layerType = properties().layerProperties().type(); + // If we are not a layer OR we cannot be rendered (eg, view was detached) + // we need to destroy any Layers we may have had previously + if (CC_LIKELY(layerType != kLayerTypeRenderLayer) || CC_UNLIKELY(!isRenderable())) { + if (layerType == kLayerTypeRenderLayer) { + info.damageAccumulator->popTransform(); + } + if (CC_UNLIKELY(mLayer)) { + LayerRenderer::destroyLayer(mLayer); + mLayer = NULL; + } + return; + } + + if (!mLayer) { + mLayer = LayerRenderer::createRenderLayer(info.renderState, getWidth(), getHeight()); + applyLayerPropertiesToLayer(info); + damageSelf(info); + } else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) { + if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) { + LayerRenderer::destroyLayer(mLayer); + mLayer = 0; + } + damageSelf(info); + } + + SkRect dirty; + info.damageAccumulator->peekAtDirty(&dirty); + info.damageAccumulator->popTransform(); + + if (!mLayer) { + if (info.errorHandler) { + std::string msg = "Unable to create layer for "; + msg += getName(); + info.errorHandler->onError(msg); + } + return; } - if (info.evaluateAnimations) { + + if (!dirty.isEmpty()) { + mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom); + } + // This is not inside the above if because we may have called + // updateDeferred on a previous prepare pass that didn't have a renderer + if (info.renderer && mLayer->deferredUpdateScheduled) { + info.renderer->pushLayerUpdate(mLayer); + } +} + +void RenderNode::prepareTreeImpl(TreeInfo& info) { + info.damageAccumulator->pushTransform(this); + if (info.mode == TreeInfo::MODE_FULL) { + pushStagingPropertiesChanges(info); evaluateAnimations(info); + } else if (info.mode == TreeInfo::MODE_MAYBE_DETACHING) { + pushStagingPropertiesChanges(info); + } else if (info.mode == TreeInfo::MODE_RT_ONLY) { + evaluateAnimations(info); + } + + prepareLayer(info); + if (info.mode == TreeInfo::MODE_FULL) { + pushStagingDisplayListChanges(info); } prepareSubTree(info, mDisplayListData); + pushLayerUpdate(info); + + info.damageAccumulator->popTransform(); } class PushAnimatorsFunctor { @@ -134,7 +224,7 @@ private: TreeInfo& mInfo; }; -void RenderNode::pushStagingChanges(TreeInfo& info) { +void RenderNode::pushStagingPropertiesChanges(TreeInfo& info) { // Push the animators first so that setupStartValueIfNecessary() is called // before properties() is trampled by stagingProperties(), as they are // required by some animators. @@ -149,18 +239,41 @@ void RenderNode::pushStagingChanges(TreeInfo& info) { } if (mDirtyPropertyFields) { mDirtyPropertyFields = 0; + damageSelf(info); + info.damageAccumulator->popTransform(); mProperties = mStagingProperties; + applyLayerPropertiesToLayer(info); + // We could try to be clever and only re-damage if the matrix changed. + // However, we don't need to worry about that. The cost of over-damaging + // here is only going to be a single additional map rect of this node + // plus a rect join(). The parent's transform (and up) will only be + // performed once. + info.damageAccumulator->pushTransform(this); + damageSelf(info); } +} + +void RenderNode::applyLayerPropertiesToLayer(TreeInfo& info) { + if (CC_LIKELY(!mLayer)) return; + + const LayerProperties& props = properties().layerProperties(); + mLayer->setAlpha(props.alpha(), props.xferMode()); + mLayer->setColorFilter(props.colorFilter()); + mLayer->setBlend(props.needsBlending()); +} + +void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) { if (mNeedsDisplayListDataSync) { mNeedsDisplayListDataSync = false; // Do a push pass on the old tree to handle freeing DisplayListData // that are no longer used - TreeInfo oldTreeInfo; + TreeInfo oldTreeInfo(TreeInfo::MODE_MAYBE_DETACHING, info.renderState); + oldTreeInfo.damageAccumulator = info.damageAccumulator; prepareSubTree(oldTreeInfo, mDisplayListData); - // TODO: The damage for the old tree should be accounted for delete mDisplayListData; mDisplayListData = mStagingDisplayListData; mStagingDisplayListData = 0; + damageSelf(info); } } @@ -180,12 +293,21 @@ private: void RenderNode::evaluateAnimations(TreeInfo& info) { if (!mAnimators.size()) return; + // TODO: Can we target this better? For now treat it like any other staging + // property push and just damage self before and after animators are run + + damageSelf(info); + info.damageAccumulator->popTransform(); + AnimateFunctor functor(this, info); std::vector< sp<BaseRenderNodeAnimator> >::iterator newEnd; newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor); mAnimators.erase(newEnd, mAnimators.end()); mProperties.updateMatrix(); info.out.hasAnimations |= mAnimators.size(); + + info.damageAccumulator->pushTransform(this); + damageSelf(info); } void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) { @@ -201,8 +323,11 @@ void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) { info.prepareTextures = cache.prefetchAndMarkInUse(subtree->bitmapResources[i]); } for (size_t i = 0; i < subtree->children().size(); i++) { - RenderNode* childNode = subtree->children()[i]->mDisplayList; + DrawRenderNodeOp* op = subtree->children()[i]; + RenderNode* childNode = op->mRenderNode; + info.damageAccumulator->pushTransform(&op->mTransformFromParent); childNode->prepareTreeImpl(info); + info.damageAccumulator->popTransform(); } } } @@ -223,9 +348,9 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { renderer.translate(properties().getLeft(), properties().getTop()); } if (properties().getStaticMatrix()) { - renderer.concatMatrix(properties().getStaticMatrix()); + renderer.concatMatrix(*properties().getStaticMatrix()); } else if (properties().getAnimationMatrix()) { - renderer.concatMatrix(properties().getAnimationMatrix()); + renderer.concatMatrix(*properties().getAnimationMatrix()); } if (properties().hasTransformMatrix()) { if (properties().isTransformTranslateOnly()) { @@ -234,9 +359,10 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) { renderer.concatMatrix(*properties().getTransformMatrix()); } } - bool clipToBoundsNeeded = properties().getCaching() ? false : properties().getClipToBounds(); + const bool isLayer = properties().layerProperties().type() != kLayerTypeNone; + bool clipToBoundsNeeded = isLayer ? false : properties().getClipToBounds(); if (properties().getAlpha() < 1) { - if (properties().getCaching()) { + if (isLayer) { renderer.setOverrideLayerAlpha(properties().getAlpha()); } else if (!properties().getHasOverlappingRendering()) { renderer.scaleAlpha(properties().getAlpha()); @@ -329,16 +455,16 @@ void RenderNode::computeOrdering() { // transform properties are applied correctly to top level children if (mDisplayListData == NULL) return; for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) { - DrawDisplayListOp* childOp = mDisplayListData->children()[i]; - childOp->mDisplayList->computeOrderingImpl(childOp, + DrawRenderNodeOp* childOp = mDisplayListData->children()[i]; + childOp->mRenderNode->computeOrderingImpl(childOp, properties().getOutline().getPath(), &mProjectedNodes, &mat4::identity()); } } void RenderNode::computeOrderingImpl( - DrawDisplayListOp* opState, + DrawRenderNodeOp* opState, const SkPath* outlineOfProjectionSurface, - Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, + Vector<DrawRenderNodeOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface) { mProjectedNodes.clear(); if (mDisplayListData == NULL || mDisplayListData->isEmpty()) return; @@ -362,11 +488,11 @@ void RenderNode::computeOrderingImpl( const bool isProjectionReceiver = mDisplayListData->projectionReceiveIndex >= 0; bool haveAppliedPropertiesToProjection = false; for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) { - DrawDisplayListOp* childOp = mDisplayListData->children()[i]; - RenderNode* child = childOp->mDisplayList; + DrawRenderNodeOp* childOp = mDisplayListData->children()[i]; + RenderNode* child = childOp->mRenderNode; const SkPath* projectionOutline = NULL; - Vector<DrawDisplayListOp*>* projectionChildren = NULL; + Vector<DrawRenderNodeOp*>* projectionChildren = NULL; const mat4* projectionTransform = NULL; if (isProjectionReceiver && !child->properties().getProjectBackwards()) { // if receiving projections, collect projecting descendent @@ -410,15 +536,7 @@ private: const int mLevel; }; -void RenderNode::deferNodeTree(DeferStateStruct& deferStruct) { - DeferOperationHandler handler(deferStruct, 0); - if (MathUtils::isPositive(properties().getZ())) { - issueDrawShadowOperation(Matrix4::identity(), handler); - } - issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler); -} - -void RenderNode::deferNodeInParent(DeferStateStruct& deferStruct, const int level) { +void RenderNode::defer(DeferStateStruct& deferStruct, const int level) { DeferOperationHandler handler(deferStruct, level); issueOperations<DeferOperationHandler>(deferStruct.mRenderer, handler); } @@ -448,29 +566,21 @@ private: const int mLevel; }; -void RenderNode::replayNodeTree(ReplayStateStruct& replayStruct) { - ReplayOperationHandler handler(replayStruct, 0); - if (MathUtils::isPositive(properties().getZ())) { - issueDrawShadowOperation(Matrix4::identity(), handler); - } - issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler); -} - -void RenderNode::replayNodeInParent(ReplayStateStruct& replayStruct, const int level) { +void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) { ReplayOperationHandler handler(replayStruct, level); issueOperations<ReplayOperationHandler>(replayStruct.mRenderer, handler); } -void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) { +void RenderNode::buildZSortedChildList(Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes) { if (mDisplayListData == NULL || mDisplayListData->children().size() == 0) return; for (unsigned int i = 0; i < mDisplayListData->children().size(); i++) { - DrawDisplayListOp* childOp = mDisplayListData->children()[i]; - RenderNode* child = childOp->mDisplayList; + DrawRenderNodeOp* childOp = mDisplayListData->children()[i]; + RenderNode* child = childOp->mRenderNode; float childZ = child->properties().getZ(); if (!MathUtils::isZero(childZ)) { - zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp)); + zTranslatedNodes.add(ZDrawRenderNodeOpPair(childZ, childOp)); childOp->mSkipInOrderDraw = true; } else if (!child->properties().getProjectBackwards()) { // regular, in order drawing DisplayList @@ -515,10 +625,40 @@ void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler(shadowOp, PROPERTY_SAVECOUNT, properties().getClipToBounds()); } +template <class T> +int RenderNode::issueOperationsOfNegZChildren( + const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes, + OpenGLRenderer& renderer, T& handler) { + if (zTranslatedNodes.isEmpty()) return -1; + + // create a save around the body of the ViewGroup's draw method, so that + // matrix/clip methods don't affect composited children + int shadowSaveCount = renderer.getSaveCount(); + handler(new (handler.allocator()) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), + PROPERTY_SAVECOUNT, properties().getClipToBounds()); + + issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler); + return shadowSaveCount; +} + +template <class T> +void RenderNode::issueOperationsOfPosZChildren(int shadowRestoreTo, + const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes, + OpenGLRenderer& renderer, T& handler) { + if (zTranslatedNodes.isEmpty()) return; + + LOG_ALWAYS_FATAL_IF(shadowRestoreTo < 0, "invalid save to restore to"); + handler(new (handler.allocator()) RestoreToCountOp(shadowRestoreTo), + PROPERTY_SAVECOUNT, properties().getClipToBounds()); + renderer.setOverrideLayerAlpha(1.0f); + + issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler); +} + #define SHADOW_DELTA 0.1f template <class T> -void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, +void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawRenderNodeOpPair>& zTranslatedNodes, ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) { const int size = zTranslatedNodes.size(); if (size == 0 @@ -553,8 +693,8 @@ void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair float lastCasterZ = 0.0f; while (shadowIndex < endIndex || drawIndex < endIndex) { if (shadowIndex < endIndex) { - DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value; - RenderNode* caster = casterOp->mDisplayList; + DrawRenderNodeOp* casterOp = zTranslatedNodes[shadowIndex].value; + RenderNode* caster = casterOp->mRenderNode; 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 @@ -571,8 +711,8 @@ void RenderNode::issueOperationsOf3dChildren(const Vector<ZDrawDisplayListOpPair // since it modifies the renderer's matrix int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); - DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value; - RenderNode* child = childOp->mDisplayList; + DrawRenderNodeOp* childOp = zTranslatedNodes[drawIndex].value; + RenderNode* child = childOp->mRenderNode; renderer.concatMatrix(childOp->mTransformFromParent); childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone @@ -588,8 +728,6 @@ template <class T> void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& handler) { DISPLAY_LIST_LOGD("%*s%d projected children:", (handler.level() + 1) * 2, "", mProjectedNodes.size()); const SkPath* projectionReceiverOutline = properties().getOutline().getPath(); - bool maskProjecteesWithPath = projectionReceiverOutline != NULL - && !projectionReceiverOutline->isRect(NULL); int restoreTo = renderer.getSaveCount(); // If the projection reciever has an outline, we mask each of the projected rendernodes to it @@ -610,7 +748,7 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& SaveLayerOp* op = new (alloc) SaveLayerOp( outlineBounds.left(), outlineBounds.top(), outlineBounds.right(), outlineBounds.bottom(), - 255, SkCanvas::kARGB_ClipLayer_SaveFlag); + 255, SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag | SkCanvas::kARGB_ClipLayer_SaveFlag); op->setMask(projectionReceiverOutline); handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds()); @@ -623,7 +761,7 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& // draw projected nodes for (size_t i = 0; i < mProjectedNodes.size(); i++) { - DrawDisplayListOp* childOp = mProjectedNodes[i]; + DrawRenderNodeOp* childOp = mProjectedNodes[i]; // matrix save, concat, and restore can be done safely without allocating operations int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); @@ -651,8 +789,14 @@ void RenderNode::issueOperationsOfProjectedChildren(OpenGLRenderer& renderer, T& */ template <class T> void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { + const bool drawLayer = (mLayer && (&renderer != mLayer->renderer)); + // If we are updating the contents of mLayer, we don't want to apply any of + // the RenderNode's properties to this issueOperations pass. Those will all + // be applied when the layer is drawn, aka when this is true. + const bool useViewProperties = (!mLayer || drawLayer); + const int level = handler.level(); - if (mDisplayListData->isEmpty() || properties().getAlpha() <= 0) { + if (mDisplayListData->isEmpty() || (useViewProperties && properties().getAlpha() <= 0)) { DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, getName()); return; } @@ -674,7 +818,9 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); - setViewProperties<T>(renderer, handler); + if (useViewProperties) { + setViewProperties<T>(renderer, handler); + } bool quickRejected = properties().getClipToBounds() && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight()); @@ -683,31 +829,36 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) { renderer.setClippingOutline(alloc, &(mProperties.getOutline())); } - Vector<ZDrawDisplayListOpPair> zTranslatedNodes; - buildZSortedChildList(zTranslatedNodes); + if (drawLayer) { + handler(new (alloc) DrawLayerOp(mLayer, 0, 0), + renderer.getSaveCount() - 1, properties().getClipToBounds()); + } else { + Vector<ZDrawRenderNodeOpPair> zTranslatedNodes; + buildZSortedChildList(zTranslatedNodes); - // for 3d root, draw children with negative z values - issueOperationsOf3dChildren(zTranslatedNodes, kNegativeZChildren, renderer, handler); + // for 3d root, draw children with negative z values + int shadowRestoreTo = issueOperationsOfNegZChildren(zTranslatedNodes, renderer, handler); - DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); - const int saveCountOffset = renderer.getSaveCount() - 1; - const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex; - 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; + const int projectionReceiveIndex = mDisplayListData->projectionReceiveIndex; + 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, saveCountOffset, properties().getClipToBounds()); + logBuffer.writeCommand(level, op->name()); + handler(op, saveCountOffset, properties().getClipToBounds()); - if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) { - issueOperationsOfProjectedChildren(renderer, handler); + if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) { + issueOperationsOfProjectedChildren(renderer, handler); + } } - } - // for 3d root, draw children with positive z values - issueOperationsOf3dChildren(zTranslatedNodes, kPositiveZChildren, renderer, handler); + // for 3d root, draw children with positive z values + issueOperationsOfPosZChildren(shadowRestoreTo, zTranslatedNodes, renderer, handler); + } } DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); |