Bug 1457466 - Make the GenerateFrame transaction bypass the scene builder thread. r=nical
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 11 May 2018 09:09:19 -0400
changeset 794459 8c90bee8f6f35448ac5a9485a4637a0910226ecf
parent 794458 31d09eea36298ad41da435883babb243a2a4271c
child 794460 d555b3a047d1311ea91b5c08fd3d38049cc90ee4
push id109697
push userbmo:sledru@mozilla.com
push dateSat, 12 May 2018 10:04:34 +0000
reviewersnical
bugs1457466
milestone62.0a1
Bug 1457466 - Make the GenerateFrame transaction bypass the scene builder thread. r=nical This allows frames to be generated by the render backend thread even while the scene builder thread is busy with a long scene build. The GenerateFrame transaction also contains APZ and OMTA information, so this allows the user to scroll and view OMTAnimations during long scene builds. MozReview-Commit-ID: KG5YC2KwIaH
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -1291,39 +1291,47 @@ WebRenderBridgeParent::CompositeToTarget
     // Render thread is busy, try next time.
     mCompositorScheduler->ScheduleComposition();
     mPreviousFrameTimeStamp = TimeStamp();
     return;
   }
 
   mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
 
-  // TODO: We can improve upon this by using two transactions: one for everything that
-  // doesn't change the display list (in other words does not cause the scene to be
-  // re-built), and one for the rest. This way, if an async pipeline needs to re-build
-  // its display list, other async pipelines can still be rendered while the scene is
-  // building.
-  wr::TransactionBuilder txn;
-  mAsyncImageManager->ApplyAsyncImages(txn);
-  mApi->SendTransaction(txn);
+  {
+    // TODO: We can improve upon this by using two transactions: one for everything that
+    // doesn't change the display list (in other words does not cause the scene to be
+    // re-built), and one for the rest. This way, if an async pipeline needs to re-build
+    // its display list, other async pipelines can still be rendered while the scene is
+    // building. Those other async pipelines can go in the other transaction that
+    // we create below.
+    wr::TransactionBuilder txn;
+    mAsyncImageManager->ApplyAsyncImages(txn);
+    mApi->SendTransaction(txn);
+  }
 
   if (!mAsyncImageManager->GetCompositeUntilTime().IsNull()) {
     // Trigger another CompositeToTarget() call because there might be another
     // frame that we want to generate after this one.
     // It will check if we actually want to generate the frame or not.
     mCompositorScheduler->ScheduleComposition();
   }
 
   if (!mAsyncImageManager->GetAndResetWillGenerateFrame() &&
       !mForceRendering) {
     // Could skip generating frame now.
     mPreviousFrameTimeStamp = TimeStamp();
     return;
   }
 
+  // Ensure this GenerateFrame is handled on the render backend thread rather
+  // than going through the scene builder thread. That way we continue generating
+  // frames with the old scene even during slow scene builds.
+  wr::TransactionBuilder txn(/* aUseSceneBuilderThread */ false);
+
   nsTArray<wr::WrOpacityProperty> opacityArray;
   nsTArray<wr::WrTransformProperty> transformArray;
 
   if (SampleAnimations(opacityArray, transformArray)) {
     ScheduleGenerateFrame();
   }
   // We do this even if the arrays are empty, because it will clear out any
   // previous properties store on the WR side, which is desirable.
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -128,18 +128,18 @@ public:
     layers::AutoCompleteTask complete(mTask);
   }
 
 private:
   layers::SynchronousTask* mTask;
 };
 
 
-TransactionBuilder::TransactionBuilder()
-  : mUseSceneBuilderThread(gfxPrefs::WebRenderAsyncSceneBuild())
+TransactionBuilder::TransactionBuilder(bool aUseSceneBuilderThread)
+  : mUseSceneBuilderThread(gfxPrefs::WebRenderAsyncSceneBuild() && aUseSceneBuilderThread)
 {
   mTxn = wr_transaction_new(mUseSceneBuilderThread);
   mResourceUpdates = wr_resource_updates_new();
 }
 
 TransactionBuilder::~TransactionBuilder()
 {
   wr_transaction_delete(mTxn);
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -46,17 +46,17 @@ struct Line {
   wr::LineOrientation orientation;
   wr::ColorF color;
   wr::LineStyle style;
 };
 
 
 class TransactionBuilder {
 public:
-  TransactionBuilder();
+  explicit TransactionBuilder(bool aUseSceneBuilderThread = true);
 
   ~TransactionBuilder();
 
   void UpdateEpoch(PipelineId aPipelineId, Epoch aEpoch);
 
   void SetRootPipeline(PipelineId aPipelineId);
 
   void RemovePipeline(PipelineId aPipelineId);