Bug 1409446 - Modify the extra-clip flag to instead track more useful information. r=ethlin,mstange

Instead of just keeping a count of how many "extra clips" (aka
out-of-band clips) we have pushed, track more complex information for
each clip. In particular, track the display item's normal clip chain, as
well as the clip id of the extra clip that was pushed. This will be
needed to override clip cache information in the next patch.

MozReview-Commit-ID: AWKDTkelhyL

--HG--
extra : rebase_source : 379e38550cf45d54862850f6c4aad0ac488f6ca9
This commit is contained in:
Kartikaya Gupta 2017-10-24 15:45:59 -04:00
parent 54e570d116
commit eae58bd759
8 changed files with 56 additions and 23 deletions

View File

@ -631,7 +631,6 @@ WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent)
DisplayListBuilder::DisplayListBuilder(PipelineId aId,
const wr::LayoutSize& aContentSize,
size_t aCapacity)
: mExtraClipCount(0)
{
MOZ_COUNT_CTOR(DisplayListBuilder);
mWrState = wr_state_new(aId, aContentSize, aCapacity);
@ -720,30 +719,47 @@ DisplayListBuilder::DefineClip(const Maybe<layers::FrameMetrics::ViewID>& aAnces
}
void
DisplayListBuilder::PushClip(const wr::WrClipId& aClipId, bool aExtra)
DisplayListBuilder::PushClip(const wr::WrClipId& aClipId,
const DisplayItemClipChain* aParent)
{
wr_dp_push_clip(mWrState, aClipId.id);
WRDL_LOG("PushClip id=%" PRIu64 "\n", mWrState, aClipId.id);
if (!aExtra) {
if (!aParent) {
mClipStack.push_back(wr::ScrollOrClipId(aClipId));
} else {
mExtraClipCount++;
auto it = mCacheOverride.insert({ aParent, std::vector<wr::WrClipId>() });
it.first->second.push_back(aClipId);
WRDL_LOG("Pushing override %p -> %" PRIu64 "\n", mWrState, aParent, aClipId.id);
}
}
void
DisplayListBuilder::PopClip(bool aExtra)
DisplayListBuilder::PopClip(const DisplayItemClipChain* aParent)
{
WRDL_LOG("PopClip\n", mWrState);
if (!aExtra) {
if (!aParent) {
MOZ_ASSERT(mClipStack.back().is<wr::WrClipId>());
mClipStack.pop_back();
} else {
mExtraClipCount--;
auto it = mCacheOverride.find(aParent);
MOZ_ASSERT(it != mCacheOverride.end());
MOZ_ASSERT(!(it->second.empty()));
WRDL_LOG("Popping override %p -> %" PRIu64 "\n", mWrState, aParent, it->second.back().id);
it->second.pop_back();
if (it->second.empty()) {
mCacheOverride.erase(it);
}
}
wr_dp_pop_clip(mWrState);
}
Maybe<wr::WrClipId>
DisplayListBuilder::GetCacheOverride(const DisplayItemClipChain* aParent)
{
auto it = mCacheOverride.find(aParent);
return it == mCacheOverride.end() ? Nothing() : Some(it->second.back());
}
wr::WrStickyId
DisplayListBuilder::DefineStickyFrame(const wr::LayoutRect& aContentRect,
const wr::StickySideConstraint* aTop,

View File

@ -22,6 +22,8 @@
namespace mozilla {
struct DisplayItemClipChain;
namespace widget {
class CompositorWidget;
}
@ -234,8 +236,9 @@ public:
const wr::LayoutRect& aClipRect,
const nsTArray<wr::ComplexClipRegion>* aComplex = nullptr,
const wr::WrImageMask* aMask = nullptr);
void PushClip(const wr::WrClipId& aClipId, bool aExtra = false);
void PopClip(bool aExtra = false);
void PushClip(const wr::WrClipId& aClipId, const DisplayItemClipChain* aParent = nullptr);
void PopClip(const DisplayItemClipChain* aParent = nullptr);
Maybe<wr::WrClipId> GetCacheOverride(const DisplayItemClipChain* aParent);
wr::WrStickyId DefineStickyFrame(const wr::LayoutRect& aContentRect,
const wr::StickySideConstraint* aTop,
@ -407,7 +410,7 @@ public:
wr::WrState* Raw() { return mWrState; }
// Return true if the current clip stack has any extra clip.
bool HasExtraClip() { return mExtraClipCount > 0; }
bool HasExtraClip() { return !mCacheOverride.empty(); }
protected:
wr::WrState* mWrState;
@ -422,8 +425,20 @@ protected:
// as that results in undefined behaviour in WR.
std::unordered_set<layers::FrameMetrics::ViewID> mScrollIdsDefined;
// The number of extra clips that are in the stack.
uint32_t mExtraClipCount;
// A map that holds the cache overrides creates by "out of band" clips, i.e.
// clips that are generated by display items but that ScrollingLayersHelper
// doesn't know about. These are called "cache overrides" because while we're
// inside one of these clips, the WR clip stack is different from what
// ScrollingLayersHelper thinks it actually is (because of the out-of-band
// clip that was pushed onto the stack) and so ScrollingLayersHelper cannot
// use its clip cache as-is. Instead, any time ScrollingLayersHelper wants
// to define a new clip as a child of clip X, it should first check the
// cache overrides to see if there is an out-of-band clip Y that is already a
// child of X, and then define its clip as a child of Y instead. This map
// stores X -> ClipId of Y, which allows ScrollingLayersHelper to do the
// necessary lookup. Note that there theoretically might be multiple
// different "Y" clips which is why we need a vector.
std::unordered_map<const DisplayItemClipChain*, std::vector<wr::WrClipId>> mCacheOverride;
friend class WebRenderAPI;
};

View File

@ -383,7 +383,7 @@ nsDisplayButtonBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder&
visible,
mFrame,
buttonRect);
mBorderRenderer->CreateWebRenderCommands(aBuilder, aResources, aSc);
mBorderRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
return true;
}
@ -551,7 +551,7 @@ nsDisplayButtonForeground::CreateWebRenderCommands(mozilla::wr::DisplayListBuild
return false;
}
mBorderRenderer->CreateWebRenderCommands(aBuilder, aResources, aSc);
mBorderRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
return true;
}

View File

@ -127,7 +127,7 @@ nsDisplayColumnRule::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aB
}
for (auto iter = mBorderRenderers.begin(); iter != mBorderRenderers.end(); iter++) {
iter->CreateWebRenderCommands(aBuilder, aResources, aSc);
iter->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
}
return true;

