Ugrade to wgpu
version 25.0
(#19563)
# Objective Upgrade to `wgpu` version `25.0`. Depends on https://github.com/bevyengine/naga_oil/pull/121 ## Solution ### Problem The biggest issue we face upgrading is the following requirement: > To facilitate this change, there was an additional validation rule put in place: if there is a binding array in a bind group, you may not use dynamic offset buffers or uniform buffers in that bind group. This requirement comes from vulkan rules on UpdateAfterBind descriptors. This is a major difficulty for us, as there are a number of binding arrays that are used in the view bind group. Note, this requirement does not affect merely uniform buffors that use dynamic offset but the use of *any* uniform in a bind group that also has a binding array. ### Attempted fixes The easiest fix would be to change uniforms to be storage buffers whenever binding arrays are in use: ```wgsl #ifdef BINDING_ARRAYS_ARE_USED @group(0) @binding(0) var<uniform> view: View; @group(0) @binding(1) var<uniform> lights: types::Lights; #else @group(0) @binding(0) var<storage> view: array<View>; @group(0) @binding(1) var<storage> lights: array<types::Lights>; #endif ``` This requires passing the view index to the shader so that we know where to index into the buffer: ```wgsl struct PushConstants { view_index: u32, } var<push_constant> push_constants: PushConstants; ``` Using push constants is no problem because binding arrays are only usable on native anyway. However, this greatly complicates the ability to access `view` in shaders. For example: ```wgsl #ifdef BINDING_ARRAYS_ARE_USED mesh_view_bindings::view.view_from_world[0].z #else mesh_view_bindings::view[mesh_view_bindings::view_index].view_from_world[0].z #endif ``` Using this approach would work but would have the effect of polluting our shaders with ifdef spam basically *everywhere*. Why not use a function? Unfortunately, the following is not valid wgsl as it returns a binding directly from a function in the uniform path. ```wgsl fn get_view() -> View { #if BINDING_ARRAYS_ARE_USED let view_index = push_constants.view_index; let view = views[view_index]; #endif return view; } ``` This also poses problems for things like lights where we want to return a ptr to the light data. Returning ptrs from wgsl functions isn't allowed even if both bindings were buffers. The next attempt was to simply use indexed buffers everywhere, in both the binding array and non binding array path. This would be viable if push constants were available everywhere to pass the view index, but unfortunately they are not available on webgpu. This means either passing the view index in a storage buffer (not ideal for such a small amount of state) or using push constants sometimes and uniform buffers only on webgpu. However, this kind of conditional layout infects absolutely everything. Even if we were to accept just using storage buffer for the view index, there's also the additional problem that some dynamic offsets aren't actually per-view but per-use of a setting on a camera, which would require passing that uniform data on *every* camera regardless of whether that rendering feature is being used, which is also gross. As such, although it's gross, the simplest solution just to bump binding arrays into `@group(1)` and all other bindings up one bind group. This should still bring us under the device limit of 4 for most users. ### Next steps / looking towards the future I'd like to avoid needing split our view bind group into multiple parts. In the future, if `wgpu` were to add `@builtin(draw_index)`, we could build a list of draw state in gpu processing and avoid the need for any kind of state change at all (see https://github.com/gfx-rs/wgpu/issues/6823). This would also provide significantly more flexibility to handle things like offsets into other arrays that may not be per-view. ### Testing Tested a number of examples, there are probably more that are still broken. --------- Co-authored-by: François Mockers <mockersf@gmail.com> Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
This commit is contained in:
parent
92e65d5eb1
commit
96dcbc5f8c
@ -7,8 +7,8 @@
|
||||
}
|
||||
#import bevy_core_pipeline::tonemapping::tone_mapping
|
||||
|
||||
@group(2) @binding(0) var my_array_texture: texture_2d_array<f32>;
|
||||
@group(2) @binding(1) var my_array_texture_sampler: sampler;
|
||||
@group(3) @binding(0) var my_array_texture: texture_2d_array<f32>;
|
||||
@group(3) @binding(1) var my_array_texture_sampler: sampler;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -3,8 +3,8 @@
|
||||
view_transformations::position_world_to_clip
|
||||
}
|
||||
|
||||
@group(2) @binding(0) var texture: texture_2d<f32>;
|
||||
@group(2) @binding(1) var texture_sampler: sampler;
|
||||
@group(3) @binding(0) var texture: texture_2d<f32>;
|
||||
@group(3) @binding(1) var texture_sampler: sampler;
|
||||
|
||||
struct Vertex {
|
||||
@builtin(instance_index) instance_index: u32,
|
||||
|
@ -15,12 +15,12 @@ struct MaterialBindings {
|
||||
}
|
||||
|
||||
#ifdef BINDLESS
|
||||
@group(2) @binding(0) var<storage> materials: array<MaterialBindings>;
|
||||
@group(2) @binding(10) var<storage> material_color: binding_array<Color>;
|
||||
@group(3) @binding(0) var<storage> materials: array<MaterialBindings>;
|
||||
@group(3) @binding(10) var<storage> material_color: binding_array<Color>;
|
||||
#else // BINDLESS
|
||||
@group(2) @binding(0) var<uniform> material_color: Color;
|
||||
@group(2) @binding(1) var material_color_texture: texture_2d<f32>;
|
||||
@group(2) @binding(2) var material_color_sampler: sampler;
|
||||
@group(3) @binding(0) var<uniform> material_color: Color;
|
||||
@group(3) @binding(1) var material_color_texture: texture_2d<f32>;
|
||||
@group(3) @binding(2) var material_color_sampler: sampler;
|
||||
#endif // BINDLESS
|
||||
|
||||
@fragment
|
||||
|
@ -1,12 +1,12 @@
|
||||
#import bevy_pbr::forward_io::VertexOutput
|
||||
|
||||
#ifdef CUBEMAP_ARRAY
|
||||
@group(2) @binding(0) var base_color_texture: texture_cube_array<f32>;
|
||||
@group(3) @binding(0) var base_color_texture: texture_cube_array<f32>;
|
||||
#else
|
||||
@group(2) @binding(0) var base_color_texture: texture_cube<f32>;
|
||||
@group(3) @binding(0) var base_color_texture: texture_cube<f32>;
|
||||
#endif
|
||||
|
||||
@group(2) @binding(1) var base_color_sampler: sampler;
|
||||
@group(3) @binding(1) var base_color_sampler: sampler;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -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 ...
|
||||
|
@ -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
|
||||
|
@ -10,7 +10,7 @@ struct CustomMaterial {
|
||||
time: vec4<f32>,
|
||||
}
|
||||
|
||||
@group(2) @binding(0) var<uniform> material: CustomMaterial;
|
||||
@group(3) @binding(0) var<uniform> material: CustomMaterial;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -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<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;
|
||||
@group(3) @binding(0) var<uniform> material_color: vec4<f32>;
|
||||
@group(3) @binding(1) var material_color_texture: texture_2d<f32>;
|
||||
@group(3) @binding(2) var material_color_sampler: sampler;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -4,8 +4,8 @@
|
||||
utils::coords_to_viewport_uv,
|
||||
}
|
||||
|
||||
@group(2) @binding(0) var texture: texture_2d<f32>;
|
||||
@group(2) @binding(1) var texture_sampler: sampler;
|
||||
@group(3) @binding(0) var texture: texture_2d<f32>;
|
||||
@group(3) @binding(1) var texture_sampler: sampler;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -3,7 +3,7 @@
|
||||
struct CustomMaterial {
|
||||
color: vec4<f32>,
|
||||
};
|
||||
@group(2) @binding(0) var<uniform> material: CustomMaterial;
|
||||
@group(3) @binding(0) var<uniform> material: CustomMaterial;
|
||||
|
||||
struct Vertex {
|
||||
@builtin(instance_index) instance_index: u32,
|
||||
|
@ -19,7 +19,7 @@ struct MyExtendedMaterial {
|
||||
quantize_steps: u32,
|
||||
}
|
||||
|
||||
@group(2) @binding(100)
|
||||
@group(3) @binding(100)
|
||||
var<uniform> my_extended_material: MyExtendedMaterial;
|
||||
|
||||
@fragment
|
||||
|
@ -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<storage> example_extended_material_indices:
|
||||
@group(3) @binding(100) var<storage> example_extended_material_indices:
|
||||
array<ExampleBindlessExtendedMaterialIndices>;
|
||||
// An array that holds the `ExampleBindlessExtendedMaterial` plain old data,
|
||||
// indexed by `ExampleBindlessExtendedMaterialIndices.material`.
|
||||
@group(2) @binding(101) var<storage> example_extended_material:
|
||||
@group(3) @binding(101) var<storage> example_extended_material:
|
||||
array<ExampleBindlessExtendedMaterial>;
|
||||
|
||||
#else // BINDLESS
|
||||
|
||||
// In non-bindless mode, we simply use a uniform for the plain old data.
|
||||
@group(2) @binding(50) var<uniform> example_extended_material: ExampleBindlessExtendedMaterial;
|
||||
@group(2) @binding(51) var modulate_texture: texture_2d<f32>;
|
||||
@group(2) @binding(52) var modulate_sampler: sampler;
|
||||
@group(3) @binding(50) var<uniform> example_extended_material: ExampleBindlessExtendedMaterial;
|
||||
@group(3) @binding(51) var modulate_texture: texture_2d<f32>;
|
||||
@group(3) @binding(52) var modulate_sampler: sampler;
|
||||
|
||||
#endif // BINDLESS
|
||||
|
||||
|
@ -1,22 +1,22 @@
|
||||
#import bevy_pbr::forward_io::VertexOutput
|
||||
|
||||
@group(2) @binding(0) var test_texture_1d: texture_1d<f32>;
|
||||
@group(2) @binding(1) var test_texture_1d_sampler: sampler;
|
||||
@group(3) @binding(0) var test_texture_1d: texture_1d<f32>;
|
||||
@group(3) @binding(1) var test_texture_1d_sampler: sampler;
|
||||
|
||||
@group(2) @binding(2) var test_texture_2d: texture_2d<f32>;
|
||||
@group(2) @binding(3) var test_texture_2d_sampler: sampler;
|
||||
@group(3) @binding(2) var test_texture_2d: texture_2d<f32>;
|
||||
@group(3) @binding(3) var test_texture_2d_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(3) @binding(4) var test_texture_2d_array: texture_2d_array<f32>;
|
||||
@group(3) @binding(5) var test_texture_2d_array_sampler: sampler;
|
||||
|
||||
@group(2) @binding(6) var test_texture_cube: texture_cube<f32>;
|
||||
@group(2) @binding(7) var test_texture_cube_sampler: sampler;
|
||||
@group(3) @binding(6) var test_texture_cube: texture_cube<f32>;
|
||||
@group(3) @binding(7) var test_texture_cube_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(3) @binding(8) var test_texture_cube_array: texture_cube_array<f32>;
|
||||
@group(3) @binding(9) var test_texture_cube_array_sampler: sampler;
|
||||
|
||||
@group(2) @binding(10) var test_texture_3d: texture_3d<f32>;
|
||||
@group(2) @binding(11) var test_texture_3d_sampler: sampler;
|
||||
@group(3) @binding(10) var test_texture_3d: texture_3d<f32>;
|
||||
@group(3) @binding(11) var test_texture_3d_sampler: sampler;
|
||||
|
||||
@fragment
|
||||
fn fragment(in: VertexOutput) {}
|
||||
|
@ -12,7 +12,7 @@ struct VoxelVisualizationIrradianceVolumeInfo {
|
||||
intensity: f32,
|
||||
}
|
||||
|
||||
@group(2) @binding(100)
|
||||
@group(3) @binding(100)
|
||||
var<uniform> irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo;
|
||||
|
||||
@fragment
|
||||
|
@ -4,7 +4,7 @@ struct LineMaterial {
|
||||
color: vec4<f32>,
|
||||
};
|
||||
|
||||
@group(2) @binding(0) var<uniform> material: LineMaterial;
|
||||
@group(3) @binding(0) var<uniform> material: LineMaterial;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -4,7 +4,7 @@ struct CustomMaterial {
|
||||
color: vec4<f32>,
|
||||
};
|
||||
|
||||
@group(2) @binding(0) var<uniform> material: CustomMaterial;
|
||||
@group(3) @binding(0) var<uniform> material: CustomMaterial;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -11,7 +11,7 @@ struct ShowPrepassSettings {
|
||||
padding_1: u32,
|
||||
padding_2: u32,
|
||||
}
|
||||
@group(2) @binding(0) var<uniform> settings: ShowPrepassSettings;
|
||||
@group(3) @binding(0) var<uniform> settings: ShowPrepassSettings;
|
||||
|
||||
@fragment
|
||||
fn fragment(
|
||||
|
@ -3,7 +3,7 @@
|
||||
view_transformations::position_world_to_clip
|
||||
}
|
||||
|
||||
@group(2) @binding(0) var<storage, read> colors: array<vec4<f32>, 5>;
|
||||
@group(3) @binding(0) var<storage, read> colors: array<vec4<f32>, 5>;
|
||||
|
||||
struct Vertex {
|
||||
@builtin(instance_index) instance_index: u32,
|
||||
|
@ -1,7 +1,7 @@
|
||||
#import bevy_pbr::forward_io::VertexOutput
|
||||
|
||||
@group(2) @binding(0) var textures: binding_array<texture_2d<f32>>;
|
||||
@group(2) @binding(1) var nearest_sampler: sampler;
|
||||
@group(3) @binding(0) var textures: binding_array<texture_2d<f32>>;
|
||||
@group(3) @binding(1) var nearest_sampler: sampler;
|
||||
// We can also have array of samplers
|
||||
// var samplers: binding_array<sampler>;
|
||||
|
||||
|
@ -23,9 +23,9 @@ struct WaterSettings {
|
||||
|
||||
@group(0) @binding(1) var<uniform> globals: Globals;
|
||||
|
||||
@group(2) @binding(100) var water_normals_texture: texture_2d<f32>;
|
||||
@group(2) @binding(101) var water_normals_sampler: sampler;
|
||||
@group(2) @binding(102) var<uniform> water_settings: WaterSettings;
|
||||
@group(3) @binding(100) var water_normals_texture: texture_2d<f32>;
|
||||
@group(3) @binding(101) var water_normals_sampler: sampler;
|
||||
@group(3) @binding(102) var<uniform> water_settings: WaterSettings;
|
||||
|
||||
// Samples a single octave of noise and returns the resulting normal.
|
||||
fn sample_noise_octave(uv: vec2<f32>, strength: f32) -> vec3<f32> {
|
||||
|
@ -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]
|
||||
|
@ -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.");
|
||||
|
@ -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"
|
||||
|
@ -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 }
|
||||
|
@ -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<f32>,
|
||||
#ifdef DUAL_SOURCE_BLENDING
|
||||
@location(0) @second_blend_source transmittance: vec4<f32>,
|
||||
@location(0) @blend_src(0) inscattering: vec4<f32>,
|
||||
@location(0) @blend_src(1) transmittance: vec4<f32>,
|
||||
#else
|
||||
@location(0) inscattering: vec4<f32>,
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
}
|
||||
#import bevy_render::maths::project_onto
|
||||
|
||||
@group(2) @binding(200)
|
||||
@group(3) @binding(200)
|
||||
var<uniform> inv_depth_fade_factor: f32;
|
||||
|
||||
struct ForwardDecalInformation {
|
||||
|
@ -29,7 +29,7 @@ struct PbrDeferredLightingDepthId {
|
||||
_webgl2_padding_2: f32,
|
||||
#endif
|
||||
}
|
||||
@group(1) @binding(0)
|
||||
@group(2) @binding(0)
|
||||
var<uniform> depth_id: PbrDeferredLightingDepthId;
|
||||
|
||||
@vertex
|
||||
|
@ -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<Shader>,
|
||||
}
|
||||
|
||||
@ -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::<MeshPipeline>().clone(),
|
||||
bind_group_layout_1: layout,
|
||||
bind_group_layout_2: layout,
|
||||
deferred_lighting_shader: load_embedded_asset!(world, "deferred_lighting.wgsl"),
|
||||
}
|
||||
}
|
||||
|
@ -152,8 +152,8 @@ fn shader_ref(path: PathBuf) -> ShaderRef {
|
||||
const MESHLET_VISIBILITY_BUFFER_RESOLVE_SHADER_HANDLE: Handle<Shader> =
|
||||
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 {
|
||||
|
@ -3,11 +3,11 @@
|
||||
#import bevy_pbr::mesh_bindings::mesh
|
||||
|
||||
#ifdef MULTIPLE_LIGHTMAPS_IN_ARRAY
|
||||
@group(1) @binding(4) var lightmaps_textures: binding_array<texture_2d<f32>, 4>;
|
||||
@group(1) @binding(5) var lightmaps_samplers: binding_array<sampler, 4>;
|
||||
@group(2) @binding(4) var lightmaps_textures: binding_array<texture_2d<f32>, 4>;
|
||||
@group(2) @binding(5) var lightmaps_samplers: binding_array<sampler, 4>;
|
||||
#else // MULTIPLE_LIGHTMAPS_IN_ARRAY
|
||||
@group(1) @binding(4) var lightmaps_texture: texture_2d<f32>;
|
||||
@group(1) @binding(5) var lightmaps_sampler: sampler;
|
||||
@group(2) @binding(4) var lightmaps_texture: texture_2d<f32>;
|
||||
@group(2) @binding(5) var lightmaps_sampler: sampler;
|
||||
#endif // MULTIPLE_LIGHTMAPS_IN_ARRAY
|
||||
|
||||
// Samples the lightmap, if any, and returns indirect illumination from it.
|
||||
|
@ -120,9 +120,9 @@ use tracing::error;
|
||||
/// In WGSL shaders, the material's binding would look like this:
|
||||
///
|
||||
/// ```wgsl
|
||||
/// @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(3) @binding(0) var<uniform> color: vec4<f32>;
|
||||
/// @group(3) @binding(1) var color_texture: texture_2d<f32>;
|
||||
/// @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<M: Material> FromWorld for MaterialPipeline<M> {
|
||||
type DrawMaterial<M> = (
|
||||
SetItemPipeline,
|
||||
SetMeshViewBindGroup<0>,
|
||||
SetMeshBindGroup<1>,
|
||||
SetMaterialBindGroup<M, 2>,
|
||||
SetMeshViewBindingArrayBindGroup<1>,
|
||||
SetMeshBindGroup<2>,
|
||||
SetMaterialBindGroup<M, 3>,
|
||||
DrawMesh,
|
||||
);
|
||||
|
||||
|
@ -186,13 +186,17 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass<M: Material>(
|
||||
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,
|
||||
|
@ -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,
|
||||
|
@ -149,15 +149,15 @@ fn get_meshlet_vertex_position(meshlet: ptr<function, Meshlet>, vertex_id: u32)
|
||||
#endif
|
||||
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
@group(1) @binding(0) var meshlet_visibility_buffer: texture_storage_2d<r64uint, read>;
|
||||
@group(1) @binding(1) var<storage, read> meshlet_cluster_meshlet_ids: array<u32>; // Per cluster
|
||||
@group(1) @binding(2) var<storage, read> meshlets: array<Meshlet>; // Per meshlet
|
||||
@group(1) @binding(3) var<storage, read> meshlet_indices: array<u32>; // Many per meshlet
|
||||
@group(1) @binding(4) var<storage, read> meshlet_vertex_positions: array<u32>; // Many per meshlet
|
||||
@group(1) @binding(5) var<storage, read> meshlet_vertex_normals: array<u32>; // Many per meshlet
|
||||
@group(1) @binding(6) var<storage, read> meshlet_vertex_uvs: array<vec2<f32>>; // Many per meshlet
|
||||
@group(1) @binding(7) var<storage, read> meshlet_cluster_instance_ids: array<u32>; // Per cluster
|
||||
@group(1) @binding(8) var<storage, read> meshlet_instance_uniforms: array<Mesh>; // Per entity instance
|
||||
@group(2) @binding(0) var meshlet_visibility_buffer: texture_storage_2d<r64uint, read>;
|
||||
@group(2) @binding(1) var<storage, read> meshlet_cluster_meshlet_ids: array<u32>; // Per cluster
|
||||
@group(2) @binding(2) var<storage, read> meshlets: array<Meshlet>; // Per meshlet
|
||||
@group(2) @binding(3) var<storage, read> meshlet_indices: array<u32>; // Many per meshlet
|
||||
@group(2) @binding(4) var<storage, read> meshlet_vertex_positions: array<u32>; // Many per meshlet
|
||||
@group(2) @binding(5) var<storage, read> meshlet_vertex_normals: array<u32>; // Many per meshlet
|
||||
@group(2) @binding(6) var<storage, read> meshlet_vertex_uvs: array<vec2<f32>>; // Many per meshlet
|
||||
@group(2) @binding(7) var<storage, read> meshlet_cluster_instance_ids: array<u32>; // Per cluster
|
||||
@group(2) @binding(8) var<storage, read> meshlet_instance_uniforms: array<Mesh>; // 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 {
|
||||
|
@ -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),
|
||||
|
@ -95,7 +95,6 @@ where
|
||||
Render,
|
||||
prepare_prepass_view_bind_group::<M>.in_set(RenderSystems::PrepareBindGroups),
|
||||
)
|
||||
.init_resource::<PrepassViewBindGroup>()
|
||||
.init_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>()
|
||||
.allow_ambiguous_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>();
|
||||
}
|
||||
@ -105,7 +104,9 @@ where
|
||||
return;
|
||||
};
|
||||
|
||||
render_app.init_resource::<PrepassPipeline<M>>();
|
||||
render_app
|
||||
.init_resource::<PrepassPipeline<M>>()
|
||||
.init_resource::<PrepassViewBindGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Handle<Shader>>,
|
||||
pub prepass_material_fragment_shader: Option<Handle<Shader>>,
|
||||
@ -381,6 +383,7 @@ impl<M: Material> FromWorld for PrepassPipeline<M> {
|
||||
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<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
||||
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<BindGroup>,
|
||||
pub no_motion_vectors: Option<BindGroup>,
|
||||
pub empty_bind_group: BindGroup,
|
||||
}
|
||||
|
||||
impl FromWorld for PrepassViewBindGroup {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let pipeline = world.resource::<PrepassPipeline<StandardMaterial>>();
|
||||
|
||||
let render_device = world.resource::<RenderDevice>();
|
||||
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<M: Material>(
|
||||
@ -1284,7 +1307,26 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<
|
||||
);
|
||||
}
|
||||
}
|
||||
RenderCommandResult::Success
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SetPrepassViewEmptyBindGroup<const I: usize>;
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewEmptyBindGroup<I> {
|
||||
type Param = SRes<PrepassViewBindGroup>;
|
||||
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<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<
|
||||
pub type DrawPrepass<M> = (
|
||||
SetItemPipeline,
|
||||
SetPrepassViewBindGroup<0>,
|
||||
SetMeshBindGroup<1>,
|
||||
SetMaterialBindGroup<M, 2>,
|
||||
SetPrepassViewEmptyBindGroup<1>,
|
||||
SetMeshBindGroup<2>,
|
||||
SetMaterialBindGroup<M, 3>,
|
||||
DrawMesh,
|
||||
);
|
||||
|
@ -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<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindGroup<I>
|
||||
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<const I: usize>;
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewBindingArrayBindGroup<I> {
|
||||
type Param = ();
|
||||
type ViewQuery = (Read<MeshViewBindGroup>,);
|
||||
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<const I: usize>;
|
||||
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetMeshViewEmptyBindGroup<I> {
|
||||
type Param = ();
|
||||
type ViewQuery = (Read<MeshViewBindGroup>,);
|
||||
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
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#ifndef MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef PER_OBJECT_BUFFER_BATCH_SIZE
|
||||
@group(1) @binding(0) var<uniform> mesh: array<Mesh, #{PER_OBJECT_BUFFER_BATCH_SIZE}u>;
|
||||
@group(2) @binding(0) var<uniform> mesh: array<Mesh, #{PER_OBJECT_BUFFER_BATCH_SIZE}u>;
|
||||
#else
|
||||
@group(1) @binding(0) var<storage> mesh: array<Mesh>;
|
||||
@group(2) @binding(0) var<storage> mesh: array<Mesh>;
|
||||
#endif // PER_OBJECT_BUFFER_BATCH_SIZE
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
|
@ -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,
|
||||
@ -213,7 +215,11 @@ fn layout_entries(
|
||||
layout_key: MeshPipelineViewLayoutKey,
|
||||
render_device: &RenderDevice,
|
||||
render_adapter: &RenderAdapter,
|
||||
) -> Vec<BindGroupLayoutEntry> {
|
||||
) -> [Vec<BindGroupLayoutEntry>; 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,
|
||||
(
|
||||
@ -325,45 +331,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
|
||||
@ -373,7 +349,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),));
|
||||
@ -384,10 +360,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
|
||||
@ -398,19 +374,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::<OrderIndependentTransparencySettings>(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.
|
||||
@ -447,12 +451,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,
|
||||
}
|
||||
@ -461,7 +474,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];
|
||||
|
||||
@ -471,7 +487,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
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,12 +512,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,
|
||||
}
|
||||
@ -510,7 +534,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(
|
||||
@ -597,7 +623,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()),
|
||||
@ -626,6 +652,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,
|
||||
@ -633,18 +711,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 {
|
||||
@ -652,11 +728,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),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -678,14 +753,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 => {}
|
||||
}
|
||||
@ -701,76 +777,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,
|
||||
&[],
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -50,70 +50,70 @@ const VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE: u32 = 64u;
|
||||
|
||||
@group(0) @binding(15) var<uniform> ssr_settings: types::ScreenSpaceReflectionsSettings;
|
||||
@group(0) @binding(16) var screen_space_ambient_occlusion_texture: texture_2d<f32>;
|
||||
|
||||
#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY
|
||||
@group(0) @binding(17) var diffuse_environment_maps: binding_array<texture_cube<f32>, 8u>;
|
||||
@group(0) @binding(18) var specular_environment_maps: binding_array<texture_cube<f32>, 8u>;
|
||||
#else
|
||||
@group(0) @binding(17) var diffuse_environment_map: texture_cube<f32>;
|
||||
@group(0) @binding(18) var specular_environment_map: texture_cube<f32>;
|
||||
#endif
|
||||
@group(0) @binding(19) var environment_map_sampler: sampler;
|
||||
@group(0) @binding(20) var<uniform> 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<texture_3d<f32>, 8u>;
|
||||
#else
|
||||
@group(0) @binding(21) var irradiance_volume: texture_3d<f32>;
|
||||
#endif
|
||||
@group(0) @binding(22) var irradiance_volume_sampler: sampler;
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTERED_DECALS_ARE_USABLE
|
||||
@group(0) @binding(23) var<storage> clustered_decals: types::ClusteredDecals;
|
||||
@group(0) @binding(24) var clustered_decal_textures: binding_array<texture_2d<f32>, 8u>;
|
||||
@group(0) @binding(25) var clustered_decal_sampler: sampler;
|
||||
#endif // CLUSTERED_DECALS_ARE_USABLE
|
||||
@group(0) @binding(17) var<uniform> 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<f32>;
|
||||
@group(0) @binding(27) var dt_lut_sampler: sampler;
|
||||
@group(0) @binding(18) var dt_lut_texture: texture_3d<f32>;
|
||||
@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<f32>;
|
||||
@group(0) @binding(21) var normal_prepass_texture: texture_multisampled_2d<f32>;
|
||||
#endif // NORMAL_PREPASS
|
||||
#ifdef MOTION_VECTOR_PREPASS
|
||||
@group(0) @binding(30) var motion_vector_prepass_texture: texture_multisampled_2d<f32>;
|
||||
@group(0) @binding(22) var motion_vector_prepass_texture: texture_multisampled_2d<f32>;
|
||||
#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<f32>;
|
||||
@group(0) @binding(21) var normal_prepass_texture: texture_2d<f32>;
|
||||
#endif // NORMAL_PREPASS
|
||||
#ifdef MOTION_VECTOR_PREPASS
|
||||
@group(0) @binding(30) var motion_vector_prepass_texture: texture_2d<f32>;
|
||||
@group(0) @binding(22) var motion_vector_prepass_texture: texture_2d<f32>;
|
||||
#endif // MOTION_VECTOR_PREPASS
|
||||
|
||||
#endif // MULTISAMPLED
|
||||
|
||||
#ifdef DEFERRED_PREPASS
|
||||
@group(0) @binding(31) var deferred_prepass_texture: texture_2d<u32>;
|
||||
@group(0) @binding(23) var deferred_prepass_texture: texture_2d<u32>;
|
||||
#endif // DEFERRED_PREPASS
|
||||
|
||||
@group(0) @binding(32) var view_transmission_texture: texture_2d<f32>;
|
||||
@group(0) @binding(33) var view_transmission_sampler: sampler;
|
||||
@group(0) @binding(24) var view_transmission_texture: texture_2d<f32>;
|
||||
@group(0) @binding(25) var view_transmission_sampler: sampler;
|
||||
|
||||
#ifdef OIT_ENABLED
|
||||
@group(0) @binding(34) var<storage, read_write> oit_layers: array<vec2<u32>>;
|
||||
@group(0) @binding(35) var<storage, read_write> oit_layer_ids: array<atomic<i32>>;
|
||||
@group(0) @binding(36) var<uniform> oit_settings: types::OrderIndependentTransparencySettings;
|
||||
@group(0) @binding(26) var<storage, read_write> oit_layers: array<vec2<u32>>;
|
||||
@group(0) @binding(27) var<storage, read_write> oit_layer_ids: array<atomic<i32>>;
|
||||
@group(0) @binding(28) var<uniform> oit_settings: types::OrderIndependentTransparencySettings;
|
||||
#endif // OIT_ENABLED
|
||||
|
||||
#ifdef MULTIPLE_LIGHT_PROBES_IN_ARRAY
|
||||
@group(1) @binding(0) var diffuse_environment_maps: binding_array<texture_cube<f32>, 8u>;
|
||||
@group(1) @binding(1) var specular_environment_maps: binding_array<texture_cube<f32>, 8u>;
|
||||
#else
|
||||
@group(1) @binding(0) var diffuse_environment_map: texture_cube<f32>;
|
||||
@group(1) @binding(1) var specular_environment_map: texture_cube<f32>;
|
||||
#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<texture_3d<f32>, 8u>;
|
||||
#else
|
||||
@group(1) @binding(3) var irradiance_volume: texture_3d<f32>;
|
||||
#endif
|
||||
@group(1) @binding(4) var irradiance_volume_sampler: sampler;
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTERED_DECALS_ARE_USABLE
|
||||
@group(1) @binding(5) var<storage> clustered_decals: types::ClusteredDecals;
|
||||
@group(1) @binding(6) var clustered_decal_textures: binding_array<texture_2d<f32>, 8u>;
|
||||
@group(1) @binding(7) var clustered_decal_sampler: sampler;
|
||||
#endif // CLUSTERED_DECALS_ARE_USABLE
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
#import bevy_pbr::mesh_types::MorphWeights;
|
||||
|
||||
@group(1) @binding(2) var<uniform> morph_weights: MorphWeights;
|
||||
@group(1) @binding(3) var morph_targets: texture_3d<f32>;
|
||||
@group(1) @binding(7) var<uniform> prev_morph_weights: MorphWeights;
|
||||
@group(2) @binding(2) var<uniform> morph_weights: MorphWeights;
|
||||
@group(2) @binding(3) var morph_targets: texture_3d<f32>;
|
||||
@group(2) @binding(7) var<uniform> prev_morph_weights: MorphWeights;
|
||||
|
||||
// NOTE: Those are the "hardcoded" values found in `MorphAttributes` struct
|
||||
// in crates/bevy_render/src/mesh/morph/visitors.rs
|
||||
|
@ -37,53 +37,53 @@ struct StandardMaterialBindings {
|
||||
specular_tint_sampler: u32, // 30
|
||||
}
|
||||
|
||||
@group(2) @binding(0) var<storage> material_indices: array<StandardMaterialBindings>;
|
||||
@group(2) @binding(10) var<storage> material_array: array<StandardMaterial>;
|
||||
@group(3) @binding(0) var<storage> material_indices: array<StandardMaterialBindings>;
|
||||
@group(3) @binding(10) var<storage> material_array: array<StandardMaterial>;
|
||||
|
||||
#else // BINDLESS
|
||||
|
||||
@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;
|
||||
@group(3) @binding(0) var<uniform> material: StandardMaterial;
|
||||
@group(3) @binding(1) var base_color_texture: texture_2d<f32>;
|
||||
@group(3) @binding(2) var base_color_sampler: sampler;
|
||||
@group(3) @binding(3) var emissive_texture: texture_2d<f32>;
|
||||
@group(3) @binding(4) var emissive_sampler: sampler;
|
||||
@group(3) @binding(5) var metallic_roughness_texture: texture_2d<f32>;
|
||||
@group(3) @binding(6) var metallic_roughness_sampler: sampler;
|
||||
@group(3) @binding(7) var occlusion_texture: texture_2d<f32>;
|
||||
@group(3) @binding(8) var occlusion_sampler: sampler;
|
||||
@group(3) @binding(9) var normal_map_texture: texture_2d<f32>;
|
||||
@group(3) @binding(10) var normal_map_sampler: sampler;
|
||||
@group(3) @binding(11) var depth_map_texture: texture_2d<f32>;
|
||||
@group(3) @binding(12) var depth_map_sampler: sampler;
|
||||
|
||||
#ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED
|
||||
@group(2) @binding(13) var anisotropy_texture: texture_2d<f32>;
|
||||
@group(2) @binding(14) var anisotropy_sampler: sampler;
|
||||
@group(3) @binding(13) var anisotropy_texture: texture_2d<f32>;
|
||||
@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<f32>;
|
||||
@group(2) @binding(16) var specular_transmission_sampler: sampler;
|
||||
@group(2) @binding(17) var thickness_texture: texture_2d<f32>;
|
||||
@group(2) @binding(18) var thickness_sampler: sampler;
|
||||
@group(2) @binding(19) var diffuse_transmission_texture: texture_2d<f32>;
|
||||
@group(2) @binding(20) var diffuse_transmission_sampler: sampler;
|
||||
@group(3) @binding(15) var specular_transmission_texture: texture_2d<f32>;
|
||||
@group(3) @binding(16) var specular_transmission_sampler: sampler;
|
||||
@group(3) @binding(17) var thickness_texture: texture_2d<f32>;
|
||||
@group(3) @binding(18) var thickness_sampler: sampler;
|
||||
@group(3) @binding(19) var diffuse_transmission_texture: texture_2d<f32>;
|
||||
@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<f32>;
|
||||
@group(2) @binding(22) var clearcoat_sampler: sampler;
|
||||
@group(2) @binding(23) var clearcoat_roughness_texture: texture_2d<f32>;
|
||||
@group(2) @binding(24) var clearcoat_roughness_sampler: sampler;
|
||||
@group(2) @binding(25) var clearcoat_normal_texture: texture_2d<f32>;
|
||||
@group(2) @binding(26) var clearcoat_normal_sampler: sampler;
|
||||
@group(3) @binding(21) var clearcoat_texture: texture_2d<f32>;
|
||||
@group(3) @binding(22) var clearcoat_sampler: sampler;
|
||||
@group(3) @binding(23) var clearcoat_roughness_texture: texture_2d<f32>;
|
||||
@group(3) @binding(24) var clearcoat_roughness_sampler: sampler;
|
||||
@group(3) @binding(25) var clearcoat_normal_texture: texture_2d<f32>;
|
||||
@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<f32>;
|
||||
@group(2) @binding(28) var specular_sampler: sampler;
|
||||
@group(2) @binding(29) var specular_tint_texture: texture_2d<f32>;
|
||||
@group(2) @binding(30) var specular_tint_sampler: sampler;
|
||||
@group(3) @binding(27) var specular_texture: texture_2d<f32>;
|
||||
@group(3) @binding(28) var specular_sampler: sampler;
|
||||
@group(3) @binding(29) var specular_tint_texture: texture_2d<f32>;
|
||||
@group(3) @binding(30) var specular_tint_sampler: sampler;
|
||||
#endif // PBR_SPECULAR_TEXTURES_SUPPORTED
|
||||
|
||||
#endif // BINDLESS
|
||||
|
@ -6,9 +6,9 @@
|
||||
#ifdef SKINNED
|
||||
|
||||
#ifdef SKINS_USE_UNIFORM_BUFFERS
|
||||
@group(1) @binding(1) var<uniform> joint_matrices: SkinnedMesh;
|
||||
@group(2) @binding(1) var<uniform> joint_matrices: SkinnedMesh;
|
||||
#else // SKINS_USE_UNIFORM_BUFFERS
|
||||
@group(1) @binding(1) var<storage> joint_matrices: array<mat4x4<f32>>;
|
||||
@group(2) @binding(1) var<storage> joint_matrices: array<mat4x4<f32>>;
|
||||
#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<uniform> prev_joint_matrices: SkinnedMesh;
|
||||
@group(2) @binding(6) var<uniform> prev_joint_matrices: SkinnedMesh;
|
||||
#else // SKINS_USE_UNIFORM_BUFFERS
|
||||
@group(1) @binding(6) var<storage> prev_joint_matrices: array<mat4x4<f32>>;
|
||||
@group(2) @binding(6) var<storage> prev_joint_matrices: array<mat4x4<f32>>;
|
||||
#endif // SKINS_USE_UNIFORM_BUFFERS
|
||||
|
||||
fn skin_model(
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
||||
|
@ -36,10 +36,10 @@
|
||||
#endif
|
||||
|
||||
// The texture representing the color framebuffer.
|
||||
@group(1) @binding(0) var color_texture: texture_2d<f32>;
|
||||
@group(2) @binding(0) var color_texture: texture_2d<f32>;
|
||||
|
||||
// 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`.
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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<P: PhaseItem> RenderCommand<P> for SetWireframe3dPushConstants {
|
||||
pub type DrawWireframe3d = (
|
||||
SetItemPipeline,
|
||||
SetMeshViewBindGroup<0>,
|
||||
SetMeshBindGroup<1>,
|
||||
SetMeshViewBindingArrayBindGroup<1>,
|
||||
SetMeshBindGroup<2>,
|
||||
SetWireframe3dPushConstants,
|
||||
DrawMesh,
|
||||
);
|
||||
|
@ -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 }
|
||||
|
||||
|
@ -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',
|
||||
|
@ -204,7 +204,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
|
||||
#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<TokenStream> {
|
||||
#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<TokenStream> {
|
||||
#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<TokenStream> {
|
||||
#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<TokenStream> {
|
||||
#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<TokenStream> {
|
||||
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();
|
||||
|
@ -16,22 +16,22 @@
|
||||
|
||||
// Binding 0 is the bindless index table.
|
||||
// Filtering samplers.
|
||||
@group(2) @binding(1) var bindless_samplers_filtering: binding_array<sampler>;
|
||||
@group(3) @binding(1) var bindless_samplers_filtering: binding_array<sampler>;
|
||||
// Non-filtering samplers (nearest neighbor).
|
||||
@group(2) @binding(2) var bindless_samplers_non_filtering: binding_array<sampler>;
|
||||
@group(3) @binding(2) var bindless_samplers_non_filtering: binding_array<sampler>;
|
||||
// Comparison samplers (typically for shadow mapping).
|
||||
@group(2) @binding(3) var bindless_samplers_comparison: binding_array<sampler>;
|
||||
@group(3) @binding(3) var bindless_samplers_comparison: binding_array<sampler>;
|
||||
// 1D textures.
|
||||
@group(2) @binding(4) var bindless_textures_1d: binding_array<texture_1d<f32>>;
|
||||
@group(3) @binding(4) var bindless_textures_1d: binding_array<texture_1d<f32>>;
|
||||
// 2D textures.
|
||||
@group(2) @binding(5) var bindless_textures_2d: binding_array<texture_2d<f32>>;
|
||||
@group(3) @binding(5) var bindless_textures_2d: binding_array<texture_2d<f32>>;
|
||||
// 2D array textures.
|
||||
@group(2) @binding(6) var bindless_textures_2d_array: binding_array<texture_2d_array<f32>>;
|
||||
@group(3) @binding(6) var bindless_textures_2d_array: binding_array<texture_2d_array<f32>>;
|
||||
// 3D textures.
|
||||
@group(2) @binding(7) var bindless_textures_3d: binding_array<texture_3d<f32>>;
|
||||
@group(3) @binding(7) var bindless_textures_3d: binding_array<texture_3d<f32>>;
|
||||
// Cubemap textures.
|
||||
@group(2) @binding(8) var bindless_textures_cube: binding_array<texture_cube<f32>>;
|
||||
@group(3) @binding(8) var bindless_textures_cube: binding_array<texture_cube<f32>>;
|
||||
// Cubemap array textures.
|
||||
@group(2) @binding(9) var bindless_textures_cube_array: binding_array<texture_cube_array<f32>>;
|
||||
@group(3) @binding(9) var bindless_textures_cube_array: binding_array<texture_cube_array<f32>>;
|
||||
|
||||
#endif // BINDLESS
|
||||
|
@ -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())
|
||||
|
@ -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 },
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -168,14 +168,16 @@ impl<P: PhaseItem> DrawFunctions<P> {
|
||||
/// ```
|
||||
/// # use bevy_render::render_phase::SetItemPipeline;
|
||||
/// # struct SetMeshViewBindGroup<const N: usize>;
|
||||
/// # struct SetMeshViewBindingArrayBindGroup<const N: usize>;
|
||||
/// # struct SetMeshBindGroup<const N: usize>;
|
||||
/// # struct SetMaterialBindGroup<M, const N: usize>(std::marker::PhantomData<M>);
|
||||
/// # struct DrawMesh;
|
||||
/// pub type DrawMaterial<M> = (
|
||||
/// SetItemPipeline,
|
||||
/// SetMeshViewBindGroup<0>,
|
||||
/// SetMeshBindGroup<1>,
|
||||
/// SetMaterialBindGroup<M, 2>,
|
||||
/// SetMeshViewBindingArrayBindGroup<1>,
|
||||
/// SetMeshBindGroup<2>,
|
||||
/// SetMaterialBindGroup<M, 3>,
|
||||
/// DrawMesh,
|
||||
/// );
|
||||
/// ```
|
||||
|
@ -133,12 +133,12 @@ impl Deref for BindGroup {
|
||||
/// In WGSL shaders, the binding would look like this:
|
||||
///
|
||||
/// ```wgsl
|
||||
/// @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> storage_buffer: array<f32>;
|
||||
/// @group(2) @binding(4) var<storage> raw_buffer: array<f32>;
|
||||
/// @group(2) @binding(5) var storage_texture: texture_storage_2d<rgba8unorm, read_write>;
|
||||
/// @group(3) @binding(0) var<uniform> color: vec4<f32>;
|
||||
/// @group(3) @binding(1) var color_texture: texture_2d<f32>;
|
||||
/// @group(3) @binding(2) var color_sampler: sampler;
|
||||
/// @group(3) @binding(3) var<storage> storage_buffer: array<f32>;
|
||||
/// @group(3) @binding(4) var<storage> raw_buffer: array<f32>;
|
||||
/// @group(3) @binding(5) var storage_texture: texture_storage_2d<rgba8unorm, read_write>;
|
||||
/// ```
|
||||
/// 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<uniform> material: CoolMaterial;
|
||||
/// @group(3) @binding(0) var<uniform> 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<storage> material_array: binding_array<StandardMaterial>;
|
||||
/// @group(3) @binding(10) var<storage> material_array: binding_array<StandardMaterial>;
|
||||
/// ```
|
||||
///
|
||||
/// 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<storage> material_array: array<StandardMaterial>;
|
||||
/// @group(3) @binding(10) var<storage> material_array: array<StandardMaterial>;
|
||||
/// ```
|
||||
///
|
||||
/// * 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<uniform> material: StandardMaterial;
|
||||
/// @group(3) @binding(0) var<uniform> material: StandardMaterial;
|
||||
/// ```
|
||||
///
|
||||
/// * For efficiency reasons, `data` is generally preferred over `uniform`
|
||||
|
@ -287,6 +287,12 @@ impl<'b> DynamicBindGroupEntries<'b> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
entries: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend_with_indices<const N: usize>(
|
||||
mut self,
|
||||
entries: impl IntoIndexedBindingArray<'b, N>,
|
||||
|
@ -334,6 +334,13 @@ impl DynamicBindGroupLayoutEntries {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(default_visibility: ShaderStages) -> Self {
|
||||
Self {
|
||||
default_visibility,
|
||||
entries: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extend_with_indices<const N: usize>(
|
||||
mut self,
|
||||
entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -243,35 +243,65 @@ pub fn create_bindless_bind_group_layout_entries(
|
||||
false,
|
||||
NonZeroU64::new(bindless_index_table_length as u64 * size_of::<u32>() 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,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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!(
|
||||
|
@ -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));
|
||||
|
@ -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<PollStatus, PollError> {
|
||||
self.device.poll(maintain)
|
||||
}
|
||||
|
||||
|
@ -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<PathBuf>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ struct DirectionalLight {
|
||||
@group(0) @binding(9) var<storage> light_sources: array<LightSource>;
|
||||
@group(0) @binding(10) var<storage> directional_lights: array<DirectionalLight>;
|
||||
|
||||
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<f32>) -> 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<f32>) -> ResolvedRayHitFull {
|
||||
|
@ -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"] }
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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,
|
||||
);
|
||||
|
||||
|
@ -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![],
|
||||
|
@ -163,7 +163,7 @@ impl AsBindGroup for BindlessMaterial {
|
||||
(
|
||||
// Screen texture
|
||||
//
|
||||
// @group(2) @binding(0) var textures: binding_array<texture_2d<f32>>;
|
||||
// @group(3) @binding(0) var textures: binding_array<texture_2d<f32>>;
|
||||
(
|
||||
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:
|
||||
|
22
release-content/migration-guides/wgpu_25.md
Normal file
22
release-content/migration-guides/wgpu_25.md
Normal file
@ -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).
|
Loading…
Reference in New Issue
Block a user