Bug 1345054 part 2 -Reduce DisplayList update and ImageKey generation r=nical
authorsotaro <sotaro.ikeda.g@gmail.com>
Fri, 02 Jun 2017 16:11:53 +0900
changeset 412474 5f944d9ffbe0080d9a1b7410224570c857a82993
parent 412473 7c57e39a677a9def9f0ff3c7eecf407579a83e1e
child 412475 2a8478029a0ca491fe914ffa619afc155b828b88
child 412477 27a355cf603699b458a0509bfa5719ae3cbd82f3
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnical
bugs1345054
milestone55.0a1
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
Bug 1345054 part 2 -Reduce DisplayList update and ImageKey generation r=nical
gfx/layers/wr/WebRenderCompositableHolder.cpp
gfx/layers/wr/WebRenderCompositableHolder.h
--- a/gfx/layers/wr/WebRenderCompositableHolder.cpp
+++ b/gfx/layers/wr/WebRenderCompositableHolder.cpp
@@ -12,16 +12,23 @@
 #include "mozilla/webrender/WebRenderAPI.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
+WebRenderCompositableHolder::AsyncImagePipelineHolder::AsyncImagePipelineHolder()
+ : mInitialised(false)
+ , mIsChanged(false)
+ , mFilter(WrImageRendering::Auto)
+ , mMixBlendMode(WrMixBlendMode::Normal)
+{}
+
 WebRenderCompositableHolder::WebRenderCompositableHolder(uint32_t aIdNamespace)
  : mIdNamespace(aIdNamespace)
  , mResourceId(0)
  , mAsyncImageEpoch(0)
  , mDestroyed(false)
 {
   MOZ_COUNT_CTOR(WebRenderCompositableHolder);
 }