View File

@ -719,7 +719,7 @@ nsCSSRendering::CreateWebRenderCommandsForBorder(nsDisplayItem* aItem,
if (!br->CanCreateWebRenderCommands()) {
return false;
}
br->CreateWebRenderCommands(aBuilder, aResources, aSc);
br->CreateWebRenderCommands(aItem, aBuilder, aResources, aSc);
return true;
}
}

View File

@ -3602,7 +3602,8 @@ nsCSSBorderRenderer::CanCreateWebRenderCommands()
}
void
nsCSSBorderRenderer::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
nsCSSBorderRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const layers::StackingContextHelper& aSc)
{
@ -3622,7 +3623,7 @@ nsCSSBorderRenderer::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
LayoutDeviceRect clip = LayoutDeviceRect::FromUnknownRect(mLocalClip.value());
wr::LayoutRect clipRect = aSc.ToRelativeLayoutRect(clip);
wr::WrClipId clipId = aBuilder.DefineClip(Nothing(), Nothing(), clipRect);
aBuilder.PushClip(clipId, true);
aBuilder.PushClip(clipId, aItem->GetClipChain());
}
Range<const wr::BorderSide> wrsides(side, 4);
@ -3634,7 +3635,7 @@ nsCSSBorderRenderer::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
borderRadius);
if (mLocalClip) {
aBuilder.PopClip(true);
aBuilder.PopClip(aItem->GetClipChain());
}
}

View File

@ -108,7 +108,8 @@ public:
void DrawBorders();
bool CanCreateWebRenderCommands();
void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
void CreateWebRenderCommands(nsDisplayItem* aItem,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc);

View File

@ -4731,7 +4731,7 @@ nsDisplayOutline::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuil
return false;
}
mBorderRenderer->CreateWebRenderCommands(aBuilder, aResources, aSc);
mBorderRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
return true;
}
@ -9413,13 +9413,13 @@ nsDisplayMask::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder
// Don't record this clip push in aBuilder's internal clip stack, because
// otherwise any nested ScrollingLayersHelper instances that are created
// will get confused about which clips are pushed.
aBuilder.PushClip(clipId, /*aMask*/ true);
aBuilder.PushClip(clipId, GetClipChain());
}
nsDisplaySVGEffects::CreateWebRenderCommands(aBuilder, aResources, aSc, aManager, aDisplayListBuilder);
if (mask) {
aBuilder.PopClip(/*aMask*/ true);
aBuilder.PopClip(GetClipChain());
}
return true;