diff --git a/assets/shaders/array_texture.wgsl b/assets/shaders/array_texture.wgsl index d49d492a06396..293f3316654e4 100644 --- a/assets/shaders/array_texture.wgsl +++ b/assets/shaders/array_texture.wgsl @@ -7,8 +7,8 @@ } #import bevy_core_pipeline::tonemapping::tone_mapping -@group(2) @binding(0) var my_array_texture: texture_2d_array; -@group(2) @binding(1) var my_array_texture_sampler: sampler; +@group(3) @binding(0) var my_array_texture: texture_2d_array; +@group(3) @binding(1) var my_array_texture_sampler: sampler; @fragment fn fragment( diff --git a/assets/shaders/automatic_instancing.wgsl b/assets/shaders/automatic_instancing.wgsl index 35276246b094e..ca2195df0d4de 100644 --- a/assets/shaders/automatic_instancing.wgsl +++ b/assets/shaders/automatic_instancing.wgsl @@ -3,8 +3,8 @@ view_transformations::position_world_to_clip } -@group(2) @binding(0) var texture: texture_2d; -@group(2) @binding(1) var texture_sampler: sampler; +@group(3) @binding(0) var texture: texture_2d; +@group(3) @binding(1) var texture_sampler: sampler; struct Vertex { @builtin(instance_index) instance_index: u32, diff --git a/assets/shaders/bindless_material.wgsl b/assets/shaders/bindless_material.wgsl index 3de313b81afa9..f7fa795d94c1c 100644 --- a/assets/shaders/bindless_material.wgsl +++ b/assets/shaders/bindless_material.wgsl @@ -15,12 +15,12 @@ struct MaterialBindings { } #ifdef BINDLESS -@group(2) @binding(0) var materials: array; -@group(2) @binding(10) var material_color: binding_array; +@group(3) @binding(0) var materials: array; +@group(3) @binding(10) var material_color: binding_array; #else // BINDLESS -@group(2) @binding(0) var material_color: Color; -@group(2) @binding(1) var material_color_texture: texture_2d; -@group(2) @binding(2) var material_color_sampler: sampler; +@group(3) @binding(0) var material_color: Color; +@group(3) @binding(1) var material_color_texture: texture_2d; +@group(3) @binding(2) var material_color_sampler: sampler; #endif // BINDLESS @fragment diff --git a/assets/shaders/cubemap_unlit.wgsl b/assets/shaders/cubemap_unlit.wgsl index 14e45a045bfdb..81e153e408dfb 100644 --- a/assets/shaders/cubemap_unlit.wgsl +++ b/assets/shaders/cubemap_unlit.wgsl @@ -1,12 +1,12 @@ #import bevy_pbr::forward_io::VertexOutput #ifdef CUBEMAP_ARRAY -@group(2) @binding(0) var base_color_texture: texture_cube_array; +@group(3) @binding(0) var base_color_texture: texture_cube_array; #else -@group(2) @binding(0) var base_color_texture: texture_cube; +@group(3) @binding(0) var base_color_texture: texture_cube; #endif -@group(2) @binding(1) var base_color_sampler: sampler; +@group(3) @binding(1) var base_color_sampler: sampler; @fragment fn fragment( diff --git a/assets/shaders/custom_material.frag b/assets/shaders/custom_material.frag index a6bc9af0d2a7d..0617a08ae7291 100644 --- a/assets/shaders/custom_material.frag +++ b/assets/shaders/custom_material.frag @@ -3,10 +3,10 @@ layout(location = 0) in vec2 v_Uv; layout(location = 0) out vec4 o_Target; -layout(set = 2, binding = 0) uniform vec4 CustomMaterial_color; +layout(set = 3, binding = 0) uniform vec4 CustomMaterial_color; -layout(set = 2, binding = 1) uniform texture2D CustomMaterial_texture; -layout(set = 2, binding = 2) uniform sampler CustomMaterial_sampler; +layout(set = 3, binding = 1) uniform texture2D CustomMaterial_texture; +layout(set = 3, binding = 2) uniform sampler CustomMaterial_sampler; // wgsl modules can be imported and used in glsl // FIXME - this doesn't work any more ... diff --git a/assets/shaders/custom_material.vert b/assets/shaders/custom_material.vert index 86ca3629e261f..f9a2813a37994 100644 --- a/assets/shaders/custom_material.vert +++ b/assets/shaders/custom_material.vert @@ -25,9 +25,9 @@ struct Mesh { }; #ifdef PER_OBJECT_BUFFER_BATCH_SIZE -layout(set = 1, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}]; +layout(set = 2, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}]; #else -layout(set = 1, binding = 0) readonly buffer _Meshes { +layout(set = 2, binding = 0) readonly buffer _Meshes { Mesh Meshes[]; }; #endif // PER_OBJECT_BUFFER_BATCH_SIZE diff --git a/assets/shaders/custom_material.wesl b/assets/shaders/custom_material.wesl index 5113e1cbe0b39..ca946687845ab 100644 --- a/assets/shaders/custom_material.wesl +++ b/assets/shaders/custom_material.wesl @@ -10,7 +10,7 @@ struct CustomMaterial { time: vec4, } -@group(2) @binding(0) var material: CustomMaterial; +@group(3) @binding(0) var material: CustomMaterial; @fragment fn fragment( diff --git a/assets/shaders/custom_material.wgsl b/assets/shaders/custom_material.wgsl index 1b65627d45b32..7548d2223c8af 100644 --- a/assets/shaders/custom_material.wgsl +++ b/assets/shaders/custom_material.wgsl @@ -2,9 +2,9 @@ // we can import items from shader modules in the assets folder with a quoted path #import "shaders/custom_material_import.wgsl"::COLOR_MULTIPLIER -@group(2) @binding(0) var material_color: vec4; -@group(2) @binding(1) var material_color_texture: texture_2d; -@group(2) @binding(2) var material_color_sampler: sampler; +@group(3) @binding(0) var material_color: vec4; +@group(3) @binding(1) var material_color_texture: texture_2d; +@group(3) @binding(2) var material_color_sampler: sampler; @fragment fn fragment( diff --git a/assets/shaders/custom_material_screenspace_texture.wgsl b/assets/shaders/custom_material_screenspace_texture.wgsl index 36da2a7f8c204..abad3cc15afd1 100644 --- a/assets/shaders/custom_material_screenspace_texture.wgsl +++ b/assets/shaders/custom_material_screenspace_texture.wgsl @@ -4,8 +4,8 @@ utils::coords_to_viewport_uv, } -@group(2) @binding(0) var texture: texture_2d; -@group(2) @binding(1) var texture_sampler: sampler; +@group(3) @binding(0) var texture: texture_2d; +@group(3) @binding(1) var texture_sampler: sampler; @fragment fn fragment( diff --git a/assets/shaders/custom_vertex_attribute.wgsl b/assets/shaders/custom_vertex_attribute.wgsl index f8062ab77be3f..6b7b93e4c7161 100644 --- a/assets/shaders/custom_vertex_attribute.wgsl +++ b/assets/shaders/custom_vertex_attribute.wgsl @@ -3,7 +3,7 @@ struct CustomMaterial { color: vec4, }; -@group(2) @binding(0) var material: CustomMaterial; +@group(3) @binding(0) var material: CustomMaterial; struct Vertex { @builtin(instance_index) instance_index: u32, diff --git a/assets/shaders/extended_material.wgsl b/assets/shaders/extended_material.wgsl index fc69f30bb56e4..7bad24a331b93 100644 --- a/assets/shaders/extended_material.wgsl +++ b/assets/shaders/extended_material.wgsl @@ -19,7 +19,7 @@ struct MyExtendedMaterial { quantize_steps: u32, } -@group(2) @binding(100) +@group(3) @binding(100) var my_extended_material: MyExtendedMaterial; @fragment diff --git a/assets/shaders/extended_material_bindless.wgsl b/assets/shaders/extended_material_bindless.wgsl index f8650b0da7f60..c9cb07e0c733e 100644 --- a/assets/shaders/extended_material_bindless.wgsl +++ b/assets/shaders/extended_material_bindless.wgsl @@ -42,19 +42,19 @@ struct ExampleBindlessExtendedMaterial { // The indices of the bindless resources in the bindless resource arrays, for // the `ExampleBindlessExtension` fields. -@group(2) @binding(100) var example_extended_material_indices: +@group(3) @binding(100) var example_extended_material_indices: array; // An array that holds the `ExampleBindlessExtendedMaterial` plain old data, // indexed by `ExampleBindlessExtendedMaterialIndices.material`. -@group(2) @binding(101) var example_extended_material: +@group(3) @binding(101) var example_extended_material: array; #else // BINDLESS // In non-bindless mode, we simply use a uniform for the plain old data. -@group(2) @binding(50) var example_extended_material: ExampleBindlessExtendedMaterial; -@group(2) @binding(51) var modulate_texture: texture_2d; -@group(2) @binding(52) var modulate_sampler: sampler; +@group(3) @binding(50) var example_extended_material: ExampleBindlessExtendedMaterial; +@group(3) @binding(51) var modulate_texture: texture_2d; +@group(3) @binding(52) var modulate_sampler: sampler; #endif // BINDLESS diff --git a/assets/shaders/fallback_image_test.wgsl b/assets/shaders/fallback_image_test.wgsl index c48f091bcca4c..c92cbd1577e4e 100644 --- a/assets/shaders/fallback_image_test.wgsl +++ b/assets/shaders/fallback_image_test.wgsl @@ -1,22 +1,22 @@ #import bevy_pbr::forward_io::VertexOutput -@group(2) @binding(0) var test_texture_1d: texture_1d; -@group(2) @binding(1) var test_texture_1d_sampler: sampler; +@group(3) @binding(0) var test_texture_1d: texture_1d; +@group(3) @binding(1) var test_texture_1d_sampler: sampler; -@group(2) @binding(2) var test_texture_2d: texture_2d; -@group(2) @binding(3) var test_texture_2d_sampler: sampler; +@group(3) @binding(2) var test_texture_2d: texture_2d; +@group(3) @binding(3) var test_texture_2d_sampler: sampler; -@group(2) @binding(4) var test_texture_2d_array: texture_2d_array; -@group(2) @binding(5) var test_texture_2d_array_sampler: sampler; +@group(3) @binding(4) var test_texture_2d_array: texture_2d_array; +@group(3) @binding(5) var test_texture_2d_array_sampler: sampler; -@group(2) @binding(6) var test_texture_cube: texture_cube; -@group(2) @binding(7) var test_texture_cube_sampler: sampler; +@group(3) @binding(6) var test_texture_cube: texture_cube; +@group(3) @binding(7) var test_texture_cube_sampler: sampler; -@group(2) @binding(8) var test_texture_cube_array: texture_cube_array; -@group(2) @binding(9) var test_texture_cube_array_sampler: sampler; +@group(3) @binding(8) var test_texture_cube_array: texture_cube_array; +@group(3) @binding(9) var test_texture_cube_array_sampler: sampler; -@group(2) @binding(10) var test_texture_3d: texture_3d; -@group(2) @binding(11) var test_texture_3d_sampler: sampler; +@group(3) @binding(10) var test_texture_3d: texture_3d; +@group(3) @binding(11) var test_texture_3d_sampler: sampler; @fragment fn fragment(in: VertexOutput) {} diff --git a/assets/shaders/irradiance_volume_voxel_visualization.wgsl b/assets/shaders/irradiance_volume_voxel_visualization.wgsl index f34e6f8453dd7..0e12110f3b1da 100644 --- a/assets/shaders/irradiance_volume_voxel_visualization.wgsl +++ b/assets/shaders/irradiance_volume_voxel_visualization.wgsl @@ -12,7 +12,7 @@ struct VoxelVisualizationIrradianceVolumeInfo { intensity: f32, } -@group(2) @binding(100) +@group(3) @binding(100) var irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo; @fragment diff --git a/assets/shaders/line_material.wgsl b/assets/shaders/line_material.wgsl index cc7ca047d5d2d..639762a444ab4 100644 --- a/assets/shaders/line_material.wgsl +++ b/assets/shaders/line_material.wgsl @@ -4,7 +4,7 @@ struct LineMaterial { color: vec4, }; -@group(2) @binding(0) var material: LineMaterial; +@group(3) @binding(0) var material: LineMaterial; @fragment fn fragment( diff --git a/assets/shaders/shader_defs.wgsl b/assets/shaders/shader_defs.wgsl index fdddc4caa1442..776fc9ffe69eb 100644 --- a/assets/shaders/shader_defs.wgsl +++ b/assets/shaders/shader_defs.wgsl @@ -4,7 +4,7 @@ struct CustomMaterial { color: vec4, }; -@group(2) @binding(0) var material: CustomMaterial; +@group(3) @binding(0) var material: CustomMaterial; @fragment fn fragment( diff --git a/assets/shaders/show_prepass.wgsl b/assets/shaders/show_prepass.wgsl index c1b3a89750227..b1a53677ac1ea 100644 --- a/assets/shaders/show_prepass.wgsl +++ b/assets/shaders/show_prepass.wgsl @@ -11,7 +11,7 @@ struct ShowPrepassSettings { padding_1: u32, padding_2: u32, } -@group(2) @binding(0) var settings: ShowPrepassSettings; +@group(3) @binding(0) var settings: ShowPrepassSettings; @fragment fn fragment( diff --git a/assets/shaders/storage_buffer.wgsl b/assets/shaders/storage_buffer.wgsl index c27053b9a21b3..f447333cc9754 100644 --- a/assets/shaders/storage_buffer.wgsl +++ b/assets/shaders/storage_buffer.wgsl @@ -3,7 +3,7 @@ view_transformations::position_world_to_clip } -@group(2) @binding(0) var colors: array, 5>; +@group(3) @binding(0) var colors: array, 5>; struct Vertex { @builtin(instance_index) instance_index: u32, diff --git a/assets/shaders/texture_binding_array.wgsl b/assets/shaders/texture_binding_array.wgsl index de7a4e1b96eca..17b94a74d3209 100644 --- a/assets/shaders/texture_binding_array.wgsl +++ b/assets/shaders/texture_binding_array.wgsl @@ -1,7 +1,7 @@ #import bevy_pbr::forward_io::VertexOutput -@group(2) @binding(0) var textures: binding_array>; -@group(2) @binding(1) var nearest_sampler: sampler; +@group(3) @binding(0) var textures: binding_array>; +@group(3) @binding(1) var nearest_sampler: sampler; // We can also have array of samplers // var samplers: binding_array; diff --git a/assets/shaders/water_material.wgsl b/assets/shaders/water_material.wgsl index 31d04b5f1142d..a8a9e03df4d16 100644 --- a/assets/shaders/water_material.wgsl +++ b/assets/shaders/water_material.wgsl @@ -23,9 +23,9 @@ struct WaterSettings { @group(0) @binding(1) var globals: Globals; -@group(2) @binding(100) var water_normals_texture: texture_2d; -@group(2) @binding(101) var water_normals_sampler: sampler; -@group(2) @binding(102) var water_settings: WaterSettings; +@group(3) @binding(100) var water_normals_texture: texture_2d; +@group(3) @binding(101) var water_normals_sampler: sampler; +@group(3) @binding(102) var water_settings: WaterSettings; // Samples a single octave of noise and returns the resulting normal. fn sample_noise_octave(uv: vec2, strength: f32) -> vec3 { diff --git a/crates/bevy_color/Cargo.toml b/crates/bevy_color/Cargo.toml index 99ac8a70da911..22ade1270900b 100644 --- a/crates/bevy_color/Cargo.toml +++ b/crates/bevy_color/Cargo.toml @@ -20,7 +20,7 @@ serde = { version = "1.0", features = [ ], default-features = false, optional = true } thiserror = { version = "2", default-features = false } derive_more = { version = "2", default-features = false, features = ["from"] } -wgpu-types = { version = "24", default-features = false, optional = true } +wgpu-types = { version = "25", default-features = false, optional = true } encase = { version = "0.10", default-features = false, optional = true } [features] diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index 1cc70c67cb313..69854f7de4818 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -123,8 +123,7 @@ impl SpecializedRenderPipeline for LineGizmoPipeline { .mesh_pipeline .get_view_layout(key.view_key.into()) .clone(); - - let layout = vec![view_layout, self.uniform_layout.clone()]; + let layout = vec![view_layout.main_layout.clone(), self.uniform_layout.clone()]; let fragment_entry_point = match key.line_style { GizmoLineStyle::Solid => "fragment_solid", @@ -220,8 +219,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline { .mesh_pipeline .get_view_layout(key.view_key.into()) .clone(); - - let layout = vec![view_layout, self.uniform_layout.clone()]; + let layout = vec![view_layout.main_layout.clone(), self.uniform_layout.clone()]; if key.joints == GizmoLineJoint::None { error!("There is no entry point for line joints with GizmoLineJoints::None. Please consider aborting the drawing process before reaching this stage."); diff --git a/crates/bevy_image/Cargo.toml b/crates/bevy_image/Cargo.toml index 54559d60d3d1d..1ed4f29ca624b 100644 --- a/crates/bevy_image/Cargo.toml +++ b/crates/bevy_image/Cargo.toml @@ -63,7 +63,7 @@ image = { version = "0.25.2", default-features = false } # misc bitflags = { version = "2.3", features = ["serde"] } bytemuck = { version = "1.5" } -wgpu-types = { version = "24", default-features = false } +wgpu-types = { version = "25", default-features = false } serde = { version = "1", features = ["derive"] } thiserror = { version = "2", default-features = false } futures-lite = "2.0.1" diff --git a/crates/bevy_mesh/Cargo.toml b/crates/bevy_mesh/Cargo.toml index 0b77bdb619218..7807acbb9d074 100644 --- a/crates/bevy_mesh/Cargo.toml +++ b/crates/bevy_mesh/Cargo.toml @@ -27,7 +27,7 @@ bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-fea # other bitflags = { version = "2.3", features = ["serde"] } bytemuck = { version = "1.5" } -wgpu-types = { version = "24", default-features = false } +wgpu-types = { version = "25", default-features = false } serde = { version = "1", default-features = false, features = [ "derive", ], optional = true } diff --git a/crates/bevy_pbr/src/atmosphere/render_sky.wgsl b/crates/bevy_pbr/src/atmosphere/render_sky.wgsl index e488656df4cd6..f8298272caa69 100644 --- a/crates/bevy_pbr/src/atmosphere/render_sky.wgsl +++ b/crates/bevy_pbr/src/atmosphere/render_sky.wgsl @@ -1,3 +1,5 @@ +enable dual_source_blending; + #import bevy_pbr::atmosphere::{ types::{Atmosphere, AtmosphereSettings}, bindings::{atmosphere, view, atmosphere_transforms}, @@ -19,9 +21,11 @@ #endif struct RenderSkyOutput { - @location(0) inscattering: vec4, #ifdef DUAL_SOURCE_BLENDING - @location(0) @second_blend_source transmittance: vec4, + @location(0) @blend_src(0) inscattering: vec4, + @location(0) @blend_src(1) transmittance: vec4, +#else + @location(0) inscattering: vec4, #endif } diff --git a/crates/bevy_pbr/src/decal/forward_decal.wgsl b/crates/bevy_pbr/src/decal/forward_decal.wgsl index ce24d57bf5998..f0414bc807625 100644 --- a/crates/bevy_pbr/src/decal/forward_decal.wgsl +++ b/crates/bevy_pbr/src/decal/forward_decal.wgsl @@ -10,7 +10,7 @@ } #import bevy_render::maths::project_onto -@group(2) @binding(200) +@group(3) @binding(200) var inv_depth_fade_factor: f32; struct ForwardDecalInformation { diff --git a/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl b/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl index 843ed2bbf69ab..7c14eea4baf99 100644 --- a/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl +++ b/crates/bevy_pbr/src/deferred/deferred_lighting.wgsl @@ -29,7 +29,7 @@ struct PbrDeferredLightingDepthId { _webgl2_padding_2: f32, #endif } -@group(1) @binding(0) +@group(2) @binding(0) var depth_id: PbrDeferredLightingDepthId; @vertex diff --git a/crates/bevy_pbr/src/deferred/mod.rs b/crates/bevy_pbr/src/deferred/mod.rs index 28edd38c52fb0..b8f3a660c0eed 100644 --- a/crates/bevy_pbr/src/deferred/mod.rs +++ b/crates/bevy_pbr/src/deferred/mod.rs @@ -184,9 +184,9 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode { return Ok(()); }; - let bind_group_1 = render_context.render_device().create_bind_group( - "deferred_lighting_layout_group_1", - &deferred_lighting_layout.bind_group_layout_1, + let bind_group_2 = render_context.render_device().create_bind_group( + "deferred_lighting_layout_group_2", + &deferred_lighting_layout.bind_group_layout_2, &BindGroupEntries::single(deferred_lighting_pass_id_binding), ); @@ -208,7 +208,7 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode { render_pass.set_render_pipeline(pipeline); render_pass.set_bind_group( 0, - &mesh_view_bind_group.value, + &mesh_view_bind_group.main, &[ view_uniform_offset.offset, view_lights_offset.offset, @@ -218,7 +218,8 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode { **view_environment_map_offset, ], ); - render_pass.set_bind_group(1, &bind_group_1, &[]); + render_pass.set_bind_group(1, &mesh_view_bind_group.binding_array, &[]); + render_pass.set_bind_group(2, &bind_group_2, &[]); render_pass.draw(0..3, 0..1); Ok(()) @@ -228,7 +229,7 @@ impl ViewNode for DeferredOpaquePass3dPbrLightingNode { #[derive(Resource)] pub struct DeferredLightingLayout { mesh_pipeline: MeshPipeline, - bind_group_layout_1: BindGroupLayout, + bind_group_layout_2: BindGroupLayout, deferred_lighting_shader: Handle, } @@ -346,11 +347,13 @@ impl SpecializedRenderPipeline for DeferredLightingLayout { #[cfg(all(feature = "webgl", target_arch = "wasm32", not(feature = "webgpu")))] shader_defs.push("SIXTEEN_BYTE_ALIGNMENT".into()); + let layout = self.mesh_pipeline.get_view_layout(key.into()); RenderPipelineDescriptor { label: Some("deferred_lighting_pipeline".into()), layout: vec![ - self.mesh_pipeline.get_view_layout(key.into()).clone(), - self.bind_group_layout_1.clone(), + layout.main_layout.clone(), + layout.binding_array_layout.clone(), + self.bind_group_layout_2.clone(), ], vertex: VertexState { shader: self.deferred_lighting_shader.clone(), @@ -408,7 +411,7 @@ impl FromWorld for DeferredLightingLayout { ); Self { mesh_pipeline: world.resource::().clone(), - bind_group_layout_1: layout, + bind_group_layout_2: layout, deferred_lighting_shader: load_embedded_asset!(world, "deferred_lighting.wgsl"), } } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 945bc9c55bcd7..517ef0eb5cbe2 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -152,8 +152,8 @@ fn shader_ref(path: PathBuf) -> ShaderRef { const MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE: Handle = weak_handle!("69187376-3dea-4d0f-b3f5-185bde63d6a2"); -pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 26; -pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 27; +pub const TONEMAPPING_LUT_TEXTURE_BINDING_INDEX: u32 = 18; +pub const TONEMAPPING_LUT_SAMPLER_BINDING_INDEX: u32 = 19; /// Sets up the entire PBR infrastructure of bevy. pub struct PbrPlugin { diff --git a/crates/bevy_pbr/src/lightmap/lightmap.wgsl b/crates/bevy_pbr/src/lightmap/lightmap.wgsl index da10ece9b1c01..4ba6f51bc9a4b 100644 --- a/crates/bevy_pbr/src/lightmap/lightmap.wgsl +++ b/crates/bevy_pbr/src/lightmap/lightmap.wgsl @@ -3,11 +3,11 @@ #import bevy_pbr::mesh_bindings::mesh #ifdef MULTIPLE_LIGHTMAPS_IN_ARRAY -@group(1) @binding(4) var lightmaps_textures: binding_array, 4>; -@group(1) @binding(5) var lightmaps_samplers: binding_array; +@group(2) @binding(4) var lightmaps_textures: binding_array, 4>; +@group(2) @binding(5) var lightmaps_samplers: binding_array; #else // MULTIPLE_LIGHTMAPS_IN_ARRAY -@group(1) @binding(4) var lightmaps_texture: texture_2d; -@group(1) @binding(5) var lightmaps_sampler: sampler; +@group(2) @binding(4) var lightmaps_texture: texture_2d; +@group(2) @binding(5) var lightmaps_sampler: sampler; #endif // MULTIPLE_LIGHTMAPS_IN_ARRAY // Samples the lightmap, if any, and returns indirect illumination from it. diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index d17599c106862..f73f1392bb1d5 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -120,9 +120,9 @@ use tracing::error; /// In WGSL shaders, the material's binding would look like this: /// /// ```wgsl -/// @group(2) @binding(0) var color: vec4; -/// @group(2) @binding(1) var color_texture: texture_2d; -/// @group(2) @binding(2) var color_sampler: sampler; +/// @group(3) @binding(0) var color: vec4; +/// @group(3) @binding(1) var color_texture: texture_2d; +/// @group(3) @binding(2) var color_sampler: sampler; /// ``` pub trait Material: Asset + AsBindGroup + Clone + Sized { /// Returns this material's vertex shader. If [`ShaderRef::Default`] is returned, the default mesh vertex shader @@ -501,7 +501,7 @@ where descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone(); } - descriptor.layout.insert(2, self.material_layout.clone()); + descriptor.layout.insert(3, self.material_layout.clone()); M::specialize(self, &mut descriptor, layout, key)?; @@ -544,8 +544,9 @@ impl FromWorld for MaterialPipeline { type DrawMaterial = ( SetItemPipeline, SetMeshViewBindGroup<0>, - SetMeshBindGroup<1>, - SetMaterialBindGroup, + SetMeshViewBindingArrayBindGroup<1>, + SetMeshBindGroup<2>, + SetMaterialBindGroup, DrawMesh, ); diff --git a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs index 57762bfc8a609..90d35d05142a2 100644 --- a/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs +++ b/crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs @@ -186,13 +186,17 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass( let mut shader_defs = material_fragment.shader_defs; shader_defs.push("MESHLET_MESH_MATERIAL_PASS".into()); + let layout = mesh_pipeline.get_view_layout(view_key.into()); + let layout = vec![ + layout.main_layout.clone(), + layout.binding_array_layout.clone(), + resource_manager.material_shade_bind_group_layout.clone(), + material_pipeline.material_layout.clone(), + ]; + let pipeline_descriptor = RenderPipelineDescriptor { label: material_pipeline_descriptor.label, - layout: vec![ - mesh_pipeline.get_view_layout(view_key.into()).clone(), - resource_manager.material_shade_bind_group_layout.clone(), - material_pipeline.material_layout.clone(), - ], + layout, push_constant_ranges: vec![], vertex: VertexState { shader: MESHLET_MESH_MATERIAL_SHADER_HANDLE, diff --git a/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs b/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs index 9c2d432d8856a..cb05de38fb822 100644 --- a/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs +++ b/crates/bevy_pbr/src/meshlet/material_shade_nodes.rs @@ -106,7 +106,7 @@ impl ViewNode for MeshletMainOpaquePass3dNode { render_pass.set_bind_group( 0, - &mesh_view_bind_group.value, + &mesh_view_bind_group.main, &[ view_uniform_offset.offset, view_lights_offset.offset, diff --git a/crates/bevy_pbr/src/meshlet/meshlet_bindings.wgsl b/crates/bevy_pbr/src/meshlet/meshlet_bindings.wgsl index e179e78b7ae5e..63e92f15e6feb 100644 --- a/crates/bevy_pbr/src/meshlet/meshlet_bindings.wgsl +++ b/crates/bevy_pbr/src/meshlet/meshlet_bindings.wgsl @@ -149,15 +149,15 @@ fn get_meshlet_vertex_position(meshlet: ptr, vertex_id: u32) #endif #ifdef MESHLET_MESH_MATERIAL_PASS -@group(1) @binding(0) var meshlet_visibility_buffer: texture_storage_2d; -@group(1) @binding(1) var meshlet_cluster_meshlet_ids: array; // Per cluster -@group(1) @binding(2) var meshlets: array; // Per meshlet -@group(1) @binding(3) var meshlet_indices: array; // Many per meshlet -@group(1) @binding(4) var meshlet_vertex_positions: array; // Many per meshlet -@group(1) @binding(5) var meshlet_vertex_normals: array; // Many per meshlet -@group(1) @binding(6) var meshlet_vertex_uvs: array>; // Many per meshlet -@group(1) @binding(7) var meshlet_cluster_instance_ids: array; // Per cluster -@group(1) @binding(8) var meshlet_instance_uniforms: array; // Per entity instance +@group(2) @binding(0) var meshlet_visibility_buffer: texture_storage_2d; +@group(2) @binding(1) var meshlet_cluster_meshlet_ids: array; // Per cluster +@group(2) @binding(2) var meshlets: array; // Per meshlet +@group(2) @binding(3) var meshlet_indices: array; // Many per meshlet +@group(2) @binding(4) var meshlet_vertex_positions: array; // Many per meshlet +@group(2) @binding(5) var meshlet_vertex_normals: array; // Many per meshlet +@group(2) @binding(6) var meshlet_vertex_uvs: array>; // Many per meshlet +@group(2) @binding(7) var meshlet_cluster_instance_ids: array; // Per cluster +@group(2) @binding(8) var meshlet_instance_uniforms: array; // Per entity instance // TODO: Load only twice, instead of 3x in cases where you load 3 indices per thread? fn get_meshlet_vertex_id(index_id: u32) -> u32 { diff --git a/crates/bevy_pbr/src/meshlet/resource_manager.rs b/crates/bevy_pbr/src/meshlet/resource_manager.rs index 9b45d7676ab43..d33752d426142 100644 --- a/crates/bevy_pbr/src/meshlet/resource_manager.rs +++ b/crates/bevy_pbr/src/meshlet/resource_manager.rs @@ -206,7 +206,7 @@ impl ResourceManager { visibility_buffer_raster_bind_group_layout: render_device.create_bind_group_layout( "meshlet_visibility_buffer_raster_bind_group_layout", &BindGroupLayoutEntries::sequential( - ShaderStages::all(), + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, ( storage_buffer_read_only_sized(false, None), storage_buffer_read_only_sized(false, None), @@ -225,7 +225,7 @@ impl ResourceManager { .create_bind_group_layout( "meshlet_visibility_buffer_raster_shadow_view_bind_group_layout", &BindGroupLayoutEntries::sequential( - ShaderStages::all(), + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, ( storage_buffer_read_only_sized(false, None), storage_buffer_read_only_sized(false, None), diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index aef2b74177b3e..8732f92e8277e 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -95,7 +95,6 @@ where Render, prepare_prepass_view_bind_group::.in_set(RenderSystems::PrepareBindGroups), ) - .init_resource::() .init_resource::>>() .allow_ambiguous_resource::>>(); } @@ -105,7 +104,9 @@ where return; }; - render_app.init_resource::>(); + render_app + .init_resource::>() + .init_resource::(); } } @@ -272,6 +273,7 @@ pub struct PrepassPipelineInternal { pub view_layout_motion_vectors: BindGroupLayout, pub view_layout_no_motion_vectors: BindGroupLayout, pub mesh_layouts: MeshLayouts, + pub empty_layout: BindGroupLayout, pub material_layout: BindGroupLayout, pub prepass_material_vertex_shader: Option>, pub prepass_material_fragment_shader: Option>, @@ -381,6 +383,7 @@ impl FromWorld for PrepassPipeline { skins_use_uniform_buffers: skin::skins_use_uniform_buffers(render_device), depth_clip_control_supported, binding_arrays_are_usable: binding_arrays_are_usable(render_device, render_adapter), + empty_layout: render_device.create_bind_group_layout("prepass_empty_layout", &[]), }; PrepassPipeline { internal, @@ -425,13 +428,14 @@ impl PrepassPipelineInternal { layout: &MeshVertexBufferLayoutRef, ) -> Result { let mut shader_defs = shader_defs; - let mut bind_group_layouts = vec![if mesh_key - .contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) - { - self.view_layout_motion_vectors.clone() - } else { - self.view_layout_no_motion_vectors.clone() - }]; + let mut bind_group_layouts = vec![ + if mesh_key.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS) { + self.view_layout_motion_vectors.clone() + } else { + self.view_layout_no_motion_vectors.clone() + }, + self.empty_layout.clone(), + ]; let mut vertex_attributes = Vec::new(); // Let the shader code know that it's running in a prepass pipeline. @@ -556,7 +560,7 @@ impl PrepassPipelineInternal { &mut vertex_attributes, self.skins_use_uniform_buffers, ); - bind_group_layouts.insert(1, bind_group); + bind_group_layouts.insert(2, bind_group); let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?; // Setup prepass fragment targets - normals in slot 0 (or None if not needed), motion vectors in slot 1 let mut targets = prepass_target_descriptors( @@ -723,10 +727,29 @@ pub fn prepare_previous_view_uniforms( } } -#[derive(Default, Resource)] +#[derive(Resource)] pub struct PrepassViewBindGroup { pub motion_vectors: Option, pub no_motion_vectors: Option, + pub empty_bind_group: BindGroup, +} + +impl FromWorld for PrepassViewBindGroup { + fn from_world(world: &mut World) -> Self { + let pipeline = world.resource::>(); + + let render_device = world.resource::(); + let empty_bind_group = render_device.create_bind_group( + "prepass_view_empty_bind_group", + &pipeline.internal.empty_layout, + &[], + ); + PrepassViewBindGroup { + motion_vectors: None, + no_motion_vectors: None, + empty_bind_group, + } + } } pub fn prepare_prepass_view_bind_group( @@ -1284,7 +1307,26 @@ impl RenderCommand

