Skip to content

Commit

Permalink
Swap material and mesh bind groups (#10485)
Browse files Browse the repository at this point in the history
# Objective
- Materials should be a more frequent rebind then meshes (due to being
able to use a single vertex buffer, such as in #10164) and therefore
should be in a higher bind group.

---

## Changelog
- For 2d and 3d mesh/material setups (but not UI materials, or other
rendering setups such as gizmos, sprites, or text), mesh data is now in
bind group 1, and material data is now in bind group 2, which is swapped
from how they were before.

## Migration Guide
- Custom 2d and 3d mesh/material shaders should now use bind group 2
`@group(2) @binding(x)` for their bound resources, instead of bind group
1.
- Many internal pieces of rendering code have changed so that mesh data
is now in bind group 1, and material data is now in bind group 2.
Semi-custom rendering setups (that don't use the Material or Material2d
APIs) should adapt to these changes.
  • Loading branch information
JMS55 committed Nov 28, 2023
1 parent a902ea6 commit 4bf20e7
Show file tree
Hide file tree
Showing 30 changed files with 88 additions and 141 deletions.
4 changes: 2 additions & 2 deletions assets/shaders/array_texture.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
}
#import bevy_core_pipeline::tonemapping::tone_mapping

@group(1) @binding(0) var my_array_texture: texture_2d_array<f32>;
@group(1) @binding(1) var my_array_texture_sampler: sampler;
@group(2) @binding(0) var my_array_texture: texture_2d_array<f32>;
@group(2) @binding(1) var my_array_texture_sampler: sampler;

@fragment
fn fragment(
Expand Down
3 changes: 1 addition & 2 deletions assets/shaders/circle_shader.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ var<uniform> input: CustomUiMaterial;
fn fragment(in: UiVertexOutput) -> @location(0) vec4<f32> {
// the UVs are now adjusted around the middle of the rect.
let uv = in.uv * 2.0 - 1.0;

// circle alpha, the higher the power the harsher the falloff.
let alpha = 1.0 - pow(sqrt(dot(uv, uv)), 100.0);

return vec4<f32>(input.color.rgb, alpha);
}

6 changes: 3 additions & 3 deletions assets/shaders/cubemap_unlit.wgsl
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#import bevy_pbr::forward_io::VertexOutput

#ifdef CUBEMAP_ARRAY
@group(1) @binding(0) var base_color_texture: texture_cube_array<f32>;
@group(2) @binding(0) var base_color_texture: texture_cube_array<f32>;
#else
@group(1) @binding(0) var base_color_texture: texture_cube<f32>;
@group(2) @binding(0) var base_color_texture: texture_cube<f32>;
#endif

@group(1) @binding(1) var base_color_sampler: sampler;
@group(2) @binding(1) var base_color_sampler: sampler;

@fragment
fn fragment(
Expand Down
6 changes: 3 additions & 3 deletions assets/shaders/custom_material.frag
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ layout(location = 0) in vec2 v_Uv;

layout(location = 0) out vec4 o_Target;

layout(set = 1, binding = 0) uniform vec4 CustomMaterial_color;
layout(set = 2, binding = 0) uniform vec4 CustomMaterial_color;

layout(set = 1, binding = 1) uniform texture2D CustomMaterial_texture;
layout(set = 1, binding = 2) uniform sampler CustomMaterial_sampler;
layout(set = 2, binding = 1) uniform texture2D CustomMaterial_texture;
layout(set = 2, binding = 2) uniform sampler CustomMaterial_sampler;

// wgsl modules can be imported and used in glsl
// FIXME - this doesn't work any more ...
Expand Down
4 changes: 2 additions & 2 deletions assets/shaders/custom_material.vert
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ struct Mesh {
};

#ifdef PER_OBJECT_BUFFER_BATCH_SIZE
layout(set = 2, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}];
layout(set = 1, binding = 0) uniform Mesh Meshes[#{PER_OBJECT_BUFFER_BATCH_SIZE}];
#else
layout(set = 2, binding = 0) readonly buffer _Meshes {
layout(set = 1, binding = 0) readonly buffer _Meshes {
Mesh Meshes[];
};
#endif // PER_OBJECT_BUFFER_BATCH_SIZE
Expand Down
6 changes: 3 additions & 3 deletions assets/shaders/custom_material.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -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(1) @binding(0) var<uniform> material_color: vec4<f32>;
@group(1) @binding(1) var material_color_texture: texture_2d<f32>;
@group(1) @binding(2) var material_color_sampler: sampler;
@group(2) @binding(0) var<uniform> material_color: vec4<f32>;
@group(2) @binding(1) var material_color_texture: texture_2d<f32>;
@group(2) @binding(2) var material_color_sampler: sampler;

@fragment
fn fragment(
Expand Down
4 changes: 2 additions & 2 deletions assets/shaders/custom_material_screenspace_texture.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
utils::coords_to_viewport_uv,
}

@group(1) @binding(0) var texture: texture_2d<f32>;
@group(1) @binding(1) var texture_sampler: sampler;
@group(2) @binding(0) var texture: texture_2d<f32>;
@group(2) @binding(1) var texture_sampler: sampler;

@fragment
fn fragment(
Expand Down
2 changes: 1 addition & 1 deletion assets/shaders/custom_vertex_attribute.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
struct CustomMaterial {
color: vec4<f32>,
};
@group(1) @binding(0) var<uniform> material: CustomMaterial;
@group(2) @binding(0) var<uniform> material: CustomMaterial;

struct Vertex {
@builtin(instance_index) instance_index: u32,
Expand Down
2 changes: 1 addition & 1 deletion assets/shaders/extended_material.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct MyExtendedMaterial {
quantize_steps: u32,
}

@group(1) @binding(100)
@group(2) @binding(100)
var<uniform> my_extended_material: MyExtendedMaterial;

@fragment
Expand Down
24 changes: 12 additions & 12 deletions assets/shaders/fallback_image_test.wgsl
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
#import bevy_pbr::forward_io::VertexOutput

@group(1) @binding(0) var test_texture_1d: texture_1d<f32>;
@group(1) @binding(1) var test_texture_1d_sampler: sampler;
@group(2) @binding(0) var test_texture_1d: texture_1d<f32>;
@group(2) @binding(1) var test_texture_1d_sampler: sampler;

@group(1) @binding(2) var test_texture_2d: texture_2d<f32>;
@group(1) @binding(3) var test_texture_2d_sampler: sampler;
@group(2) @binding(2) var test_texture_2d: texture_2d<f32>;
@group(2) @binding(3) var test_texture_2d_sampler: sampler;

@group(1) @binding(4) var test_texture_2d_array: texture_2d_array<f32>;
@group(1) @binding(5) var test_texture_2d_array_sampler: sampler;
@group(2) @binding(4) var test_texture_2d_array: texture_2d_array<f32>;
@group(2) @binding(5) var test_texture_2d_array_sampler: sampler;

@group(1) @binding(6) var test_texture_cube: texture_cube<f32>;
@group(1) @binding(7) var test_texture_cube_sampler: sampler;
@group(2) @binding(6) var test_texture_cube: texture_cube<f32>;
@group(2) @binding(7) var test_texture_cube_sampler: sampler;

@group(1) @binding(8) var test_texture_cube_array: texture_cube_array<f32>;
@group(1) @binding(9) var test_texture_cube_array_sampler: sampler;
@group(2) @binding(8) var test_texture_cube_array: texture_cube_array<f32>;
@group(2) @binding(9) var test_texture_cube_array_sampler: sampler;

@group(1) @binding(10) var test_texture_3d: texture_3d<f32>;
@group(1) @binding(11) var test_texture_3d_sampler: sampler;
@group(2) @binding(10) var test_texture_3d: texture_3d<f32>;
@group(2) @binding(11) var test_texture_3d_sampler: sampler;

@fragment
fn fragment(in: VertexOutput) {}
2 changes: 1 addition & 1 deletion assets/shaders/line_material.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ struct LineMaterial {
color: vec4<f32>,
};

@group(1) @binding(0) var<uniform> material: LineMaterial;
@group(2) @binding(0) var<uniform> material: LineMaterial;

@fragment
fn fragment(
Expand Down
2 changes: 1 addition & 1 deletion assets/shaders/shader_defs.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ struct CustomMaterial {
color: vec4<f32>,
};

@group(1) @binding(0) var<uniform> material: CustomMaterial;
@group(2) @binding(0) var<uniform> material: CustomMaterial;

@fragment
fn fragment(
Expand Down
2 changes: 1 addition & 1 deletion assets/shaders/show_prepass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct ShowPrepassSettings {
padding_1: u32,
padding_2: u32,
}
@group(1) @binding(0) var<uniform> settings: ShowPrepassSettings;
@group(2) @binding(0) var<uniform> settings: ShowPrepassSettings;

@fragment
fn fragment(
Expand Down
4 changes: 2 additions & 2 deletions assets/shaders/texture_binding_array.wgsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#import bevy_pbr::forward_io::VertexOutput

@group(1) @binding(0) var textures: binding_array<texture_2d<f32>>;
@group(1) @binding(1) var nearest_sampler: sampler;
@group(2) @binding(0) var textures: binding_array<texture_2d<f32>>;
@group(2) @binding(1) var nearest_sampler: sampler;
// We can also have array of samplers
// var samplers: binding_array<sampler>;

Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ use std::marker::PhantomData;
/// In WGSL shaders, the material's binding would look like this:
///
/// ```wgsl
/// @group(1) @binding(0) var<uniform> color: vec4<f32>;
/// @group(1) @binding(1) var color_texture: texture_2d<f32>;
/// @group(1) @binding(2) var color_sampler: sampler;
/// @group(2) @binding(0) var<uniform> color: vec4<f32>;
/// @group(2) @binding(1) var color_texture: texture_2d<f32>;
/// @group(2) @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
Expand Down Expand Up @@ -335,7 +335,7 @@ where
descriptor.fragment.as_mut().unwrap().shader = fragment_shader.clone();
}

descriptor.layout.insert(1, self.material_layout.clone());
descriptor.layout.insert(2, self.material_layout.clone());

M::specialize(self, &mut descriptor, layout, key)?;
Ok(descriptor)
Expand Down Expand Up @@ -368,8 +368,8 @@ impl<M: Material> FromWorld for MaterialPipeline<M> {
type DrawMaterial<M> = (
SetItemPipeline,
SetMeshViewBindGroup<0>,
SetMaterialBindGroup<M, 1>,
SetMeshBindGroup<2>,
SetMeshBindGroup<1>,
SetMaterialBindGroup<M, 2>,
DrawMesh,
);

Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ where

// NOTE: Eventually, it would be nice to only add this when the shaders are overloaded by the Material.
// The main limitation right now is that bind group order is hardcoded in shaders.
bind_group_layouts.insert(1, self.material_layout.clone());
bind_group_layouts.push(self.material_layout.clone());

#[cfg(all(feature = "webgl", target_arch = "wasm32"))]
shader_defs.push("WEBGL2".into());
Expand Down Expand Up @@ -421,7 +421,7 @@ where
&mut shader_defs,
&mut vertex_attributes,
);
bind_group_layouts.insert(2, bind_group);
bind_group_layouts.insert(1, bind_group);

let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;

Expand Down Expand Up @@ -919,8 +919,8 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<
pub type DrawPrepass<M> = (
SetItemPipeline,
SetPrepassViewBindGroup<0>,
SetMaterialBindGroup<M, 1>,
SetMeshBindGroup<2>,
SetMeshBindGroup<1>,
SetMaterialBindGroup<M, 2>,
DrawMesh,
);

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/prepass/prepass_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
@group(0) @binding(2) var<uniform> previous_view_proj: mat4x4<f32>;
#endif // MOTION_VECTOR_PREPASS

// Material bindings will be in @group(1)
// Material bindings will be in @group(2)
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,9 @@ pub struct MeshPipeline {
/// Use code like this in custom shaders:
/// ```wgsl
/// ##ifdef PER_OBJECT_BUFFER_BATCH_SIZE
/// @group(2) @binding(0) var<uniform> mesh: array<Mesh, #{PER_OBJECT_BUFFER_BATCH_SIZE}u>;
/// @group(1) @binding(0) var<uniform> mesh: array<Mesh, #{PER_OBJECT_BUFFER_BATCH_SIZE}u>;
/// ##else
/// @group(2) @binding(0) var<storage> mesh: array<Mesh>;
/// @group(1) @binding(0) var<storage> mesh: array<Mesh>;
/// ##endif // PER_OBJECT_BUFFER_BATCH_SIZE
/// ```
pub per_object_buffer_batch_size: Option<u32>,
Expand Down
12 changes: 0 additions & 12 deletions crates/bevy_pbr/src/render/mesh_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,8 @@

#import bevy_pbr::mesh_types::Mesh

#ifdef MESH_BINDGROUP_1

#ifdef PER_OBJECT_BUFFER_BATCH_SIZE
@group(1) @binding(0) var<uniform> mesh: array<Mesh, #{PER_OBJECT_BUFFER_BATCH_SIZE}u>;
#else
@group(1) @binding(0) var<storage> mesh: array<Mesh>;
#endif // PER_OBJECT_BUFFER_BATCH_SIZE

#else // MESH_BINDGROUP_1

#ifdef PER_OBJECT_BUFFER_BATCH_SIZE
@group(2) @binding(0) var<uniform> mesh: array<Mesh, #{PER_OBJECT_BUFFER_BATCH_SIZE}u>;
#else
@group(2) @binding(0) var<storage> mesh: array<Mesh>;
#endif // PER_OBJECT_BUFFER_BATCH_SIZE

#endif // MESH_BINDGROUP_1
10 changes: 0 additions & 10 deletions crates/bevy_pbr/src/render/morph.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,9 @@

#import bevy_pbr::mesh_types::MorphWeights;

#ifdef MESH_BINDGROUP_1

@group(1) @binding(2) var<uniform> morph_weights: MorphWeights;
@group(1) @binding(3) var morph_targets: texture_3d<f32>;

#else

@group(2) @binding(2) var<uniform> morph_weights: MorphWeights;
@group(2) @binding(3) var morph_targets: texture_3d<f32>;

#endif


// NOTE: Those are the "hardcoded" values found in `MorphAttributes` struct
// in crates/bevy_render/src/mesh/morph/visitors.rs
// In an ideal world, the offsets are established dynamically and passed as #defines
Expand Down
38 changes: 19 additions & 19 deletions crates/bevy_pbr/src/render/pbr_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@

#import bevy_pbr::pbr_types::StandardMaterial

@group(1) @binding(0) var<uniform> material: StandardMaterial;
@group(1) @binding(1) var base_color_texture: texture_2d<f32>;
@group(1) @binding(2) var base_color_sampler: sampler;
@group(1) @binding(3) var emissive_texture: texture_2d<f32>;
@group(1) @binding(4) var emissive_sampler: sampler;
@group(1) @binding(5) var metallic_roughness_texture: texture_2d<f32>;
@group(1) @binding(6) var metallic_roughness_sampler: sampler;
@group(1) @binding(7) var occlusion_texture: texture_2d<f32>;
@group(1) @binding(8) var occlusion_sampler: sampler;
@group(1) @binding(9) var normal_map_texture: texture_2d<f32>;
@group(1) @binding(10) var normal_map_sampler: sampler;
@group(1) @binding(11) var depth_map_texture: texture_2d<f32>;
@group(1) @binding(12) var depth_map_sampler: sampler;
@group(2) @binding(0) var<uniform> material: StandardMaterial;
@group(2) @binding(1) var base_color_texture: texture_2d<f32>;
@group(2) @binding(2) var base_color_sampler: sampler;
@group(2) @binding(3) var emissive_texture: texture_2d<f32>;
@group(2) @binding(4) var emissive_sampler: sampler;
@group(2) @binding(5) var metallic_roughness_texture: texture_2d<f32>;
@group(2) @binding(6) var metallic_roughness_sampler: sampler;
@group(2) @binding(7) var occlusion_texture: texture_2d<f32>;
@group(2) @binding(8) var occlusion_sampler: sampler;
@group(2) @binding(9) var normal_map_texture: texture_2d<f32>;
@group(2) @binding(10) var normal_map_sampler: sampler;
@group(2) @binding(11) var depth_map_texture: texture_2d<f32>;
@group(2) @binding(12) var depth_map_sampler: sampler;
#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
@group(1) @binding(13) var specular_transmission_texture: texture_2d<f32>;
@group(1) @binding(14) var specular_transmission_sampler: sampler;
@group(1) @binding(15) var thickness_texture: texture_2d<f32>;
@group(1) @binding(16) var thickness_sampler: sampler;
@group(1) @binding(17) var diffuse_transmission_texture: texture_2d<f32>;
@group(1) @binding(18) var diffuse_transmission_sampler: sampler;
@group(2) @binding(13) var specular_transmission_texture: texture_2d<f32>;
@group(2) @binding(14) var specular_transmission_sampler: sampler;
@group(2) @binding(15) var thickness_texture: texture_2d<f32>;
@group(2) @binding(16) var thickness_sampler: sampler;
@group(2) @binding(17) var diffuse_transmission_texture: texture_2d<f32>;
@group(2) @binding(18) var diffuse_transmission_sampler: sampler;
#endif
7 changes: 1 addition & 6 deletions crates/bevy_pbr/src/render/skinning.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@

#ifdef SKINNED

#ifdef MESH_BINDGROUP_1
@group(1) @binding(1) var<uniform> joint_matrices: SkinnedMesh;
#else
@group(2) @binding(1) var<uniform> joint_matrices: SkinnedMesh;
#endif

@group(1) @binding(1) var<uniform> joint_matrices: SkinnedMesh;

fn skin_model(
indexes: vec4<u32>,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render/wireframe.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ struct WireframeMaterial {
color: vec4<f32>,
};

@group(1) @binding(0)
@group(2) @binding(0)
var<uniform> material: WireframeMaterial;
@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_render/src/render_resource/bind_group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,13 @@ impl Deref for BindGroup {
/// In WGSL shaders, the binding would look like this:
///
/// ```wgsl
/// @group(1) @binding(0) var<uniform> color: vec4<f32>;
/// @group(1) @binding(1) var color_texture: texture_2d<f32>;
/// @group(1) @binding(2) var color_sampler: sampler;
/// @group(1) @binding(3) var<storage> values: array<f32>;
/// @group(2) @binding(0) var<uniform> color: vec4<f32>;
/// @group(2) @binding(1) var color_texture: texture_2d<f32>;
/// @group(2) @binding(2) var color_sampler: sampler;
/// @group(2) @binding(3) var<storage> values: array<f32>;
/// ```
/// 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 1.
/// are generally bound to group 2.
///
/// The following field-level attributes are supported:
///
Expand Down Expand Up @@ -191,7 +191,7 @@ impl Deref for BindGroup {
/// roughness: f32,
/// };
///
/// @group(1) @binding(0) var<uniform> material: CoolMaterial;
/// @group(2) @binding(0) var<uniform> material: CoolMaterial;
/// ```
///
/// Some less common scenarios will require "struct-level" attributes. These are the currently supported struct-level attributes:
Expand Down
Loading

0 comments on commit 4bf20e7

Please sign in to comment.