Skip to content

Commit

Permalink
Bug 1580117 - Pause composition for minimized windows on macOS. r=mst…
Browse files Browse the repository at this point in the history
…ange

This pauses composition when a window becomes minimized.

This is particularly important for platforms like macOS, where minimized /
hidden windows historically would remain compositing, potentially on every vsync
if the hidden window contained animations. This should lead to a nice power
savings by skipping this unnecessary work.

This change affects both the WebRender and legacy compositor paths.

As bug 1580117 is believed to be a macOS specific issue, this is currently
implemented for macOS only, but could in the future be generalized to other
platforms as well.

Differential Revision: https://phabricator.services.mozilla.com/D85954
  • Loading branch information
jryans committed Sep 17, 2020
1 parent ce292d8 commit c7fe5d3
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
6 changes: 6 additions & 0 deletions modules/libpref/init/StaticPrefList.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10015,6 +10015,12 @@
value: true
mirror: always

# Whether to pause the compositor when a native window is minimized.
- name: widget.pause-compositor-when-minimized
type: bool
value: true
mirror: always

#ifdef MOZ_WAYLAND
#ifdef NIGHTLY_BUILD
# Keep those pref hidden on non-nightly builds to avoid people accidentally
Expand Down
3 changes: 3 additions & 0 deletions widget/cocoa/nsCocoaWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,9 @@ class nsCocoaWindow final : public nsBaseWidget, public nsPIWidgetCocoa {

bool InFullScreenMode() const { return mInFullScreenMode; }

void PauseCompositor();
void ResumeCompositor();

protected:
virtual ~nsCocoaWindow();

Expand Down
77 changes: 77 additions & 0 deletions widget/cocoa/nsCocoaWindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include "nsIScreenManager.h"
#include "nsIWidgetListener.h"
#include "VibrancyManager.h"
#include "nsPresContext.h"
#include "nsDocShell.h"

#include "gfxPlatform.h"
#include "qcms.h"
Expand All @@ -44,6 +46,7 @@
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_widget.h"
#include "mozilla/PresShell.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include <algorithm>

namespace mozilla {
Expand Down Expand Up @@ -2072,6 +2075,14 @@ static nsSizeMode GetWindowSizeMode(NSWindow* aWindow, bool aFullScreen) {
if (mWidgetListener) {
mWidgetListener->SizeModeChanged(newMode);
}

if (StaticPrefs::widget_pause_compositor_when_minimized()) {
if (newMode == nsSizeMode_Minimized) {
PauseCompositor();
} else {
ResumeCompositor();
}
}
}

void nsCocoaWindow::DispatchOcclusionEvent() {
Expand Down Expand Up @@ -2105,6 +2116,72 @@ static nsSizeMode GetWindowSizeMode(NSWindow* aWindow, bool aFullScreen) {
NS_OBJC_END_TRY_ABORT_BLOCK;
}

void nsCocoaWindow::PauseCompositor() {
nsIWidget* mainChildView = static_cast<nsIWidget*>([[mWindow mainChildView] widget]);
if (!mainChildView) {
return;
}
CompositorBridgeChild* remoteRenderer = mainChildView->GetRemoteRenderer();
if (!remoteRenderer) {
return;
}
remoteRenderer->SendPause();

// Now that the compositor has paused, we also try to mark the browser window
// docshell inactive to stop any animations. This does not affect docshells
// for browsers in other processes, but browser UI code should be managing
// their active state appropriately.
if (!mWidgetListener) {
return;
}
PresShell* presShell = mWidgetListener->GetPresShell();
if (!presShell) {
return;
}
nsPresContext* presContext = presShell->GetPresContext();
if (!presContext) {
return;
}
nsDocShell* docShell = presContext->GetDocShell();
if (!docShell) {
return;
}
docShell->SetIsActive(false);
}

void nsCocoaWindow::ResumeCompositor() {
nsIWidget* mainChildView = static_cast<nsIWidget*>([[mWindow mainChildView] widget]);
if (!mainChildView) {
return;
}
CompositorBridgeChild* remoteRenderer = mainChildView->GetRemoteRenderer();
if (!remoteRenderer) {
return;
}
remoteRenderer->SendResume();

// Now that the compositor has resumed, we also try to mark the browser window
// docshell active to restart any animations. This does not affect docshells
// for browsers in other processes, but browser UI code should be managing
// their active state appropriately.
if (!mWidgetListener) {
return;
}
PresShell* presShell = mWidgetListener->GetPresShell();
if (!presShell) {
return;
}
nsPresContext* presContext = presShell->GetPresContext();
if (!presContext) {
return;
}
nsDocShell* docShell = presContext->GetDocShell();
if (!docShell) {
return;
}
docShell->SetIsActive(true);
}

void nsCocoaWindow::SetMenuBar(nsMenuBarX* aMenuBar) {
if (mMenuBar) mMenuBar->SetParent(nullptr);
if (!mWindow) {
Expand Down

0 comments on commit c7fe5d3

Please sign in to comment.