@@ -101,22 +108,26 @@ WebRenderCompositableHolder::AddAsyncIma
 void
 WebRenderCompositableHolder::RemoveAsyncImagePipeline(wr::WebRenderAPI* aApi, const wr::PipelineId& aPipelineId)
 {
   if (mDestroyed) {
     return;
   }
 
   uint64_t id = wr::AsUint64(aPipelineId);
-  if (!mAsyncImagePipelineHolders.Get(id)) {
+  AsyncImagePipelineHolder* holder = mAsyncImagePipelineHolders.Get(id);
+  if (!holder) {
     return;
   }
 
   ++mAsyncImageEpoch; // Update webrender epoch
   aApi->ClearRootDisplayList(wr::NewEpoch(mAsyncImageEpoch), aPipelineId);
+  for (wr::ImageKey key : holder->mKeys) {
+    aApi->DeleteImage(key);
+  }
   mAsyncImagePipelineHolders.Remove(id);
   RemovePipeline(aPipelineId, wr::NewEpoch(mAsyncImageEpoch));
 }
 
 void
 WebRenderCompositableHolder::UpdateAsyncImagePipeline(const wr::PipelineId& aPipelineId,
                                                       const LayerRect& aScBounds,
                                                       const gfx::Matrix4x4& aScTransform,
@@ -129,16 +140,18 @@ WebRenderCompositableHolder::UpdateAsync
   if (mDestroyed) {
     return;
   }
   AsyncImagePipelineHolder* holder = mAsyncImagePipelineHolders.Get(wr::AsUint64(aPipelineId));
   MOZ_ASSERT(holder);
   if (!holder) {
     return;
   }
+  holder->mInitialised = true;
+  holder->mIsChanged = true;
   holder->mScBounds = aScBounds;
   holder->mScTransform = aScTransform;
   holder->mScaleToSize = aScaleToSize;
   holder->mClipRect = aClipRect;
   holder->mMask = aMask;
   holder->mFilter = aFilter;
   holder->mMixBlendMode = aMixBlendMode;
 }
@@ -181,20 +194,17 @@ WebRenderCompositableHolder::GetImageKey
 
   MOZ_ASSERT(!aKeys.IsEmpty());
 }
 
 bool
 WebRenderCompositableHolder::GetImageKeyForTextureHost(wr::WebRenderAPI* aApi, TextureHost* aTexture, nsTArray<wr::ImageKey>& aKeys)
 {
   MOZ_ASSERT(aKeys.IsEmpty());
-
-  if (!aTexture) {
-    return false;
-  }
+  MOZ_ASSERT(aTexture);
 
   WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
 
   if (wrTexture) {
     GetImageKeysForExternalImage(aKeys);
     MOZ_ASSERT(!aKeys.IsEmpty());
     Range<const wr::ImageKey> keys(&aKeys[0], aKeys.Length());
     wrTexture->AddWRImage(aApi, keys, wrTexture->GetExternalImageKey());
@@ -252,72 +262,127 @@ WebRenderCompositableHolder::PushExterna
   aBuilder.PushImage(aBounds, aClip, aFilter, aKeys[0]);
 #elif defined(ANDROID)
   // Use libyuv to convert the buffer to rgba format.
   MOZ_ASSERT(aKeys.Length() == 1);
   aBuilder.PushImage(aBounds, aClip, aFilter, aKeys[0]);
 #endif
 }
 
+bool
+WebRenderCompositableHolder::UpdateImageKeys(wr::WebRenderAPI* aApi,
+                                             bool& aUseExternalImage,
+                                             AsyncImagePipelineHolder* aHolder,
+                                             nsTArray<wr::ImageKey>& aKeys,
+                                             nsTArray<wr::ImageKey>& aKeysToDelete)
+{
+  MOZ_ASSERT(aKeys.IsEmpty());
+  MOZ_ASSERT(aHolder);
+  TextureHost* texture = aHolder->mImageHost->GetAsTextureHostForComposite();
+
+  if (!aHolder->mInitialised) {
+    return false;
+  }
+
+  // No change
+  if (!aHolder->mIsChanged && texture == aHolder->mCurrentTexture) {
+    // No need to update DisplayList.
+    return false;
+  }
+
+  aHolder->mIsChanged = false;
+
+  if (texture == aHolder->mCurrentTexture) {
+    // Reuse previous ImageKeys.
+    aKeys.AppendElements(aHolder->mKeys);
+    return true;
+  }
+
+  // Delete old ImageKeys
+  aKeysToDelete.AppendElements(aHolder->mKeys);
+  aHolder->mKeys.Clear();
+  aHolder->mCurrentTexture = nullptr;
+
+  // No txture to render
+  if (!texture) {
+    return true;
+  }
+
+  aUseExternalImage = GetImageKeyForTextureHost(aApi, texture, aKeys);
+  MOZ_ASSERT(!aKeys.IsEmpty());
+  aHolder->mKeys.AppendElements(aKeys);
+  aHolder->mCurrentTexture = texture;
+  return true;
+}
+
 void
 WebRenderCompositableHolder::ApplyAsyncImages(wr::WebRenderAPI* aApi)
 {
-  if (mDestroyed) {
+  if (mDestroyed || mAsyncImagePipelineHolders.Count() == 0) {
     return;
   }
+
   ++mAsyncImageEpoch; // Update webrender epoch
   wr::Epoch epoch = wr::NewEpoch(mAsyncImageEpoch);
   nsTArray<wr::ImageKey> keysToDelete;
 
   for (auto iter = mAsyncImagePipelineHolders.Iter(); !iter.Done(); iter.Next()) {
     wr::PipelineId pipelineId = wr::AsPipelineId(iter.Key());
     AsyncImagePipelineHolder* holder = iter.Data();
 
+    nsTArray<wr::ImageKey> keys;
+    bool useExternalImage = false;
+    bool updateDisplayList = UpdateImageKeys(aApi,
+                                             useExternalImage,
+                                             holder,
+                                             keys,
+                                             keysToDelete);
+    if (!updateDisplayList) {
+      continue;
+    }
+
     WrSize contentSize { holder->mScBounds.width, holder->mScBounds.height };
     wr::DisplayListBuilder builder(pipelineId, contentSize);
-    float opacity = 1.0f;
-    builder.PushStackingContext(wr::ToWrRect(holder->mScBounds),
-                                0,
-                                &opacity,
-                                holder->mScTransform.IsIdentity() ? nullptr : &holder->mScTransform,
-                                holder->mMixBlendMode);
-
-    TextureHost* texture = holder->mImageHost->GetAsTextureHostForComposite();
-    nsTArray<wr::ImageKey> keys;
-    bool useExternalImage = GetImageKeyForTextureHost(aApi, texture, keys);
 
     if (!keys.IsEmpty()) {
-      LayerRect rect(0, 0, texture->GetSize().width, texture->GetSize().height);
+      MOZ_ASSERT(holder->mCurrentTexture.get());
+
+      float opacity = 1.0f;
+      builder.PushStackingContext(wr::ToWrRect(holder->mScBounds),
+                                  0,
+                                  &opacity,
+                                  holder->mScTransform.IsIdentity() ? nullptr : &holder->mScTransform,
+                                  holder->mMixBlendMode);
+
+      LayerRect rect(0, 0, holder->mCurrentTexture->GetSize().width, holder->mCurrentTexture->GetSize().height);
       if (holder->mScaleToSize.isSome()) {
         rect = LayerRect(0, 0, holder->mScaleToSize.value().width, holder->mScaleToSize.value().height);
       }
       LayerRect clipRect = holder->mClipRect.valueOr(rect);
       WrClipRegionToken clip = builder.PushClipRegion(
         wr::ToWrRect(clipRect),
         holder->mMask.ptrOr(nullptr));
 
       if (useExternalImage) {
-        MOZ_ASSERT(texture->AsWebRenderTextureHost());
+        MOZ_ASSERT(holder->mCurrentTexture->AsWebRenderTextureHost());
         PushExternalImage(builder,
                           wr::ToWrRect(rect),
                           clip,
                           holder->mFilter,
                           keys);
-        HoldExternalImage(pipelineId, epoch, texture->AsWebRenderTextureHost());
+        HoldExternalImage(pipelineId, epoch, holder->mCurrentTexture->AsWebRenderTextureHost());
       } else {
         MOZ_ASSERT(keys.Length() == 1);
         builder.PushImage(wr::ToWrRect(rect),
                           clip,
                           holder->mFilter,
                           keys[0]);
       }
-      // XXX do not delete ImageKey for every rendering.
-      keysToDelete.AppendElements(keys);
+      builder.PopStackingContext();
     }
-    builder.PopStackingContext();
 
     wr::BuiltDisplayList dl;
     WrSize builderContentSize;
     builder.Finalize(builderContentSize, dl);
     aApi->SetRootDisplayList(gfx::Color(0.f, 0.f, 0.f, 0.f), epoch, LayerSize(holder->mScBounds.width, holder->mScBounds.height),
                              pipelineId, builderContentSize,
                              dl.dl_desc, dl.dl.inner.data, dl.dl.inner.length);
   }
@@ -350,16 +415,17 @@ WebRenderCompositableHolder::Update(cons
   }
   PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
   if (!holder) {
     return;
   }
 
   // Remove Pipeline
   if (holder->mDestroyedEpoch.isSome() && holder->mDestroyedEpoch.ref() <= aEpoch) {
+
     mPipelineTexturesHolders.Remove(wr::AsUint64(aPipelineId));
     return;
   }
 
   // Release TextureHosts based on Epoch
   while (!holder->mTextureHosts.empty()) {
     if (aEpoch <= holder->mTextureHosts.front().mEpoch) {
       break;
--- a/gfx/layers/wr/WebRenderCompositableHolder.h
+++ b/gfx/layers/wr/WebRenderCompositableHolder.h
@@ -113,27 +113,38 @@ private:
 
   struct PipelineTexturesHolder {
     // Holds forwarding WebRenderTextureHosts.
     std::queue<ForwardingTextureHost> mTextureHosts;
     Maybe<wr::Epoch> mDestroyedEpoch;
   };
 
   struct AsyncImagePipelineHolder {
+    AsyncImagePipelineHolder();
+
+    bool mInitialised;
+    bool mIsChanged;
     LayerRect mScBounds;
     gfx::Matrix4x4 mScTransform;
     gfx::MaybeIntSize mScaleToSize;
     MaybeLayerRect mClipRect;
     MaybeImageMask mMask;
     WrImageRendering mFilter;
     WrMixBlendMode mMixBlendMode;
     RefPtr<WebRenderImageHost> mImageHost;
-    CompositableTextureHostRef mCurrentTextureHost;
+    CompositableTextureHostRef mCurrentTexture;
+    nsTArray<wr::ImageKey> mKeys;
   };
 
+  bool UpdateImageKeys(wr::WebRenderAPI* aApi,
+                       bool& aUseExternalImage,
+                       AsyncImagePipelineHolder* aHolder,
+                       nsTArray<wr::ImageKey>& aKeys,
+                       nsTArray<wr::ImageKey>& aKeysToDelete);
+
   uint32_t mIdNamespace;
   uint32_t mResourceId;
 
   nsClassHashtable<nsUint64HashKey, PipelineTexturesHolder> mPipelineTexturesHolders;
   nsClassHashtable<nsUint64HashKey, AsyncImagePipelineHolder> mAsyncImagePipelineHolders;
   uint32_t mAsyncImageEpoch;
   nsTArray<wr::ImageKey> mKeysToDelete;
   bool mDestroyed;