Bug 1417784 - Properly implement SyncWithCompositor for WebRender. r?sotaro
This defines three flushing functions that flush different parts of the
WR pipeline. Using all three guarantees that everything sent to WR will
have been flushed. This is what we need to do in SyncWithCompositor to
ensure that it meets the API contract.
In addition, this patch updates the existing FlushRendering function to
use the new functions (no functional changes intended here).
MozReview-Commit-ID: GzxwpF4JT04
--- a/gfx/layers/ipc/PWebRenderBridge.ipdl
+++ b/gfx/layers/ipc/PWebRenderBridge.ipdl
@@ -52,16 +52,21 @@ parent:
sync GetSnapshot(PTexture texture);
async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
async ClearCachedResources();
// Schedule a composite if one isn't already scheduled.
async ScheduleComposite();
// Save the frame capture to disk
async Capture();
+ // Replacement for PCompositorBridge::SyncWithCompositor, but for WR. We need
+ // it on PWebRenderBridge because it associated with a particular top-level
+ // window, and PCompositorBridge doesn't allow doing that in a secure manner.
+ sync SyncWithCompositor();
+
// These correspond exactly to the equivalent APIs in PLayerTransaction -
// see those for documentation.
async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
// More copied from PLayerTransaction, but these are only used for testing.
sync SetTestSampleTime(TimeStamp sampleTime);
sync LeaveTestMode();
sync GetAnimationOpacity(uint64_t aCompositorAnimationsId) returns (float opacity,
bool hasAnimationOpacity);
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -390,20 +390,20 @@ LayersIPCActor*
WebRenderBridgeChild::GetLayersIPCActor()
{
return static_cast<LayersIPCActor*>(GetCompositorBridgeChild());
}
void
WebRenderBridgeChild::SyncWithCompositor()
{
- auto compositorBridge = GetCompositorBridgeChild();
- if (compositorBridge && compositorBridge->IPCOpen()) {
- compositorBridge->SendSyncWithCompositor();
+ if (!IPCOpen()) {
+ return;
}
+ SendSyncWithCompositor();
}
void
WebRenderBridgeChild::Connect(CompositableClient* aCompositable,
ImageContainer* aImageContainer)
{
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(aCompositable);
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -847,16 +847,72 @@ WebRenderBridgeParent::ProcessWebRenderP
default: {
// other commands are handle on the child
break;
}
}
}
}
+void
+WebRenderBridgeParent::FlushSceneBuilds()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ if (gfxPrefs::WebRenderAsyncSceneBuild()) {
+ // If we are sending transactions through the scene builder thread, we need
+ // to block until all the inflight transactions have been processed. This
+ // flush message blocks until all previously sent scenes have been built
+ // and received by the render backend thread.
+ mApi->FlushSceneBuilder();
+ // The post-swap hook for async-scene-building calls the
+ // ScheduleRenderOnCompositorThread function from the scene builder thread,
+ // which then triggers a call to ScheduleGenerateFrame() on the compositor
+ // thread. But since *this* function is running on the compositor thread,
+ // that scheduling will not happen until this call stack unwinds (or we
+ // could spin a nested event loop, but that's more messy). Instead, we
+ // simulate it ourselves by calling ScheduleGenerateFrame() directly.
+ // In the case where async scene building is disabled, the
+ // ScheduleGenerateFrame() call in RecvSetDisplayList() serves this purpose.
+ // Note also that the post-swap hook will run and do another
+ // ScheduleGenerateFrame() after we unwind here, so we will end up with an
+ // extra render/composite that is probably avoidable, but in practice we
+ // shouldn't be calling this function all that much in production so this
+ // is probably fine. If it becomes an issue we can add more state tracking
+ // machinery to optimize it away.
+ ScheduleGenerateFrame();
+ }
+}
+
+void
+WebRenderBridgeParent::FlushFrameGeneration()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ MOZ_ASSERT(mWidget); // This function is only useful on the root WRBP
+
+ // This forces a new GenerateFrame transaction to be sent to the render
+ // backend thread, if one is pending. This doesn't block on any other threads.
+ mForceRendering = true;
+ mCompositorScheduler->FlushPendingComposite();
+ mForceRendering = false;
+}
+
+void
+WebRenderBridgeParent::FlushFramePresentation()
+{
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+
+ // This sends a message to the render backend thread to send a message
+ // to the renderer thread, and waits for that message to be processed. So
+ // this effectively blocks on the render backend and renderer threads,
+ // following the same codepath that WebRender takes to render and composite
+ // a frame.
+ mApi->WaitFlushed();
+}
+
mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvGetSnapshot(PTextureParent* aTexture)
{
if (mDestroyed) {
return IPC_OK();
}
MOZ_ASSERT(!mPaused);
@@ -1115,16 +1171,33 @@ WebRenderBridgeParent::RecvCapture()
{
if (!mDestroyed) {
mApi->Capture();
}
return IPC_OK();
}
mozilla::ipc::IPCResult
+WebRenderBridgeParent::RecvSyncWithCompositor()
+{
+ FlushSceneBuilds();
+ if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
+ root->FlushFrameGeneration();
+ }
+ FlushFramePresentation();
+ // Finally, we force the AsyncImagePipelineManager to handle all the
+ // pipeline updates produced in the last step, so that it frees any
+ // unneeded textures. Then we can return from this sync IPC call knowing
+ // that we've done everything we can to flush stuff on the compositor.
+ mAsyncImageManager->ProcessPipelineUpdates();
+
+ return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
WebRenderBridgeParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets)
{
if (mDestroyed) {
return IPC_OK();
}
mCompositorBridge->SetConfirmedTargetAPZC(GetLayersId(), aBlockId, aTargets);
return IPC_OK();
@@ -1451,21 +1524,19 @@ WebRenderBridgeParent::ScheduleGenerateF
void
WebRenderBridgeParent::FlushRendering()
{
if (mDestroyed) {
return;
}
- mForceRendering = true;
- mCompositorScheduler->FlushPendingComposite();
- // Always meed to wait flushed, since WebRender might have ongoing tasks.
- mApi->WaitFlushed();
- mForceRendering = false;
+ // XXX: do we need to flush any scene building here?
+ FlushFrameGeneration();
+ FlushFramePresentation();
}
void
WebRenderBridgeParent::FlushRenderingAsync()
{
if (mDestroyed) {
return;
}
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -103,16 +103,17 @@ public:
mozilla::ipc::IPCResult RecvParentCommands(nsTArray<WebRenderParentCommand>&& commands) override;
mozilla::ipc::IPCResult RecvGetSnapshot(PTextureParent* aTexture) override;
mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
mozilla::ipc::IPCResult RecvClearCachedResources() override;
mozilla::ipc::IPCResult RecvScheduleComposite() override;
mozilla::ipc::IPCResult RecvCapture() override;
+ mozilla::ipc::IPCResult RecvSyncWithCompositor() override;
mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets) override;
mozilla::ipc::IPCResult RecvSetTestSampleTime(const TimeStamp& aTime) override;
mozilla::ipc::IPCResult RecvLeaveTestMode() override;
mozilla::ipc::IPCResult RecvGetAnimationOpacity(const uint64_t& aCompositorAnimationsId,
float* aOpacity,
@@ -232,16 +233,20 @@ private:
RefPtr<WebRenderBridgeParent> GetRootWebRenderBridgeParent() const;
// Tell APZ what the subsequent sampling's timestamp should be.
void SetAPZSampleTime();
wr::Epoch GetNextWrEpoch();
+ void FlushSceneBuilds();
+ void FlushFrameGeneration();
+ void FlushFramePresentation();
+
private:
struct PendingTransactionId {
PendingTransactionId(const wr::Epoch& aEpoch, TransactionId aId, const TimeStamp& aTxnStartTime, const TimeStamp& aFwdTime)
: mEpoch(aEpoch)
, mId(aId)
, mTxnStartTime(aTxnStartTime)
, mFwdTime(aFwdTime)
{}
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -1031,16 +1031,18 @@ description = test only
[PWebRenderBridge::SetAsyncScrollOffset]
description = test only
[PWebRenderBridge::SetAsyncZoom]
description = test only
[PWebRenderBridge::GetAPZTestData]
description = test only
[PWebRenderBridge::ShutdownSync]
description = bug 1377024
+[PWebRenderBridge::SyncWithCompositor]
+description = WebRender equivalent for PCompositorBridge::SyncWithCompositor
[PHal::GetCurrentBatteryInformation]
description =
[PHal::GetCurrentNetworkInformation]
description =
[PHal::GetWakeLockInfo]
description =
[PHal::LockScreenOrientation]
description =