From b48f9e2a4b8728cfe572114113ec58f401a699ed Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 8 Oct 2024 07:50:35 -0700 Subject: [PATCH] Fix oit webgl (#15728) The previous fixes were breaking pretty much everything on main due to naga-oil complaining about the OIT shader not being loaded, since apparently webgl is a default feature. This fix is a bit messier, but properly warns the user and is probably what we should have gone for in the first place. --- crates/bevy_core_pipeline/src/lib.rs | 3 -- .../bevy_core_pipeline/src/oit/resolve/mod.rs | 51 +++++++++++-------- .../bevy_pbr/src/render/mesh_view_bindings.rs | 37 ++++++++++---- crates/bevy_render/src/render_resource/mod.rs | 4 +- 4 files changed, 57 insertions(+), 38 deletions(-) diff --git a/crates/bevy_core_pipeline/src/lib.rs b/crates/bevy_core_pipeline/src/lib.rs index c7a65a3e1f1c9..731b50a7576ea 100644 --- a/crates/bevy_core_pipeline/src/lib.rs +++ b/crates/bevy_core_pipeline/src/lib.rs @@ -76,7 +76,6 @@ use crate::{ use bevy_app::{App, Plugin}; use bevy_asset::load_internal_asset; use bevy_render::prelude::Shader; -#[cfg(not(feature = "webgl"))] use oit::OrderIndependentTransparencyPlugin; #[derive(Default)] @@ -110,8 +109,6 @@ impl Plugin for CorePipelinePlugin { DepthOfFieldPlugin, SmaaPlugin, PostProcessingPlugin, - // DownlevelFlags::FRAGMENT_WRITABLE_STORAGE is required for OIT - #[cfg(not(feature = "webgl"))] OrderIndependentTransparencyPlugin, )); } diff --git a/crates/bevy_core_pipeline/src/oit/resolve/mod.rs b/crates/bevy_core_pipeline/src/oit/resolve/mod.rs index e728ec004aa2b..37e8a4065b9f4 100644 --- a/crates/bevy_core_pipeline/src/oit/resolve/mod.rs +++ b/crates/bevy_core_pipeline/src/oit/resolve/mod.rs @@ -1,3 +1,7 @@ +use crate::{ + fullscreen_vertex_shader::fullscreen_shader_vertex_state, + oit::OrderIndependentTransparencySettings, +}; use bevy_app::Plugin; use bevy_asset::{load_internal_asset, Handle}; use bevy_derive::Deref; @@ -9,20 +13,16 @@ use bevy_render::{ render_resource::{ binding_types::{storage_buffer_sized, texture_depth_2d, uniform_buffer}, BindGroup, BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, BlendComponent, - BlendState, CachedRenderPipelineId, ColorTargetState, ColorWrites, FragmentState, - MultisampleState, PipelineCache, PrimitiveState, RenderPipelineDescriptor, Shader, - ShaderStages, TextureFormat, + BlendState, CachedRenderPipelineId, ColorTargetState, ColorWrites, DownlevelFlags, + FragmentState, MultisampleState, PipelineCache, PrimitiveState, RenderPipelineDescriptor, + Shader, ShaderStages, TextureFormat, }, - renderer::RenderDevice, + renderer::{RenderAdapter, RenderDevice}, texture::BevyDefault, view::{ExtractedView, ViewTarget, ViewUniform, ViewUniforms}, Render, RenderApp, RenderSet, }; - -use crate::{ - fullscreen_vertex_shader::fullscreen_shader_vertex_state, - oit::OrderIndependentTransparencySettings, -}; +use bevy_utils::tracing::warn; use super::OitBuffers; @@ -42,18 +42,6 @@ impl Plugin for OitResolvePlugin { "oit_resolve.wgsl", Shader::from_wgsl ); - - let Some(render_app) = app.get_sub_app_mut(RenderApp) else { - return; - }; - - render_app.add_systems( - Render, - ( - queue_oit_resolve_pipeline.in_set(RenderSet::Queue), - prepare_oit_resolve_bind_group.in_set(RenderSet::PrepareBindGroups), - ), - ); } fn finish(&self, app: &mut bevy_app::App) { @@ -61,7 +49,26 @@ impl Plugin for OitResolvePlugin { return; }; - render_app.init_resource::(); + if !render_app + .world() + .resource::() + .get_downlevel_capabilities() + .flags + .contains(DownlevelFlags::FRAGMENT_WRITABLE_STORAGE) + { + warn!("OrderIndependentTransparencyPlugin not loaded. GPU lacks support: DownlevelFlags::FRAGMENT_WRITABLE_STORAGE."); + return; + } + + render_app + .add_systems( + Render, + ( + queue_oit_resolve_pipeline.in_set(RenderSet::Queue), + prepare_oit_resolve_bind_group.in_set(RenderSet::PrepareBindGroups), + ), + ) + .init_resource::(); } } diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 2ad6ad8499e77..8a55aecacc545 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -1,6 +1,4 @@ use alloc::sync::Arc; -use core::{array, num::NonZero}; - use bevy_core_pipeline::{ core_3d::ViewTransmissionTexture, oit::{OitBuffers, OrderIndependentTransparencySettings}, @@ -29,9 +27,11 @@ use bevy_render::{ VISIBILITY_RANGES_STORAGE_BUFFER_COUNT, }, }; +use core::{array, num::NonZero}; #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))] use bevy_render::render_resource::binding_types::texture_cube; +use bevy_render::renderer::RenderAdapter; #[cfg(debug_assertions)] use bevy_utils::warn_once; use environment_map::EnvironmentMapLight; @@ -194,6 +194,7 @@ fn layout_entries( visibility_ranges_buffer_binding_type: BufferBindingType, layout_key: MeshPipelineViewLayoutKey, render_device: &RenderDevice, + render_adapter: &RenderAdapter, ) -> Vec { let mut entries = DynamicBindGroupLayoutEntries::new_with_indices( ShaderStages::FRAGMENT, @@ -358,15 +359,25 @@ fn layout_entries( )); // OIT - if cfg!(not(feature = "webgl")) && layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) { - entries = entries.extend_with_indices(( - // oit_layers - (31, storage_buffer_sized(false, None)), - // oit_layer_ids, - (32, storage_buffer_sized(false, None)), - // oit_layer_count - (33, uniform_buffer::(true)), - )); + if layout_key.contains(MeshPipelineViewLayoutKey::OIT_ENABLED) { + // Check if the GPU supports writable storage buffers in the fragment shader + // If not, we can't use OIT, so we skip the OIT bindings. + // This is a hack to avoid errors on webgl -- the OIT plugin will warn the user that OIT + // is not supported on their platform, so we don't need to do it here. + if render_adapter + .get_downlevel_capabilities() + .flags + .contains(DownlevelFlags::FRAGMENT_WRITABLE_STORAGE) + { + entries = entries.extend_with_indices(( + // oit_layers + (31, storage_buffer_sized(false, None)), + // oit_layer_ids, + (32, storage_buffer_sized(false, None)), + // oit_layer_count + (33, uniform_buffer::(true)), + )); + } } entries.to_vec() @@ -387,6 +398,7 @@ impl FromWorld for MeshPipelineViewLayouts { // [`MeshPipelineViewLayoutKey`] flags. let render_device = world.resource::(); + let render_adapter = world.resource::(); let clustered_forward_buffer_binding_type = render_device .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT); @@ -400,6 +412,7 @@ impl FromWorld for MeshPipelineViewLayouts { visibility_ranges_buffer_binding_type, key, render_device, + render_adapter, ); #[cfg(debug_assertions)] let texture_count: usize = entries @@ -436,6 +449,7 @@ impl MeshPipelineViewLayouts { /// [`MeshPipelineViewLayoutKey`] flags. pub fn generate_view_layouts( render_device: &RenderDevice, + render_adapter: &RenderAdapter, clustered_forward_buffer_binding_type: BufferBindingType, visibility_ranges_buffer_binding_type: BufferBindingType, ) -> [MeshPipelineViewLayout; MeshPipelineViewLayoutKey::COUNT] { @@ -446,6 +460,7 @@ pub fn generate_view_layouts( visibility_ranges_buffer_binding_type, key, render_device, + render_adapter, ); #[cfg(debug_assertions)] diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index 02e60fa1914ce..068bf74fa06d8 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -42,8 +42,8 @@ pub use wgpu::{ BufferBinding, BufferBindingType, BufferDescriptor, BufferSize, BufferUsages, ColorTargetState, ColorWrites, CommandEncoder, CommandEncoderDescriptor, CompareFunction, ComputePass, ComputePassDescriptor, ComputePipelineDescriptor as RawComputePipelineDescriptor, - DepthBiasState, DepthStencilState, Extent3d, Face, Features as WgpuFeatures, FilterMode, - FragmentState as RawFragmentState, FrontFace, ImageCopyBuffer, ImageCopyBufferBase, + DepthBiasState, DepthStencilState, DownlevelFlags, Extent3d, Face, Features as WgpuFeatures, + FilterMode, FragmentState as RawFragmentState, FrontFace, ImageCopyBuffer, ImageCopyBufferBase, ImageCopyTexture, ImageCopyTextureBase, ImageDataLayout, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, Maintain, MapMode, MultisampleState, Operations, Origin3d, PipelineCompilationOptions, PipelineLayout, PipelineLayoutDescriptor, PolygonMode,