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

Resizing 2D camera's viewport drops FPS and crashes (with HDR and bloom enabled) #16182

Open
bloopyboop opened this issue Oct 31, 2024 · 3 comments
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior S-Ready-For-Implementation This issue is ready for an implementation PR. Go for it!

Comments

@bloopyboop
Copy link

bloopyboop commented Oct 31, 2024

Bevy version

0.14.2, 0.15.0-dev (rev #4656698), 0.15.0-rc.2

All of them are affected.

Relevant system information

  • Rust version: cargo 1.84.0-nightly (e75214ea4 2024-10-25)
    • Happens on stable, too
  • OS: Linux
    • Display Server: Wayland (happens on X with i3wm, too)
    • Compositor: Hyprland (sway-wm based)
  • AdapterInfo { name: "NVIDIA GeForce GTX 1080", vendor: 4318, device: 7040, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "560.35.03", backend: Vulkan }

What you did

Added a system which animates the viewport's size on a 2D camera which has HDR enabled and a Bloom component with intensity > 0 (BloomSettings component instead for 0.14.2).

What went wrong

  • Debug: FPS drop more and more each frame.
  • Release: FPS do not drop each frame, instead only when the viewport's X size is large and Y size small.
  • Debug and Release: bevy crashes when the viewport's (valid) dimensions are very long and thin. The error message is the following:
ERROR wgpu::backend::wgpu_core: Handling wgpu errors as fatal by default    
thread 'Compute Task Pool (4)' panicked at [REDACTED]/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.20.1/src/backend/wgpu_core.rs:2996:5:
wgpu error: Validation Error

Caused by:
In Device::create_texture
note: label = `bloom_texture`
Dimension X value 35170 exceeds the limit of 32768

Additional information

Click here for a minimal repo that demonstrates the bug. There is also additional info and steps to reproduce in the README.

EDIT: Added details to "What went wrong" section.
EDIT2: Tested bevy versions 0.15.0-dev and 0.15.0-rc.2, too. Bug occurs there, too. Linked repo has branches for each bevy version for reproduction.

@bloopyboop bloopyboop added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Oct 31, 2024
@BenjaminBrienen BenjaminBrienen added A-Rendering Drawing game state to the screen S-Needs-Investigation This issue requires detective work to figure out what's going wrong and removed S-Needs-Triage This issue needs to be labelled labels Oct 31, 2024
@bloopyboop
Copy link
Author

bloopyboop commented Nov 1, 2024

I have added branches to the linked repo which test bevy versions 0.15.0-dev and 0.15.0-rc.2 as well. I have found the bug happens on all of them. I have edited the OP to reflect this. Please re-triage.

@BenjaminBrienen BenjaminBrienen added S-Ready-For-Implementation This issue is ready for an implementation PR. Go for it! and removed S-Needs-Investigation This issue requires detective work to figure out what's going wrong labels Nov 1, 2024
@BenjaminBrienen
Copy link
Contributor

Thanks for the deep dive

@bloopyboop
Copy link
Author

bloopyboop commented Nov 1, 2024

I have found the likely source of the bug.

In bloom/mod.rs:

fn prepare_bloom_textures(
    <snip>
    views: Query<(Entity, &ExtractedCamera, &Bloom)>,
) {
    for (entity, camera, bloom) in &views {
        if let Some(UVec2 {
            x: width,
            y: height,
        }) = camera.physical_viewport_size
        {
            // How many times we can halve the resolution minus one so we don't go unnecessarily low
            let mip_count = bloom.max_mip_dimension.ilog2().max(2) - 1;
            let mip_height_ratio = if height != 0 {
                bloom.max_mip_dimension as f32 / height as f32
            } else {
                0.
            };

            let texture_descriptor = TextureDescriptor {
                label: Some("bloom_texture"),
                size: Extent3d {
                    width: ((width as f32 * mip_height_ratio).round() as u32).max(1),
                    height: ((height as f32 * mip_height_ratio).round() as u32).max(1),
                    depth_or_array_layers: 1,
                },
                mip_level_count: mip_count,

                <snip>
            };

            <snip>
        }
    }
}

A new texture is created and cached for each different viewport size (caching is not seen in the code snippet, happens elsewhere). This leads to the FPS drops.
If you set the Bloom component's max_mip_dimension to 1 or another low value, the bug disappears (both FPS drops and crash). This snippet shows that's because the size of the created bloom texture depends on max_mip_dimension. Of course, the consequence of setting it low is the bloom looking unusably bad.

In fact, the bloom looks unusably bad for any viewports with small heights, even with the default setting for max_mip_dimension. Additionally, this explains why FPS are dropping in Release builds only for one axis: Both width and height in the Extent3d are based on mip_height_ratio.

The crash occurs, because wgpu_core seems to enforce a size limit on textures (32768 for me). The width and height calculation in the Extent3d can easily go way beyond that size limit. This is exactly what happens when the viewport is very long and thin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior S-Ready-For-Implementation This issue is ready for an implementation PR. Go for it!
Projects
None yet
Development

No branches or pull requests

2 participants