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
--- 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);