for SetPrepassViewBindGroup< ); } } + RenderCommandResult::Success + } +} +pub struct SetPrepassViewEmptyBindGroup; +impl RenderCommand

for SetPrepassViewEmptyBindGroup { + type Param = SRes; + type ViewQuery = (); + type ItemQuery = (); + + #[inline] + fn render<'w>( + _item: &P, + _view: (), + _entity: Option<()>, + prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>, + pass: &mut TrackedRenderPass<'w>, + ) -> RenderCommandResult { + let prepass_view_bind_group = prepass_view_bind_group.into_inner(); + pass.set_bind_group(I, &prepass_view_bind_group.empty_bind_group, &[]); RenderCommandResult::Success } } @@ -1292,7 +1334,8 @@ impl RenderCommand

for SetPrepassViewBindGroup< pub type DrawPrepass = ( SetItemPipeline, SetPrepassViewBindGroup<0>, - SetMeshBindGroup<1>, - SetMaterialBindGroup, + SetPrepassViewEmptyBindGroup<1>, + SetMeshBindGroup<2>, + SetMaterialBindGroup, DrawMesh, ); diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index d8a3256b13460..50d7e98a48011 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -1864,7 +1864,10 @@ impl MeshPipeline { } } - pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> &BindGroupLayout { + pub fn get_view_layout( + &self, + layout_key: MeshPipelineViewLayoutKey, + ) -> &MeshPipelineViewLayout { self.view_layouts.get_view_layout(layout_key) } } @@ -2320,7 +2323,11 @@ impl SpecializedMeshPipeline for MeshPipeline { shader_defs.push("PBR_SPECULAR_TEXTURES_SUPPORTED".into()); } - let mut bind_group_layout = vec![self.get_view_layout(key.into()).clone()]; + let bind_group_layout = self.get_view_layout(key.into()); + let mut bind_group_layout = vec![ + bind_group_layout.main_layout.clone(), + bind_group_layout.binding_array_layout.clone(), + ]; if key.msaa_samples() > 1 { shader_defs.push("MULTISAMPLED".into()); @@ -2890,7 +2897,47 @@ impl RenderCommand

for SetMeshViewBindGroup if let Some(layers_count_offset) = maybe_oit_layers_count_offset { offsets.push(layers_count_offset.offset); } - pass.set_bind_group(I, &mesh_view_bind_group.value, &offsets); + pass.set_bind_group(I, &mesh_view_bind_group.main, &offsets); + + RenderCommandResult::Success + } +} + +pub struct SetMeshViewBindingArrayBindGroup; +impl RenderCommand

