Backed out changeset 91760460f914 (bug 1620005) for build bustages on a CLOSED TREE

This commit is contained in:
Andreea Pavel 2020-03-11 19:57:28 +02:00
Родитель ccd17c0d43
Коммит b154619cbb
13 изменённых файлов: 344 добавлений и 435 удалений

Просмотреть файл

@ -9,157 +9,134 @@
namespace mozilla {
namespace layers {
static const size_t kInitialCacheSize = 1024;
static const size_t kMaximumCacheSize = 10240;
static const size_t kCacheThreshold = 1;
DisplayItemCache::DisplayItemCache()
: mMaximumSize(0), mConsecutivePartialDisplayLists(0) {
if (XRE_IsContentProcess() &&
StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
SetCapacity(kInitialCacheSize, kMaximumCacheSize);
}
}
void DisplayItemCache::ClearCache() {
memset(mSlots.Elements(), 0, mSlots.Length() * sizeof(Slot));
mFreeSlots.ClearAndRetainStorage();
for (size_t i = 0; i < CurrentSize(); ++i) {
mFreeSlots.AppendElement(i);
}
}
Maybe<uint16_t> DisplayItemCache::GetNextFreeSlot() {
if (mFreeSlots.IsEmpty() && !GrowIfPossible()) {
return Nothing();
}
return Some(mFreeSlots.PopLastElement());
}
bool DisplayItemCache::GrowIfPossible() {
if (IsFull()) {
return false;
}
const auto currentSize = CurrentSize();
MOZ_ASSERT(currentSize <= mMaximumSize);
// New slots are added one by one, which is amortized O(1) time complexity due
// to underlying storage implementation.
mSlots.AppendElement();
mFreeSlots.AppendElement(currentSize);
return true;
}
void DisplayItemCache::FreeUnusedSlots() {
for (size_t i = 0; i < CurrentSize(); ++i) {
auto& slot = mSlots[i];
if (!slot.mUsed && slot.mOccupied) {
// This entry contained a cached item, but was not used.
slot.mOccupied = false;
mFreeSlots.AppendElement(i);
}
slot.mUsed = false;
}
}
void DisplayItemCache::SetCapacity(const size_t aInitialSize,
const size_t aMaximumSize) {
mMaximumSize = aMaximumSize;
mSlots.SetCapacity(aMaximumSize);
mSlots.SetLength(aInitialSize);
mFreeSlots.SetCapacity(aMaximumSize);
ClearCache();
}
Maybe<uint16_t> DisplayItemCache::AssignSlot(nsPaintedDisplayItem* aItem) {
if (kCacheThreshold > mConsecutivePartialDisplayLists) {
// Wait for |kCacheThreshold| partial display list builds, before caching
// display items. This is meant to avoid caching overhead for interactions
// or pages that do not work well with retained display lists.
// TODO: This is a speculative optimization to minimize regressions.
return Nothing();
}
if (!aItem->CanBeReused()) {
// Do not try to cache items that cannot be reused.
return Nothing();
}
auto& slot = aItem->CacheIndex();
if (!slot) {
slot = GetNextFreeSlot();
if (!slot) {
// The item does not fit in the cache.
return Nothing();
}
}
MOZ_ASSERT(slot && CurrentSize() > *slot);
return slot;
}
void DisplayItemCache::MarkSlotOccupied(
uint16_t aSlotIndex, const wr::WrSpaceAndClipChain& aSpaceAndClip) {
// Caching of the item succeeded, update the slot state.
auto& slot = mSlots[aSlotIndex];
MOZ_ASSERT(!slot.mOccupied);
slot.mOccupied = true;
MOZ_ASSERT(!slot.mUsed);
slot.mUsed = true;
slot.mSpaceAndClip = aSpaceAndClip;
}
Maybe<uint16_t> DisplayItemCache::CanReuseItem(
nsPaintedDisplayItem* aItem, const wr::WrSpaceAndClipChain& aSpaceAndClip) {
auto& slotIndex = aItem->CacheIndex();
if (!slotIndex) {
return Nothing();
}
MOZ_ASSERT(slotIndex && CurrentSize() > *slotIndex);
auto& slot = mSlots[*slotIndex];
if (!slot.mOccupied) {
// The display item has a stale cache slot. Recache the item.
return Nothing();
}
// Spatial id and clip id can change between display lists.
if (!(aSpaceAndClip == slot.mSpaceAndClip)) {
// Mark the cache slot inactive and recache the item.
slot.mOccupied = false;
return Nothing();
}
slot.mUsed = true;
return slotIndex;
}
void DisplayItemCache::UpdateState(const bool aPartialDisplayListBuildFailed,
const wr::PipelineId& aPipelineId) {
const bool pipelineIdChanged = UpdatePipelineId(aPipelineId);
const bool invalidate = pipelineIdChanged || aPartialDisplayListBuildFailed;
mConsecutivePartialDisplayLists =
invalidate ? 0 : mConsecutivePartialDisplayLists + 1;
if (IsEmpty()) {
// The cache is empty so nothing needs to be updated.
if (!IsEnabled()) {
return;
}
// Clear the cache if the partial display list build failed, or if the
// pipeline id changed.
if (invalidate) {
ClearCache();
} else {
FreeUnusedSlots();
const bool clearCache =
UpdatePipelineId(aPipelineId) || aPartialDisplayListBuildFailed;
if (clearCache) {
memset(mCachedItemState.Elements(), 0,
mCachedItemState.Length() * sizeof(CacheEntry));
mNextIndex = 0;
mFreeList.Clear();
}
PopulateFreeList(clearCache);
}
void DisplayItemCache::PopulateFreeList(const bool aAddAll) {
uint16_t index = 0;
for (auto& state : mCachedItemState) {
if (aAddAll || (!state.mUsed && state.mCached)) {
// This entry contained a cached item, but was not used.
state.mCached = false;
mFreeList.AppendElement(index);
}
state.mUsed = false;
index++;
}
}
static bool CanCacheItem(const nsPaintedDisplayItem* aItem) {
// Only cache leaf display items that can be reused.
if (!aItem->CanBeReused()) {
return false;
}
return aItem->CanBeCached();
}
void DisplayItemCache::MaybeStartCaching(nsPaintedDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder) {
if (!IsEnabled()) {
return;
}
Stats().AddTotal();
auto& index = aItem->CacheIndex();
if (!index) {
if (!CanCacheItem(aItem)) {
// The item cannot be cached.
return;
}
index = GetNextCacheIndex();
if (!index) {
// The item does not fit in the cache.
return;
}
}
// Update the current cache index, which is used by |MaybeEndCaching()| below.
MOZ_ASSERT(!mCurrentIndex);
mCurrentIndex = index;
MOZ_ASSERT(CanCacheItem(aItem));
MOZ_ASSERT(mCurrentIndex && CurrentCacheSize() > *mCurrentIndex);
aBuilder.StartCachedItem(*mCurrentIndex);
}
void DisplayItemCache::MaybeEndCaching(wr::DisplayListBuilder& aBuilder) {
if (!IsEnabled() || !mCurrentIndex) {
return;
}
if (aBuilder.EndCachedItem(*mCurrentIndex)) {
// Caching of the item succeeded, update the cached item state.
auto& state = mCachedItemState[*mCurrentIndex];
MOZ_ASSERT(!state.mCached);
state.mCached = true;
MOZ_ASSERT(!state.mUsed);
state.mUsed = true;
state.mSpaceAndClip = aBuilder.CurrentSpaceAndClipChain();
Stats().AddCached();
}
mCurrentIndex = Nothing();
}
bool DisplayItemCache::ReuseItem(nsPaintedDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder) {
if (!IsEnabled()) {
return false;
}
auto& index = aItem->CacheIndex();
if (!index) {
return false;
}
auto& state = mCachedItemState[*index];
if (!state.mCached) {
// The display item has a stale cache state.
return false; // Recache item.
}
// Spatial id and clip id can change between display lists.
if (!(aBuilder.CurrentSpaceAndClipChain() == state.mSpaceAndClip)) {
// TODO(miko): Technically we might be able to update just the changed data
// here but it adds a lot of complexity.
// Mark the cache state false and recache the item.
state.mCached = false;
return false;
}
Stats().AddReused();
Stats().AddTotal();
state.mUsed = true;
aBuilder.ReuseItem(*index);
return true;
}
} // namespace layers

Просмотреть файл

@ -28,17 +28,7 @@ class CacheStats {
void Reset() { mCached = mReused = mTotal = 0; }
void Print() {
static uint64_t avgC = 1;
static uint64_t avgR = 1;
static uint64_t avgT = 1;
avgC += mCached;
avgR += mReused;
avgT += mTotal;
printf("Cached: %zu (avg: %f), Reused: %zu (avg: %f), Total: %zu\n",
mCached, (double)avgC / (double)avgT, mReused,
(double)avgR / (double)avgT, mTotal);
printf("Cached: %zu, Reused: %zu, Total: %zu\n", mCached, mReused, mTotal);
}
void AddCached() { mCached++; }
@ -62,24 +52,9 @@ class CacheStats {
*/
class DisplayItemCache final {
public:
DisplayItemCache();
DisplayItemCache() : mMaxCacheSize(0), mNextIndex(0) {}
/**
* Returns true if display item caching is enabled, otherwise false.
*/
bool IsEnabled() const { return mMaximumSize > 0; }
/**
* Returns true if there are no cached items, otherwise false.
*/
bool IsEmpty() const { return mFreeSlots.Length() == CurrentSize(); }
/**
* Returns true if the cache has reached the maximum size, otherwise false.
*/
bool IsFull() const {
return mFreeSlots.IsEmpty() && CurrentSize() == mMaximumSize;
}
bool IsEnabled() const { return mMaxCacheSize > 0; }
/**
* Updates the cache state based on the given display list build information
@ -94,50 +69,69 @@ class DisplayItemCache final {
/**
* Returns the current cache size.
*/
size_t CurrentSize() const { return mSlots.Length(); }
size_t CurrentCacheSize() const {
return IsEnabled() ? mCachedItemState.Length() : 0;
}
/**
* If there are free slots in the cache, assigns a cache slot to the given
* display item |aItem| and returns it. Otherwise returns Nothing().
* Sets the initial and max cache size to given |aInitialSize| and |aMaxSize|.
*
* Currently the cache size is constant, but a good improvement would be to
* set the initial and maximum size based on the display list length.
*/
Maybe<uint16_t> AssignSlot(nsPaintedDisplayItem* aItem);
void SetCapacity(const size_t aInitialSize, const size_t aMaxSize) {
mMaxCacheSize = aMaxSize;
mCachedItemState.SetCapacity(aMaxSize);
mCachedItemState.SetLength(aInitialSize);
mFreeList.SetCapacity(aMaxSize);
}
/**
* Marks the slot with the given |slotIndex| occupied and used.
* Also stores the current space and clipchain |aSpaceAndClip|.
* If the given display item |aItem| can be cached, update the cache state of
* the item and tell WR DisplayListBuilder |aBuilder| to cache WR display
* items until |EndCaching()| is called.
*
* If the display item cannot be cached, this function does nothing.
*/
void MarkSlotOccupied(uint16_t slotIndex,
const wr::WrSpaceAndClipChain& aSpaceAndClip);
void MaybeStartCaching(nsPaintedDisplayItem* aItem,
wr::DisplayListBuilder& aBuilder);
/**
* Returns the slot index of the the given display item |aItem|, if the item
* can be reused. The current space and clipchain |aSpaceAndClip| is used to
* check whether the cached item is still valid.
* If the item cannot be reused, returns Nothing().
* Tell WR DisplayListBuilder |aBuilder| to stop caching WR display items.
*
* If the display item cannot be cached, this function does nothing.
*/
Maybe<uint16_t> CanReuseItem(nsPaintedDisplayItem* aItem,
const wr::WrSpaceAndClipChain& aSpaceAndClip);
void MaybeEndCaching(wr::DisplayListBuilder& aBuilder);
/**
* If the given |aItem| has been cached, tell WR DisplayListBuilder |aBuilder|
* to reuse it.
* Returns true if the item was reused, otherwise returns false.
*/
bool ReuseItem(nsPaintedDisplayItem* aItem, wr::DisplayListBuilder& aBuilder);
CacheStats& Stats() { return mCacheStats; }
private:
struct Slot {
Slot() : mSpaceAndClip{}, mOccupied(false), mUsed(false) {}
struct CacheEntry {
wr::WrSpaceAndClipChain mSpaceAndClip;
bool mOccupied;
bool mCached;
bool mUsed;
};
void ClearCache();
void FreeUnusedSlots();
bool GrowIfPossible();
Maybe<uint16_t> GetNextFreeSlot();
Maybe<uint16_t> GetNextCacheIndex() {
if (mFreeList.IsEmpty()) {
return Nothing();
}
return Some(mFreeList.PopLastElement());
}
/**
* Sets the initial and max cache size to given |aInitialSize| and |aMaxSize|.
* Iterates through |mCachedItemState| and adds unused entries to free list.
* If |aAddAll| is true, adds every entry regardless of the state.
*/
void SetCapacity(const size_t aInitialSize, const size_t aMaximumSize);
void PopulateFreeList(const bool aAddAll);
/**
* Returns true if the given |aPipelineId| is different from the previous one,
@ -149,11 +143,12 @@ class DisplayItemCache final {
return !isSame;
}
size_t mMaximumSize;
nsTArray<Slot> mSlots;
nsTArray<uint16_t> mFreeSlots;
nsTArray<CacheEntry> mCachedItemState;
nsTArray<uint16_t> mFreeList;
size_t mMaxCacheSize;
uint16_t mNextIndex;
Maybe<uint16_t> mCurrentIndex;
Maybe<wr::PipelineId> mPreviousPipelineId;
size_t mConsecutivePartialDisplayLists;
CacheStats mCacheStats;
};

Просмотреть файл

@ -1552,7 +1552,12 @@ WebRenderCommandBuilder::WebRenderCommandBuilder(
mLastAsr(nullptr),
mDumpIndent(0),
mDoGrouping(false),
mContainsSVGGroup(false) {}
mContainsSVGGroup(false) {
if (XRE_IsContentProcess() &&
StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
mDisplayItemCache.SetCapacity(10000, 10000);
}
}
void WebRenderCommandBuilder::Destroy() {
mLastCanvasDatas.Clear();
@ -1598,6 +1603,13 @@ void WebRenderCommandBuilder::BuildWebRenderCommands(
mContainsSVGGroup = false;
MOZ_ASSERT(mDumpIndent == 0);
if (mDisplayItemCache.IsEnabled()) {
mDisplayItemCache.UpdateState(aDisplayListBuilder->PartialBuildFailed(),
aBuilder.CurrentPipelineId());
aBuilder.SetDisplayListCacheSize(mDisplayItemCache.CurrentCacheSize());
// mDisplayItemCache.Stats().Reset();
}
{
nsPresContext* presContext =
aDisplayListBuilder->RootReferenceFrame()->PresContext();
@ -1667,6 +1679,10 @@ void WebRenderCommandBuilder::BuildWebRenderCommands(
// Remove the user data those are not displayed on the screen and
// also reset the data to unused for next transaction.
RemoveUnusedAndResetWebRenderUserData();
if (mDisplayItemCache.IsEnabled()) {
// mDisplayItemCache.Stats().Print();
}
}
bool WebRenderCommandBuilder::ShouldDumpDisplayList(
@ -1686,11 +1702,13 @@ void WebRenderCommandBuilder::CreateWebRenderCommands(
auto* item = aItem->AsPaintedDisplayItem();
MOZ_RELEASE_ASSERT(item, "Tried to paint item that cannot be painted");
if (aBuilder.ReuseItem(item)) {
if (mDisplayItemCache.ReuseItem(item, aBuilder)) {
// No further processing should be needed, since the item was reused.
return;
}
mDisplayItemCache.MaybeStartCaching(item, aBuilder);
aItem->SetPaintRect(aItem->GetBuildingRect());
RenderRootStateManager* manager =
mManager->GetRenderRootStateManager(aBuilder.GetRenderRoot());
@ -1703,6 +1721,8 @@ void WebRenderCommandBuilder::CreateWebRenderCommands(
if (!createdWRCommands) {
PushItemAsImage(aItem, aBuilder, aResources, aSc, aDisplayListBuilder);
}
mDisplayItemCache.MaybeEndCaching(aBuilder);
}
void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(

Просмотреть файл

@ -255,6 +255,8 @@ class WebRenderCommandBuilder final {
wr::RenderRootArray<wr::usize> mBuilderDumpIndex;
wr::usize mDumpIndent;
DisplayItemCache mDisplayItemCache;
public:
// Whether consecutive inactive display items should be grouped into one
// blob image.

Просмотреть файл

@ -317,13 +317,11 @@ void WebRenderLayerManager::EndTransactionWithoutLayer(
wr::DisplayListBuilder builder(
WrBridge()->GetPipeline(), wrRects[wr::RenderRoot::Default].size,
mLastDisplayListSizes[wr::RenderRoot::Default], &mDisplayItemCache);
mLastDisplayListSizes[wr::RenderRoot::Default]);
for (auto renderRoot : wr::kNonDefaultRenderRoots) {
if (!rects[renderRoot].IsEmpty()) {
builder.CreateSubBuilder(wrRects[renderRoot].size,
mLastDisplayListSizes[renderRoot], nullptr,
renderRoot);
mLastDisplayListSizes[renderRoot], renderRoot);
}
}
@ -347,14 +345,9 @@ void WebRenderLayerManager::EndTransactionWithoutLayer(
// generating the WR display list is the closest equivalent
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
builder.UpdateCacheState(aDisplayListBuilder->PartialBuildFailed());
mWebRenderCommandBuilder.BuildWebRenderCommands(
builder, resourceUpdates, aDisplayList, aDisplayListBuilder,
mScrollDatas, std::move(aFilters));
builder.UpdateCacheSize();
builderDumpIndex =
mWebRenderCommandBuilder.GetBuilderDumpIndex(builder.GetRenderRoot());
containsSVGGroup = mWebRenderCommandBuilder.GetContainsSVGGroup();

Просмотреть файл

@ -238,7 +238,6 @@ class WebRenderLayerManager final : public LayerManager {
wr::RenderRootArray<size_t> mLastDisplayListSizes;
wr::RenderRootArray<RenderRootStateManager> mStateManagers;
DisplayItemCache mDisplayItemCache;
};
} // namespace layers

Просмотреть файл

@ -924,16 +924,13 @@ void WebRenderAPI::RunOnRenderThread(UniquePtr<RendererEvent> aEvent) {
DisplayListBuilder::DisplayListBuilder(PipelineId aId,
const wr::LayoutSize& aContentSize,
size_t aCapacity,
layers::DisplayItemCache* aCache,
RenderRoot aRenderRoot)
size_t aCapacity, RenderRoot aRenderRoot)
: mCurrentSpaceAndClipChain(wr::RootScrollNodeWithChain()),
mActiveFixedPosTracker(nullptr),
mPipelineId(aId),
mContentSize(aContentSize),
mRenderRoot(aRenderRoot),
mSendSubBuilderDisplayList(aRenderRoot == wr::RenderRoot::Default),
mDisplayItemCache(aCache) {
mSendSubBuilderDisplayList(aRenderRoot == wr::RenderRoot::Default) {
MOZ_COUNT_CTOR(DisplayListBuilder);
mWrState = wr_state_new(aId, aContentSize, aCapacity);
}
@ -949,11 +946,11 @@ void DisplayListBuilder::ClearSave() { wr_dp_clear_save(mWrState); }
DisplayListBuilder& DisplayListBuilder::CreateSubBuilder(
const wr::LayoutSize& aContentSize, size_t aCapacity,
layers::DisplayItemCache* aCache, wr::RenderRoot aRenderRoot) {
wr::RenderRoot aRenderRoot) {
MOZ_ASSERT(mRenderRoot == wr::RenderRoot::Default);
MOZ_ASSERT(!mSubBuilders[aRenderRoot]);
mSubBuilders[aRenderRoot] = MakeUnique<DisplayListBuilder>(
mPipelineId, aContentSize, aCapacity, aCache, aRenderRoot);
mPipelineId, aContentSize, aCapacity, aRenderRoot);
return *mSubBuilders[aRenderRoot];
}
@ -1488,83 +1485,20 @@ void DisplayListBuilder::PushBoxShadow(
aBorderRadius, aClipMode);
}
void DisplayListBuilder::StartGroup(nsPaintedDisplayItem* aItem) {
if (!mDisplayItemCache || mDisplayItemCache->IsFull()) {
return;
}
MOZ_ASSERT(!mCurrentCacheSlot);
mCurrentCacheSlot = mDisplayItemCache->AssignSlot(aItem);
if (mCurrentCacheSlot) {
wr_dp_start_item_group(mWrState, mCurrentCacheSlot.ref());
}
void DisplayListBuilder::ReuseItem(wr::ItemKey aKey) {
wr_dp_push_reuse_item(mWrState, aKey);
}
void DisplayListBuilder::CancelGroup() {
if (!mDisplayItemCache || !mCurrentCacheSlot) {
return;
}
wr_dp_cancel_item_group(mWrState);
mCurrentCacheSlot = Nothing();
void DisplayListBuilder::StartCachedItem(wr::ItemKey aKey) {
wr_dp_start_cached_item(mWrState, aKey);
}
void DisplayListBuilder::FinishGroup() {
if (!mDisplayItemCache || !mCurrentCacheSlot) {
return;
}
MOZ_ASSERT(mCurrentCacheSlot);
if (wr_dp_finish_item_group(mWrState, mCurrentCacheSlot.ref())) {
mDisplayItemCache->MarkSlotOccupied(mCurrentCacheSlot.ref(),
CurrentSpaceAndClipChain());
mDisplayItemCache->Stats().AddCached();
}
mCurrentCacheSlot = Nothing();
bool DisplayListBuilder::EndCachedItem(wr::ItemKey aKey) {
return wr_dp_end_cached_item(mWrState, aKey);
}
bool DisplayListBuilder::ReuseItem(nsPaintedDisplayItem* aItem) {
if (!mDisplayItemCache) {
return false;
}
mDisplayItemCache->Stats().AddTotal();
if (mDisplayItemCache->IsEmpty()) {
return false;
}
Maybe<uint16_t> slot =
mDisplayItemCache->CanReuseItem(aItem, CurrentSpaceAndClipChain());
if (slot) {
mDisplayItemCache->Stats().AddReused();
wr_dp_push_reuse_items(mWrState, slot.ref());
return true;
}
return false;
}
void DisplayListBuilder::UpdateCacheState(
const bool aPartialDisplayListBuildFailed) {
if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) {
mDisplayItemCache->UpdateState(aPartialDisplayListBuildFailed,
CurrentPipelineId());
#if 0
mDisplayItemCache->Stats().Print();
mDisplayItemCache->Stats().Reset();
#endif
}
}
void DisplayListBuilder::UpdateCacheSize() {
if (mDisplayItemCache && mDisplayItemCache->IsEnabled()) {
wr_dp_set_cache_size(mWrState, mDisplayItemCache->CurrentSize());
}
void DisplayListBuilder::SetDisplayListCacheSize(const size_t aCacheSize) {
wr_dp_set_cache_size(mWrState, aCacheSize);
}
Maybe<layers::ScrollableLayerGuid::ViewID>

Просмотреть файл

@ -25,7 +25,6 @@
#include "Units.h"
class nsDisplayItem;
class nsPaintedDisplayItem;
class nsDisplayTransform;
#undef None
@ -40,7 +39,6 @@ class CompositorWidget;
namespace layers {
class CompositorBridgeParent;
class DisplayItemCache;
class WebRenderBridgeParent;
class RenderRootStateManager;
struct RenderRootDisplayListData;
@ -413,7 +411,6 @@ class DisplayListBuilder final {
public:
DisplayListBuilder(wr::PipelineId aId, const wr::LayoutSize& aContentSize,
size_t aCapacity = 0,
layers::DisplayItemCache* aCache = nullptr,
RenderRoot aRenderRoot = RenderRoot::Default);
DisplayListBuilder(DisplayListBuilder&&) = default;
@ -435,7 +432,6 @@ class DisplayListBuilder final {
bool HasSubBuilder(RenderRoot aRenderRoot);
DisplayListBuilder& CreateSubBuilder(const wr::LayoutSize& aContentSize,
size_t aCapacity,
layers::DisplayItemCache* aCache,
RenderRoot aRenderRoot);
DisplayListBuilder& SubBuilder(RenderRoot aRenderRoot);
@ -626,33 +622,10 @@ class DisplayListBuilder final {
const wr::BorderRadius& aBorderRadius,
const wr::BoxShadowClipMode& aClipMode);
/**
* Notifies the DisplayListBuilder that it can group together WR display items
* that are pushed until |CancelGroup()| or |FinishGroup()| call.
*/
void StartGroup(nsPaintedDisplayItem* aItem);
/**
* Cancels grouping of the display items and discards all the display items
* pushed between the |StartGroup()| and |CancelGroup()| calls.
*/
void CancelGroup();
/**
* Finishes the display item group. The group is stored in WebRender backend,
* and can be reused with |ReuseItem()|, if the Gecko display item is reused.
*/
void FinishGroup();
/**
* Try to reuse the previously created WebRender display items for the given
* Gecko display item |aItem|.
* Returns true if the items were reused, otherwise returns false.
*/
bool ReuseItem(nsPaintedDisplayItem* aItem);
void UpdateCacheState(const bool aPartialDisplayListBuildFailed);
void UpdateCacheSize();
void StartCachedItem(wr::ItemKey aKey);
bool EndCachedItem(wr::ItemKey aKey);
void ReuseItem(wr::ItemKey aKey);
void SetDisplayListCacheSize(const size_t aCacheSize);
uint64_t CurrentClipChainId() const {
return mCurrentSpaceAndClipChain.clip_chain;
@ -759,9 +732,6 @@ class DisplayListBuilder final {
RenderRoot mRenderRoot;
bool mSendSubBuilderDisplayList;
layers::DisplayItemCache* mDisplayItemCache;
Maybe<uint16_t> mCurrentCacheSlot;
friend class WebRenderAPI;
friend class SpaceAndClipChainHelper;
};

Просмотреть файл

@ -33,11 +33,11 @@ use program_cache::{remove_disk_cache, WrProgramCache};
use rayon;
use thread_profiler::register_thread_with_profiler;
use webrender::{
api::units::*, api::*, set_profiler_hooks, ApiRecordingReceiver, AsyncPropertySampler, AsyncScreenshotHandle,
BinaryRecorder, Compositor, CompositorCapabilities, CompositorConfig, DebugFlags, Device, NativeSurfaceId,
NativeSurfaceInfo, NativeTileId, PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererOptions,
RendererStats, SceneBuilderHooks, ShaderPrecacheFlags, Shaders, ThreadListener, UploadMethod, VertexUsageHint,
WrShaders,
api::*, api::units::*, ApiRecordingReceiver, AsyncPropertySampler, AsyncScreenshotHandle,
BinaryRecorder, Compositor, CompositorCapabilities, DebugFlags, Device,
NativeSurfaceId, PipelineInfo, ProfilerHooks, RecordedFrameHandle, Renderer, RendererOptions, RendererStats,
SceneBuilderHooks, ShaderPrecacheFlags, Shaders, ThreadListener, UploadMethod, VertexUsageHint,
WrShaders, set_profiler_hooks, CompositorConfig, NativeSurfaceInfo, NativeTileId
};
#[cfg(target_os = "macos")]
@ -972,7 +972,9 @@ pub struct WrHitTester {
}
#[no_mangle]
pub extern "C" fn wr_api_request_hit_tester(dh: &DocumentHandle) -> *mut WrHitTester {
pub extern "C" fn wr_api_request_hit_tester(
dh: &DocumentHandle,
) -> *mut WrHitTester {
let hit_tester = dh.api.request_hit_tester(dh.document_id);
Box::into_raw(Box::new(WrHitTester { ptr: hit_tester }))
}
@ -983,15 +985,20 @@ pub unsafe extern "C" fn wr_hit_tester_clone(hit_tester: *mut WrHitTester) -> *m
Box::into_raw(Box::new(WrHitTester { ptr: new_ref }))
}
#[no_mangle]
pub extern "C" fn wr_hit_tester_hit_test(
hit_tester: &WrHitTester,
point: WorldPoint,
out_pipeline_id: &mut WrPipelineId,
out_scroll_id: &mut u64,
out_hit_info: &mut u16,
out_hit_info: &mut u16
) -> bool {
let result = hit_tester.ptr.hit_test(None, point, HitTestFlags::empty());
let result = hit_tester.ptr.hit_test(
None,
point,
HitTestFlags::empty()
);
for item in &result.items {
// For now we should never be getting results back for which the tag is
@ -1205,8 +1212,13 @@ extern "C" {
clip_rect: DeviceIntRect,
);
fn wr_compositor_end_frame(compositor: *mut c_void);
fn wr_compositor_enable_native_compositor(compositor: *mut c_void, enable: bool);
fn wr_compositor_get_capabilities(compositor: *mut c_void) -> CompositorCapabilities;
fn wr_compositor_enable_native_compositor(
compositor: *mut c_void,
enable: bool,
);
fn wr_compositor_get_capabilities(
compositor: *mut c_void,
) -> CompositorCapabilities;
}
pub struct WrCompositor(*mut c_void);
@ -1220,7 +1232,13 @@ impl Compositor for WrCompositor {
is_opaque: bool,
) {
unsafe {
wr_compositor_create_surface(self.0, id, virtual_offset, tile_size, is_opaque);
wr_compositor_create_surface(
self.0,
id,
virtual_offset,
tile_size,
is_opaque,
);
}
}
@ -1293,7 +1311,9 @@ impl Compositor for WrCompositor {
}
fn get_capabilities(&self) -> CompositorCapabilities {
unsafe { wr_compositor_get_capabilities(self.0) }
unsafe {
wr_compositor_get_capabilities(self.0)
}
}
}
@ -2546,7 +2566,10 @@ pub extern "C" fn wr_dp_push_iframe(
}
// A helper fn to construct a PrimitiveFlags
fn prim_flags(is_backface_visible: bool, prefer_compositor_surface: bool) -> PrimitiveFlags {
fn prim_flags(
is_backface_visible: bool,
prefer_compositor_surface: bool,
) -> PrimitiveFlags {
let mut flags = PrimitiveFlags::empty();
if is_backface_visible {
@ -2796,18 +2819,16 @@ pub extern "C" fn wr_dp_push_clear_rect_with_parent_clip(
}
#[no_mangle]
pub extern "C" fn wr_dp_push_image(
state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_rendering: ImageRendering,
key: WrImageKey,
premultiplied_alpha: bool,
color: ColorF,
prefer_compositor_surface: bool,
) {
pub extern "C" fn wr_dp_push_image(state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_rendering: ImageRendering,
key: WrImageKey,
premultiplied_alpha: bool,
color: ColorF,
prefer_compositor_surface: bool) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
let space_and_clip = parent.to_webrender(state.pipeline_id);
@ -2880,21 +2901,19 @@ pub extern "C" fn wr_dp_push_repeating_image(
/// Push a 3 planar yuv image.
#[no_mangle]
pub extern "C" fn wr_dp_push_yuv_planar_image(
state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_key_0: WrImageKey,
image_key_1: WrImageKey,
image_key_2: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
color_range: WrColorRange,
image_rendering: ImageRendering,
prefer_compositor_surface: bool,
) {
pub extern "C" fn wr_dp_push_yuv_planar_image(state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_key_0: WrImageKey,
image_key_1: WrImageKey,
image_key_2: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
color_range: WrColorRange,
image_rendering: ImageRendering,
prefer_compositor_surface: bool) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
let space_and_clip = parent.to_webrender(state.pipeline_id);
@ -2921,20 +2940,18 @@ pub extern "C" fn wr_dp_push_yuv_planar_image(
/// Push a 2 planar NV12 image.
#[no_mangle]
pub extern "C" fn wr_dp_push_yuv_NV12_image(
state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_key_0: WrImageKey,
image_key_1: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
color_range: WrColorRange,
image_rendering: ImageRendering,
prefer_compositor_surface: bool,
) {
pub extern "C" fn wr_dp_push_yuv_NV12_image(state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_key_0: WrImageKey,
image_key_1: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
color_range: WrColorRange,
image_rendering: ImageRendering,
prefer_compositor_surface: bool) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
let space_and_clip = parent.to_webrender(state.pipeline_id);
@ -2961,19 +2978,17 @@ pub extern "C" fn wr_dp_push_yuv_NV12_image(
/// Push a yuv interleaved image.
#[no_mangle]
pub extern "C" fn wr_dp_push_yuv_interleaved_image(
state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_key_0: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
color_range: WrColorRange,
image_rendering: ImageRendering,
prefer_compositor_surface: bool,
) {
pub extern "C" fn wr_dp_push_yuv_interleaved_image(state: &mut WrState,
bounds: LayoutRect,
clip: LayoutRect,
is_backface_visible: bool,
parent: &WrSpaceAndClipChain,
image_key_0: WrImageKey,
color_depth: WrColorDepth,
color_space: WrYuvColorSpace,
color_range: WrColorRange,
image_rendering: ImageRendering,
prefer_compositor_surface: bool) {
debug_assert!(unsafe { is_in_main_thread() || is_in_compositor_thread() });
let space_and_clip = parent.to_webrender(state.pipeline_id);
@ -3543,26 +3558,25 @@ pub extern "C" fn wr_dp_start_cached_item(state: &mut WrState, key: ItemKey) {
debug_assert!(state.current_item_key.is_none(), "Nested item keys");
state.current_item_key = Some(key);
state.frame_builder.dl_builder.start_item_group(key);
state.frame_builder.dl_builder.start_extra_data_chunk();
}
#[no_mangle]
pub extern "C" fn wr_dp_cancel_item_group(state: &mut WrState) {
state.current_item_key = None;
pub extern "C" fn wr_dp_end_cached_item(state: &mut WrState, key: ItemKey) -> bool {
let _previous = state.current_item_key.take().expect("Nested item keys");
debug_assert!(_previous == key, "Item key changed during caching");
state.frame_builder.dl_builder.cancel_item_group();
if !state.frame_builder.dl_builder.end_extra_data_chunk() {
return false;
}
state.frame_builder.dl_builder.push_reuse_item(key);
true
}
#[no_mangle]
pub extern "C" fn wr_dp_finish_item_group(state: &mut WrState, key: ItemKey) -> bool {
state.current_item_key = None;
state.frame_builder.dl_builder.finish_item_group(key)
}
#[no_mangle]
pub extern "C" fn wr_dp_push_reuse_items(state: &mut WrState, key: ItemKey) {
state.frame_builder.dl_builder.push_reuse_items(key);
pub extern "C" fn wr_dp_push_reuse_item(state: &mut WrState, key: ItemKey) {
state.frame_builder.dl_builder.push_reuse_item(key);
}
#[no_mangle]

Просмотреть файл

@ -68,8 +68,8 @@ impl DisplayItemCache {
) {
if capacity > self.items.len() {
self.items.resize_with(capacity, || None::<CachedDisplayItem>);
// println!("Current cache size: {:?} elements, {:?} bytes",
// capacity, std::mem::size_of::<CachedDisplayItem>() * capacity);
// println!("Current cache size: {:?}",
// mem::size_of::<CachedDisplayItem>() * capacity);
}
}

Просмотреть файл

@ -911,7 +911,7 @@ pub struct DisplayListBuilder {
pub pipeline_id: PipelineId,
extra_data: Vec<u8>,
extra_data_chunk_start: usize,
extra_data_chunk_len: usize,
writing_extra_data_chunk: bool,
next_clip_index: usize,
@ -945,7 +945,7 @@ impl DisplayListBuilder {
pipeline_id,
extra_data: Vec::new(),
extra_data_chunk_start: 0,
extra_data_chunk_len: 0,
writing_extra_data_chunk: false,
next_clip_index: FIRST_CLIP_NODE_INDEX,
@ -1744,38 +1744,29 @@ impl DisplayListBuilder {
self.push_item(&di::DisplayItem::PopAllShadows);
}
fn truncate_extra_data_chunk(&mut self) {
self.extra_data.truncate(self.extra_data_chunk_start)
}
pub fn start_item_group(&mut self, _key: di::ItemKey) {
pub fn start_extra_data_chunk(&mut self) {
self.writing_extra_data_chunk = true;
self.extra_data_chunk_start = self.extra_data.len();
self.extra_data_chunk_len = self.extra_data.len();
}
pub fn finish_item_group(&mut self, key: di::ItemKey) -> bool {
/// Returns true, if any bytes were written to extra data buffer.
pub fn end_extra_data_chunk(&mut self) -> bool {
self.writing_extra_data_chunk = false;
let chunk_size = self.extra_data.len() - self.extra_data_chunk_start;
if chunk_size > 0 {
self.push_reuse_items(key);
return true
}
false
(self.extra_data.len() - self.extra_data_chunk_len) > 0
}
pub fn cancel_item_group(&mut self) {
debug_assert!(self.writing_extra_data_chunk);
self.writing_extra_data_chunk = false;
self.truncate_extra_data_chunk();
pub fn push_reuse_item(
&mut self,
key: di::ItemKey,
) {
let item = di::DisplayItem::ReuseItem(key);
self.push_item(&item);
}
pub fn push_reuse_items(&mut self, key: di::ItemKey) {
self.push_item(&di::DisplayItem::ReuseItem(key));
}
pub fn set_cache_size(&mut self, cache_size: usize) {
pub fn set_cache_size(
&mut self,
cache_size: usize,
) {
self.cache_size = cache_size;
}

Просмотреть файл

@ -5185,10 +5185,8 @@ bool nsDisplayBackgroundColor::CreateWebRenderCommands(
aBuilder.PushRectWithAnimation(r, r, !BackfaceIsHidden(),
wr::ToColorF(ToDeviceColor(mColor)), &prop);
} else {
aBuilder.StartGroup(this);
aBuilder.PushRect(r, r, !BackfaceIsHidden(),
wr::ToColorF(ToDeviceColor(mColor)));
aBuilder.FinishGroup();
}
return true;
@ -5542,9 +5540,7 @@ bool nsDisplayCompositorHitTestInfo::CreateWebRenderCommands(
const wr::LayoutRect rect = wr::ToLayoutRect(devRect);
aBuilder.StartGroup(this);
aBuilder.PushHitTest(rect, rect, !BackfaceIsHidden());
aBuilder.FinishGroup();
aBuilder.ClearHitTestInfo();
return true;

Просмотреть файл

@ -3215,6 +3215,16 @@ class nsPaintedDisplayItem : public nsDisplayItem {
MOZ_ASSERT_UNREACHABLE("Paint() is not implemented!");
}
/**
* Display items that are guaranteed to produce the same output from
* |CreateWebRenderCommands()|, regardless of the surrounding state,
* can return true. This allows |DisplayItemCache| to cache the output of
* |CreateWebRenderCommands()|, and avoid the call for successive paints, if
* the item is reused. If calling |CreateWebRenderCommands()| would not create
* any WebRender display items, |CanBeCached()| should return false.
*/
virtual bool CanBeCached() const { return false; }
/**
* External storage used by |DisplayItemCache| to avoid hashmap lookups.
* If an item is reused and has the cache index set, it means that
@ -4913,6 +4923,8 @@ class nsDisplayBackgroundColor : public nsPaintedDisplayItem {
}
}
bool CanBeCached() const final { return !HasBackgroundClipText(); }
NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR)
void RestoreState() override {
@ -5303,6 +5315,12 @@ class nsDisplayCompositorHitTestInfo : public nsDisplayHitTestInfoBase {
MOZ_COUNTED_DTOR_OVERRIDE(nsDisplayCompositorHitTestInfo)
bool CanBeCached() const final {
// Do not try to cache gecko hit test items with empty hit test area,
// because they would not create any WebRender display items.
return !HitTestArea().IsEmpty();
}
NS_DISPLAY_DECL_NAME("CompositorHitTestInfo", TYPE_COMPOSITOR_HITTEST_INFO)
void InitializeScrollTarget(nsDisplayListBuilder* aBuilder);