Backed out 5 changesets (bug 1558926) for WebRender build bustages. CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Fri, 24 Jan 2020 20:42:16 +0200
changeset 511705 65b1787817bdd4addf847582f564a68afabdb932
parent 511704 519a3bf8de9403f05b526a501b1543e7eb52a0c2
child 511706 3803b2403fa26a9726088bd66e043760b9915273
push id37054
push userbtara@mozilla.com
push dateSat, 25 Jan 2020 09:45:27 +0000
treeherdermozilla-central@f7f534f08b48 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1558926
milestone74.0a1
backs out974bcab6b1bf3cea22595e23d06cd9457d302299
1865e6d29dcfdcc1ec7adb5a5fa8fa9df183083b
92b415dac733b24ce8013e2ba6dd629c25c7af5c
30481c41873ab75cb2b0c49860d6b67ad7e38bf5
a4d9a1af297af013b60da92594942f02c955a338
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 5 changesets (bug 1558926) for WebRender build bustages. CLOSED TREE Backed out changeset 974bcab6b1bf (bug 1558926) Backed out changeset 1865e6d29dcf (bug 1558926) Backed out changeset 92b415dac733 (bug 1558926) Backed out changeset 30481c41873a (bug 1558926) Backed out changeset a4d9a1af297a (bug 1558926)
gfx/layers/moz.build
gfx/layers/wr/DisplayItemCache.cpp
gfx/layers/wr/DisplayItemCache.h
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/layers/wr/WebRenderCommandBuilder.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/wr/webrender/src/scene.rs
gfx/wr/webrender/src/scene_builder_thread.rs
gfx/wr/webrender/src/scene_building.rs
gfx/wr/webrender_api/src/display_item.rs
gfx/wr/webrender_api/src/display_item_cache.rs
gfx/wr/webrender_api/src/display_list.rs
gfx/wr/webrender_api/src/lib.rs
layout/painting/RetainedDisplayListBuilder.cpp
layout/painting/nsDisplayList.h
modules/libpref/init/StaticPrefList.yaml
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -251,17 +251,16 @@ EXPORTS.mozilla.layers += [
     'SyncObject.h',
     'TextureSourceProvider.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
     'TreeTraversal.h',
     'UpdateImageHelper.h',
     'wr/AsyncImagePipelineManager.h',
     'wr/ClipManager.h',
-    'wr/DisplayItemCache.h',
     'wr/IpcResourceUpdateQueue.h',
     'wr/RenderRootBoundary.h',
     'wr/RenderRootStateManager.h',
     'wr/RenderRootTypes.h',
     'wr/StackingContextHelper.h',
     'wr/WebRenderBridgeChild.h',
     'wr/WebRenderBridgeParent.h',
     'wr/WebRenderCanvasRenderer.h',
@@ -519,17 +518,16 @@ UNIFIED_SOURCES += [
     'ShareableCanvasRenderer.cpp',
     'SourceSurfaceSharedData.cpp',
     'SourceSurfaceVolatileData.cpp',
     'SyncObject.cpp',
     'TextureSourceProvider.cpp',
     'TextureWrapperImage.cpp',
     'wr/AsyncImagePipelineManager.cpp',
     'wr/ClipManager.cpp',
-    'wr/DisplayItemCache.cpp',
     'wr/IpcResourceUpdateQueue.cpp',
     'wr/RenderRootStateManager.cpp',
     'wr/RenderRootTypes.cpp',
     'wr/StackingContextHelper.cpp',
     'wr/WebRenderBridgeChild.cpp',
     'wr/WebRenderBridgeParent.cpp',
     'wr/WebRenderCanvasRenderer.cpp',
     'wr/WebRenderCommandBuilder.cpp',
deleted file mode 100644
--- a/gfx/layers/wr/DisplayItemCache.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/* -*- 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/. */
-
-#include "DisplayItemCache.h"
-
-namespace mozilla {
-namespace layers {
-
-void DisplayItemCache::UpdateState(const bool aPartialDisplayListBuildFailed,
-                                   const wr::PipelineId& aPipelineId) {
-  if (!IsEnabled()) {
-    return;
-  }
-
-  // Clear the cache if the partial display list build failed, or if the
-  // pipeline id changed.
-  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 nsDisplayItem* aItem) {
-  // Only cache leaf display items that can be reused.
-  if (!aItem->CanBeReused()) {
-    return false;
-  }
-
-  switch (aItem->GetType()) {
-    case DisplayItemType::TYPE_BACKGROUND_COLOR:
-      // case DisplayItemType::TYPE_TEXT:
-      MOZ_ASSERT(!aItem->HasChildren());
-      return true;
-    default:
-      return false;
-  }
-}
-
-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);
-
-  auto& state = mCachedItemState[*mCurrentIndex];
-  MOZ_ASSERT(!state.mCached);
-  state.mCached = true;
-  MOZ_ASSERT(!state.mUsed);
-  state.mUsed = true;
-  state.mSpaceAndClip = aBuilder.CurrentSpaceAndClipChain();
-
-  Stats().AddCached();
-  aBuilder.StartCachedItem(*mCurrentIndex);
-}
-
-void DisplayItemCache::MaybeEndCaching(wr::DisplayListBuilder& aBuilder) {
-  if (IsEnabled() && mCurrentIndex) {
-    aBuilder.EndCachedItem(*mCurrentIndex);
-    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
-}  // namespace mozilla
deleted file mode 100644
--- a/gfx/layers/wr/DisplayItemCache.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/* -*- 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 "mozilla/Maybe.h"
-#include "nsTArray.h"
-
-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() {
-    printf("Cached: %zu, Reused: %zu, Total: %zu\n", mCached, mReused, 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() : mMaxCacheSize(0), mNextIndex(0) {}
-
-  bool IsEnabled() const { return mMaxCacheSize > 0; }
-
-  /**
-   * Updates the cache state based on the given display list build information
-   * and pipeline id.
-   *
-   * This is necessary because Gecko display items can only be reused for the
-   * partial display list builds following a full display list build.
-   */
-  void UpdateState(const bool aPartialDisplayListBuildFailed,
-                   const wr::PipelineId& aPipelineId);
-
-  /**
-   * Returns the current cache size.
-   */
-  size_t CurrentCacheSize() const {
-    return IsEnabled() ? mCachedItemState.Length() : 0;
-  }
-
-  /**
-   * 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.
-   */
-  void SetCapacity(const size_t aInitialSize, const size_t aMaxSize) {
-    mMaxCacheSize = aMaxSize;
-    mCachedItemState.SetCapacity(aMaxSize);
-    mCachedItemState.SetLength(aInitialSize);
-    mFreeList.SetCapacity(aMaxSize);
-  }
-
-  /**
-   * 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 MaybeStartCaching(nsPaintedDisplayItem* aItem,
-                         wr::DisplayListBuilder& aBuilder);
-
-  /**
-   * Tell WR DisplayListBuilder |aBuilder| to stop caching WR display items.
-   *
-   * If the display item cannot be cached, this function does nothing.
-   */
-  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 CacheEntry {
-    wr::WrSpaceAndClipChain mSpaceAndClip;
-    bool mCached;
-    bool mUsed;
-  };
-
-  Maybe<uint16_t> GetNextCacheIndex() {
-    if (mFreeList.IsEmpty()) {
-      return Nothing();
-    }
-
-    return Some(mFreeList.PopLastElement());
-  }
-
-  /**
-   * Iterates through |mCachedItemState| and adds unused entries to free list.
-   * If |aAddAll| is true, adds every entry regardless of the state.
-   */
-  void PopulateFreeList(const bool aAddAll);
-
-  /**
-   * Returns true if the given |aPipelineId| is different from the previous one,
-   * otherwise returns false.
-   */
-  bool UpdatePipelineId(const wr::PipelineId& aPipelineId) {
-    const bool isSame = mPreviousPipelineId.refOr(aPipelineId) == aPipelineId;
-    mPreviousPipelineId = Some(aPipelineId);
-    return !isSame;
-  }
-
-  nsTArray<CacheEntry> mCachedItemState;
-  nsTArray<uint16_t> mFreeList;
-  size_t mMaxCacheSize;
-  uint16_t mNextIndex;
-  Maybe<uint16_t> mCurrentIndex;
-  Maybe<wr::PipelineId> mPreviousPipelineId;
-  CacheStats mCacheStats;
-};
-
-}  // namespace layers
-}  // namespace mozilla
-
-#endif /* GFX_DISPLAY_ITEM_CACHE_H */
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1539,31 +1539,16 @@ void WebRenderCommandBuilder::DoGrouping
                      .PostTranslate(residualOffset.x, residualOffset.y);
   group.mScale = scale;
   group.mScrollId = scrollId;
   g.ConstructGroups(aDisplayListBuilder, this, aBuilder, aResources, &group,
                     aList, aSc);
   mCurrentClipManager->EndList(aSc);
 }
 
