am 4c9dafbf: Merge "Put WebViews with on a HW layer if stencil/shader clipping is needed" into mnc-dev
* commit '4c9dafbfecf00ba3dca0c5de61d889676bfdc7af': Put WebViews with on a HW layer if stencil/shader clipping is needed
This commit is contained in:
@@ -155,8 +155,9 @@ public:
|
||||
inline bool currentlyIgnored() const { return currentSnapshot()->isIgnored(); }
|
||||
int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
|
||||
int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
|
||||
int getWidth() { return mWidth; }
|
||||
int getHeight() { return mHeight; }
|
||||
int getWidth() const { return mWidth; }
|
||||
int getHeight() const { return mHeight; }
|
||||
bool clipIsSimple() const { return currentSnapshot()->clipIsSimple(); }
|
||||
|
||||
inline const Snapshot* currentSnapshot() const {
|
||||
return mSnapshot != nullptr ? mSnapshot.get() : mFirstSnapshot.get();
|
||||
|
||||
@@ -203,10 +203,10 @@ bool DisplayListCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
|
||||
|
||||
void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) {
|
||||
LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
|
||||
|
||||
// dirty is an out parameter and should not be recorded,
|
||||
// it matters only when replaying the display list
|
||||
DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, *mState.currentTransform());
|
||||
DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(
|
||||
renderNode,
|
||||
*mState.currentTransform(),
|
||||
mState.clipIsSimple());
|
||||
addRenderNodeOp(op);
|
||||
}
|
||||
|
||||
|
||||
@@ -1398,9 +1398,10 @@ class DrawRenderNodeOp : public DrawBoundedOp {
|
||||
friend class RenderNode; // grant RenderNode access to info of child
|
||||
friend class DisplayListData; // grant DisplayListData access to info of child
|
||||
public:
|
||||
DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent)
|
||||
DrawRenderNodeOp(RenderNode* renderNode, const mat4& transformFromParent, bool clipIsSimple)
|
||||
: DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
|
||||
, mRenderNode(renderNode)
|
||||
, mRecordedWithPotentialStencilClip(!clipIsSimple || !transformFromParent.isSimple())
|
||||
, mTransformFromParent(transformFromParent)
|
||||
, mSkipInOrderDraw(false) {}
|
||||
|
||||
@@ -1436,6 +1437,20 @@ public:
|
||||
private:
|
||||
RenderNode* mRenderNode;
|
||||
|
||||
/**
|
||||
* This RenderNode was drawn into a DisplayList with the canvas in a state that will likely
|
||||
* require rendering with stencil clipping. Either:
|
||||
*
|
||||
* 1) A path clip or rotated rect clip was in effect on the canvas at record time
|
||||
* 2) The RenderNode was recorded with a non-simple canvas transform (e.g. rotation)
|
||||
*
|
||||
* Note: even if this is false, non-rect clipping may still be applied applied either due to
|
||||
* property-driven rotation (either in this RenderNode, or any ancestor), or record time
|
||||
* clipping in an ancestor. These are handled in RenderNode::prepareTreeImpl since they are
|
||||
* dynamic (relative to a static DisplayList of a parent), and don't affect this flag.
|
||||
*/
|
||||
bool mRecordedWithPotentialStencilClip;
|
||||
|
||||
///////////////////////////
|
||||
// Properties below are used by RenderNode::computeOrderingImpl() and issueOperations()
|
||||
///////////////////////////
|
||||
|
||||
@@ -120,7 +120,10 @@ void RenderNode::prepareTree(TreeInfo& info) {
|
||||
ATRACE_CALL();
|
||||
LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
|
||||
|
||||
prepareTreeImpl(info);
|
||||
// Functors don't correctly handle stencil usage of overdraw debugging - shove 'em in a layer.
|
||||
bool functorsNeedLayer = Properties::debugOverdraw;
|
||||
|
||||
prepareTreeImpl(info, functorsNeedLayer);
|
||||
}
|
||||
|
||||
void RenderNode::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
|
||||
@@ -219,7 +222,15 @@ void RenderNode::pushLayerUpdate(TreeInfo& info) {
|
||||
}
|
||||
}
|
||||
|
||||
void RenderNode::prepareTreeImpl(TreeInfo& info) {
|
||||
/**
|
||||
* Traverse down the the draw tree to prepare for a frame.
|
||||
*
|
||||
* MODE_FULL = UI Thread-driven (thus properties must be synced), otherwise RT driven
|
||||
*
|
||||
* While traversing down the tree, functorsNeedLayer flag is set to true if anything that uses the
|
||||
* stencil buffer may be needed. Views that use a functor to draw will be forced onto a layer.
|
||||
*/
|
||||
void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
|
||||
info.damageAccumulator->pushTransform(this);
|
||||
|
||||
if (info.mode == TreeInfo::MODE_FULL) {
|
||||
@@ -229,11 +240,17 @@ void RenderNode::prepareTreeImpl(TreeInfo& info) {
|
||||
if (CC_LIKELY(info.runAnimations)) {
|
||||
animatorDirtyMask = mAnimatorManager.animate(info);
|
||||
}
|
||||
|
||||
bool willHaveFunctor = info.mode == TreeInfo::MODE_FULL && mStagingDisplayListData
|
||||
? !mStagingDisplayListData->functors.isEmpty() : !mDisplayListData->functors.isEmpty();
|
||||
bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
|
||||
willHaveFunctor, functorsNeedLayer);
|
||||
|
||||
prepareLayer(info, animatorDirtyMask);
|
||||
if (info.mode == TreeInfo::MODE_FULL) {
|
||||
pushStagingDisplayListChanges(info);
|
||||
}
|
||||
prepareSubTree(info, mDisplayListData);
|
||||
prepareSubTree(info, childFunctorsNeedLayer, mDisplayListData);
|
||||
pushLayerUpdate(info);
|
||||
|
||||
info.damageAccumulator->popTransform();
|
||||
@@ -313,7 +330,7 @@ void RenderNode::deleteDisplayListData() {
|
||||
mDisplayListData = nullptr;
|
||||
}
|
||||
|
||||
void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
|
||||
void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayListData* subtree) {
|
||||
if (subtree) {
|
||||
TextureCache& cache = Caches::getInstance().textureCache;
|
||||
info.out.hasFunctors |= subtree->functors.size();
|
||||
@@ -324,7 +341,10 @@ void RenderNode::prepareSubTree(TreeInfo& info, DisplayListData* subtree) {
|
||||
DrawRenderNodeOp* op = subtree->children()[i];
|
||||
RenderNode* childNode = op->mRenderNode;
|
||||
info.damageAccumulator->pushTransform(&op->mTransformFromParent);
|
||||
childNode->prepareTreeImpl(info);
|
||||
bool childFunctorsNeedLayer = functorsNeedLayer
|
||||
// Recorded with non-rect clip, or canvas-rotated by parent
|
||||
|| op->mRecordedWithPotentialStencilClip;
|
||||
childNode->prepareTreeImpl(info, childFunctorsNeedLayer);
|
||||
info.damageAccumulator->popTransform();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,10 +235,10 @@ private:
|
||||
const char* mText;
|
||||
};
|
||||
|
||||
void prepareTreeImpl(TreeInfo& info);
|
||||
void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
|
||||
void pushStagingPropertiesChanges(TreeInfo& info);
|
||||
void pushStagingDisplayListChanges(TreeInfo& info);
|
||||
void prepareSubTree(TreeInfo& info, DisplayListData* subtree);
|
||||
void prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayListData* subtree);
|
||||
void applyLayerPropertiesToLayer(TreeInfo& info);
|
||||
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
|
||||
void pushLayerUpdate(TreeInfo& info);
|
||||
|
||||
@@ -158,6 +158,32 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set internal layer state based on whether this layer
|
||||
*
|
||||
* Additionally, returns true if child RenderNodes with functors will need to use a layer
|
||||
* to support clipping.
|
||||
*/
|
||||
bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) {
|
||||
// parent may have already dictated that a descendant layer is needed
|
||||
bool functorsNeedLayer = ancestorDictatesFunctorsNeedLayer
|
||||
|
||||
// Round rect clipping forces layer for functors
|
||||
|| CC_UNLIKELY(getOutline().willClip())
|
||||
|| CC_UNLIKELY(getRevealClip().willClip())
|
||||
|
||||
// Complex matrices forces layer, due to stencil clipping
|
||||
|| CC_UNLIKELY(getTransformMatrix() && !getTransformMatrix()->isScaleTranslate())
|
||||
|| CC_UNLIKELY(getAnimationMatrix() && !getAnimationMatrix()->isScaleTranslate())
|
||||
|| CC_UNLIKELY(getStaticMatrix() && !getStaticMatrix()->isScaleTranslate());
|
||||
|
||||
mComputedFields.mNeedLayerForFunctors = (willHaveFunctor && functorsNeedLayer);
|
||||
|
||||
// If on a layer, will have consumed the need for isolating functors from stencil.
|
||||
// Thus, it's safe to reset the flag until some descendent sets it.
|
||||
return CC_LIKELY(effectiveLayerType() == LayerType::None) && functorsNeedLayer;
|
||||
}
|
||||
|
||||
RenderProperties& operator=(const RenderProperties& other);
|
||||
|
||||
bool setClipToBounds(bool clipToBounds) {
|
||||
@@ -580,15 +606,16 @@ public:
|
||||
bool promotedToLayer() const {
|
||||
const int maxTextureSize = Caches::getInstance().maxTextureSize;
|
||||
return mLayerProperties.mType == LayerType::None
|
||||
&& !MathUtils::isZero(mPrimitiveFields.mAlpha)
|
||||
&& mPrimitiveFields.mAlpha < 1
|
||||
&& mPrimitiveFields.mHasOverlappingRendering
|
||||
&& mPrimitiveFields.mWidth <= maxTextureSize
|
||||
&& mPrimitiveFields.mHeight <= maxTextureSize;
|
||||
&& mPrimitiveFields.mHeight <= maxTextureSize
|
||||
&& (mComputedFields.mNeedLayerForFunctors
|
||||
|| (!MathUtils::isZero(mPrimitiveFields.mAlpha)
|
||||
&& mPrimitiveFields.mAlpha < 1
|
||||
&& mPrimitiveFields.mHasOverlappingRendering));
|
||||
}
|
||||
|
||||
LayerType effectiveLayerType() const {
|
||||
return promotedToLayer() ? LayerType::RenderLayer : mLayerProperties.mType;
|
||||
return CC_UNLIKELY(promotedToLayer()) ? LayerType::RenderLayer : mLayerProperties.mType;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -636,6 +663,9 @@ private:
|
||||
SkMatrix* mTransformMatrix;
|
||||
|
||||
Sk3DView mTransformCamera;
|
||||
|
||||
// Force layer on for functors to enable render features they don't yet support (clipping)
|
||||
bool mNeedLayerForFunctors = false;
|
||||
} mComputedFields;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user