Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS: Memory usage skyrockets when window is occluded #5856

Closed
Nnubes256 opened this issue Sep 1, 2022 · 1 comment · Fixed by #7611
Closed

macOS: Memory usage skyrockets when window is occluded #5856

Nnubes256 opened this issue Sep 1, 2022 · 1 comment · Fixed by #7611
Labels
A-Windowing Platform-agnostic interface layer to run your app in C-Bug An unexpected or incorrect behavior O-MacOS Specific to the MacOS (Apple) desktop operating system

Comments

@Nnubes256
Copy link

Nnubes256 commented Sep 1, 2022

Bevy version

0.8.1

[Optional] Relevant system information

MacBook Pro (16-inch, 2021)

`AdapterInfo { name: "Apple M1 Max", vendor: 0, device: 0, device_type: IntegratedGpu, backend: Metal }`

What you did

  1. Cloned out the repository.
  2. Checked out the v0.8.1 tag.
  3. Tried the shader-instancing example locally on release mode: cargo run --release --example shader_instancing.

What went wrong

When occluding or minimizing the Bevy window, memory usages skyrockets at gigabytes per second until the window is shown again.

Additional information

The memory usage is caused by gfx-rs/wgpu#1783. The following information stems from a long and somewhat redundant investigation on this issue, plus a bunch of other macOS-related issues (discord thread).

It was concluded that this is impractical to solve entirely at the wgpu level, and that there are two primary workarounds for this issue:

  1. Detecting window occlusion using winit's WindowEvent::Occluded and avoiding any rendering at all when the window is occluded.

    + Probably easier to plumb into an existing codebase.
    
    / WindowEvent::Occluded was introduced on winit 0.27.0.
    / Care must be taken to throtte the winit loop (or put it on ControlLoop::Wait) when
      the window is occluded, (and/or drive the app world through a different means?),
      since without wgpu surface obtention throttling it at vsync, it would just collapse into
      a tight loop, causing massive CPU usage.
    
    - Only mitigates the memory leak; on optimized builds it will still leak around 100 Mb
      when un-occluding the window.
    
  2. Driving rendering through CVDisplayLink (macOS) / CADisplayLink (iOS) frame callbacks (both essentially do kind of the same).
    Preliminary tests using the display-link 0.2 crate on raw wgpu examples were successful, but more interesting stuff is exposed on the raw APIs themselves (documentation). Apple itself explains how it works in this WWDC 2021 talk.

    It is noted exploring such integration for Bevy is already being studied as part of macOS and iOS CPU ussage fix #5713.

    + Fixes the memory leak.
    + If used as a way to drive winit redraw requests, can potentially ensure it keeps
      looping at target framerate even if the window is in the background.
    + Automatically handles system conditions (e.g. can throttle the application down
      automatically when thermals are high)
    
    / Likely the Apple recommended way to do it, given I have not seen any official Metal
      examples that *don't* use it.
    / Callback comes with nanosecond-precision timestamp(-s), could be used to derive
      delta timestamps?
    / Can be configured to target a specified framerate as long as it's divisible by vsync.
    
    - Essentially forces Vsync.
    - Likely very annoying to plumb on an existing codebase?
    
@Nnubes256 Nnubes256 added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Sep 1, 2022
@Nnubes256
Copy link
Author

Nnubes256 commented Sep 2, 2022

As part of filling information on the related issue on sotrh/learn-wgpu#207 (comment) (which contains sample code on both approaches on a smaller-scale wgpu project), I found out that approach 1 is not perfect when compiling with --release due to the heavy timing-dependent nature of the problem. On my testing with learn-wgpu, while it won't leak uncontrollably anymore, it will still leak around 100 Mb when un-occluding the window.

I have updated the main issue body as a result of this.

@alice-i-cecile alice-i-cecile added A-Windowing Platform-agnostic interface layer to run your app in O-MacOS Specific to the MacOS (Apple) desktop operating system and removed S-Needs-Triage This issue needs to be labelled labels Sep 8, 2022
@B-head B-head mentioned this issue Jul 6, 2023
8 tasks
@cart cart closed this as completed in #7611 Aug 3, 2023
github-merge-queue bot pushed a commit that referenced this issue Aug 3, 2023
…s not visible (#7611)

Fixes #5856. Fixes #8080. Fixes #9040.

# Objective

We need to limit the update rate of games whose windows are not visible
(minimized or completely occluded). Compositors typically ignore the
VSync settings of windows that aren't visible. That, combined with the
lack of rendering work, results in a scenario where an app becomes
completely CPU-bound and starts updating without limit.

There are currently three update modes.
- `Continuous` updates an app as often as possible.
- `Reactive` updates when new window or device events have appeared, a
timer expires, or a redraw is requested.
- `ReactiveLowPower` is the same as `Reactive` except it ignores device
events (e.g. general mouse movement).

The problem is that the default "game" settings are set to `Contiuous`
even when no windows are visible.

### More Context

- libsdl-org/SDL#1871
- glfw/glfw#680
- godotengine/godot#19741
- godotengine/godot#64708

## Solution

Change the default "unfocused" `UpdateMode` for games to
`ReactiveLowPower` just like desktop apps. This way, even when the
window is occluded, the app still updates at a sensible rate or if
something about the window changes. I chose 20Hz arbitrarily.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Windowing Platform-agnostic interface layer to run your app in C-Bug An unexpected or incorrect behavior O-MacOS Specific to the MacOS (Apple) desktop operating system
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants