Skip to content

macOS: Memory usage skyrockets when window is occluded #5856

@Nnubes256

Description

@Nnubes256

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?
    

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-WindowingPlatform-agnostic interface layer to run your app inC-BugAn unexpected or incorrect behaviorO-MacOSSpecific to the MacOS (Apple) desktop operating system

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions