Bug 1656211 - Force recompositing frames on GTK when popup window configuration changes. r=nical

Similar to bug 1280653, it appears that GLX invalidates the back buffer
while we are drawing. The only indication we get of this are resize and
configure events from X. We suppress the configure event for popups for
various reasons, so this patch explicitly generates a forced recomposite
of the frame. It does it immediately so that most of the time it should
beat the presentation of the buffer and avoid displaying of the bad
frame to the user; popups generally are not complicated and should have
plenty of budget to perform the second composite.

Differential Revision: https://phabricator.services.mozilla.com/D93862
This commit is contained in:
Andrew Osmond 2020-10-19 07:44:59 +00:00
parent da10e9b814
commit 38752f6def
7 changed files with 37 additions and 0 deletions

View File

@ -381,6 +381,12 @@ class LayerManager : public FrameRecorder {
*/
virtual void ScheduleComposite() {}
/**
* Force a composition with the remote Compositor, if one exists
* for this LayerManager, as soon as possible.
*/
virtual void ForceComposite() {}
virtual void SetNeedsComposite(bool aNeedsComposite) {}
virtual bool NeedsComposite() const { return false; }

View File

@ -71,6 +71,8 @@ parent:
async InvalidateRenderedFrame();
// Schedule a composite if one isn't already scheduled.
async ScheduleComposite();
// Force a composite immediately.
async ForceComposite();
// Save the frame capture to disk
async Capture();
// Start capturing each frame and save to disk, and if already started, stop.

View File

@ -1809,6 +1809,23 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvScheduleComposite() {
return IPC_OK();
}
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvForceComposite() {
MOZ_ASSERT(IsRootWebRenderBridgeParent());
if (mDestroyed) {
return IPC_OK();
}
TimeStamp start = TimeStamp::Now();
wr::RenderThread::Get()->IncPendingFrameCount(mApi->GetId(), VsyncId(),
start);
wr::TransactionBuilder fastTxn(/* aUseSceneBuilderThread */ false);
fastTxn.InvalidateRenderedFrame();
fastTxn.GenerateFrame();
mApi->SendTransaction(fastTxn);
return IPC_OK();
}
void WebRenderBridgeParent::InvalidateRenderedFrame() {
if (mDestroyed) {
return;

View File

@ -179,6 +179,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
mozilla::ipc::IPCResult RecvClearCachedResources() override;
mozilla::ipc::IPCResult RecvInvalidateRenderedFrame() override;
mozilla::ipc::IPCResult RecvScheduleComposite() override;
mozilla::ipc::IPCResult RecvForceComposite() override;
mozilla::ipc::IPCResult RecvCapture() override;
mozilla::ipc::IPCResult RecvToggleCaptureSequence() override;
mozilla::ipc::IPCResult RecvSyncWithCompositor() override;

View File

@ -709,6 +709,10 @@ void WebRenderLayerManager::ScheduleComposite() {
WrBridge()->SendScheduleComposite();
}
void WebRenderLayerManager::ForceComposite() {
WrBridge()->SendForceComposite();
}
void WebRenderLayerManager::SetRoot(Layer* aLayer) {
// This should never get called
MOZ_ASSERT(false);

View File

@ -122,6 +122,7 @@ class WebRenderLayerManager final : public LayerManager {
void SendInvalidRegion(const nsIntRegion& aRegion) override;
void ScheduleComposite() override;
void ForceComposite() override;
void SetNeedsComposite(bool aNeedsComposite) override {
mNeedsComposite = aNeedsComposite;

View File

@ -3067,6 +3067,12 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
// loop when nsXULPopupManager::PopupMoved moves the window to the new
// position and nsMenuPopupFrame::SetPopupPosition adds
// offsetForContextMenu on each iteration.
// Our back buffer might have been invalidated while we drew the last
// frame, and its contents might be incorrect. See bug 1280653 comment 7
// and comment 10. Specifically we must ensure we recomposite the frame
// as soon as possible to avoid the corrupted frame being displayed.
GetLayerManager()->ForceComposite();
return FALSE;
}