From e4382fcfc44776e15dd941a71aadf0da568498f0 Mon Sep 17 00:00:00 2001 From: Greeble <166992735+greeble-dev@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:00:48 +0000 Subject: [PATCH 1/2] Added limit checks. --- .../src/experimental/mip_generation/mod.rs | 1 + crates/bevy_core_pipeline/src/oit/resolve/mod.rs | 14 ++++++++++++++ crates/bevy_pbr/src/render/mesh_view_bindings.rs | 6 +++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs b/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs index f324193983f3c..39d5e5f2df1c8 100644 --- a/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs +++ b/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs @@ -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) { return; } diff --git a/crates/bevy_core_pipeline/src/oit/resolve/mod.rs b/crates/bevy_core_pipeline/src/oit/resolve/mod.rs index f73192b19dec9..d53cafae05171 100644 --- a/crates/bevy_core_pipeline/src/oit/resolve/mod.rs +++ b/crates/bevy_core_pipeline/src/oit/resolve/mod.rs @@ -33,6 +33,9 @@ pub const OIT_RESOLVE_SHADER_HANDLE: Handle = /// Contains the render node used to run the resolve pass. pub mod node; +/// Minimum required value of `wgpu::Limits::max_storage_buffers_per_shader_stage`. +pub const OIT_REQUIRED_STORAGE_BUFFERS: u32 = 2; + /// Plugin needed to resolve the Order Independent Transparency (OIT) buffer to the screen. pub struct OitResolvePlugin; impl Plugin for OitResolvePlugin { @@ -61,6 +64,17 @@ impl Plugin for OitResolvePlugin { return; } + if render_app + .world() + .resource::() + .limits() + .max_storage_buffers_per_shader_stage + < OIT_REQUIRED_STORAGE_BUFFERS + { + warn!("OrderIndependentTransparencyPlugin not loaded. RenderDevice lacks support: max_storage_buffers_per_shader_stage < OIT_REQUIRED_STORAGE_BUFFERS."); + return; + } + render_app .add_systems( Render, diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 796ae096c2e26..dbcd308b306bc 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -1,7 +1,9 @@ use alloc::sync::Arc; use bevy_core_pipeline::{ core_3d::ViewTransmissionTexture, - oit::{OitBuffers, OrderIndependentTransparencySettings}, + oit::{ + resolve::OIT_REQUIRED_STORAGE_BUFFERS, OitBuffers, OrderIndependentTransparencySettings, + }, prepass::ViewPrepassTextures, tonemapping::{ get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts, @@ -388,6 +390,8 @@ fn layout_entries( .get_downlevel_capabilities() .flags .contains(DownlevelFlags::FRAGMENT_WRITABLE_STORAGE) + && (render_device.limits().max_storage_buffers_per_shader_stage + >= OIT_REQUIRED_STORAGE_BUFFERS) { entries = entries.extend_with_indices(( // oit_layers From d89d39ce692497d1eef7741afb814a9199e034ab Mon Sep 17 00:00:00 2001 From: Greeble <166992735+greeble-dev@users.noreply.github.com> Date: Mon, 3 Mar 2025 10:13:38 +0000 Subject: [PATCH 2/2] Clarified logic. --- .../src/experimental/mip_generation/mod.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs b/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs index 39d5e5f2df1c8..8b8cbacaff980 100644 --- a/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs +++ b/crates/bevy_core_pipeline/src/experimental/mip_generation/mod.rs @@ -325,6 +325,18 @@ pub struct DownsampleDepthPipelines { sampler: Sampler, } +fn supports_compute_shaders(device: &RenderDevice, adapter: &RenderAdapter) -> bool { + adapter + .get_downlevel_capabilities() + .flags + .contains(DownlevelFlags::COMPUTE_SHADERS) + // Even if the adapter supports compute, we might be simulating a lack of + // compute via device limits (see `WgpuSettingsPriority::WebGL2` and + // `wgpu::Limits::downlevel_webgl2_defaults()`). This will have set all the + // `max_compute_*` limits to zero, so we arbitrarily pick one as a canary. + && (device.limits().max_compute_workgroup_storage_size != 0) +} + /// Creates the [`DownsampleDepthPipelines`] if downsampling is supported on the /// current platform. fn create_downsample_depth_pipelines( @@ -346,12 +358,7 @@ fn create_downsample_depth_pipelines( // If we don't have compute shaders, we can't invoke the downsample depth // compute shader. - if !render_adapter - .get_downlevel_capabilities() - .flags - .contains(DownlevelFlags::COMPUTE_SHADERS) - || (render_device.limits().max_compute_workgroup_storage_size == 0) - { + if !supports_compute_shaders(&render_device, &render_adapter) { return; }