-WebRenderCommandBuilder::WebRenderCommandBuilder(
-    WebRenderLayerManager* aManager)
-    : mManager(aManager),
-      mRootStackingContexts(nullptr),
-      mCurrentClipManager(nullptr),
-      mLastAsr(nullptr),
-      mDumpIndent(0),
-      mDoGrouping(false),
-      mContainsSVGGroup(false) {
-  if (XRE_IsContentProcess() &&
-      StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
-    mDisplayItemCache.SetCapacity(10000, 10000);
-  }
-}
-
 void WebRenderCommandBuilder::Destroy() {
   mLastCanvasDatas.Clear();
   ClearCachedResources();
 }
 
 void WebRenderCommandBuilder::EmptyTransaction() {
   // We need to update canvases that might have changed.
   for (auto iter = mLastCanvasDatas.Iter(); !iter.Done(); iter.Next()) {
@@ -1598,23 +1583,16 @@ void WebRenderCommandBuilder::BuildWebRe
     mBuilderDumpIndex[renderRoot] = 0;
   }
   MOZ_ASSERT(mLayerScrollDatas.IsEmpty());
   mLastCanvasDatas.Clear();
   mLastAsr = nullptr;
   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();
     bool isTopLevelContent =
         presContext->Document()->IsTopLevelContentDocument();
 
     wr::RenderRootArray<Maybe<StackingContextHelper>> pageRootScs;
     for (auto renderRoot : wr::kRenderRoots) {
@@ -1674,62 +1652,27 @@ void WebRenderCommandBuilder::BuildWebRe
       mClipManagers[renderRoot].EndBuild();
     }
   }
   mLayerScrollDatas.Clear();
 
   // 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(
     nsDisplayListBuilder* aBuilder) {
   return aBuilder != nullptr && aBuilder->IsInActiveDocShell() &&
          ((XRE_IsParentProcess() &&
            StaticPrefs::gfx_webrender_dl_dump_parent()) ||
           (XRE_IsContentProcess() &&
            StaticPrefs::gfx_webrender_dl_dump_content()));
 }
 