for SetMeshViewBindingArrayBindGroup { + type Param = (); + type ViewQuery = (Read,); + type ItemQuery = (); + + #[inline] + fn render<'w>( + _item: &P, + (mesh_view_bind_group,): ROQueryItem<'w, '_, Self::ViewQuery>, + _entity: Option<()>, + _: SystemParamItem<'w, '_, Self::Param>, + pass: &mut TrackedRenderPass<'w>, + ) -> RenderCommandResult { + pass.set_bind_group(I, &mesh_view_bind_group.binding_array, &[]); + + RenderCommandResult::Success + } +} + +pub struct SetMeshViewEmptyBindGroup; +impl RenderCommand

for SetMeshViewEmptyBindGroup { + type Param = (); + type ViewQuery = (Read,); + type ItemQuery = (); + + #[inline] + fn render<'w>( + _item: &P, + (mesh_view_bind_group,): ROQueryItem<'w, '_, Self::ViewQuery>, + _entity: Option<()>, + _: SystemParamItem<'w, '_, Self::Param>, + pass: &mut TrackedRenderPass<'w>, + ) -> RenderCommandResult { + pass.set_bind_group(I, &mesh_view_bind_group.empty, &[]); RenderCommandResult::Success } diff --git a/crates/bevy_pbr/src/render/mesh_bindings.wgsl b/crates/bevy_pbr/src/render/mesh_bindings.wgsl index 62b967c56f1b9..6e78dc4337a8b 100644 --- a/crates/bevy_pbr/src/render/mesh_bindings.wgsl +++ b/crates/bevy_pbr/src/render/mesh_bindings.wgsl @@ -4,8 +4,8 @@ #ifndef MESHLET_MESH_MATERIAL_PASS #ifdef PER_OBJECT_BUFFER_BATCH_SIZE -@group(1) @binding(0) var mesh: array; +@group(2) @binding(0) var mesh: array; #else -@group(1) @binding(0) var mesh: array; +@group(2) @binding(0) var mesh: array; #endif // PER_OBJECT_BUFFER_BATCH_SIZE #endif // MESHLET_MESH_MATERIAL_PASS diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.rs b/crates/bevy_pbr/src/render/mesh_view_bindings.rs index 8e231886bae1e..50bbcd20fa9b6 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.rs +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.rs @@ -59,7 +59,9 @@ use {crate::MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES, bevy_utils::once, traci #[derive(Clone)] pub struct MeshPipelineViewLayout { - pub bind_group_layout: BindGroupLayout, + pub main_layout: BindGroupLayout, + pub binding_array_layout: BindGroupLayout, + pub empty_layout: BindGroupLayout, #[cfg(debug_assertions)] pub texture_count: usize, @@ -201,7 +203,11 @@ fn layout_entries( layout_key: MeshPipelineViewLayoutKey, render_device: &RenderDevice, render_adapter: &RenderAdapter, -) -> Vec { +) -> [Vec; 2] { + // EnvironmentMapLight + let environment_map_entries = + environment_map::get_bind_group_layout_entries(render_device, render_adapter); + let mut entries = DynamicBindGroupLayoutEntries::new_with_indices( ShaderStages::FRAGMENT, ( @@ -313,45 +319,15 @@ fn layout_entries( 16, texture_2d(TextureSampleType::Float { filterable: false }), ), + (17, environment_map_entries[3]), ), ); - // EnvironmentMapLight - let environment_map_entries = - environment_map::get_bind_group_layout_entries(render_device, render_adapter); - entries = entries.extend_with_indices(( - (17, environment_map_entries[0]), - (18, environment_map_entries[1]), - (19, environment_map_entries[2]), - (20, environment_map_entries[3]), - )); - - // Irradiance volumes - if IRRADIANCE_VOLUMES_ARE_USABLE { - let irradiance_volume_entries = - irradiance_volume::get_bind_group_layout_entries(render_device, render_adapter); - entries = entries.extend_with_indices(( - (21, irradiance_volume_entries[0]), - (22, irradiance_volume_entries[1]), - )); - } - - // Clustered decals - if let Some(clustered_decal_entries) = - decal::clustered::get_bind_group_layout_entries(render_device, render_adapter) - { - entries = entries.extend_with_indices(( - (23, clustered_decal_entries[0]), - (24, clustered_decal_entries[1]), - (25, clustered_decal_entries[2]), - )); - } - // Tonemapping let tonemapping_lut_entries = get_lut_bind_group_layout_entries(); entries = entries.extend_with_indices(( - (26, tonemapping_lut_entries[0]), - (27, tonemapping_lut_entries[1]), + (18, tonemapping_lut_entries[0]), + (19, tonemapping_lut_entries[1]), )); // Prepass @@ -361,7 +337,7 @@ fn layout_entries( { for (entry, binding) in prepass::get_bind_group_layout_entries(layout_key) .iter() - .zip([28, 29, 30, 31]) + .zip([20, 21, 22, 23]) { if let Some(entry) = entry { entries = entries.extend_with_indices(((binding as u32, *entry),)); @@ -372,10 +348,10 @@ fn layout_entries( // View Transmission Texture entries = entries.extend_with_indices(( ( - 32, + 24, texture_2d(TextureSampleType::Float { filterable: true }), ), - (33, sampler(SamplerBindingType::Filtering)), + (25, sampler(SamplerBindingType::Filtering)), )); // OIT @@ -386,19 +362,47 @@ fn layout_entries( if is_oit_supported(render_adapter, render_device, false) { entries = entries.extend_with_indices(( // oit_layers - (34, storage_buffer_sized(false, None)), + (26, storage_buffer_sized(false, None)), // oit_layer_ids, - (35, storage_buffer_sized(false, None)), + (27, storage_buffer_sized(false, None)), // oit_layer_count ( - 36, + 28, uniform_buffer::(true), ), )); } } - entries.to_vec() + let mut binding_array_entries = DynamicBindGroupLayoutEntries::new(ShaderStages::FRAGMENT); + binding_array_entries = binding_array_entries.extend_with_indices(( + (0, environment_map_entries[0]), + (1, environment_map_entries[1]), + (2, environment_map_entries[2]), + )); + + // Irradiance volumes + if IRRADIANCE_VOLUMES_ARE_USABLE { + let irradiance_volume_entries = + irradiance_volume::get_bind_group_layout_entries(render_device, render_adapter); + binding_array_entries = binding_array_entries.extend_with_indices(( + (3, irradiance_volume_entries[0]), + (4, irradiance_volume_entries[1]), + )); + } + + // Clustered decals + if let Some(clustered_decal_entries) = + decal::clustered::get_bind_group_layout_entries(render_device, render_adapter) + { + binding_array_entries = binding_array_entries.extend_with_indices(( + (5, clustered_decal_entries[0]), + (6, clustered_decal_entries[1]), + (7, clustered_decal_entries[2]), + )); + } + + [entries.to_vec(), binding_array_entries.to_vec()] } /// Stores the view layouts for every combination of pipeline keys. @@ -435,12 +439,21 @@ impl FromWorld for MeshPipelineViewLayouts { #[cfg(debug_assertions)] let texture_count: usize = entries .iter() - .filter(|entry| matches!(entry.ty, BindingType::Texture { .. })) + .flat_map(|e| { + e.iter() + .filter(|entry| matches!(entry.ty, BindingType::Texture { .. })) + }) .count(); MeshPipelineViewLayout { - bind_group_layout: render_device - .create_bind_group_layout(key.label().as_str(), &entries), + main_layout: render_device + .create_bind_group_layout(key.label().as_str(), &entries[0]), + binding_array_layout: render_device.create_bind_group_layout( + format!("{}_binding_array", key.label()).as_str(), + &entries[1], + ), + empty_layout: render_device + .create_bind_group_layout(format!("{}_empty", key.label()).as_str(), &[]), #[cfg(debug_assertions)] texture_count, } @@ -449,7 +462,10 @@ impl FromWorld for MeshPipelineViewLayouts { } impl MeshPipelineViewLayouts { - pub fn get_view_layout(&self, layout_key: MeshPipelineViewLayoutKey) -> &BindGroupLayout { + pub fn get_view_layout( + &self, + layout_key: MeshPipelineViewLayoutKey, + ) -> &MeshPipelineViewLayout { let index = layout_key.bits() as usize; let layout = &self[index]; @@ -459,7 +475,7 @@ impl MeshPipelineViewLayouts { once!(warn!("Too many textures in mesh pipeline view layout, this might cause us to hit `wgpu::Limits::max_sampled_textures_per_shader_stage` in some environments.")); } - &layout.bind_group_layout + layout } } @@ -484,12 +500,20 @@ pub fn generate_view_layouts( #[cfg(debug_assertions)] let texture_count: usize = entries .iter() - .filter(|entry| matches!(entry.ty, BindingType::Texture { .. })) + .flat_map(|e| { + e.iter() + .filter(|entry| matches!(entry.ty, BindingType::Texture { .. })) + }) .count(); MeshPipelineViewLayout { - bind_group_layout: render_device - .create_bind_group_layout(key.label().as_str(), &entries), + main_layout: render_device.create_bind_group_layout(key.label().as_str(), &entries[0]), + binding_array_layout: render_device.create_bind_group_layout( + format!("{}_binding_array", key.label()).as_str(), + &entries[1], + ), + empty_layout: render_device + .create_bind_group_layout(format!("{}_empty", key.label()).as_str(), &[]), #[cfg(debug_assertions)] texture_count, } @@ -498,7 +522,9 @@ pub fn generate_view_layouts( #[derive(Component)] pub struct MeshViewBindGroup { - pub value: BindGroup, + pub main: BindGroup, + pub binding_array: BindGroup, + pub empty: BindGroup, } pub fn prepare_mesh_view_bind_groups( @@ -585,7 +611,7 @@ pub fn prepare_mesh_view_bind_groups( layout_key |= MeshPipelineViewLayoutKey::OIT_ENABLED; } - let layout = &mesh_pipeline.get_view_layout(layout_key); + let layout = mesh_pipeline.get_view_layout(layout_key); let mut entries = DynamicBindGroupEntries::new_with_indices(( (0, view_binding.clone()), @@ -614,6 +640,58 @@ pub fn prepare_mesh_view_bind_groups( (16, ssao_view), )); + entries = entries.extend_with_indices(((17, environment_map_binding.clone()),)); + + let lut_bindings = + get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image); + entries = entries.extend_with_indices(((18, lut_bindings.0), (19, lut_bindings.1))); + + // When using WebGL, we can't have a depth texture with multisampling + let prepass_bindings; + if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || msaa.samples() == 1 + { + prepass_bindings = prepass::get_bindings(prepass_textures); + for (binding, index) in prepass_bindings + .iter() + .map(Option::as_ref) + .zip([20, 21, 22, 23]) + .flat_map(|(b, i)| b.map(|b| (b, i))) + { + entries = entries.extend_with_indices(((index, binding),)); + } + }; + + let transmission_view = transmission_texture + .map(|transmission| &transmission.view) + .unwrap_or(&fallback_image_zero.texture_view); + + let transmission_sampler = transmission_texture + .map(|transmission| &transmission.sampler) + .unwrap_or(&fallback_image_zero.sampler); + + entries = + entries.extend_with_indices(((24, transmission_view), (25, transmission_sampler))); + + if has_oit { + if let ( + Some(oit_layers_binding), + Some(oit_layer_ids_binding), + Some(oit_settings_binding), + ) = ( + oit_buffers.layers.binding(), + oit_buffers.layer_ids.binding(), + oit_buffers.settings.binding(), + ) { + entries = entries.extend_with_indices(( + (26, oit_layers_binding.clone()), + (27, oit_layer_ids_binding.clone()), + (28, oit_settings_binding.clone()), + )); + } + } + + let mut entries_binding_array = DynamicBindGroupEntries::new(); + let environment_map_bind_group_entries = RenderViewEnvironmentMapBindGroupEntries::get( render_view_environment_maps, &images, @@ -621,18 +699,16 @@ pub fn prepare_mesh_view_bind_groups( &render_device, &render_adapter, ); - match environment_map_bind_group_entries { RenderViewEnvironmentMapBindGroupEntries::Single { diffuse_texture_view, specular_texture_view, sampler, } => { - entries = entries.extend_with_indices(( - (17, diffuse_texture_view), - (18, specular_texture_view), - (19, sampler), - (20, environment_map_binding.clone()), + entries_binding_array = entries_binding_array.extend_with_indices(( + (0, diffuse_texture_view), + (1, specular_texture_view), + (2, sampler), )); } RenderViewEnvironmentMapBindGroupEntries::Multiple { @@ -640,11 +716,10 @@ pub fn prepare_mesh_view_bind_groups( ref specular_texture_views, sampler, } => { - entries = entries.extend_with_indices(( - (17, diffuse_texture_views.as_slice()), - (18, specular_texture_views.as_slice()), - (19, sampler), - (20, environment_map_binding.clone()), + entries_binding_array = entries_binding_array.extend_with_indices(( + (0, diffuse_texture_views.as_slice()), + (1, specular_texture_views.as_slice()), + (2, sampler), )); } } @@ -666,14 +741,15 @@ pub fn prepare_mesh_view_bind_groups( texture_view, sampler, }) => { - entries = entries.extend_with_indices(((21, texture_view), (22, sampler))); + entries_binding_array = entries_binding_array + .extend_with_indices(((3, texture_view), (4, sampler))); } Some(RenderViewIrradianceVolumeBindGroupEntries::Multiple { ref texture_views, sampler, }) => { - entries = entries - .extend_with_indices(((21, texture_views.as_slice()), (22, sampler))); + entries_binding_array = entries_binding_array + .extend_with_indices(((3, texture_views.as_slice()), (4, sampler))); } None => {} } @@ -689,76 +765,42 @@ pub fn prepare_mesh_view_bind_groups( // Add the decal bind group entries. if let Some(ref render_view_decal_bind_group_entries) = decal_bind_group_entries { - entries = entries.extend_with_indices(( + entries_binding_array = entries_binding_array.extend_with_indices(( // `clustered_decals` ( - 23, + 5, render_view_decal_bind_group_entries .decals .as_entire_binding(), ), // `clustered_decal_textures` ( - 24, + 6, render_view_decal_bind_group_entries .texture_views .as_slice(), ), // `clustered_decal_sampler` - (25, render_view_decal_bind_group_entries.sampler), + (7, render_view_decal_bind_group_entries.sampler), )); } - let lut_bindings = - get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image); - entries = entries.extend_with_indices(((26, lut_bindings.0), (27, lut_bindings.1))); - - // When using WebGL, we can't have a depth texture with multisampling - let prepass_bindings; - if cfg!(any(not(feature = "webgl"), not(target_arch = "wasm32"))) || msaa.samples() == 1 - { - prepass_bindings = prepass::get_bindings(prepass_textures); - for (binding, index) in prepass_bindings - .iter() - .map(Option::as_ref) - .zip([28, 29, 30, 31]) - .flat_map(|(b, i)| b.map(|b| (b, i))) - { - entries = entries.extend_with_indices(((index, binding),)); - } - }; - - let transmission_view = transmission_texture - .map(|transmission| &transmission.view) - .unwrap_or(&fallback_image_zero.texture_view); - - let transmission_sampler = transmission_texture - .map(|transmission| &transmission.sampler) - .unwrap_or(&fallback_image_zero.sampler); - - entries = - entries.extend_with_indices(((32, transmission_view), (33, transmission_sampler))); - - if has_oit { - if let ( - Some(oit_layers_binding), - Some(oit_layer_ids_binding), - Some(oit_settings_binding), - ) = ( - oit_buffers.layers.binding(), - oit_buffers.layer_ids.binding(), - oit_buffers.settings.binding(), - ) { - entries = entries.extend_with_indices(( - (34, oit_layers_binding.clone()), - (35, oit_layer_ids_binding.clone()), - (36, oit_settings_binding.clone()), - )); - } - } - commands.entity(entity).insert(MeshViewBindGroup { - value: render_device.create_bind_group("mesh_view_bind_group", layout, &entries), + main: render_device.create_bind_group( + "mesh_view_bind_group", + &layout.main_layout, + &entries, + ), + binding_array: render_device.create_bind_group( + "mesh_view_bind_group_binding_array", + &layout.binding_array_layout, + &entries_binding_array, + ), + empty: render_device.create_bind_group( + "mesh_view_bind_group_empty", + &layout.empty_layout, + &[], + ), }); } } diff --git a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl index 2fb34d84669c9..0f650e6e54dbb 100644 --- a/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_bindings.wgsl @@ -50,70 +50,70 @@ const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u; @group(0) @binding(15) var ssr_settings: types::ScreenSpaceReflectionsSettings; @group(0) @binding(16) var screen_space_ambient_occlusion_texture: texture_2d; - -#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY -@group(0) @binding(17) var diffuse_environment_maps: binding_array, 8u>; -@group(0) @binding(18) var specular_environment_maps: binding_array, 8u>; -#else -@group(0) @binding(17) var diffuse_environment_map: texture_cube; -@group(0) @binding(18) var specular_environment_map: texture_cube; -#endif -@group(0) @binding(19) var environment_map_sampler: sampler; -@group(0) @binding(20) var environment_map_uniform: types::EnvironmentMapUniform; - -#ifdef IRRADIANCE_VOLUMES_ARE_USABLE -#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY -@group(0) @binding(21) var irradiance_volumes: binding_array, 8u>; -#else -@group(0) @binding(21) var irradiance_volume: texture_3d; -#endif -@group(0) @binding(22) var irradiance_volume_sampler: sampler; -#endif - -#ifdef CLUSTERED_DECALS_ARE_USABLE -@group(0) @binding(23) var clustered_decals: types::ClusteredDecals; -@group(0) @binding(24) var clustered_decal_textures: binding_array, 8u>; -@group(0) @binding(25) var clustered_decal_sampler: sampler; -#endif // CLUSTERED_DECALS_ARE_USABLE +@group(0) @binding(17) var environment_map_uniform: types::EnvironmentMapUniform; // NB: If you change these, make sure to update `tonemapping_shared.wgsl` too. -@group(0) @binding(26) var dt_lut_texture: texture_3d; -@group(0) @binding(27) var dt_lut_sampler: sampler; +@group(0) @binding(18) var dt_lut_texture: texture_3d; +@group(0) @binding(19) var dt_lut_sampler: sampler; #ifdef MULTISAMPLED #ifdef DEPTH_PREPASS -@group(0) @binding(28) var depth_prepass_texture: texture_depth_multisampled_2d; +@group(0) @binding(20) var depth_prepass_texture: texture_depth_multisampled_2d; #endif // DEPTH_PREPASS #ifdef NORMAL_PREPASS -@group(0) @binding(29) var normal_prepass_texture: texture_multisampled_2d; +@group(0) @binding(21) var normal_prepass_texture: texture_multisampled_2d; #endif // NORMAL_PREPASS #ifdef MOTION_VECTOR_PREPASS -@group(0) @binding(30) var motion_vector_prepass_texture: texture_multisampled_2d; +@group(0) @binding(22) var motion_vector_prepass_texture: texture_multisampled_2d; #endif // MOTION_VECTOR_PREPASS #else // MULTISAMPLED #ifdef DEPTH_PREPASS -@group(0) @binding(28) var depth_prepass_texture: texture_depth_2d; +@group(0) @binding(20) var depth_prepass_texture: texture_depth_2d; #endif // DEPTH_PREPASS #ifdef NORMAL_PREPASS -@group(0) @binding(29) var normal_prepass_texture: texture_2d; +@group(0) @binding(21) var normal_prepass_texture: texture_2d; #endif // NORMAL_PREPASS #ifdef MOTION_VECTOR_PREPASS -@group(0) @binding(30) var motion_vector_prepass_texture: texture_2d; +@group(0) @binding(22) var motion_vector_prepass_texture: texture_2d; #endif // MOTION_VECTOR_PREPASS #endif // MULTISAMPLED #ifdef DEFERRED_PREPASS -@group(0) @binding(31) var deferred_prepass_texture: texture_2d; +@group(0) @binding(23) var deferred_prepass_texture: texture_2d; #endif // DEFERRED_PREPASS -@group(0) @binding(32) var view_transmission_texture: texture_2d; -@group(0) @binding(33) var view_transmission_sampler: sampler; +@group(0) @binding(24) var view_transmission_texture: texture_2d; +@group(0) @binding(25) var view_transmission_sampler: sampler; #ifdef OIT_ENABLED -@group(0) @binding(34) var oit_layers: array>; -@group(0) @binding(35) var oit_layer_ids: array>; -@group(0) @binding(36) var oit_settings: types::OrderIndependentTransparencySettings; +@group(0) @binding(26) var oit_layers: array>; +@group(0) @binding(27) var oit_layer_ids: array>; +@group(0) @binding(28) var oit_settings: types::OrderIndependentTransparencySettings; #endif // OIT_ENABLED + +#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY +@group(1) @binding(0) var diffuse_environment_maps: binding_array, 8u>; +@group(1) @binding(1) var specular_environment_maps: binding_array, 8u>; +#else +@group(1) @binding(0) var diffuse_environment_map: texture_cube; +@group(1) @binding(1) var specular_environment_map: texture_cube; +#endif +@group(1) @binding(2) var environment_map_sampler: sampler; + +#ifdef IRRADIANCE_VOLUMES_ARE_USABLE +#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY +@group(1) @binding(3) var irradiance_volumes: binding_array, 8u>; +#else +@group(1) @binding(3) var irradiance_volume: texture_3d; +#endif +@group(1) @binding(4) var irradiance_volume_sampler: sampler; +#endif + +#ifdef CLUSTERED_DECALS_ARE_USABLE +@group(1) @binding(5) var clustered_decals: types::ClusteredDecals; +@group(1) @binding(6) var clustered_decal_textures: binding_array, 8u>; +@group(1) @binding(7) var clustered_decal_sampler: sampler; +#endif // CLUSTERED_DECALS_ARE_USABLE diff --git a/crates/bevy_pbr/src/render/morph.wgsl b/crates/bevy_pbr/src/render/morph.wgsl index 939b714c777ed..6689d68cc6415 100644 --- a/crates/bevy_pbr/src/render/morph.wgsl +++ b/crates/bevy_pbr/src/render/morph.wgsl @@ -4,9 +4,9 @@ #import bevy_pbr::mesh_types::MorphWeights; -@group(1) @binding(2) var morph_weights: MorphWeights; -@group(1) @binding(3) var morph_targets: texture_3d; -@group(1) @binding(7) var prev_morph_weights: MorphWeights; +@group(2) @binding(2) var morph_weights: MorphWeights; +@group(2) @binding(3) var morph_targets: texture_3d; +@group(2) @binding(7) var prev_morph_weights: MorphWeights; // NOTE: Those are the "hardcoded" values found in `MorphAttributes` struct // in crates/bevy_render/src/mesh/morph/visitors.rs diff --git a/crates/bevy_pbr/src/render/pbr_bindings.wgsl b/crates/bevy_pbr/src/render/pbr_bindings.wgsl index fac7b97265fdb..373d0bdd54436 100644 --- a/crates/bevy_pbr/src/render/pbr_bindings.wgsl +++ b/crates/bevy_pbr/src/render/pbr_bindings.wgsl @@ -37,53 +37,53 @@ struct StandardMaterialBindings { specular_tint_sampler: u32, // 30 } -@group(2) @binding(0) var material_indices: array; -@group(2) @binding(10) var material_array: array; +@group(3) @binding(0) var material_indices: array; +@group(3) @binding(10) var material_array: array; #else // BINDLESS -@group(2) @binding(0) var material: StandardMaterial; -@group(2) @binding(1) var base_color_texture: texture_2d; -@group(2) @binding(2) var base_color_sampler: sampler; -@group(2) @binding(3) var emissive_texture: texture_2d; -@group(2) @binding(4) var emissive_sampler: sampler; -@group(2) @binding(5) var metallic_roughness_texture: texture_2d; -@group(2) @binding(6) var metallic_roughness_sampler: sampler; -@group(2) @binding(7) var occlusion_texture: texture_2d; -@group(2) @binding(8) var occlusion_sampler: sampler; -@group(2) @binding(9) var normal_map_texture: texture_2d; -@group(2) @binding(10) var normal_map_sampler: sampler; -@group(2) @binding(11) var depth_map_texture: texture_2d; -@group(2) @binding(12) var depth_map_sampler: sampler; +@group(3) @binding(0) var material: StandardMaterial; +@group(3) @binding(1) var base_color_texture: texture_2d; +@group(3) @binding(2) var base_color_sampler: sampler; +@group(3) @binding(3) var emissive_texture: texture_2d; +@group(3) @binding(4) var emissive_sampler: sampler; +@group(3) @binding(5) var metallic_roughness_texture: texture_2d; +@group(3) @binding(6) var metallic_roughness_sampler: sampler; +@group(3) @binding(7) var occlusion_texture: texture_2d; +@group(3) @binding(8) var occlusion_sampler: sampler; +@group(3) @binding(9) var normal_map_texture: texture_2d; +@group(3) @binding(10) var normal_map_sampler: sampler; +@group(3) @binding(11) var depth_map_texture: texture_2d; +@group(3) @binding(12) var depth_map_sampler: sampler; #ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED -@group(2) @binding(13) var anisotropy_texture: texture_2d; -@group(2) @binding(14) var anisotropy_sampler: sampler; +@group(3) @binding(13) var anisotropy_texture: texture_2d; +@group(3) @binding(14) var anisotropy_sampler: sampler; #endif // PBR_ANISOTROPY_TEXTURE_SUPPORTED #ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED -@group(2) @binding(15) var specular_transmission_texture: texture_2d; -@group(2) @binding(16) var specular_transmission_sampler: sampler; -@group(2) @binding(17) var thickness_texture: texture_2d; -@group(2) @binding(18) var thickness_sampler: sampler; -@group(2) @binding(19) var diffuse_transmission_texture: texture_2d; -@group(2) @binding(20) var diffuse_transmission_sampler: sampler; +@group(3) @binding(15) var specular_transmission_texture: texture_2d; +@group(3) @binding(16) var specular_transmission_sampler: sampler; +@group(3) @binding(17) var thickness_texture: texture_2d; +@group(3) @binding(18) var thickness_sampler: sampler; +@group(3) @binding(19) var diffuse_transmission_texture: texture_2d; +@group(3) @binding(20) var diffuse_transmission_sampler: sampler; #endif // PBR_TRANSMISSION_TEXTURES_SUPPORTED #ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED -@group(2) @binding(21) var clearcoat_texture: texture_2d; -@group(2) @binding(22) var clearcoat_sampler: sampler; -@group(2) @binding(23) var clearcoat_roughness_texture: texture_2d; -@group(2) @binding(24) var clearcoat_roughness_sampler: sampler; -@group(2) @binding(25) var clearcoat_normal_texture: texture_2d; -@group(2) @binding(26) var clearcoat_normal_sampler: sampler; +@group(3) @binding(21) var clearcoat_texture: texture_2d; +@group(3) @binding(22) var clearcoat_sampler: sampler; +@group(3) @binding(23) var clearcoat_roughness_texture: texture_2d; +@group(3) @binding(24) var clearcoat_roughness_sampler: sampler; +@group(3) @binding(25) var clearcoat_normal_texture: texture_2d; +@group(3) @binding(26) var clearcoat_normal_sampler: sampler; #endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED #ifdef PBR_SPECULAR_TEXTURES_SUPPORTED -@group(2) @binding(27) var specular_texture: texture_2d; -@group(2) @binding(28) var specular_sampler: sampler; -@group(2) @binding(29) var specular_tint_texture: texture_2d; -@group(2) @binding(30) var specular_tint_sampler: sampler; +@group(3) @binding(27) var specular_texture: texture_2d; +@group(3) @binding(28) var specular_sampler: sampler; +@group(3) @binding(29) var specular_tint_texture: texture_2d; +@group(3) @binding(30) var specular_tint_sampler: sampler; #endif // PBR_SPECULAR_TEXTURES_SUPPORTED #endif // BINDLESS diff --git a/crates/bevy_pbr/src/render/skinning.wgsl b/crates/bevy_pbr/src/render/skinning.wgsl index 1762a73887c94..6c4da0754ad8f 100644 --- a/crates/bevy_pbr/src/render/skinning.wgsl +++ b/crates/bevy_pbr/src/render/skinning.wgsl @@ -6,9 +6,9 @@ #ifdef SKINNED #ifdef SKINS_USE_UNIFORM_BUFFERS -@group(1) @binding(1) var joint_matrices: SkinnedMesh; +@group(2) @binding(1) var joint_matrices: SkinnedMesh; #else // SKINS_USE_UNIFORM_BUFFERS -@group(1) @binding(1) var joint_matrices: array>; +@group(2) @binding(1) var joint_matrices: array>; #endif // SKINS_USE_UNIFORM_BUFFERS // An array of matrices specifying the joint positions from the previous frame. @@ -18,9 +18,9 @@ // If this is the first frame, or we're otherwise prevented from using data from // the previous frame, this is simply the same as `joint_matrices` above. #ifdef SKINS_USE_UNIFORM_BUFFERS -@group(1) @binding(6) var prev_joint_matrices: SkinnedMesh; +@group(2) @binding(6) var prev_joint_matrices: SkinnedMesh; #else // SKINS_USE_UNIFORM_BUFFERS -@group(1) @binding(6) var prev_joint_matrices: array>; +@group(2) @binding(6) var prev_joint_matrices: array>; #endif // SKINS_USE_UNIFORM_BUFFERS fn skin_model( diff --git a/crates/bevy_pbr/src/ssr/mod.rs b/crates/bevy_pbr/src/ssr/mod.rs index 67ca025ce7764..f3d876ffde978 100644 --- a/crates/bevy_pbr/src/ssr/mod.rs +++ b/crates/bevy_pbr/src/ssr/mod.rs @@ -323,7 +323,7 @@ impl ViewNode for ScreenSpaceReflectionsNode { render_pass.set_render_pipeline(render_pipeline); render_pass.set_bind_group( 0, - &view_bind_group.value, + &view_bind_group.main, &[ view_uniform_offset.offset, view_lights_offset.offset, @@ -333,9 +333,10 @@ impl ViewNode for ScreenSpaceReflectionsNode { **view_environment_map_offset, ], ); + render_pass.set_bind_group(1, &view_bind_group.binding_array, &[]); // Perform the SSR render pass. - render_pass.set_bind_group(1, &ssr_bind_group, &[]); + render_pass.set_bind_group(2, &ssr_bind_group, &[]); render_pass.draw(0..3, 0..1); Ok(()) @@ -517,9 +518,14 @@ impl SpecializedRenderPipeline for ScreenSpaceReflectionsPipeline { type Key = ScreenSpaceReflectionsPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let mesh_view_layout = self + let layout = self .mesh_view_layouts .get_view_layout(key.mesh_pipeline_view_key); + let layout = vec![ + layout.main_layout.clone(), + layout.binding_array_layout.clone(), + self.bind_group_layout.clone(), + ]; let mut shader_defs = vec![ "DEPTH_PREPASS".into(), @@ -537,7 +543,7 @@ impl SpecializedRenderPipeline for ScreenSpaceReflectionsPipeline { RenderPipelineDescriptor { label: Some("SSR pipeline".into()), - layout: vec![mesh_view_layout.clone(), self.bind_group_layout.clone()], + layout, vertex: self.fullscreen_shader.to_vertex_state(), fragment: Some(FragmentState { shader: self.fragment_shader.clone(), diff --git a/crates/bevy_pbr/src/ssr/raymarch.wgsl b/crates/bevy_pbr/src/ssr/raymarch.wgsl index e149edfbbc239..12140c91e3170 100644 --- a/crates/bevy_pbr/src/ssr/raymarch.wgsl +++ b/crates/bevy_pbr/src/ssr/raymarch.wgsl @@ -25,10 +25,10 @@ } // Allows us to sample from the depth buffer with bilinear filtering. -@group(1) @binding(2) var depth_linear_sampler: sampler; +@group(2) @binding(2) var depth_linear_sampler: sampler; // Allows us to sample from the depth buffer with nearest-neighbor filtering. -@group(1) @binding(3) var depth_nearest_sampler: sampler; +@group(2) @binding(3) var depth_nearest_sampler: sampler; // Main code diff --git a/crates/bevy_pbr/src/ssr/ssr.wgsl b/crates/bevy_pbr/src/ssr/ssr.wgsl index 3dddfa1ba3bda..d646ac69febf9 100644 --- a/crates/bevy_pbr/src/ssr/ssr.wgsl +++ b/crates/bevy_pbr/src/ssr/ssr.wgsl @@ -36,10 +36,10 @@ #endif // The texture representing the color framebuffer. -@group(1) @binding(0) var color_texture: texture_2d; +@group(2) @binding(0) var color_texture: texture_2d; // The sampler that lets us sample from the color framebuffer. -@group(1) @binding(1) var color_sampler: sampler; +@group(2) @binding(1) var color_sampler: sampler; // Group 1, bindings 2 and 3 are in `raymarch.wgsl`. diff --git a/crates/bevy_pbr/src/volumetric_fog/render.rs b/crates/bevy_pbr/src/volumetric_fog/render.rs index cf2989a980533..a5cd8e56f3c1e 100644 --- a/crates/bevy_pbr/src/volumetric_fog/render.rs +++ b/crates/bevy_pbr/src/volumetric_fog/render.rs @@ -461,7 +461,7 @@ impl ViewNode for VolumetricFogNode { render_pass.set_pipeline(pipeline); render_pass.set_bind_group( 0, - &view_bind_group.value, + &view_bind_group.main, &[ view_uniform_offset.offset, view_lights_offset.offset, @@ -511,10 +511,6 @@ impl SpecializedRenderPipeline for VolumetricFogPipeline { type Key = VolumetricFogPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let mesh_view_layout = self - .mesh_view_layouts - .get_view_layout(key.mesh_pipeline_view_key); - // We always use hardware 2x2 filtering for sampling the shadow map; the // more accurate versions with percentage-closer filtering aren't worth // the overhead. @@ -559,9 +555,17 @@ impl SpecializedRenderPipeline for VolumetricFogPipeline { shader_defs.push("DENSITY_TEXTURE".into()); } + let layout = self + .mesh_view_layouts + .get_view_layout(key.mesh_pipeline_view_key); + let layout = vec![ + layout.main_layout.clone(), + volumetric_view_bind_group_layout.clone(), + ]; + RenderPipelineDescriptor { label: Some("volumetric lighting pipeline".into()), - layout: vec![mesh_view_layout.clone(), volumetric_view_bind_group_layout], + layout, push_constant_ranges: vec![], vertex: VertexState { shader: self.shader.clone(), diff --git a/crates/bevy_pbr/src/wireframe.rs b/crates/bevy_pbr/src/wireframe.rs index b710141ea3cf7..f7c193161d38e 100644 --- a/crates/bevy_pbr/src/wireframe.rs +++ b/crates/bevy_pbr/src/wireframe.rs @@ -1,6 +1,7 @@ use crate::{ DrawMesh, MeshPipeline, MeshPipelineKey, RenderMeshInstanceFlags, RenderMeshInstances, - SetMeshBindGroup, SetMeshViewBindGroup, ViewKeyCache, ViewSpecializationTicks, + SetMeshBindGroup, SetMeshViewBindGroup, SetMeshViewBindingArrayBindGroup, ViewKeyCache, + ViewSpecializationTicks, }; use bevy_app::{App, Plugin, PostUpdate, Startup, Update}; use bevy_asset::{ @@ -318,7 +319,8 @@ impl RenderCommand

for SetWireframe3dPushConstants { pub type DrawWireframe3d = ( SetItemPipeline, SetMeshViewBindGroup<0>, - SetMeshBindGroup<1>, + SetMeshViewBindingArrayBindGroup<1>, + SetMeshBindGroup<2>, SetWireframe3dPushConstants, DrawMesh, ); diff --git a/crates/bevy_reflect/Cargo.toml b/crates/bevy_reflect/Cargo.toml index 60f8478bacd30..ae3a3a856e9d9 100644 --- a/crates/bevy_reflect/Cargo.toml +++ b/crates/bevy_reflect/Cargo.toml @@ -109,7 +109,7 @@ uuid = { version = "1.13.1", default-features = false, optional = true, features "serde", ] } variadics_please = "1.1" -wgpu-types = { version = "24", features = [ +wgpu-types = { version = "25", features = [ "serde", ], optional = true, default-features = false } diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 9ecbbfc744d85..a657da4f0e641 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -85,19 +85,21 @@ bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-fea image = { version = "0.25.2", default-features = false } # misc -codespan-reporting = "0.11.0" +codespan-reporting = "0.12.0" # `fragile-send-sync-non-atomic-wasm` feature means we can't use Wasm threads for rendering # It is enabled for now to avoid having to do a significant overhaul of the renderer just for wasm. # When the 'atomics' feature is enabled `fragile-send-sync-non-atomic` does nothing # and Bevy instead wraps `wgpu` types to verify they are not used off their origin thread. -wgpu = { version = "24", default-features = false, features = [ +wgpu = { version = "25", default-features = false, features = [ "wgsl", "dx12", "metal", + "vulkan", + "gles", "naga-ir", "fragile-send-sync-non-atomic-wasm", ] } -naga = { version = "24", features = ["wgsl-in"] } +naga = { version = "25", features = ["wgsl-in"] } serde = { version = "1", features = ["derive"] } bytemuck = { version = "1.5", features = ["derive", "must_cast"] } downcast-rs = { version = "2", default-features = false, features = ["std"] } @@ -123,7 +125,7 @@ wesl = { version = "0.1.2", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # Omit the `glsl` feature in non-WebAssembly by default. -naga_oil = { version = "0.17.1", default-features = false, features = [ +naga_oil = { version = "0.18", default-features = false, features = [ "test_shader", ] } @@ -131,7 +133,7 @@ naga_oil = { version = "0.17.1", default-features = false, features = [ proptest = "1" [target.'cfg(target_arch = "wasm32")'.dependencies] -naga_oil = "0.17.1" +naga_oil = { version = "0.18" } js-sys = "0.3" web-sys = { version = "0.3.67", features = [ 'Blob', diff --git a/crates/bevy_render/macros/src/as_bind_group.rs b/crates/bevy_render/macros/src/as_bind_group.rs index 4252929170f19..7bac6796acbc8 100644 --- a/crates/bevy_render/macros/src/as_bind_group.rs +++ b/crates/bevy_render/macros/src/as_bind_group.rs @@ -204,7 +204,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { #bind_group_layout_entries.push( #render_path::render_resource::BindGroupLayoutEntry { binding: #binding_array_binding, - visibility: #render_path::render_resource::ShaderStages::all(), + visibility: #render_path::render_resource::ShaderStages::FRAGMENT | #render_path::render_resource::ShaderStages::VERTEX | #render_path::render_resource::ShaderStages::COMPUTE, ty: #render_path::render_resource::BindingType::Buffer { ty: #uniform_binding_type, has_dynamic_offset: false, @@ -253,7 +253,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { #bind_group_layout_entries.push( #render_path::render_resource::BindGroupLayoutEntry { binding: #binding_array_binding, - visibility: #render_path::render_resource::ShaderStages::all(), + visibility: #render_path::render_resource::ShaderStages::FRAGMENT | #render_path::render_resource::ShaderStages::VERTEX | #render_path::render_resource::ShaderStages::COMPUTE, ty: #render_path::render_resource::BindingType::Buffer { ty: #uniform_binding_type, has_dynamic_offset: false, @@ -279,7 +279,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { #bind_group_layout_entries.push( #render_path::render_resource::BindGroupLayoutEntry { binding: #binding_index, - visibility: #render_path::render_resource::ShaderStages::all(), + visibility: #render_path::render_resource::ShaderStages::FRAGMENT | #render_path::render_resource::ShaderStages::VERTEX | #render_path::render_resource::ShaderStages::COMPUTE, ty: #render_path::render_resource::BindingType::Buffer { ty: #uniform_binding_type, has_dynamic_offset: false, @@ -519,7 +519,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { #bind_group_layout_entries.push( #render_path::render_resource::BindGroupLayoutEntry { binding: #binding_array_binding, - visibility: #render_path::render_resource::ShaderStages::all(), + visibility: #render_path::render_resource::ShaderStages::FRAGMENT | #render_path::render_resource::ShaderStages::VERTEX | #render_path::render_resource::ShaderStages::COMPUTE, ty: #render_path::render_resource::BindingType::Buffer { ty: #render_path::render_resource::BufferBindingType::Storage { read_only: #read_only @@ -834,7 +834,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { #bind_group_layout_entries.push( #render_path::render_resource::BindGroupLayoutEntry { binding: #binding_index, - visibility: #render_path::render_resource::ShaderStages::all(), + visibility: #render_path::render_resource::ShaderStages::FRAGMENT | #render_path::render_resource::ShaderStages::VERTEX | #render_path::render_resource::ShaderStages::COMPUTE, ty: #render_path::render_resource::BindingType::Buffer { ty: #uniform_binding_type, has_dynamic_offset: false, @@ -881,7 +881,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result { non_bindless_binding_layouts.push(quote!{ #bind_group_layout_entries.push(#render_path::render_resource::BindGroupLayoutEntry { binding: #binding_index, - visibility: #render_path::render_resource::ShaderStages::all(), + visibility: #render_path::render_resource::ShaderStages::FRAGMENT | #render_path::render_resource::ShaderStages::VERTEX | #render_path::render_resource::ShaderStages::COMPUTE, ty: #render_path::render_resource::BindingType::Buffer { ty: #uniform_binding_type, has_dynamic_offset: false, @@ -1337,7 +1337,13 @@ impl VisibilityFlags { impl ShaderStageVisibility { fn hygienic_quote(&self, path: &proc_macro2::TokenStream) -> proc_macro2::TokenStream { match self { - ShaderStageVisibility::All => quote! { #path::ShaderStages::all() }, + ShaderStageVisibility::All => quote! { + if cfg!(feature = "webgpu") { + todo!("Please use a more specific shader stage: https://github.com/gfx-rs/wgpu/issues/7708") + } else { + #path::ShaderStages::all() + } + }, ShaderStageVisibility::None => quote! { #path::ShaderStages::NONE }, ShaderStageVisibility::Flags(flags) => { let mut quoted = Vec::new(); diff --git a/crates/bevy_render/src/bindless.wgsl b/crates/bevy_render/src/bindless.wgsl index 05517a1746d29..717e9c1047c60 100644 --- a/crates/bevy_render/src/bindless.wgsl +++ b/crates/bevy_render/src/bindless.wgsl @@ -16,22 +16,22 @@ // Binding 0 is the bindless index table. // Filtering samplers. -@group(2) @binding(1) var bindless_samplers_filtering: binding_array; +@group(3) @binding(1) var bindless_samplers_filtering: binding_array; // Non-filtering samplers (nearest neighbor). -@group(2) @binding(2) var bindless_samplers_non_filtering: binding_array; +@group(3) @binding(2) var bindless_samplers_non_filtering: binding_array; // Comparison samplers (typically for shadow mapping). -@group(2) @binding(3) var bindless_samplers_comparison: binding_array; +@group(3) @binding(3) var bindless_samplers_comparison: binding_array; // 1D textures. -@group(2) @binding(4) var bindless_textures_1d: binding_array>; +@group(3) @binding(4) var bindless_textures_1d: binding_array>; // 2D textures. -@group(2) @binding(5) var bindless_textures_2d: binding_array>; +@group(3) @binding(5) var bindless_textures_2d: binding_array>; // 2D array textures. -@group(2) @binding(6) var bindless_textures_2d_array: binding_array>; +@group(3) @binding(6) var bindless_textures_2d_array: binding_array>; // 3D textures. -@group(2) @binding(7) var bindless_textures_3d: binding_array>; +@group(3) @binding(7) var bindless_textures_3d: binding_array>; // Cubemap textures. -@group(2) @binding(8) var bindless_textures_cube: binding_array>; +@group(3) @binding(8) var bindless_textures_cube: binding_array>; // Cubemap array textures. -@group(2) @binding(9) var bindless_textures_cube_array: binding_array>; +@group(3) @binding(9) var bindless_textures_cube_array: binding_array>; #endif // BINDLESS diff --git a/crates/bevy_render/src/diagnostic/tracy_gpu.rs b/crates/bevy_render/src/diagnostic/tracy_gpu.rs index c059b8baa5d00..7a66db4ea6da4 100644 --- a/crates/bevy_render/src/diagnostic/tracy_gpu.rs +++ b/crates/bevy_render/src/diagnostic/tracy_gpu.rs @@ -1,7 +1,7 @@ use crate::renderer::{RenderAdapterInfo, RenderDevice, RenderQueue}; use tracy_client::{Client, GpuContext, GpuContextType}; use wgpu::{ - Backend, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Maintain, MapMode, + Backend, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, MapMode, PollType, QuerySetDescriptor, QueryType, QUERY_SIZE, }; @@ -14,7 +14,7 @@ pub fn new_tracy_gpu_context( Backend::Vulkan => GpuContextType::Vulkan, Backend::Dx12 => GpuContextType::Direct3D12, Backend::Gl => GpuContextType::OpenGL, - Backend::Metal | Backend::BrowserWebGpu | Backend::Empty => GpuContextType::Invalid, + Backend::Metal | Backend::BrowserWebGpu | Backend::Noop => GpuContextType::Invalid, }; let tracy_client = Client::running().unwrap(); @@ -60,7 +60,9 @@ fn initial_timestamp(device: &RenderDevice, queue: &RenderQueue) -> i64 { queue.submit([timestamp_encoder.finish(), copy_encoder.finish()]); map_buffer.slice(..).map_async(MapMode::Read, |_| ()); - device.poll(Maintain::Wait); + device + .poll(PollType::Wait) + .expect("Failed to poll device for map async"); let view = map_buffer.slice(..).get_mapped_range(); i64::from_le_bytes((*view).try_into().unwrap()) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index a20315c0997bb..aa1e2da676082 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -352,10 +352,12 @@ impl Plugin for RenderPlugin { backend_options: wgpu::BackendOptions { gl: wgpu::GlBackendOptions { gles_minor_version: settings.gles3_minor_version, + fence_behavior: wgpu::GlFenceBehavior::Normal, }, dx12: wgpu::Dx12BackendOptions { shader_compiler: settings.dx12_shader_compiler.clone(), }, + noop: wgpu::NoopBackendOptions { enable: false }, }, }); diff --git a/crates/bevy_render/src/render_phase/draw.rs b/crates/bevy_render/src/render_phase/draw.rs index 42a6725c8c253..39c6a074e6f57 100644 --- a/crates/bevy_render/src/render_phase/draw.rs +++ b/crates/bevy_render/src/render_phase/draw.rs @@ -168,14 +168,16 @@ impl DrawFunctions

{ /// ``` /// # use bevy_render::render_phase::SetItemPipeline; /// # struct SetMeshViewBindGroup; +/// # struct SetMeshViewBindingArrayBindGroup; /// # struct SetMeshBindGroup; /// # struct SetMaterialBindGroup(std::marker::PhantomData); /// # struct DrawMesh; /// pub type DrawMaterial = ( /// SetItemPipeline, /// SetMeshViewBindGroup<0>, -/// SetMeshBindGroup<1>, -/// SetMaterialBindGroup, +/// SetMeshViewBindingArrayBindGroup<1>, +/// SetMeshBindGroup<2>, +/// SetMaterialBindGroup, /// DrawMesh, /// ); /// ``` diff --git a/crates/bevy_render/src/render_resource/bind_group.rs b/crates/bevy_render/src/render_resource/bind_group.rs index cff88bd355a62..17de8455dac5d 100644 --- a/crates/bevy_render/src/render_resource/bind_group.rs +++ b/crates/bevy_render/src/render_resource/bind_group.rs @@ -133,12 +133,12 @@ impl Deref for BindGroup { /// In WGSL shaders, the binding would look like this: /// /// ```wgsl -/// @group(2) @binding(0) var color: vec4; -/// @group(2) @binding(1) var color_texture: texture_2d; -/// @group(2) @binding(2) var color_sampler: sampler; -/// @group(2) @binding(3) var storage_buffer: array; -/// @group(2) @binding(4) var raw_buffer: array; -/// @group(2) @binding(5) var storage_texture: texture_storage_2d; +/// @group(3) @binding(0) var color: vec4; +/// @group(3) @binding(1) var color_texture: texture_2d; +/// @group(3) @binding(2) var color_sampler: sampler; +/// @group(3) @binding(3) var storage_buffer: array; +/// @group(3) @binding(4) var raw_buffer: array; +/// @group(3) @binding(5) var storage_texture: texture_storage_2d; /// ``` /// Note that the "group" index is determined by the usage context. It is not defined in [`AsBindGroup`]. For example, in Bevy material bind groups /// are generally bound to group 2. @@ -261,7 +261,7 @@ impl Deref for BindGroup { /// roughness: f32, /// }; /// -/// @group(2) @binding(0) var material: CoolMaterial; +/// @group(3) @binding(0) var material: CoolMaterial; /// ``` /// /// Some less common scenarios will require "struct-level" attributes. These are the currently supported struct-level attributes: @@ -312,7 +312,7 @@ impl Deref for BindGroup { /// declaration: /// /// ```wgsl -/// @group(2) @binding(10) var material_array: binding_array; +/// @group(3) @binding(10) var material_array: binding_array; /// ``` /// /// On the other hand, if you write this declaration: @@ -325,7 +325,7 @@ impl Deref for BindGroup { /// Then Bevy produces a binding that matches this WGSL declaration instead: /// /// ```wgsl -/// @group(2) @binding(10) var material_array: array; +/// @group(3) @binding(10) var material_array: array; /// ``` /// /// * Just as with the structure-level `uniform` attribute, Bevy converts the @@ -338,7 +338,7 @@ impl Deref for BindGroup { /// this in WGSL in non-bindless mode: /// /// ```wgsl -/// @group(2) @binding(0) var material: StandardMaterial; +/// @group(3) @binding(0) var material: StandardMaterial; /// ``` /// /// * For efficiency reasons, `data` is generally preferred over `uniform` diff --git a/crates/bevy_render/src/render_resource/bind_group_entries.rs b/crates/bevy_render/src/render_resource/bind_group_entries.rs index cc8eb188de461..847bb46f498af 100644 --- a/crates/bevy_render/src/render_resource/bind_group_entries.rs +++ b/crates/bevy_render/src/render_resource/bind_group_entries.rs @@ -287,6 +287,12 @@ impl<'b> DynamicBindGroupEntries<'b> { } } + pub fn new() -> Self { + Self { + entries: Vec::new(), + } + } + pub fn extend_with_indices( mut self, entries: impl IntoIndexedBindingArray<'b, N>, diff --git a/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs b/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs index 41affa434959a..17630b7dae2d7 100644 --- a/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs +++ b/crates/bevy_render/src/render_resource/bind_group_layout_entries.rs @@ -334,6 +334,13 @@ impl DynamicBindGroupLayoutEntries { } } + pub fn new(default_visibility: ShaderStages) -> Self { + Self { + default_visibility, + entries: Vec::new(), + } + } + pub fn extend_with_indices( mut self, entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray, @@ -570,6 +577,16 @@ pub mod binding_types { } pub fn acceleration_structure() -> BindGroupLayoutEntryBuilder { - BindingType::AccelerationStructure.into_bind_group_layout_entry_builder() + BindingType::AccelerationStructure { + vertex_return: false, + } + .into_bind_group_layout_entry_builder() + } + + pub fn acceleration_structure_vertex_return() -> BindGroupLayoutEntryBuilder { + BindingType::AccelerationStructure { + vertex_return: true, + } + .into_bind_group_layout_entry_builder() } } diff --git a/crates/bevy_render/src/render_resource/bindless.rs b/crates/bevy_render/src/render_resource/bindless.rs index 64a0fa2c1fe84..dc3bf00eee95c 100644 --- a/crates/bevy_render/src/render_resource/bindless.rs +++ b/crates/bevy_render/src/render_resource/bindless.rs @@ -243,35 +243,65 @@ pub fn create_bindless_bind_group_layout_entries( false, NonZeroU64::new(bindless_index_table_length as u64 * size_of::() as u64), ) - .build(*bindless_index_table_binding_number, ShaderStages::all()), + .build( + *bindless_index_table_binding_number, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), // Continue with the common bindless resource arrays. sampler(SamplerBindingType::Filtering) .count(bindless_slab_resource_limit) - .build(1, ShaderStages::all()), + .build( + 1, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), sampler(SamplerBindingType::NonFiltering) .count(bindless_slab_resource_limit) - .build(2, ShaderStages::all()), + .build( + 2, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), sampler(SamplerBindingType::Comparison) .count(bindless_slab_resource_limit) - .build(3, ShaderStages::all()), + .build( + 3, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), texture_1d(TextureSampleType::Float { filterable: true }) .count(bindless_slab_resource_limit) - .build(4, ShaderStages::all()), + .build( + 4, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), texture_2d(TextureSampleType::Float { filterable: true }) .count(bindless_slab_resource_limit) - .build(5, ShaderStages::all()), + .build( + 5, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), texture_2d_array(TextureSampleType::Float { filterable: true }) .count(bindless_slab_resource_limit) - .build(6, ShaderStages::all()), + .build( + 6, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), texture_3d(TextureSampleType::Float { filterable: true }) .count(bindless_slab_resource_limit) - .build(7, ShaderStages::all()), + .build( + 7, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), texture_cube(TextureSampleType::Float { filterable: true }) .count(bindless_slab_resource_limit) - .build(8, ShaderStages::all()), + .build( + 8, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), texture_cube_array(TextureSampleType::Float { filterable: true }) .count(bindless_slab_resource_limit) - .build(9, ShaderStages::all()), + .build( + 9, + ShaderStages::FRAGMENT | ShaderStages::VERTEX | ShaderStages::COMPUTE, + ), ] } diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index aecf27173d9bb..09be66e840b11 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -49,18 +49,18 @@ pub use wgpu::{ ComputePassDescriptor, ComputePipelineDescriptor as RawComputePipelineDescriptor, CreateBlasDescriptor, CreateTlasDescriptor, DepthBiasState, DepthStencilState, DownlevelFlags, Extent3d, Face, Features as WgpuFeatures, FilterMode, FragmentState as RawFragmentState, - FrontFace, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, Maintain, MapMode, + FrontFace, ImageSubresourceRange, IndexFormat, Limits as WgpuLimits, LoadOp, MapMode, MultisampleState, Operations, Origin3d, PipelineCompilationOptions, PipelineLayout, - PipelineLayoutDescriptor, PolygonMode, PrimitiveState, PrimitiveTopology, PushConstantRange, - RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, - RenderPipelineDescriptor as RawRenderPipelineDescriptor, Sampler as WgpuSampler, - SamplerBindingType, SamplerBindingType as WgpuSamplerBindingType, SamplerDescriptor, - ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, StencilFaceState, - StencilOperation, StencilState, StorageTextureAccess, StoreOp, TexelCopyBufferInfo, - TexelCopyBufferLayout, TexelCopyTextureInfo, TextureAspect, TextureDescriptor, - TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, - TextureSampleType, TextureUsages, TextureView as WgpuTextureView, TextureViewDescriptor, - TextureViewDimension, Tlas, TlasInstance, TlasPackage, VertexAttribute, + PipelineLayoutDescriptor, PollType, PolygonMode, PrimitiveState, PrimitiveTopology, + PushConstantRange, RenderPassColorAttachment, RenderPassDepthStencilAttachment, + RenderPassDescriptor, RenderPipelineDescriptor as RawRenderPipelineDescriptor, + Sampler as WgpuSampler, SamplerBindingType, SamplerBindingType as WgpuSamplerBindingType, + SamplerDescriptor, ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, + StencilFaceState, StencilOperation, StencilState, StorageTextureAccess, StoreOp, + TexelCopyBufferInfo, TexelCopyBufferLayout, TexelCopyTextureInfo, TextureAspect, + TextureDescriptor, TextureDimension, TextureFormat, TextureFormatFeatureFlags, + TextureFormatFeatures, TextureSampleType, TextureUsages, TextureView as WgpuTextureView, + TextureViewDescriptor, TextureViewDimension, Tlas, TlasInstance, TlasPackage, VertexAttribute, VertexBufferLayout as RawVertexBufferLayout, VertexFormat, VertexState as RawVertexState, VertexStepMode, COPY_BUFFER_ALIGNMENT, }; diff --git a/crates/bevy_render/src/render_resource/pipeline_cache.rs b/crates/bevy_render/src/render_resource/pipeline_cache.rs index 9d658cf361abd..ebd3229636ad5 100644 --- a/crates/bevy_render/src/render_resource/pipeline_cache.rs +++ b/crates/bevy_render/src/render_resource/pipeline_cache.rs @@ -873,7 +873,7 @@ impl PipelineCache { // TODO: Expose the rest of this somehow let compilation_options = PipelineCompilationOptions { - constants: &default(), + constants: &[], zero_initialize_workgroup_memory: descriptor.zero_initialize_workgroup_memory, }; @@ -955,7 +955,7 @@ impl PipelineCache { entry_point: Some(&descriptor.entry_point), // TODO: Expose the rest of this somehow compilation_options: PipelineCompilationOptions { - constants: &default(), + constants: &[], zero_initialize_workgroup_memory: descriptor .zero_initialize_workgroup_memory, }, @@ -1155,8 +1155,12 @@ fn get_capabilities(features: Features, downlevel: DownlevelFlags) -> Capabiliti features.contains(Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING), ); capabilities.set( - Capabilities::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, - features.contains(Features::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING), + Capabilities::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, + features.contains(Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING), + ); + capabilities.set( + Capabilities::UNIFORM_BUFFER_ARRAY_NON_UNIFORM_INDEXING, + features.contains(Features::UNIFORM_BUFFER_BINDING_ARRAYS), ); // TODO: This needs a proper wgpu feature capabilities.set( @@ -1229,6 +1233,14 @@ fn get_capabilities(features: Features, downlevel: DownlevelFlags) -> Capabiliti Capabilities::TEXTURE_INT64_ATOMIC, features.contains(Features::TEXTURE_INT64_ATOMIC), ); + capabilities.set( + Capabilities::SHADER_FLOAT16, + features.contains(Features::SHADER_F16), + ); + capabilities.set( + Capabilities::RAY_HIT_VERTEX_POSITION, + features.intersects(Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN), + ); capabilities } diff --git a/crates/bevy_render/src/render_resource/shader.rs b/crates/bevy_render/src/render_resource/shader.rs index ff8430b951f63..1be9fd7427568 100644 --- a/crates/bevy_render/src/render_resource/shader.rs +++ b/crates/bevy_render/src/render_resource/shader.rs @@ -301,6 +301,8 @@ impl From<&Source> for naga_oil::compose::ShaderType { naga::ShaderStage::Vertex => naga_oil::compose::ShaderType::GlslVertex, naga::ShaderStage::Fragment => naga_oil::compose::ShaderType::GlslFragment, naga::ShaderStage::Compute => panic!("glsl compute not yet implemented"), + naga::ShaderStage::Task => panic!("task shaders not yet implemented"), + naga::ShaderStage::Mesh => panic!("mesh shaders not yet implemented"), }, #[cfg(all(not(feature = "shader_format_glsl"), not(target_arch = "wasm32")))] Source::Glsl(_, _) => panic!( diff --git a/crates/bevy_render/src/renderer/mod.rs b/crates/bevy_render/src/renderer/mod.rs index bec30200a8a0a..5df4967757749 100644 --- a/crates/bevy_render/src/renderer/mod.rs +++ b/crates/bevy_render/src/renderer/mod.rs @@ -23,7 +23,7 @@ use bevy_platform::time::Instant; use bevy_time::TimeSender; use wgpu::{ Adapter, AdapterInfo, CommandBuffer, CommandEncoder, DeviceType, Instance, Queue, - RequestAdapterOptions, + RequestAdapterOptions, Trace, }; /// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame. @@ -177,7 +177,7 @@ pub async fn initialize_renderer( // discrete GPUs due to having to transfer data across the PCI-E bus and so it // should not be automatically enabled in this case. It is however beneficial for // integrated GPUs. - features -= wgpu::Features::MAPPABLE_PRIMARY_BUFFERS; + features.remove(wgpu::Features::MAPPABLE_PRIMARY_BUFFERS); } limits = adapter.limits(); @@ -185,7 +185,7 @@ pub async fn initialize_renderer( // Enforce the disabled features if let Some(disabled_features) = options.disabled_features { - features -= disabled_features; + features.remove(disabled_features); } // NOTE: |= is used here to ensure that any explicitly-enabled features are respected. features |= options.features; @@ -234,6 +234,12 @@ pub async fn initialize_renderer( max_uniform_buffers_per_shader_stage: limits .max_uniform_buffers_per_shader_stage .min(constrained_limits.max_uniform_buffers_per_shader_stage), + max_binding_array_elements_per_shader_stage: limits + .max_binding_array_elements_per_shader_stage + .min(constrained_limits.max_binding_array_elements_per_shader_stage), + max_binding_array_sampler_elements_per_shader_stage: limits + .max_binding_array_sampler_elements_per_shader_stage + .min(constrained_limits.max_binding_array_sampler_elements_per_shader_stage), max_uniform_buffer_binding_size: limits .max_uniform_buffer_binding_size .min(constrained_limits.max_uniform_buffer_binding_size), @@ -304,15 +310,14 @@ pub async fn initialize_renderer( } let (device, queue) = adapter - .request_device( - &wgpu::DeviceDescriptor { - label: options.device_label.as_ref().map(AsRef::as_ref), - required_features: features, - required_limits: limits, - memory_hints: options.memory_hints.clone(), - }, - options.trace_path.as_deref(), - ) + .request_device(&wgpu::DeviceDescriptor { + label: options.device_label.as_ref().map(AsRef::as_ref), + required_features: features, + required_limits: limits, + memory_hints: options.memory_hints.clone(), + // See https://github.com/gfx-rs/wgpu/issues/5974 + trace: Trace::Off, + }) .await .unwrap(); let queue = Arc::new(WgpuWrapper::new(queue)); diff --git a/crates/bevy_render/src/renderer/render_device.rs b/crates/bevy_render/src/renderer/render_device.rs index 31f47e57404c1..b1a20d2acedce 100644 --- a/crates/bevy_render/src/renderer/render_device.rs +++ b/crates/bevy_render/src/renderer/render_device.rs @@ -7,7 +7,7 @@ use bevy_ecs::resource::Resource; use bevy_utils::WgpuWrapper; use wgpu::{ util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, - BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, MaintainResult, + BindGroupLayoutEntry, BufferAsyncError, BufferBindingType, PollError, PollStatus, }; /// This GPU device is responsible for the creation of most rendering and compute resources. @@ -67,11 +67,14 @@ impl RenderDevice { // This call passes binary data to the backend as-is and can potentially result in a driver crash or bogus behavior. // No attempt is made to ensure that data is valid SPIR-V. unsafe { - self.device - .create_shader_module_spirv(&wgpu::ShaderModuleDescriptorSpirV { - label: desc.label, - source: source.clone(), - }) + self.device.create_shader_module_passthrough( + wgpu::ShaderModuleDescriptorPassthrough::SpirV( + wgpu::ShaderModuleDescriptorSpirV { + label: desc.label, + source: source.clone(), + }, + ), + ) } } // SAFETY: @@ -118,7 +121,7 @@ impl RenderDevice { /// /// no-op on the web, device is automatically polled. #[inline] - pub fn poll(&self, maintain: wgpu::Maintain) -> MaintainResult { + pub fn poll(&self, maintain: wgpu::PollType) -> Result { self.device.poll(maintain) } diff --git a/crates/bevy_render/src/settings.rs b/crates/bevy_render/src/settings.rs index ab50fc81b1a49..715bbb35f845b 100644 --- a/crates/bevy_render/src/settings.rs +++ b/crates/bevy_render/src/settings.rs @@ -2,8 +2,8 @@ use crate::renderer::{ RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue, }; use alloc::borrow::Cow; -use std::path::PathBuf; +use wgpu::DxcShaderModel; pub use wgpu::{ Backends, Dx12Compiler, Features as WgpuFeatures, Gles3MinorVersion, InstanceFlags, Limits as WgpuLimits, MemoryHints, PowerPreference, @@ -53,8 +53,6 @@ pub struct WgpuSettings { pub instance_flags: InstanceFlags, /// This hints to the WGPU device about the preferred memory allocation strategy. pub memory_hints: MemoryHints, - /// The path to pass to wgpu for API call tracing. This only has an effect if wgpu's tracing functionality is enabled. - pub trace_path: Option, } impl Default for WgpuSettings { @@ -114,6 +112,7 @@ impl Default for WgpuSettings { Dx12Compiler::DynamicDxc { dxc_path: String::from(dxc), dxil_path: String::from(dxil), + max_shader_model: DxcShaderModel::V6_7, } } else { Dx12Compiler::Fxc @@ -137,7 +136,6 @@ impl Default for WgpuSettings { gles3_minor_version, instance_flags, memory_hints: MemoryHints::default(), - trace_path: None, } } } diff --git a/crates/bevy_solari/src/lib.rs b/crates/bevy_solari/src/lib.rs index 416c850b04f41..d5a22e014b8c5 100644 --- a/crates/bevy_solari/src/lib.rs +++ b/crates/bevy_solari/src/lib.rs @@ -46,7 +46,6 @@ impl SolariPlugin { | WgpuFeatures::EXPERIMENTAL_RAY_QUERY | WgpuFeatures::BUFFER_BINDING_ARRAY | WgpuFeatures::TEXTURE_BINDING_ARRAY - | WgpuFeatures::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING | WgpuFeatures::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING | WgpuFeatures::PARTIALLY_BOUND_BINDING_ARRAY } diff --git a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl index aad064590f263..974ee50d7dc54 100644 --- a/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl +++ b/crates/bevy_solari/src/scene/raytracing_scene_bindings.wgsl @@ -71,8 +71,8 @@ struct DirectionalLight { @group(0) @binding(9) var light_sources: array; @group(0) @binding(10) var directional_lights: array; -const RAY_T_MIN = 0.01; -const RAY_T_MAX = 100000.0; +const RAY_T_MIN = 0.01f; +const RAY_T_MAX = 100000.0f; const RAY_NO_CULL = 0xFFu; @@ -120,7 +120,7 @@ fn resolve_material(material: Material, uv: vec2) -> ResolvedMaterial { fn resolve_ray_hit_full(ray_hit: RayIntersection) -> ResolvedRayHitFull { let barycentrics = vec3(1.0 - ray_hit.barycentrics.x - ray_hit.barycentrics.y, ray_hit.barycentrics); - return resolve_triangle_data_full(ray_hit.instance_id, ray_hit.primitive_index, barycentrics); + return resolve_triangle_data_full(ray_hit.instance_index, ray_hit.primitive_index, barycentrics); } fn resolve_triangle_data_full(instance_id: u32, triangle_id: u32, barycentrics: vec3) -> ResolvedRayHitFull { diff --git a/crates/bevy_winit/Cargo.toml b/crates/bevy_winit/Cargo.toml index bb28b84fb041c..43dcc0506b8aa 100644 --- a/crates/bevy_winit/Cargo.toml +++ b/crates/bevy_winit/Cargo.toml @@ -59,7 +59,7 @@ cfg-if = "1.0" raw-window-handle = "0.6" serde = { version = "1.0", features = ["derive"], optional = true } bytemuck = { version = "1.5", optional = true } -wgpu-types = { version = "24", optional = true } +wgpu-types = { version = "25", optional = true } accesskit = "0.19" tracing = { version = "0.1", default-features = false, features = ["std"] } diff --git a/examples/app/headless_renderer.rs b/examples/app/headless_renderer.rs index 2038c85a29ab7..5d027b2115580 100644 --- a/examples/app/headless_renderer.rs +++ b/examples/app/headless_renderer.rs @@ -22,8 +22,8 @@ use bevy::{ render_asset::{RenderAssetUsages, RenderAssets}, render_graph::{self, NodeRunError, RenderGraph, RenderGraphContext, RenderLabel}, render_resource::{ - Buffer, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, Maintain, - MapMode, TexelCopyBufferInfo, TexelCopyBufferLayout, TextureDimension, TextureFormat, + Buffer, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, MapMode, + PollType, TexelCopyBufferInfo, TexelCopyBufferLayout, TextureDimension, TextureFormat, TextureUsages, }, renderer::{RenderContext, RenderDevice, RenderQueue}, @@ -41,7 +41,6 @@ use std::{ }, time::Duration, }; - // To communicate between the main world and the render world we need a channel. // Since the main world and render world run in parallel, there will always be a frame of latency // between the data sent from the render world and the data received in the main world @@ -460,7 +459,9 @@ fn receive_image_from_buffer( // `Maintain::Wait` will cause the thread to wait on native but not on WebGpu. // This blocks until the gpu is done executing everything - render_device.poll(Maintain::wait()).panic_on_timeout(); + render_device + .poll(PollType::Wait) + .expect("Failed to poll device for map async"); // This blocks until the buffer is mapped r.recv().expect("Failed to receive the map_async message"); diff --git a/examples/shader/custom_render_phase.rs b/examples/shader/custom_render_phase.rs index 0f834e893a537..309954bbe39a1 100644 --- a/examples/shader/custom_render_phase.rs +++ b/examples/shader/custom_render_phase.rs @@ -12,6 +12,7 @@ use std::ops::Range; +use bevy::pbr::SetMeshViewEmptyBindGroup; use bevy::{ core_pipeline::core_3d::graph::{Core3d, Node3d}, ecs::{ @@ -193,17 +194,19 @@ impl SpecializedMeshPipeline for StencilPipeline { } // This will automatically generate the correct `VertexBufferLayout` based on the vertex attributes let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?; - + let view_layout = self + .mesh_pipeline + .get_view_layout(MeshPipelineViewLayoutKey::from(key)); Ok(RenderPipelineDescriptor { label: Some("Specialized Mesh Pipeline".into()), // We want to reuse the data from bevy so we use the same bind groups as the default // mesh pipeline layout: vec![ // Bind group 0 is the view uniform - self.mesh_pipeline - .get_view_layout(MeshPipelineViewLayoutKey::from(key)) - .clone(), - // Bind group 1 is the mesh uniform + view_layout.main_layout.clone(), + // Bind group 1 is empty + view_layout.empty_layout.clone(), + // Bind group 2 is the mesh uniform self.mesh_pipeline.mesh_layouts.model_only.clone(), ], push_constant_ranges: vec![], @@ -244,8 +247,10 @@ type DrawMesh3dStencil = ( SetItemPipeline, // This will set the view bindings in group 0 SetMeshViewBindGroup<0>, - // This will set the mesh bindings in group 1 - SetMeshBindGroup<1>, + // This will set an empty bind group in group 1 + SetMeshViewEmptyBindGroup<1>, + // This will set the mesh bindings in group 2 + SetMeshBindGroup<2>, // This will draw the mesh DrawMesh, ); diff --git a/examples/shader/custom_shader_instancing.rs b/examples/shader/custom_shader_instancing.rs index 06845b0617633..358a2beac7039 100644 --- a/examples/shader/custom_shader_instancing.rs +++ b/examples/shader/custom_shader_instancing.rs @@ -7,6 +7,7 @@ //! implementation using bevy's low level rendering api. //! It's generally recommended to try the built-in instancing before going with this approach. +use bevy::pbr::SetMeshViewBindingArrayBindGroup; use bevy::{ core_pipeline::core_3d::Transparent3d, ecs::{ @@ -248,7 +249,8 @@ impl SpecializedMeshPipeline for CustomPipeline { type DrawCustom = ( SetItemPipeline, SetMeshViewBindGroup<0>, - SetMeshBindGroup<1>, + SetMeshViewBindingArrayBindGroup<1>, + SetMeshBindGroup<2>, DrawMeshInstanced, ); diff --git a/examples/shader/specialized_mesh_pipeline.rs b/examples/shader/specialized_mesh_pipeline.rs index 9a7a3fce96cc1..eeeeeb4a1e37b 100644 --- a/examples/shader/specialized_mesh_pipeline.rs +++ b/examples/shader/specialized_mesh_pipeline.rs @@ -12,7 +12,7 @@ use bevy::{ math::{vec3, vec4}, pbr::{ DrawMesh, MeshPipeline, MeshPipelineKey, MeshPipelineViewLayoutKey, RenderMeshInstances, - SetMeshBindGroup, SetMeshViewBindGroup, + SetMeshBindGroup, SetMeshViewBindGroup, SetMeshViewEmptyBindGroup, }, prelude::*, render::{ @@ -153,8 +153,10 @@ type DrawSpecializedPipelineCommands = ( SetItemPipeline, // Set the view uniform at bind group 0 SetMeshViewBindGroup<0>, - // Set the mesh uniform at bind group 1 - SetMeshBindGroup<1>, + // Set an empty material bind group at bind group 1 + SetMeshViewEmptyBindGroup<1>, + // Set the mesh uniform at bind group 2 + SetMeshBindGroup<2>, // Draw the mesh DrawMesh, ); @@ -210,14 +212,15 @@ impl SpecializedMeshPipeline for CustomMeshPipeline { // This will automatically generate the correct `VertexBufferLayout` based on the vertex attributes let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?; + let view_layout = self + .mesh_pipeline + .get_view_layout(MeshPipelineViewLayoutKey::from(mesh_key)); + Ok(RenderPipelineDescriptor { label: Some("Specialized Mesh Pipeline".into()), layout: vec![ - // Bind group 0 is the view uniform - self.mesh_pipeline - .get_view_layout(MeshPipelineViewLayoutKey::from(mesh_key)) - .clone(), - // Bind group 1 is the mesh uniform + view_layout.main_layout.clone(), + view_layout.empty_layout.clone(), self.mesh_pipeline.mesh_layouts.model_only.clone(), ], push_constant_ranges: vec![], diff --git a/examples/shader/texture_binding_array.rs b/examples/shader/texture_binding_array.rs index bf5dc3da9debe..e4939edf6ae86 100644 --- a/examples/shader/texture_binding_array.rs +++ b/examples/shader/texture_binding_array.rs @@ -163,7 +163,7 @@ impl AsBindGroup for BindlessMaterial { ( // Screen texture // - // @group(2) @binding(0) var textures: binding_array>; + // @group(3) @binding(0) var textures: binding_array>; ( 0, texture_2d(TextureSampleType::Float { filterable: true }) @@ -171,7 +171,7 @@ impl AsBindGroup for BindlessMaterial { ), // Sampler // - // @group(2) @binding(1) var nearest_sampler: sampler; + // @group(3) @binding(1) var nearest_sampler: sampler; // // Note: as with textures, multiple samplers can also be bound // onto one binding slot: diff --git a/release-content/migration-guides/wgpu_25.md b/release-content/migration-guides/wgpu_25.md new file mode 100644 index 0000000000000..dfbead7e286ca --- /dev/null +++ b/release-content/migration-guides/wgpu_25.md @@ -0,0 +1,22 @@ +--- +title: `wgpu` 25 +pull_requests: [ 19563 ] +--- + +`wgpu` 25 introduces a number of breaking changes, most notably in the way Bevy is required to handle +uniforms with dynamic offsets which are used pervasively in the renderer. Dynamic offsets and uniforms +of any kind are no longer allowed to be used in the same bind group as binding arrays. As such, the +following changes to the default bind group numbering have been made in 3d: + +- `@group(0)` view binding resources +- `@group(1)` view resources requiring binding arrays +- `@group(2)` mesh binding resources +- `@group(3)` material binding resources + +Most users who are not using mid-level render APIs will simply need to switch their material bind groups +from `@group(2)` to `@group(3)`. + +Exported float constants from shaders without an explicit type declaration like `const FOO = 1.0;` are no +longer supported and must be explicitly typed like `const FOO: f32 = 1.0;`. + +See the full changelog [here](https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#v2500-2025-04-10).