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

Partially fix panics when setting WGPU_SETTINGS_PRIO=webgl2 #18113

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

greeble-dev
Copy link
Contributor

@greeble-dev greeble-dev commented Mar 2, 2025

Overview

Fixes #17869.

Summary

WGPU_SETTINGS_PRIO changes various limits on RenderDevice. This is useful to simulate platforms with lower limits.

However, some plugins only check the limits on RenderAdapter (the actual GPU) - these limits are not affected by WGPU_SETTINGS_PRIO. So the plugins try to use features that are unavailable and wgpu says "oh no". See #17869 for details.

The PR adds various checks on RenderDevice limits. This in enough to get most examples working, but some are not fixed (see below).

Testing

  • Tested native, with and without "WGPU_SETTINGS=webgl2". Win10/Vulkan/Nvidia".
  • Also WebGL. Win10/Chrome/Nvidia.
$env:WGPU_SETTINGS_PRIO = "webgl2"
cargo run --example testbed_3d
cargo run --example testbed_2d
cargo run --example testbed_ui
cargo run --example deferred_rendering
cargo run --example many_lights
cargo run --example order_independent_transparency # Still broken, see below.
cargo run --example occlusion_culling # Still broken, see below.

Not Fixed

While testing I found a few other cases of limits being broken.

"Compatibility" settings (WebGPU minimums) breaks native in various examples.

$env:WGPU_SETTINGS_PRIO = "compatibility"
cargo run --example testbed_3d

  In Device::create_bind_group_layout, label = 'build mesh uniforms GPU early occlusion culling bind group layout'
    Too many bindings of type StorageBuffers in Stage ShaderStages(COMPUTE), limit is 8, count was 9. Check the limit `max_storage_buffers_per_shader_stage` passed to `Adapter::request_device`

occlusion_culling breaks fake webgl.

$env:WGPU_SETTINGS_PRIO = "webgl2"
cargo run --example occlusion_culling

thread '<unnamed>' panicked at C:\Projects\bevy\crates\bevy_render\src\render_resource\pipeline_cache.rs:555:28:
index out of bounds: the len is 0 but the index is 2
Encountered a panic in system `bevy_render::renderer::render_system`!

occlusion_culling breaks real webgl.

cargo run --example occlusion_culling --target wasm32-unknown-unknown

ERROR app: panicked at C:\Users\T\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\glow-0.16.0\src\web_sys.rs:4223:9:
Tex storage 2D multisample is not supported

OIT breaks fake webgl.

$env:WGPU_SETTINGS_PRIO = "webgl2"
cargo run --example order_independent_transparency

  In Device::create_bind_group, label = 'mesh_view_bind_group'
    Number of bindings in bind group descriptor (28) does not match the number of bindings defined in the bind group layout (25)

OIT breaks real webgl

cargo run --example order_independent_transparency --target wasm32-unknown-unknown

  In Device::create_render_pipeline, label = 'pbr_oit_mesh_pipeline'
    Error matching ShaderStages(FRAGMENT) shader requirements against the pipeline
      Shader global ResourceBinding { group: 0, binding: 34 } is not available in the pipeline layout
        Binding is missing from the pipeline layout

@@ -350,6 +350,7 @@ fn create_downsample_depth_pipelines(
.get_downlevel_capabilities()
.flags
.contains(DownlevelFlags::COMPUTE_SHADERS)
|| (render_device.limits().max_compute_workgroup_storage_size == 0)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is a little awkward - there's no straightforward "is compute available" on wgpu::Limits.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bizarre. The default for WebGPU is fairly high https://gpuweb.github.io/gpuweb/#dom-supported-limits-maxcomputeworkgroupstoragesize. I didn't even know some platforms support compute shaders, but not workgroup-shared data.

@cwfitzgerald, can we get some input from wgpu/gpuweb people? Is this valid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have added a comment to clarify. I don't think this can ever happen on a real GPU. But the downlevel_webgl2_defaults() override simulates a lack of compute by setting all max_compute_* limits to zero. I arbitrarily picked one limit as a canary.

I'll see if I can make this cleaner or come up with an alternative.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified in d89d39c. Still kinda icky though.

I also considered working out some real limits for the mip generation, e.g. a minimum for max_compute_workgroup_size_x/y/z. But I'm not confident I can get that right.

Copy link

@cwfitzgerald cwfitzgerald Mar 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't even know some platforms support compute shaders, but not workgroup-shared data.

You don't have to worry about this, compute shaders imply some amount of workgroup shared data.

downlevel_webgl2_defaults()

You should only need to check the COMPUTE_SHADERS downlevel flag to know if compute shaders are supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, checking COMPUTE_SHADERS on the adapter is not sufficient when the device limits have been overridden via DeviceDescriptor::limits (with the intent of simulating webgl2 limits on another platform).

If I rely only on COMPUTE_SHADERS:

$env:WGPU_SETTINGS_PRIO = "webgl2"
cargo run --example occlusion_culling

  In Device::create_bind_group_layout, label = 'downsample depth bind group layout'
    Too many bindings of type StorageTextures in Stage ShaderStages(COMPUTE), limit is 0, count was 12. Check the limit `max_storage_textures_per_shader_stage` passed to `Adapter::request_device`

I guess there's a deeper question on whether setting device limits is the right way to simulate another platform's limits?

@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-Rendering Drawing game state to the screen O-WebGL2 Specific to the WebGL2 render API S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 2, 2025
@alice-i-cecile alice-i-cecile added this to the 0.16 milestone Mar 2, 2025
@alice-i-cecile alice-i-cecile requested a review from rparrett March 2, 2025 18:10
@JMS55
Copy link
Contributor

JMS55 commented Mar 3, 2025

If we can get this setup in CI, I would love automated tests for this. It's not feasible to manually test this kind of stuff myself, but it would be really nice to have CI let me know when we're going above WebGL2 or WebGPU minspec.

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 O-WebGL2 Specific to the WebGL2 render API S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

WGPU_SETTINGS_PRIO=webgl2 causes panics
4 participants