-void WebRenderCommandBuilder::CreateWebRenderCommands(
-    nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
-    mozilla::wr::IpcResourceUpdateQueue& aResources,
-    const StackingContextHelper& aSc,
-    nsDisplayListBuilder* aDisplayListBuilder) {
-  auto* item = aItem->AsPaintedDisplayItem();
-  MOZ_RELEASE_ASSERT(item, "Tried to paint item that cannot be painted");
-
-  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());
-
-  // Note: this call to CreateWebRenderCommands can recurse back into
-  // this function if the |item| is a wrapper for a sublist.
-  const bool createdWRCommands = aItem->CreateWebRenderCommands(
-      aBuilder, aResources, aSc, manager, aDisplayListBuilder);
-
-  if (!createdWRCommands) {
-    PushItemAsImage(aItem, aBuilder, aResources, aSc, aDisplayListBuilder);
-  }
-
-  mDisplayItemCache.MaybeEndCaching(aBuilder);
-}
-
 void WebRenderCommandBuilder::CreateWebRenderCommandsFromDisplayList(
     nsDisplayList* aDisplayList, nsDisplayItem* aWrappingItem,
     nsDisplayListBuilder* aDisplayListBuilder, const StackingContextHelper& aSc,
     wr::DisplayListBuilder& aBuilder, wr::IpcResourceUpdateQueue& aResources) {
   AutoRestore<ClipManager*> prevClipManager(mCurrentClipManager);
   mCurrentClipManager = &mClipManagers[aBuilder.GetRenderRoot()];
   if (mDoGrouping) {
     MOZ_RELEASE_ASSERT(
@@ -1821,18 +1764,26 @@ void WebRenderCommandBuilder::CreateWebR
 
       if (dumpEnabled) {
         std::stringstream ss;
         nsFrame::PrintDisplayItem(aDisplayListBuilder, item, ss,
                                   static_cast<uint32_t>(mDumpIndent));
         printf_stderr("%s", ss.str().c_str());
       }
 
-      CreateWebRenderCommands(item, aBuilder, aResources, aSc,
-                              aDisplayListBuilder);
+      // Note: this call to CreateWebRenderCommands can recurse back into
+      // this function if the |item| is a wrapper for a sublist.
+      item->SetPaintRect(item->GetBuildingRect());
+      RenderRootStateManager* manager =
+          mManager->GetRenderRootStateManager(aBuilder.GetRenderRoot());
+      bool createdWRCommands = item->CreateWebRenderCommands(
+          aBuilder, aResources, aSc, manager, aDisplayListBuilder);
+      if (!createdWRCommands) {
+        PushItemAsImage(item, aBuilder, aResources, aSc, aDisplayListBuilder);
+      }
 
       if (dumpEnabled) {
         mBuilderDumpIndex[aBuilder.GetRenderRoot()] = aBuilder.Dump(
             mDumpIndent + 1, Some(mBuilderDumpIndex[aBuilder.GetRenderRoot()]),
             Nothing());
       }
     }
 
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -10,17 +10,16 @@
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/layers/ClipManager.h"
 #include "mozilla/layers/RenderRootBoundary.h"
 #include "mozilla/layers/WebRenderMessages.h"
 #include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/layers/WebRenderUserData.h"
 #include "nsDisplayList.h"
 #include "nsIFrame.h"
-#include "DisplayItemCache.h"
 
 namespace mozilla {
 
 namespace layers {
 
 class CanvasLayer;
 class ImageClient;
 class ImageContainer;
@@ -78,17 +77,24 @@ class WebRenderScrollDataCollection {
 };
 
 class WebRenderCommandBuilder final {
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderUserData>>
       WebRenderUserDataRefTable;
   typedef nsTHashtable<nsRefPtrHashKey<WebRenderCanvasData>> CanvasDataSet;
 
  public:
-  explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager);
+  explicit WebRenderCommandBuilder(WebRenderLayerManager* aManager)
+      : mManager(aManager),
+        mRootStackingContexts(nullptr),
+        mCurrentClipManager(nullptr),
+        mLastAsr(nullptr),
+        mDumpIndent(0),
+        mDoGrouping(false),
+        mContainsSVGGroup(false) {}
 
   void Destroy();
 
   void EmptyTransaction();
 
   bool NeedsEmptyTransaction();
 
   void BuildWebRenderCommands(
@@ -222,21 +228,16 @@ class WebRenderCommandBuilder final {
     WebRenderCommandBuilder& mBuilder;
     RenderRootBoundary mBoundary;
     size_t mLayerCountBeforeRecursing;
   };
   friend class ScrollDataBoundaryWrapper;
 
  private:
   RenderRootStateManager* GetRenderRootStateManager(wr::RenderRoot aRenderRoot);
-  void CreateWebRenderCommands(nsDisplayItem* aItem,
-                               mozilla::wr::DisplayListBuilder& aBuilder,
-                               mozilla::wr::IpcResourceUpdateQueue& aResources,
-                               const StackingContextHelper& aSc,
-                               nsDisplayListBuilder* aDisplayListBuilder);
 
   wr::RenderRootArray<Maybe<StackingContextHelper>>* mRootStackingContexts;
   wr::RenderRootArray<ClipManager> mClipManagers;
   ClipManager* mCurrentClipManager;
 
   // We use this as a temporary data structure while building the mScrollData
   // inside a layers-free transaction.
   WebRenderScrollDataCollection mLayerScrollDatas;
@@ -250,18 +251,16 @@ class WebRenderCommandBuilder final {
   WebRenderUserDataRefTable mWebRenderUserDatas;
 
   // Store of WebRenderCanvasData objects for use in empty transactions
   CanvasDataSet mLastCanvasDatas;
 
   wr::RenderRootArray<wr::usize> mBuilderDumpIndex;
   wr::usize mDumpIndent;
 
-  DisplayItemCache mDisplayItemCache;
-
  public:
   // Whether consecutive inactive display items should be grouped into one
   // blob image.
   bool mDoGrouping;
 
   // True if the most recently build display list contained an svg that
   // we did grouping for.
   bool mContainsSVGGroup;
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -1390,32 +1390,16 @@ void DisplayListBuilder::PushBoxShadow(
     const wr::BorderRadius& aBorderRadius,
     const wr::BoxShadowClipMode& aClipMode) {
   wr_dp_push_box_shadow(mWrState, aRect, MergeClipLeaf(aClip),
                         aIsBackfaceVisible, &mCurrentSpaceAndClipChain,
                         aBoxBounds, aOffset, aColor, aBlurRadius, aSpreadRadius,
                         aBorderRadius, aClipMode);
 }
 
-void DisplayListBuilder::ReuseItem(wr::ItemKey aKey) {
-  wr_dp_push_reuse_item(mWrState, aKey);
-}
-
-void DisplayListBuilder::StartCachedItem(wr::ItemKey aKey) {
-  wr_dp_start_cached_item(mWrState, aKey);
-}
-
-void DisplayListBuilder::EndCachedItem(wr::ItemKey aKey) {
-  wr_dp_end_cached_item(mWrState, aKey);
-}
-
-void DisplayListBuilder::SetDisplayListCacheSize(const size_t aCacheSize) {
-  wr_dp_set_cache_size(mWrState, aCacheSize);
-}
-
 Maybe<layers::ScrollableLayerGuid::ViewID>
 DisplayListBuilder::GetContainingFixedPosScrollTarget(
     const ActiveScrolledRoot* aAsr) {
   return mActiveFixedPosTracker
              ? mActiveFixedPosTracker->GetScrollTargetForASR(aAsr)
              : Nothing();
 }
 
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -395,17 +395,16 @@ class DisplayListBuilder final {
                      RenderRoot aRenderRoot = RenderRoot::Default);
   DisplayListBuilder(DisplayListBuilder&&) = default;
 
   ~DisplayListBuilder();
 
   void Save();
   void Restore();
   void ClearSave();
-
   usize Dump(usize aIndent, const Maybe<usize>& aStart,
              const Maybe<usize>& aEnd);
 
   void Finalize(wr::LayoutSize& aOutContentSizes,
                 wr::BuiltDisplayList& aOutDisplayList);
   void Finalize(layers::RenderRootDisplayListData& aOutTransaction);
 
   RenderRoot GetRenderRoot() const { return mRenderRoot; }
@@ -574,31 +573,20 @@ class DisplayListBuilder final {
   void PushBoxShadow(const wr::LayoutRect& aRect, const wr::LayoutRect& aClip,
                      bool aIsBackfaceVisible, const wr::LayoutRect& aBoxBounds,
                      const wr::LayoutVector2D& aOffset,
                      const wr::ColorF& aColor, const float& aBlurRadius,
                      const float& aSpreadRadius,
                      const wr::BorderRadius& aBorderRadius,
                      const wr::BoxShadowClipMode& aClipMode);
 
-  void StartCachedItem(wr::ItemKey aKey);
-  void EndCachedItem(wr::ItemKey aKey);
-  void ReuseItem(wr::ItemKey aKey);
-  void SetDisplayListCacheSize(const size_t aCacheSize);
-
   uint64_t CurrentClipChainId() const {
     return mCurrentSpaceAndClipChain.clip_chain;
   }
 
-  const wr::WrSpaceAndClipChain& CurrentSpaceAndClipChain() const {
-    return mCurrentSpaceAndClipChain;
-  }
-
-  const wr::PipelineId& CurrentPipelineId() const { return mPipelineId; }
-
   // Checks to see if the innermost enclosing fixed pos item has the same
   // ASR. If so, it returns the scroll target for that fixed-pos item.
   // Otherwise, it returns Nothing().
   Maybe<layers::ScrollableLayerGuid::ViewID> GetContainingFixedPosScrollTarget(
       const ActiveScrolledRoot* aAsr);
 
   Maybe<SideBits> GetContainingFixedPosSideBits(const ActiveScrolledRoot* aAsr);
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -2287,32 +2287,30 @@ impl WebRenderFrameBuilder {
     }
 
 }
 
 pub struct WrState {
     pipeline_id: WrPipelineId,
     frame_builder: WebRenderFrameBuilder,
     current_tag: Option<ItemTag>,
-    current_item_key: Option<ItemKey>,
 }
 
 #[no_mangle]
 pub extern "C" fn wr_state_new(pipeline_id: WrPipelineId,
                                content_size: LayoutSize,
                                capacity: usize) -> *mut WrState {
     assert!(unsafe { !is_in_render_thread() });
 
     let state = Box::new(WrState {
                              pipeline_id: pipeline_id,
                              frame_builder: WebRenderFrameBuilder::with_capacity(pipeline_id,
                                                                                  content_size,
                                                                                  capacity),
                              current_tag: None,
-                             current_item_key: None,
                          });
 
     Box::into_raw(state)
 }
 
 #[no_mangle]
 pub extern "C" fn wr_state_delete(state: *mut WrState) {
     assert!(unsafe { !is_in_render_thread() });
@@ -2673,17 +2671,16 @@ pub extern "C" fn wr_dp_push_rect(state:
         // NB: the damp-e10s talos-test will frequently crash on startup if we
         // early-return here for empty rects. I couldn't figure out why, but
         // it's pretty harmless to feed these through, so, uh, we do?
         clip_rect: clip_rect.unwrap_or(LayoutRect::zero()),
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_rect(
         &prim_info,
         color,
     );
 }
 
@@ -2704,17 +2701,16 @@ pub extern "C" fn wr_dp_push_rect_with_p
     if clip_rect.is_none() { return; }
 
     let prim_info = CommonItemProperties {
         clip_rect: clip_rect.unwrap(),
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_rect(
         &prim_info,
         color,
     );
 }
 
@@ -2757,17 +2753,16 @@ pub extern "C" fn wr_dp_push_backdrop_fi
     if clip_rect.is_none() { return; }
 
     let prim_info = CommonItemProperties {
         clip_rect: clip_rect.unwrap(),
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_backdrop_filter(
         &prim_info,
         &filters,
         &filter_datas,
         &[],
     );
@@ -2786,17 +2781,16 @@ pub extern "C" fn wr_dp_push_clear_rect(
     if clip_rect.is_none() { return; }
 
     let prim_info = CommonItemProperties {
         clip_rect: clip_rect.unwrap(),
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(true),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_clear_rect(
         &prim_info,
     );
 }
 
 #[no_mangle]
@@ -2813,17 +2807,16 @@ pub extern "C" fn wr_dp_push_hit_test(st
     if clip_rect.is_none() { return; }
 
     let prim_info = CommonItemProperties {
         clip_rect: clip_rect.unwrap(),
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_hit_test(
         &prim_info,
     );
 }
 
 #[no_mangle]
@@ -2841,17 +2834,16 @@ pub extern "C" fn wr_dp_push_clear_rect_
     if clip_rect.is_none() { return; }
 
     let prim_info = CommonItemProperties {
         clip_rect: clip_rect.unwrap(),
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(true),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_clear_rect(
         &prim_info,
     );
 }
 
 #[no_mangle]
@@ -2869,17 +2861,16 @@ pub extern "C" fn wr_dp_push_image(state
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     let alpha_type = if premultiplied_alpha {
         AlphaType::PremultipliedAlpha
     } else {
         AlphaType::Alpha
     };
 
@@ -2910,17 +2901,16 @@ pub extern "C" fn wr_dp_push_repeating_i
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     let alpha_type = if premultiplied_alpha {
         AlphaType::PremultipliedAlpha
     } else {
         AlphaType::Alpha
     };
 
@@ -2955,17 +2945,16 @@ pub extern "C" fn wr_dp_push_yuv_planar_
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder
          .dl_builder
          .push_yuv_image(&prim_info,
                          bounds,
                          YuvData::PlanarYCbCr(image_key_0, image_key_1, image_key_2),
                          color_depth,
@@ -2992,17 +2981,16 @@ pub extern "C" fn wr_dp_push_yuv_NV12_im
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder
          .dl_builder
          .push_yuv_image(&prim_info,
                          bounds,
                          YuvData::NV12(image_key_0, image_key_1),
                          color_depth,
@@ -3028,17 +3016,16 @@ pub extern "C" fn wr_dp_push_yuv_interle
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder
          .dl_builder
          .push_yuv_image(&prim_info,
                          bounds,
                          YuvData::InterleavedYCbCr(image_key_0),
                          color_depth,
@@ -3064,18 +3051,17 @@ pub extern "C" fn wr_dp_push_text(state:
 
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         spatial_id: space_and_clip.spatial_id,
         clip_id: space_and_clip.clip_id,
         flags: prim_flags(is_backface_visible),
-        hit_info: state.current_tag,
-        item_key: state.current_item_key,
+        hit_info: state.current_tag
     };
 
     state.frame_builder
          .dl_builder
          .push_text(&prim_info,
                     bounds,
                     &glyph_slice,
                     font_key,
@@ -3122,17 +3108,16 @@ pub extern "C" fn wr_dp_push_line(state:
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: *clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder
          .dl_builder
          .push_line(&prim_info,
                     bounds,
                     wavy_line_thickness,
                     orientation,
@@ -3168,17 +3153,16 @@ pub extern "C" fn wr_dp_push_border(stat
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder
          .dl_builder
          .push_border(&prim_info,
                       rect,
                       widths,
                       border_details);
@@ -3218,17 +3202,16 @@ pub extern "C" fn wr_dp_push_border_imag
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_border(
         &prim_info,
         rect,
         params.widths,
         border_details,
     );
@@ -3277,17 +3260,16 @@ pub extern "C" fn wr_dp_push_border_grad
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_border(
         &prim_info,
         rect,
         widths.into(),
         border_details,
     );
@@ -3340,17 +3322,16 @@ pub extern "C" fn wr_dp_push_border_radi
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_border(
         &prim_info,
         rect,
         widths.into(),
         border_details,
     );
@@ -3384,17 +3365,16 @@ pub extern "C" fn wr_dp_push_linear_grad
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_gradient(
         &prim_info,
         rect,
         gradient,
         tile_size.into(),
         tile_spacing.into(),
@@ -3429,17 +3409,16 @@ pub extern "C" fn wr_dp_push_radial_grad
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder.dl_builder.push_radial_gradient(
         &prim_info,
         rect,
         gradient,
         tile_size,
         tile_spacing);
@@ -3463,70 +3442,31 @@ pub extern "C" fn wr_dp_push_box_shadow(
     let space_and_clip = parent.to_webrender(state.pipeline_id);
 
     let prim_info = CommonItemProperties {
         clip_rect: clip,
         clip_id: space_and_clip.clip_id,
         spatial_id: space_and_clip.spatial_id,
         flags: prim_flags(is_backface_visible),
         hit_info: state.current_tag,
-        item_key: state.current_item_key,
     };
 
     state.frame_builder
          .dl_builder
          .push_box_shadow(&prim_info,
                           box_bounds,
                           offset,
                           color,
                           blur_radius,
                           spread_radius,
                           border_radius,
                           clip_mode);
 }
 
 #[no_mangle]
-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_extra_data_chunk();
-}
-
-#[no_mangle]
-pub extern "C" fn wr_dp_end_cached_item(state: &mut WrState,
-                                        key: ItemKey) {
-    // Avoid pushing reuse item marker when no extra data was written.
-    if state.frame_builder.dl_builder.end_extra_data_chunk() > 0 {
-        state.frame_builder.dl_builder.push_reuse_item(key);
-    }
-
-    debug_assert!(state.current_item_key.is_some(), "Nested item keys");
-    state.current_item_key = None;
-}
-
-#[no_mangle]
-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]
-pub extern "C" fn wr_dp_set_cache_size(state: &mut WrState,
-                                       cache_size: usize) {
-    state.frame_builder
-        .dl_builder
-        .set_cache_size(cache_size);
-}
-
-
-#[no_mangle]
 pub extern "C" fn wr_dump_display_list(state: &mut WrState,
                                        indent: usize,
                                        start: *const usize,
                                        end: *const usize) -> usize {
     let start = unsafe { start.as_ref().cloned() };
     let end = unsafe { end.as_ref().cloned() };
     let range = Range { start, end };
     let mut sink = Cursor::new(Vec::new());
--- a/gfx/wr/webrender/src/scene.rs
+++ b/gfx/wr/webrender/src/scene.rs
@@ -1,13 +1,13 @@
 /* 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/. */
 
-use api::{BuiltDisplayList, DisplayItemCache, ColorF, DynamicProperties, Epoch, FontRenderMode};
+use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, FontRenderMode};
 use api::{PipelineId, PropertyBinding, PropertyBindingId, MixBlendMode, StackingContext};
 use api::units::*;
 use crate::composite::CompositorKind;
 use crate::clip::{ClipStore, ClipDataStore};
 use crate::clip_scroll_tree::{ClipScrollTree, SpatialNodeIndex};
 use crate::frame_builder::{ChasePrimitive, FrameBuilderConfig};
 use crate::hit_test::{HitTester, HitTestingScene, HitTestingSceneStats};
 use crate::internal_types::{FastHashMap, FastHashSet};
@@ -122,28 +122,29 @@ impl SceneProperties {
     pub fn float_properties(&self) -> &FastHashMap<PropertyBindingId, f32> {
         &self.float_properties
     }
 }
 
 /// A representation of the layout within the display port for a given document or iframe.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(Clone)]
 pub struct ScenePipeline {
     pub pipeline_id: PipelineId,
     pub viewport_size: LayoutSize,
     pub content_size: LayoutSize,
     pub background_color: Option<ColorF>,
     pub display_list: BuiltDisplayList,
-    pub display_list_cache: DisplayItemCache,
 }
 
 /// A complete representation of the layout bundling visible pipelines together.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
+#[derive(Clone)]
 pub struct Scene {
     pub root_pipeline_id: Option<PipelineId>,
     pub pipelines: FastHashMap<PipelineId, ScenePipeline>,
     pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
 }
 
 impl Scene {
     pub fn new() -> Self {
@@ -162,30 +163,22 @@ impl Scene {
         &mut self,
         pipeline_id: PipelineId,
         epoch: Epoch,
         display_list: BuiltDisplayList,
         background_color: Option<ColorF>,
         viewport_size: LayoutSize,
         content_size: LayoutSize,
     ) {
-        let pipeline = self.pipelines.remove(&pipeline_id);
-        let mut display_list_cache = pipeline.map_or(Default::default(), |p| {
-            p.display_list_cache
-        });
-
-        display_list_cache.update(&display_list);
-
         let new_pipeline = ScenePipeline {
             pipeline_id,
             viewport_size,
             content_size,
             background_color,
             display_list,
-            display_list_cache,
         };
 
         self.pipelines.insert(pipeline_id, new_pipeline);
         self.pipeline_epochs.insert(pipeline_id, epoch);
     }
 
     pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
         if self.root_pipeline_id == Some(pipeline_id) {
--- a/gfx/wr/webrender/src/scene_builder_thread.rs
+++ b/gfx/wr/webrender/src/scene_builder_thread.rs
@@ -250,17 +250,16 @@ pub struct SceneBuilderThread {
     documents: FastHashMap<DocumentId, Document>,
     rx: Receiver<SceneBuilderRequest>,
     tx: Sender<SceneBuilderResult>,
     api_tx: MsgSender<ApiMsg>,
     config: FrameBuilderConfig,
     size_of_ops: Option<MallocSizeOfOps>,
     hooks: Option<Box<dyn SceneBuilderHooks + Send>>,
     simulate_slow_ms: u32,
-    removed_pipelines: FastHashSet<PipelineId>
 }
 
 pub struct SceneBuilderThreadChannels {
     rx: Receiver<SceneBuilderRequest>,
     tx: Sender<SceneBuilderResult>,
     api_tx: MsgSender<ApiMsg>,
 }
 
@@ -295,17 +294,16 @@ impl SceneBuilderThread {
             documents: Default::default(),
             rx,
             tx,
             api_tx,
             config,
             size_of_ops,
             hooks,
             simulate_slow_ms: 0,
-            removed_pipelines: FastHashSet::default(),
         }
     }
 
     /// Send a message to the render backend thread.
     ///
     /// We first put something in the result queue and then send a wake-up
     /// message to the api queue that the render backend is blocking on.
     pub fn send(&self, msg: SceneBuilderResult) {
@@ -526,45 +524,38 @@ impl SceneBuilderThread {
 
         let scene_build_start_time = precise_time_ns();
 
         let doc = self.documents
                       .entry(txn.document_id)
                       .or_insert_with(|| Document::new(Scene::new()));
         let scene = &mut doc.scene;
 
-        for &(pipeline_id, epoch) in &txn.epoch_updates {
-            scene.update_epoch(pipeline_id, epoch);
-        }
-
-        if let Some(id) = txn.set_root_pipeline {
-            scene.set_root_pipeline_id(id);
-        }
-
-        for &(pipeline_id, _) in &txn.removed_pipelines {
-            scene.remove_pipeline(pipeline_id);
-            self.removed_pipelines.insert(pipeline_id);
-        }
-
         for update in txn.display_list_updates.drain(..) {
-            if self.removed_pipelines.contains(&update.pipeline_id) {
-                continue;
-            }
-
             scene.set_display_list(
                 update.pipeline_id,
                 update.epoch,
                 update.built_display_list,
                 update.background,
                 update.viewport_size,
                 update.content_size,
             );
         }
 
-        self.removed_pipelines.clear();
+        for &(pipeline_id, epoch) in &txn.epoch_updates {
+            scene.update_epoch(pipeline_id, epoch);
+        }
+
+        if let Some(id) = txn.set_root_pipeline {
+            scene.set_root_pipeline_id(id);
+        }
+
+        for &(pipeline_id, _) in &txn.removed_pipelines {
+            scene.remove_pipeline(pipeline_id)
+        }
 
         let mut built_scene = None;
         let mut interner_updates = None;
         if scene.has_root_pipeline() {
             if let Some(request) = txn.request_scene_build.take() {
                 let built = SceneBuilder::build(
                     &scene,
                     request.font_instances,
--- a/gfx/wr/webrender/src/scene_building.rs
+++ b/gfx/wr/webrender/src/scene_building.rs
@@ -444,19 +444,18 @@ impl<'a> SceneBuilder<'a> {
             /* create_tile_cache = */ false,
             ROOT_SPATIAL_NODE_INDEX,
             ClipChainId::NONE,
             RasterSpace::Screen,
             /* is_backdrop_root = */ true,
             device_pixel_scale,
         );
 
-        let cache = &root_pipeline.display_list_cache;
         builder.build_items(
-            &mut root_pipeline.display_list.iter_with_cache(cache),
+            &mut root_pipeline.display_list.iter(),
             root_pipeline.pipeline_id,
             true,
         );
 
         builder.pop_stacking_context();
 
         debug_assert!(builder.sc_stack.is_empty());
 
@@ -683,64 +682,40 @@ impl<'a> SceneBuilder<'a> {
 
     fn build_items(
         &mut self,
         traversal: &mut BuiltDisplayListIter<'a>,
         pipeline_id: PipelineId,
         apply_pipeline_clip: bool,
     ) {
         loop {
-            let item = match traversal.next() {
-                Some(item) => item,
-                None => break,
-            };
-
-            let subtraversal = match item.item() {
-                DisplayItem::PushStackingContext(ref info) => {
-                    let space = self.get_space(&info.spatial_id);
-                    let mut subtraversal = item.sub_iter();
-                    self.build_stacking_context(
-                        &mut subtraversal,
-                        pipeline_id,
-                        &info.stacking_context,
-                        space,
-                        info.origin,
-                        item.filters(),
-                        &item.filter_datas(),
-                        item.filter_primitives(),
-                        info.prim_flags,
-                        apply_pipeline_clip,
-                    );
-                    Some(subtraversal)
+            let subtraversal = {
+                let item = match traversal.next() {
+                    Some(item) => item,
+                    None => break,
+                };
+
+                match item.item() {
+                    DisplayItem::PopReferenceFrame |
+                    DisplayItem::PopStackingContext => return,
+                    _ => (),
                 }
-                DisplayItem::PushReferenceFrame(ref info) => {
-                    let parent_space = self.get_space(&info.parent_spatial_id);
-                    let mut subtraversal = item.sub_iter();
-                    self.build_reference_frame(
-                        &mut subtraversal,
-                        pipeline_id,
-                        parent_space,
-                        info.origin,
-                        &info.reference_frame,
-                        apply_pipeline_clip,
-                    );
-                    Some(subtraversal)
-                }
-                DisplayItem::PopReferenceFrame |
-                DisplayItem::PopStackingContext => return,
-                _ => None,
+
+                self.build_item(
+                    item,
+                    pipeline_id,
+                    apply_pipeline_clip,
+                )
             };
 
             // If build_item created a sub-traversal, we need `traversal` to have the
             // same state as the completed subtraversal, so we reinitialize it here.
             if let Some(mut subtraversal) = subtraversal {
                 subtraversal.merge_debug_stats_from(traversal);
                 *traversal = subtraversal;
-            } else {
-                self.build_item(item, pipeline_id, apply_pipeline_clip);
             }
         }
 
         // TODO: factor this out to be part of capture
         if cfg!(feature = "display_list_stats") {
             let stats = traversal.debug_stats();
             let total_bytes: usize = stats.iter().map(|(_, stats)| stats.num_bytes).sum();
             println!("item, total count, total bytes, % of DL bytes, bytes per item");
@@ -978,20 +953,18 @@ impl<'a> SceneBuilder<'a> {
             &content_size,
             ScrollSensitivity::ScriptAndInputEvents,
             ScrollFrameKind::PipelineRoot,
             LayoutVector2D::zero(),
         );
 
         self.rf_mapper.push_scope();
         self.iframe_depth += 1;
-
-        let cache = &pipeline.display_list_cache;
         self.build_items(
-            &mut pipeline.display_list.iter_with_cache(cache),
+            &mut pipeline.display_list.iter(),
             pipeline.pipeline_id,
             true,
         );
         self.iframe_depth -= 1;
         self.rf_mapper.pop_scope();
 
         self.pipeline_clip_chain_stack.pop();
     }
@@ -1083,20 +1056,20 @@ impl<'a> SceneBuilder<'a> {
             target_spatial_node,
             &self.clip_scroll_tree
         );
         snap_to_device.snap_rect(rect)
     }
 
     fn build_item<'b>(
         &'b mut self,
-        item: DisplayItemRef,
+        item: DisplayItemRef<'a, 'b>,
         pipeline_id: PipelineId,
         apply_pipeline_clip: bool,
-    ) {
+    ) -> Option<BuiltDisplayListIter<'a>> {
         match *item.item() {
             DisplayItem::Image(ref info) => {
                 let (layout, _, clip_and_scroll) = self.process_common_properties_with_bounds(
                     &info.common,
                     &info.bounds,
                     apply_pipeline_clip,
                 );
 
@@ -1321,16 +1294,46 @@ impl<'a> SceneBuilder<'a> {
 
                 self.add_border(
                     clip_and_scroll,
                     &layout,
                     info,
                     item.gradient_stops(),
                 );
             }
+            DisplayItem::PushStackingContext(ref info) => {
+                let space = self.get_space(&info.spatial_id);
+                let mut subtraversal = item.sub_iter();
+                self.build_stacking_context(
+                    &mut subtraversal,
+                    pipeline_id,
+                    &info.stacking_context,
+                    space,
+                    info.origin,
+                    item.filters(),
+                    item.filter_datas(),
+                    item.filter_primitives(),
+                    info.prim_flags,
+                    apply_pipeline_clip,
+                );
+                return Some(subtraversal);
+            }
+            DisplayItem::PushReferenceFrame(ref info) => {
+                let parent_space = self.get_space(&info.parent_spatial_id);
+                let mut subtraversal = item.sub_iter();
+                self.build_reference_frame(
+                    &mut subtraversal,
+                    pipeline_id,
+                    parent_space,
+                    info.origin,
+                    &info.reference_frame,
+                    apply_pipeline_clip,
+                );
+                return Some(subtraversal);
+            }
             DisplayItem::Iframe(ref info) => {
                 let space = self.get_space(&info.space_and_clip.spatial_id);
                 self.build_iframe(
                     info,
                     space,
                 );
             }
             DisplayItem::Clip(ref info) => {
@@ -1448,41 +1451,35 @@ impl<'a> SceneBuilder<'a> {
             }
 
             // Do nothing; these are dummy items for the display list parser
             DisplayItem::SetGradientStops |
             DisplayItem::SetFilterOps |
             DisplayItem::SetFilterData |
             DisplayItem::SetFilterPrimitives => {}
 
-            // Special items that are handled in the parent method
-            DisplayItem::PushStackingContext(..) |
-            DisplayItem::PushReferenceFrame(..) |
             DisplayItem::PopReferenceFrame |
             DisplayItem::PopStackingContext => {
                 unreachable!("Should have returned in parent method.")
             }
-
-            DisplayItem::ReuseItem(..) => {
-                unreachable!("Iterator logic error")
-            }
-
             DisplayItem::PushShadow(info) => {
                 let clip_and_scroll = self.get_clip_and_scroll(
                     &info.space_and_clip.clip_id,
                     &info.space_and_clip.spatial_id,
                     apply_pipeline_clip
                 );
 
                 self.push_shadow(info.shadow, clip_and_scroll, info.should_inflate);
             }
             DisplayItem::PopAllShadows => {
                 self.pop_all_shadows();
             }
         }
+
+        None
     }
 
     // Given a list of clip sources, a positioning node and
     // a parent clip chain, return a new clip chain entry.
     // If the supplied list of clip sources is empty, then
     // just return the parent clip chain id directly.
     fn build_clip_chain(
         &mut self,
--- a/gfx/wr/webrender_api/src/display_item.rs
+++ b/gfx/wr/webrender_api/src/display_item.rs
@@ -28,20 +28,16 @@ pub const MAX_BLUR_RADIUS: f32 = 300.;
 /// is missing then the item doesn't take part in hit testing at all. This
 /// is composed of two numbers. In Servo, the first is an identifier while the
 /// second is used to select the cursor that should be used during mouse
 /// movement. In Gecko, the first is a scrollframe identifier, while the second
 /// is used to store various flags that APZ needs to properly process input
 /// events.
 pub type ItemTag = (u64, u16);
 
-/// An identifier used to refer to previously sent display items. Currently it
-/// refers to individual display items, but this may change later.
-pub type ItemKey = u16;
-
 bitflags! {
     #[repr(C)]
     #[derive(Deserialize, MallocSizeOf, Serialize, PeekPoke)]
     pub struct PrimitiveFlags: u8 {
         /// The CSS backface-visibility property (yes, it can be really granular)
         const IS_BACKFACE_VISIBLE = 1 << 0;
         /// If set, this primitive represents a scroll bar container
         const IS_SCROLLBAR_CONTAINER = 1 << 1;
@@ -73,33 +69,30 @@ pub struct CommonItemProperties {
     /// The coordinate-space the item is in (yes, it can be really granular)
     pub spatial_id: SpatialId,
     /// Opaque bits for our clients to use for hit-testing. This is the most
     /// dubious "common" field, but because it's an Option, it usually only
     /// wastes a single byte (for None).
     pub hit_info: Option<ItemTag>,
     /// Various flags describing properties of this primitive.
     pub flags: PrimitiveFlags,
-    /// The unique id of this display item.
-    pub item_key: Option<ItemKey>
 }
 
 impl CommonItemProperties {
     /// Convenience for tests.
     pub fn new(
         clip_rect: LayoutRect,
         space_and_clip: SpaceAndClipInfo,
     ) -> Self {
         Self {
             clip_rect,
             spatial_id: space_and_clip.spatial_id,
             clip_id: space_and_clip.clip_id,
             hit_info: None,
             flags: PrimitiveFlags::default(),
-            item_key: None,
         }
     }
 }
 
 /// Per-primitive information about the nodes in the clip tree and
 /// the spatial tree that the primitive belongs to.
 ///
 /// Note: this is a separate struct from `PrimitiveInfo` because
@@ -158,18 +151,16 @@ pub enum DisplayItem {
     SetFilterOps,
     SetFilterData,
     SetFilterPrimitives,
 
     // These marker items terminate a scope introduced by a previous item.
     PopReferenceFrame,
     PopStackingContext,
     PopAllShadows,
-
-    ReuseItem(ItemKey),
 }
 
 /// This is a "complete" version of the DisplayItem, with all implicit trailing
 /// arrays included, for debug serialization (captures).
 #[cfg(any(feature = "serialize", feature = "deserialize"))]
 #[cfg_attr(feature = "serialize", derive(Serialize))]
 #[cfg_attr(feature = "deserialize", derive(Deserialize))]
 pub enum DebugDisplayItem {
@@ -200,18 +191,16 @@ pub enum DebugDisplayItem {
     SetGradientStops(Vec<GradientStop>),
     SetFilterOps(Vec<FilterOp>),
     SetFilterData(FilterData),
     SetFilterPrimitives(Vec<FilterPrimitive>),
 
     PopReferenceFrame,
     PopStackingContext,
     PopAllShadows,
-
-    ReuseItem(ItemKey),
 }
 
 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
 pub struct ClipDisplayItem {
     pub id: ClipId,
     pub parent_space_and_clip: SpaceAndClipInfo,
     pub clip_rect: LayoutRect,
     pub image_mask: Option<ImageMask>,
@@ -1475,17 +1464,16 @@ impl DisplayItem {
             DisplayItem::PushStackingContext(..) => "push_stacking_context",
             DisplayItem::SetFilterOps => "set_filter_ops",
             DisplayItem::SetFilterData => "set_filter_data",
             DisplayItem::SetFilterPrimitives => "set_filter_primitives",
             DisplayItem::RadialGradient(..) => "radial_gradient",
             DisplayItem::Rectangle(..) => "rectangle",
             DisplayItem::ScrollFrame(..) => "scroll_frame",
             DisplayItem::SetGradientStops => "set_gradient_stops",
-            DisplayItem::ReuseItem(..) => "reuse_item",
             DisplayItem::StickyFrame(..) => "sticky_frame",
             DisplayItem::Text(..) => "text",
             DisplayItem::YuvImage(..) => "yuv_image",
             DisplayItem::BackdropFilter(..) => "backdrop_filter",
         }
     }
 }
 
deleted file mode 100644
--- a/gfx/wr/webrender_api/src/display_item_cache.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-/* 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/. */
-
-use crate::display_item::*;
-use crate::display_list::*;
-
-#[derive(Debug, Deserialize, PartialEq, Serialize)]
-pub struct CachedDisplayItem {
-    item: DisplayItem,
-    data: Vec<u8>,
-}
-
-impl CachedDisplayItem {
-    pub fn item(&self) -> &DisplayItem {
-        &self.item
-    }
-
-    pub fn data_as_item_range<T>(&self) -> ItemRange<T> {
-        ItemRange::new(&self.data)
-    }
-}
-
-impl From<DisplayItemRef<'_, '_>> for CachedDisplayItem {
-    fn from (item_ref: DisplayItemRef) -> Self {
-        let item = item_ref.item();
-
-        match item {
-            DisplayItem::Text(..) => CachedDisplayItem {
-                item: *item,
-                data: item_ref.glyphs().bytes().to_vec(),
-            },
-            DisplayItem::Rectangle(..) |
-            DisplayItem::Image(..) => CachedDisplayItem {
-                item: *item,
-                data: Vec::new(),
-            },
-            _ => { unimplemented!("Unsupported display item type"); }
-        }
-    }
-}
-
-#[derive(Default, Deserialize, Serialize)]
-pub struct DisplayItemCache {
-    items: Vec<Option<CachedDisplayItem>>
-}
-
-impl DisplayItemCache {
-    fn grow_if_needed(
-        &mut self,
-        capacity: usize
-    ) {
-        if capacity > self.items.len() {
-            self.items.resize_with(capacity, || None::<CachedDisplayItem>);
-            // println!("Current cache size: {:?}",
-            //     mem::size_of::<CachedDisplayItem>() * capacity);
-        }
-    }
-
-    pub fn add_item(
-        &mut self,
-        key: Option<ItemKey>,
-        item: DisplayItemRef
-    ) {
-        let index = usize::from(key.expect("Cached item without key"));
-        self.items[index] = Some(CachedDisplayItem::from(item));
-    }
-
-    pub fn get_item(
-        &self,
-        key: ItemKey
-    ) -> Option<&CachedDisplayItem> {
-        self.items[key as usize].as_ref()
-    }
-
-    pub fn update(
-        &mut self,
-        display_list: &BuiltDisplayList
-    ) {
-        self.grow_if_needed(display_list.cache_size());
-
-        let mut iter = display_list.extra_data_iter();
-
-        loop {
-            let item = match iter.next() {
-                Some(item) => item,
-                None => break,
-            };
-
-            match item.item() {
-                DisplayItem::Rectangle(ref info) => {
-                    self.add_item(info.common.item_key, item);
-                }
-                DisplayItem::Text(ref info) => {
-                    self.add_item(info.common.item_key, item);
-                }
-                DisplayItem::Image(ref info) => {
-                    self.add_item(info.common.item_key, item);
-                }
-                item @ _ => {
-                    unimplemented!("Unexpected item in extra data: {:?}", item);
-                }
-            }
-        }
-    }
-}
--- a/gfx/wr/webrender_api/src/display_list.rs
+++ b/gfx/wr/webrender_api/src/display_list.rs
@@ -13,17 +13,16 @@ use serde::{Deserialize, Serialize};
 use std::io::{stdout, Write};
 use std::marker::PhantomData;
 use std::ops::Range;
 use std::mem;
 use std::collections::HashMap;
 use time::precise_time_ns;
 // local imports
 use crate::display_item as di;
-use crate::display_item_cache::*;
 use crate::api::{PipelineId, PropertyBinding};
 use crate::gradient_builder::GradientBuilder;
 use crate::color::ColorF;
 use crate::font::{FontInstanceKey, GlyphInstance, GlyphOptions};
 use crate::image::{ColorDepth, ImageKey};
 use crate::units::*;
 
 
@@ -58,31 +57,20 @@ impl<'a, T> Default for ItemRange<'a, T>
         ItemRange {
             bytes: Default::default(),
             _boo: PhantomData,
         }
     }
 }
 
 impl<'a, T> ItemRange<'a, T> {
-    pub fn new(bytes: &'a [u8]) -> Self {
-        Self {
-            bytes,
-            _boo: PhantomData
-        }
-    }
-
     pub fn is_empty(&self) -> bool {
         // Nothing more than space for a length (0).
         self.bytes.len() <= mem::size_of::<usize>()
     }
-
-    pub fn bytes(&self) -> &[u8] {
-        &self.bytes
-    }
 }
 
 impl<'a, T: Default> ItemRange<'a, T> {
     pub fn iter(&self) -> AuxIter<'a, T> {
         AuxIter::new(T::default(), self.bytes)
     }
 }
 
@@ -126,28 +114,21 @@ pub struct BuiltDisplayListDescriptor {
     /// The second IPC time stamp: after serialization
     builder_finish_time: u64,
     /// The third IPC time stamp: just before sending
     send_start_time: u64,
     /// The amount of clipping nodes created while building this display list.
     total_clip_nodes: usize,
     /// The amount of spatial nodes created while building this display list.
     total_spatial_nodes: usize,
-    /// The size of the cache for this display list.
-    cache_size: usize,
-    /// The offset for additional display list data.
-    extra_data_offset: usize,
 }
 
-impl BuiltDisplayListDescriptor {}
-
 pub struct BuiltDisplayListIter<'a> {
     list: &'a BuiltDisplayList,
     data: &'a [u8],
-    cache: Option<&'a DisplayItemCache>,
     cur_item: di::DisplayItem,
     cur_stops: ItemRange<'a, di::GradientStop>,
     cur_glyphs: ItemRange<'a, GlyphInstance>,
     cur_filters: ItemRange<'a, di::FilterOp>,
     cur_filter_data: Vec<TempFilterData<'a>>,
     cur_filter_primitives: ItemRange<'a, di::FilterPrimitive>,
     cur_clip_chain_items: ItemRange<'a, di::ClipId>,
     cur_complex_clip: ItemRange<'a, di::ComplexClipRegion>,
@@ -218,68 +199,16 @@ pub struct ItemStats {
     /// How many instances of this kind of item we deserialized
     pub total_count: usize,
     /// How many bytes we processed for this kind of item
     pub num_bytes: usize,
 }
 
 pub struct DisplayItemRef<'a: 'b, 'b> {
     iter: &'b BuiltDisplayListIter<'a>,
-    cached_item: Option<&'a CachedDisplayItem>,
-}
-
-// Some of these might just become ItemRanges
-impl<'a, 'b> DisplayItemRef<'a, 'b> {
-    fn cached_or_iter_data<T>(
-        &self,
-        data: ItemRange<'a, T>
-    ) -> ItemRange<'a, T> {
-        self.cached_item.map_or(data, |i| i.data_as_item_range())
-    }
-
-    pub fn display_list(&self) -> &BuiltDisplayList {
-        self.iter.display_list()
-    }
-
-    // Creates a new iterator where this element's iterator is, to hack around borrowck.
-    pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
-        BuiltDisplayListIter::new(self.iter.list, self.iter.data, self.iter.cache)
-    }
-
-    pub fn item(&self) -> &di::DisplayItem {
-        self.cached_item.map_or(&self.iter.cur_item, |i| i.item())
-    }
-
-    pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> {
-        self.iter.cur_clip_chain_items
-    }
-
-    pub fn complex_clip(&self) -> ItemRange<di::ComplexClipRegion> {
-        self.iter.cur_complex_clip
-    }
-
-    pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
-        self.cached_or_iter_data(self.iter.cur_glyphs)
-    }
-
-    pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> {
-        self.cached_or_iter_data(self.iter.cur_stops)
-    }
-
-    pub fn filters(&self) -> ItemRange<di::FilterOp> {
-        self.iter.cur_filters
-    }
-
-    pub fn filter_datas(&self) -> &Vec<TempFilterData> {
-        &self.iter.cur_filter_data
-    }
-
-    pub fn filter_primitives(&self) -> ItemRange<di::FilterPrimitive> {
-        self.iter.cur_filter_primitives
-    }
 }
 
 #[derive(PartialEq)]
 enum Peek {
     StartPeeking,
     IsPeeking,
     NotPeeking,
 }
@@ -287,36 +216,35 @@ enum Peek {
 #[derive(Clone)]
 pub struct AuxIter<'a, T> {
     item: T,
     data: &'a [u8],
     size: usize,
 //    _boo: PhantomData<T>,
 }
 
+impl BuiltDisplayListDescriptor {}
+
 impl BuiltDisplayList {
     pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> Self {
         BuiltDisplayList { data, descriptor }
     }
 
     pub fn into_data(mut self) -> (Vec<u8>, BuiltDisplayListDescriptor) {
         self.descriptor.send_start_time = precise_time_ns();
         (self.data, self.descriptor)
     }
 
     pub fn data(&self) -> &[u8] {
         &self.data[..]
     }
 
+    // Currently redundant with data, but may be useful if we add extra data to dl
     pub fn item_slice(&self) -> &[u8] {
-        &self.data[..self.descriptor.extra_data_offset]
-    }
-
-    pub fn extra_slice(&self) -> &[u8] {
-        &self.data[self.descriptor.extra_data_offset..]
+        &self.data[..]
     }
 
     pub fn descriptor(&self) -> &BuiltDisplayListDescriptor {
         &self.descriptor
     }
 
     pub fn times(&self) -> (u64, u64, u64) {
         (
@@ -330,32 +258,17 @@ impl BuiltDisplayList {
         self.descriptor.total_clip_nodes
     }
 
     pub fn total_spatial_nodes(&self) -> usize {
         self.descriptor.total_spatial_nodes
     }
 
     pub fn iter(&self) -> BuiltDisplayListIter {
-        BuiltDisplayListIter::new(self, self.item_slice(), None)
-    }
-
-    pub fn extra_data_iter(&self) -> BuiltDisplayListIter {
-        BuiltDisplayListIter::new(self, self.extra_slice(), None)
-    }
-
-    pub fn iter_with_cache<'a>(
-        &'a self,
-        cache: &'a DisplayItemCache
-    ) -> BuiltDisplayListIter<'a> {
-        BuiltDisplayListIter::new(self, self.item_slice(), Some(cache))
-    }
-
-    pub fn cache_size(&self) -> usize {
-        self.descriptor.cache_size
+        BuiltDisplayListIter::new(self)
     }
 }
 
 /// Returns the byte-range the slice occupied.
 fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> {
     let mut skip_offset = 0usize;
     *data = peek_from_slice(data, &mut skip_offset);
     let (skip, rest) = data.split_at(skip_offset);
@@ -365,25 +278,24 @@ fn skip_slice<'a, T: peek_poke::Peek>(da
 
     ItemRange {
         bytes: skip,
         _boo: PhantomData,
     }
 }
 
 impl<'a> BuiltDisplayListIter<'a> {
-    pub fn new(
-        list: &'a BuiltDisplayList,
-        data: &'a [u8],
-        cache: Option<&'a DisplayItemCache>,
-    ) -> Self {
-        Self {
+    pub fn new(list: &'a BuiltDisplayList) -> Self {
+        Self::new_with_list_and_data(list, list.item_slice())
+    }
+
+    pub fn new_with_list_and_data(list: &'a BuiltDisplayList, data: &'a [u8]) -> Self {
+        BuiltDisplayListIter {
             list,
             data,
-            cache,
             cur_item: di::DisplayItem::PopStackingContext,
             cur_stops: ItemRange::default(),
             cur_glyphs: ItemRange::default(),
             cur_filters: ItemRange::default(),
             cur_filter_data: Vec::new(),
             cur_filter_primitives: ItemRange::default(),
             cur_clip_chain_items: ItemRange::default(),
             cur_complex_clip: ItemRange::default(),
@@ -504,28 +416,17 @@ impl<'a> BuiltDisplayListIter<'a> {
             }
             _ => { /* do nothing */ }
         }
 
         Some(self.as_ref())
     }
 
     pub fn as_ref<'b>(&'b self) -> DisplayItemRef<'a, 'b> {
-        let cached_item = match self.cur_item {
-            di::DisplayItem::ReuseItem(key) => {
-                debug_assert!(self.cache.is_some(), "Cache marker without cache!");
-                self.cache.and_then(|c| c.get_item(key))
-            }
-            _ => None
-        };
-
-        DisplayItemRef {
-            iter: self,
-            cached_item
-        }
+        DisplayItemRef { iter: self }
     }
 
     pub fn skip_current_stacking_context(&mut self) {
         let mut depth = 0;
         while let Some(item) = self.next() {
             match *item.item() {
                 di::DisplayItem::PushStackingContext(..) => depth += 1,
                 di::DisplayItem::PopStackingContext if depth == 0 => return,
@@ -575,16 +476,60 @@ impl<'a> BuiltDisplayListIter<'a> {
     fn log_item_stats(&mut self) {
         self.debug_stats.log_item(self.data, &self.cur_item);
     }
 
     #[cfg(not(feature = "display_list_stats"))]
     fn log_item_stats(&mut self) { /* no-op */ }
 }
 
+// Some of these might just become ItemRanges
+impl<'a, 'b> DisplayItemRef<'a, 'b> {
+    pub fn item(&self) -> &di::DisplayItem {
+        &self.iter.cur_item
+    }
+
+    pub fn complex_clip(&self) -> ItemRange<di::ComplexClipRegion> {
+        self.iter.cur_complex_clip
+    }
+
+    pub fn gradient_stops(&self) -> ItemRange<di::GradientStop> {
+        self.iter.cur_stops
+    }
+
+    pub fn glyphs(&self) -> ItemRange<GlyphInstance> {
+        self.iter.cur_glyphs
+    }
+
+    pub fn filters(&self) -> ItemRange<di::FilterOp> {
+        self.iter.cur_filters
+    }
+
+    pub fn filter_datas(&self) -> &Vec<TempFilterData> {
+        &self.iter.cur_filter_data
+    }
+
+    pub fn filter_primitives(&self) -> ItemRange<di::FilterPrimitive> {
+        self.iter.cur_filter_primitives
+    }
+
+    pub fn clip_chain_items(&self) -> ItemRange<di::ClipId> {
+        self.iter.cur_clip_chain_items
+    }
+
+    pub fn display_list(&self) -> &BuiltDisplayList {
+        self.iter.display_list()
+    }
+
+    // Creates a new iterator where this element's iterator is, to hack around borrowck.
+    pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
+        BuiltDisplayListIter::new_with_list_and_data(self.iter.list, self.iter.data)
+    }
+}
+
 impl<'a, T> AuxIter<'a, T> {
     pub fn new(item: T, mut data: &'a [u8]) -> Self {
         let mut size = 0usize;
         if !data.is_empty() {
             data = peek_from_slice(data, &mut size);
         };
 
         AuxIter {
@@ -688,17 +633,16 @@ impl Serialize for BuiltDisplayList {
                 Real::PushReferenceFrame(v) => Debug::PushReferenceFrame(v),
                 Real::PushStackingContext(v) => Debug::PushStackingContext(v),
                 Real::PushShadow(v) => Debug::PushShadow(v),
                 Real::BackdropFilter(v) => Debug::BackdropFilter(v),
 
                 Real::PopReferenceFrame => Debug::PopReferenceFrame,
                 Real::PopStackingContext => Debug::PopStackingContext,
                 Real::PopAllShadows => Debug::PopAllShadows,
-                Real::ReuseItem(k) => Debug::ReuseItem(k),
             };
             seq.serialize_element(&serial_di)?
         }
         seq.end()
     }
 }
 
 // The purpose of this implementation is to deserialize
@@ -792,17 +736,16 @@ impl<'de> Deserialize<'de> for BuiltDisp
                 Debug::RadialGradient(v) => Real::RadialGradient(v),
                 Debug::PushStackingContext(v) => Real::PushStackingContext(v),
                 Debug::PushShadow(v) => Real::PushShadow(v),
                 Debug::BackdropFilter(v) => Real::BackdropFilter(v),
 
                 Debug::PopStackingContext => Real::PopStackingContext,
                 Debug::PopReferenceFrame => Real::PopReferenceFrame,
                 Debug::PopAllShadows => Real::PopAllShadows,
-                Debug::ReuseItem(k) => Real::ReuseItem(k),
             };
             poke_into_vec(&item, &mut data);
             // the aux data is serialized after the item, hence the temporary
             data.extend(temp.drain(..));
         }
 
         // Add `DisplayItem::max_size` zone of zeroes to the end of display list
         // so there is at least this amount available in the display list during
@@ -829,32 +772,25 @@ pub struct SaveState {
     next_spatial_index: usize,
     next_clip_chain_id: u64,
 }
 
 #[derive(Clone)]
 pub struct DisplayListBuilder {
     pub data: Vec<u8>,
     pub pipeline_id: PipelineId,
-
-    extra_data: Vec<u8>,
-    extra_data_chunk_len: usize,
-    writing_extra_data_chunk: bool,
-
     next_clip_index: usize,
     next_spatial_index: usize,
     next_clip_chain_id: u64,
     builder_start_time: u64,
 
     /// The size of the content of this display list. This is used to allow scrolling
     /// outside the bounds of the display list items themselves.
     content_size: LayoutSize,
     save_state: Option<SaveState>,
-
-    cache_size: usize,
 }
 
 impl DisplayListBuilder {
     pub fn new(pipeline_id: PipelineId, content_size: LayoutSize) -> Self {
         Self::with_capacity(pipeline_id, content_size, 0)
     }
 
     pub fn with_capacity(
@@ -862,28 +798,22 @@ impl DisplayListBuilder {
         content_size: LayoutSize,
         capacity: usize,
     ) -> Self {
         let start_time = precise_time_ns();
 
         DisplayListBuilder {
             data: Vec::with_capacity(capacity),
             pipeline_id,
-
-            extra_data: Vec::new(),
-            extra_data_chunk_len: 0,
-            writing_extra_data_chunk: false,
-
             next_clip_index: FIRST_CLIP_NODE_INDEX,
             next_spatial_index: FIRST_SPATIAL_NODE_INDEX,
             next_clip_chain_id: 0,
             builder_start_time: start_time,
             content_size,
             save_state: None,
-            cache_size: 0,
         }
     }
 
     /// Return the content size for this display list
     pub fn content_size(&self) -> LayoutSize {
         self.content_size
     }
 
@@ -945,45 +875,37 @@ impl DisplayListBuilder {
     where
         W: Write
     {
         let mut temp = BuiltDisplayList::default();
         mem::swap(&mut temp.data, &mut self.data);
 
         let mut index: usize = 0;
         {
-            let mut iter = temp.iter();
+            let mut iter = BuiltDisplayListIter::new(&temp);
             while let Some(item) = iter.next_raw() {
                 if index >= range.start.unwrap_or(0) && range.end.map_or(true, |e| index < e) {
                     writeln!(sink, "{}{:?}", "  ".repeat(indent), item.item()).unwrap();
                 }
                 index += 1;
             }
         }
 
         self.data = temp.data;
         index
     }
 
-    fn active_buffer(&mut self) -> &mut Vec<u8> {
-        if self.writing_extra_data_chunk {
-            &mut self.extra_data
-        } else {
-            &mut self.data
-        }
-    }
-
     /// Add an item to the display list.
     ///
     /// NOTE: It is usually preferable to use the specialized methods to push
     /// display items. Pushing unexpected or invalid items here may
     /// result in WebRender panicking or behaving in unexpected ways.
     #[inline]
     pub fn push_item(&mut self, item: &di::DisplayItem) {
-        poke_into_vec(item, self.active_buffer());
+        poke_into_vec(item, &mut self.data);
     }
 
     fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I)
     where
         I: IntoIterator,
         I::IntoIter: ExactSizeIterator,
         I::Item: Poke,
     {
@@ -1019,17 +941,17 @@ impl DisplayListBuilder {
     /// NOTE: Pushing unexpected or invalid items to the display list
     /// may result in panic and confusion.
     pub fn push_iter<I>(&mut self, iter: I)
     where
         I: IntoIterator,
         I::IntoIter: ExactSizeIterator,
         I::Item: Poke,
     {
-        Self::push_iter_impl(self.active_buffer(), iter);
+        Self::push_iter_impl(&mut self.data, iter);
     }
 
     pub fn push_rect(
         &mut self,
         common: &di::CommonItemProperties,
         color: ColorF,
     ) {
         let item = di::DisplayItem::Rectangle(di::RectangleDisplayItem {
@@ -1608,68 +1530,34 @@ impl DisplayListBuilder {
         });
         self.push_item(&item);
     }
 
     pub fn pop_all_shadows(&mut self) {
         self.push_item(&di::DisplayItem::PopAllShadows);
     }
 
-    pub fn start_extra_data_chunk(&mut self) {
-        self.writing_extra_data_chunk = true;
-        self.extra_data_chunk_len = self.extra_data.len();
-    }
-
-    // Returns the amount of bytes written to extra data buffer.
-    pub fn end_extra_data_chunk(&mut self) -> usize {
-        self.writing_extra_data_chunk = false;
-        self.extra_data.len() - self.extra_data_chunk_len
-    }
-
-    pub fn push_reuse_item(
-        &mut self,
-        key: di::ItemKey,
-    ) {
-        let item = di::DisplayItem::ReuseItem(key);
-        self.push_item(&item);
-    }
-
-    pub fn set_cache_size(
-        &mut self,
-        cache_size: usize,
-    ) {
-        self.cache_size = cache_size;
-    }
-
     pub fn finalize(mut self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
         assert!(self.save_state.is_none(), "Finalized DisplayListBuilder with a pending save");
 
         // Add `DisplayItem::max_size` zone of zeroes to the end of display list
         // so there is at least this amount available in the display list during
         // serialization.
         ensure_red_zone::<di::DisplayItem>(&mut self.data);
 
-        let extra_data_offset = self.data.len();
+        let end_time = precise_time_ns();
 
-        if self.extra_data.len() > 0 {
-            ensure_red_zone::<di::DisplayItem>(&mut self.extra_data);
-            self.data.extend(self.extra_data);
-        }
-
-        let end_time = precise_time_ns();
         (
             self.pipeline_id,
             self.content_size,
             BuiltDisplayList {
                 descriptor: BuiltDisplayListDescriptor {
                     builder_start_time: self.builder_start_time,
                     builder_finish_time: end_time,
                     send_start_time: 0,
                     total_clip_nodes: self.next_clip_index,
                     total_spatial_nodes: self.next_spatial_index,
-                    cache_size: self.cache_size,
-                    extra_data_offset,
                 },
                 data: self.data,
             },
         )
     }
 }
--- a/gfx/wr/webrender_api/src/lib.rs
+++ b/gfx/wr/webrender_api/src/lib.rs
@@ -39,23 +39,21 @@ extern crate time;
 
 extern crate malloc_size_of;
 extern crate peek_poke;
 
 mod api;
 pub mod channel;
 mod color;
 mod display_item;
-mod display_item_cache;
 mod display_list;
 mod font;
 mod gradient_builder;
 mod image;
 pub mod units;
 
 pub use crate::api::*;
 pub use crate::color::*;
 pub use crate::display_item::*;
-pub use crate::display_item_cache::DisplayItemCache;
 pub use crate::display_list::*;
 pub use crate::font::*;
 pub use crate::gradient_builder::*;
 pub use crate::image::*;
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -1444,17 +1444,16 @@ PartialUpdateResult RetainedDisplayListB
 
   nsRect modifiedDirty;
   AnimatedGeometryRoot* modifiedAGR = nullptr;
   PartialUpdateResult result = PartialUpdateResult::NoChange;
   if (!shouldBuildPartial ||
       !ComputeRebuildRegion(modifiedFrames.Frames(), &modifiedDirty,
                             &modifiedAGR, framesWithProps.Frames()) ||
       !PreProcessDisplayList(&mList, modifiedAGR, result)) {
-    mBuilder.SetPartialBuildFailed(true);
     mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr);
     mList.DeleteAll(&mBuilder);
     return PartialUpdateResult::Failed;
   }
 
   // This is normally handled by EnterPresShell, but we skipped it so that we
   // didn't call MarkFrameForDisplayIfVisible before ComputeRebuildRegion.
   nsIScrollableFrame* sf = mBuilder.RootReferenceFrame()
@@ -1469,31 +1468,31 @@ PartialUpdateResult RetainedDisplayListB
   }
 
   modifiedDirty.IntersectRect(
       modifiedDirty,
       mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf());
 
   mBuilder.SetDirtyRect(modifiedDirty);
   mBuilder.SetPartialUpdate(true);
-  mBuilder.SetPartialBuildFailed(false);
 
   nsDisplayList modifiedDL;
   mBuilder.RootReferenceFrame()->BuildDisplayListForStackingContext(
       &mBuilder, &modifiedDL);
   if (!modifiedDL.IsEmpty()) {
     nsLayoutUtils::AddExtraBackgroundItems(
         &mBuilder, &modifiedDL, mBuilder.RootReferenceFrame(),
         nsRect(nsPoint(0, 0), mBuilder.RootReferenceFrame()->GetSize()),
         mBuilder.RootReferenceFrame()->GetVisualOverflowRectRelativeToSelf(),
         aBackstop);
   }
   mBuilder.SetPartialUpdate(false);
 
   if (mBuilder.PartialBuildFailed()) {
+    mBuilder.SetPartialBuildFailed(false);
     mBuilder.LeavePresShell(mBuilder.RootReferenceFrame(), nullptr);
     mList.DeleteAll(&mBuilder);
     modifiedDL.DeleteAll(&mBuilder);
     Metrics()->mPartialUpdateFailReason = PartialUpdateFailReason::Content;
     return PartialUpdateResult::Failed;
   }
 
   if (aChecker) {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3208,34 +3208,31 @@ class nsPaintedDisplayItem : public nsDi
   /**
    * Paint this item to some rendering context.
    */
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
     // TODO(miko): Make this a pure virtual function to force implementation.
     MOZ_ASSERT_UNREACHABLE("Paint() is not implemented!");
   }
 
-  Maybe<uint16_t>& CacheIndex() { return mCacheIndex; }
-
  protected:
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
       : nsDisplayItem(aBuilder, aFrame) {}
 
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                        const ActiveScrolledRoot* aActiveScrolledRoot)
       : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot) {}
 
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder,
                        const nsPaintedDisplayItem& aOther)
       : nsDisplayItem(aBuilder, aOther) {}
 
  private:
   mozilla::DisplayItemData* mDisplayItemData = nullptr;
   mozilla::layers::LayerManager* mDisplayItemDataLayerManager = nullptr;
-  mozilla::Maybe<uint16_t> mCacheIndex;
 };
 
 /**
  * Manages a singly-linked list of display list items.
  *
  * mSentinel is the sentinel list value, the first value in the null-terminated
  * linked list of items. mTop is the last item in the list (whose 'above'
  * pointer is null). This class has no virtual methods. So list objects are just
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -3863,21 +3863,16 @@
   type: bool
 #ifdef DEBUG
   value: true
 #else
   value: false
 #endif
   mirror: once
 
-- name: gfx.webrender.enable-item-cache
-  type: bool
-  value: false
-  mirror: once
-
 #ifdef NIGHTLY_BUILD
   # Keep this pref hidden on non-nightly builds to avoid people accidentally
   # turning it on.
 - name: gfx.webrender.panic-on-gl-error
   type: bool
   value: false
   mirror: once
 #endif