diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/layers/wr/DisplayItemCache.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/gfx/layers/wr/DisplayItemCache.h b/gfx/layers/wr/DisplayItemCache.h new file mode 100644 index 0000000000..e7a1b83e81 --- /dev/null +++ b/gfx/layers/wr/DisplayItemCache.h @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_DISPLAY_ITEM_CACHE_H +#define GFX_DISPLAY_ITEM_CACHE_H + +#include "mozilla/webrender/WebRenderAPI.h" +#include "nsTArray.h" + +class nsDisplayList; +class nsDisplayListBuilder; +class nsPaintedDisplayItem; + +namespace mozilla { + +namespace wr { +class DisplayListBuilder; +} // namespace wr + +namespace layers { + +class CacheStats { + public: + CacheStats() = default; + + 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); + } + + void AddCached() { mCached++; } + void AddReused() { mReused++; } + void AddTotal() { mTotal++; } + + private: + size_t mCached = 0; + size_t mReused = 0; + size_t mTotal = 0; +}; + +/** + * DisplayItemCache keeps track of which Gecko display items have already had + * their respective WebRender display items sent to WebRender backend. + * + * Ideally creating the WR display items for a Gecko display item would not + * depend on any external state. However currently pipeline id, clip id, and + * spatial id can change between display lists, even if the Gecko display items + * have not. This state is tracked by DisplayItemCache. + */ +class DisplayItemCache final { + public: + DisplayItemCache(); + + /** + * Clears the cache. + */ + void Clear(); + + /** + * Sets the initial and max cache size to given |aInitialSize| and |aMaxSize|. + */ + void SetCapacity(const size_t aInitialSize, const size_t aMaximumSize); + + /** + * Sets the display list used by the cache. + */ + void SetDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayList* aList); + + /** + * Sets the pipeline id used by the cache. + */ + void SetPipelineId(const wr::PipelineId& aPipelineId); + + /** + * Enables caching immediately if the cache is valid, and display list is set. + */ + void SkipWaitingForPartialDisplayList() { + mCaching = mDisplayList && !mInvalid; + } + + /** + * Returns true if display item caching is enabled, otherwise false. + */ + bool IsEnabled() const { return !mSuppressed && mMaximumSize > 0; } + + /** + * Suppress display item caching. This doesn't clear any existing cached + * items or change the underlying capacity, it just makes IsEnabled() return + * false. It is not meant to be flipped in the middle of a display list build, + * but rather set before the display list build starts to suppress use of the + * cache for that display list build. + */ + bool SetSuppressed(bool aSuppressed) { + if (aSuppressed == mSuppressed) { + return mSuppressed; + } + mSuppressed = aSuppressed; + return !mSuppressed; + } + + /** + * 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; + } + + /** + * Returns the current cache size. + */ + size_t CurrentSize() const { return mSlots.Length(); } + + /** + * If there are free slots in the cache, assigns a cache slot to the given + * display item |aItem| and returns it. Otherwise returns Nothing(). + */ + Maybe<uint16_t> AssignSlot(nsPaintedDisplayItem* aItem); + + /** + * Marks the slot with the given |slotIndex| occupied and used. + * Also stores the current space and clipchain |aSpaceAndClip|. + */ + void MarkSlotOccupied(uint16_t slotIndex, + const wr::WrSpaceAndClipChain& aSpaceAndClip); + + /** + * 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(). + */ + Maybe<uint16_t> CanReuseItem(nsPaintedDisplayItem* aItem, + const wr::WrSpaceAndClipChain& aSpaceAndClip); + + CacheStats& Stats() { return mCacheStats; } + + private: + struct Slot { + Slot() : mSpaceAndClip{}, mOccupied(false), mUsed(false) {} + + wr::WrSpaceAndClipChain mSpaceAndClip; + bool mOccupied; + bool mUsed; + }; + + void FreeUnusedSlots(); + Maybe<uint16_t> GetNextFreeSlot(); + bool GrowIfPossible(); + void UpdateState(); + + // The lifetime of display lists exceed the lifetime of DisplayItemCache. + // This pointer stores the address of the display list that is using this + // cache, and it is only used for pointer comparisons. + nsDisplayList* mDisplayList; + + size_t mMaximumSize; + nsTArray<Slot> mSlots; + nsTArray<uint16_t> mFreeSlots; + + wr::PipelineId mPipelineId; + bool mCaching; + bool mInvalid; + bool mSuppressed; + + CacheStats mCacheStats; +}; + +class MOZ_RAII AutoDisplayItemCacheSuppressor { + public: + explicit AutoDisplayItemCacheSuppressor(DisplayItemCache* aCache) + : mCache(aCache) { + mWasSuppressed = mCache->SetSuppressed(true); + } + + // Note that this restores the original state rather than unconditionally + // unsuppressing the cache for future-proofing/robustification. Currently + // we only ever use this RAII in one non-recursive function, but we might + // decide to expand its usage to other scenarios and end up with nested + // suppressions, in which case restoring the state back to what we found it + // is better. + ~AutoDisplayItemCacheSuppressor() { mCache->SetSuppressed(mWasSuppressed); } + + private: + DisplayItemCache* mCache; + bool mWasSuppressed; +}; + +} // namespace layers +} // namespace mozilla + +#endif /* GFX_DISPLAY_ITEM_CACHE_H */ |