bevyengine / bevyengine/bevy

MacOS Rendering Corruption starting on 0.19.0

Open
#25,595 0 comments 0 reactions 0 assignees View on GitHub
A-Rendering C-Bug D-Modest I-Regression O-MacOS S-Ready-For-Implementation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version and features

- Bevy 0.19.1, 0.19.0 (not reproducible in 0.18.1)
- Default features

## \[Optional\] Relevant system information

If your bug is rendering-related, copy the adapter info that appears when you run Bevy.

```ignore
AdapterInfo { name: "Apple M3 Pro", vendor: 0, device: 0, device_type: IntegratedGpu, device_pci_bus_id: "", driver: "", driver_info: "", backend: Metal, subgroup_min_size: 4, subgroup_max_size: 64, transient_saves_memory: true }
```

## What you did

I'm encountering a combination of 2 issues:
- Materials that swapping around to different meshes
- Meshes flickering in and out of visibility, every other frame

It happens under these circumstances, but I haven't been able to narrow it down specifically:
- Only impacts 0.19.x versions
- Impacts macOS, does not impact Windows
- Only happens with GPU Preprocessing - I think this is a strong clue about the root cause, see the bottom for more information
- The problem gets worse using:
- GLTF Meshes (I'm relying on instancing a lot)
- FXAA instead of MSAA

I'm working really hard to get a minimal reproducible build, But I haven't been successful. The problem seems to scale with complexity, so I think you need a complicated rendering setup to get the issue to trigger. I would be willing to share my reproduction with select maintainers if requested.

## What went wrong

Here's a video of the corruption:

https://github.com/user-attachments/assets/1ea5b0a1-3ba9-4577-86c7-5dfed40ae163

## Additional information

### Theory About GPU Preprocessing
I'm able to fix the issue by forcing the WGPU to use CPU preprocessing. This changes the log `GPU preprocessing is fully supported on this device.` to `(GPU preprocessing is not supported on this device. Falling back to CPU preprocessing.),`. When I do this, my framerate improves, and the flickering and material swapping goes away entirely.

**Hunches**: I am not super knowledgeable about WGPU internals, but doing some research, here's some thoughts:
- I tried setting `WgpuSettings::disabled_features(WgpuFeatures::TEXTURE_BINDING_ARRAY)`, thinking the issue was related to bindless textures, but this didn't solve it
- I think the issue lies in the GPU indirect drawing path that GPU preprocessing/culling turns on.
- I'm thinking this could be related to #21739, AlphaMode::Blend meshes flickering with indirect drawing
- [I did some AI-assisted digging here] There was a change between 0.18 and 0.19 where MeshAllocator's slab-resize still does a queue.submit that never joined the new batched PendingCommandBuffers model everything else in the render graph now goes through, so there's one remaining out-of-band submission in an otherwise fully-batched frame

Here's the workaround that fixes the issue even on 0.19.1:

```rust
let render_plugin = bevy::render::RenderPlugin {
render_creation: macos_wgpu_settings_forcing_cpu_preprocessing().into(),
..default()
};
app.add_plugins((DefaultPlugins.set(render_plugin),...));

...

// Hack to disable GPU preprocessing on macOS
#[cfg(target_os = "macos")]
fn macos_wgpu_settings_forcing_cpu_preprocessing() -> bevy::render::settings::WgpuSettings {
use bevy::render::settings::WgpuLimits;

bevy::render::settings::WgpuSettings {
constrained_limits: Some(
WgpuLimits {
max_binding_array_elements_per_shader_stage: u32::MAX,
max_binding_array_sampler_elements_per_shader_stage: u32::MAX,
..WgpuLimits::downlevel_webgl2_defaults()
}
.using_resolution(WgpuLimits::default()),
),
..default()
}
}
```

Contributor guide

Open the contributing guide

Research direction

Start with the reported reproduction conditions: Bevy 0.19.x on macOS with an Apple Metal GPU and GPU preprocessing enabled, then compare against the CPU-preprocessing workaround. Inspect the RenderPlugin/WgpuSettings entry points, MeshAllocator slab resizing, and the indirect drawing path; done means identifying and fixing the corruption so meshes no longer flicker or swap materials.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics, game-dev
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.