Skip to content

Commit 6fcf9a6

Browse files
beicausealice-i-cecilekfc35
authored
Create mesh view bind group layout on demand to remove unused bindings (#23982)
# Objective Fixes #23627. `MeshPipelineViewLayoutKey` uses too many bindings even if features like ssr, environment map are unused. ## Solution Don't pre-allocate every combination that grows exponentially. Instead, create mesh view bind group layout on demand so that we can add more view keys to reduce unused bindings. `MeshPipelineViewLayouts::get_view_layout` will be slower, but I'm not sure how slow it is. My feeling is that the overhead is not high, compared to when we clone it before. ## Testing ``` WGPU_SETTINGS_PRIO=webgl2 cargo r --example 3d_scene cargo r --example ssr --features bluenoise_texture cargo r --example ssao cargo r --example irradiance_volumes ``` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
1 parent b00ff93 commit 6fcf9a6

19 files changed

Lines changed: 623 additions & 693 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
title: Mesh view bind group layout is changed
3+
pull_requests: [23982]
4+
---
5+
6+
`MeshPipelineViewLayouts` no longer stores all possible view layouts. Now it only stores necessary parameters for creating bind group layouts on demand. And `MeshPipelineViewLayouts::get_view_layout` returns `MeshPipelineViewLayout`
7+
by value instead of by reference.
8+
9+
`generate_view_layouts` is removed and `layout_entries` is private now. Please use `MeshPipelineViewLayouts::get_view_layout`.
10+
11+
Mesh view bind group layout has more variants now and some dynamic uniforms such as distance fog, ssr, contact shadows,
12+
environment map are not guaranteed to exist. Please use `MeshViewBindGroup::main_offsets` to get the dynamic offsets.
13+
14+
Before:
15+
16+
```rust
17+
let mut offsets: SmallVec<[u32; 8]> = smallvec![
18+
view_uniform_offset.offset,
19+
view_lights_offset.offset,
20+
view_fog_offset.offset,
21+
**view_light_probes_offset,
22+
**view_ssr_offset,
23+
**view_contact_shadows_offset,
24+
**view_environment_map_offset,
25+
];
26+
if let Some(oit_settings_offset) = maybe_oit_settings_offset {
27+
offsets.push(oit_settings_offset.offset);
28+
}
29+
pass.set_bind_group(I, &mesh_view_bind_group.main, &offsets);
30+
```
31+
32+
After:
33+
34+
```rust
35+
pass.set_bind_group(
36+
I,
37+
&mesh_view_bind_group.main,
38+
&mesh_view_bind_group.main_offsets,
39+
);
40+
```

crates/bevy_dev_tools/src/render_debug.rs

Lines changed: 20 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use bevy_app::{App, Plugin};
44
use bevy_asset::{embedded_asset, AssetServer, Handle};
55
use bevy_core_pipeline::{
66
mip_generation::experimental::depth::ViewDepthPyramid,
7-
oit::OrderIndependentTransparencySettingsOffset,
87
schedule::{Core3d, Core3dSystems},
98
upscaling::upscaling,
109
FullscreenShader,
@@ -25,7 +24,6 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect};
2524
use bevy_render::{
2625
extract_component::{ExtractComponent, ExtractComponentPlugin},
2726
extract_resource::{ExtractResource, ExtractResourcePlugin},
28-
render_asset::RenderAssets,
2927
render_resource::{
3028
binding_types, BindGroupEntries, BindGroupLayout, BindGroupLayoutDescriptor,
3129
BindGroupLayoutEntries, CachedRenderPipelineId, ColorTargetState, ColorWrites,
@@ -35,18 +33,16 @@ use bevy_render::{
3533
TextureSampleType, VertexState,
3634
},
3735
renderer::{RenderContext, RenderDevice, RenderQueue, ViewQuery},
38-
texture::{FallbackImage, GpuImage},
39-
view::{Msaa, ViewTarget, ViewUniformOffset},
36+
texture::FallbackImage,
37+
view::{ExtractedView, ViewTarget},
4038
GpuResourceAppExt, Render, RenderApp, RenderStartup, RenderSystems,
4139
};
4240
use bevy_shader::Shader;
4341
use bevy_ui_render::render_pass::ui_pass;
4442

4543
use bevy_pbr::{
46-
Bluenoise, MeshPipelineSystems, MeshPipelineViewLayoutKey, MeshPipelineViewLayouts,
47-
MeshViewBindGroup, ViewContactShadowsUniformOffset, ViewEnvironmentMapUniformOffset,
48-
ViewFogUniformOffset, ViewLightProbesUniformOffset, ViewLightsUniformOffset,
49-
ViewScreenSpaceReflectionsUniformOffset,
44+
MeshPipelineSystems, MeshPipelineViewLayoutKey, MeshPipelineViewLayouts, MeshViewBindGroup,
45+
ViewKeyCache,
5046
};
5147

5248
/// Adds a rendering debug overlay to visualize various renderer buffers.
@@ -503,8 +499,7 @@ impl SpecializedRenderPipeline for RenderDebugOverlayPipeline {
503499
let mesh_view_layout_descriptor = self
504500
.mesh_view_layouts
505501
.get_view_layout(key.view_layout_key)
506-
.main_layout
507-
.clone();
502+
.main_layout;
508503

509504
RenderPipelineDescriptor {
510505
label: Some("debug_overlay_pipeline".into()),
@@ -535,48 +530,26 @@ impl SpecializedRenderPipeline for RenderDebugOverlayPipeline {
535530
fn prepare_debug_overlay_pipelines(
536531
mut commands: Commands,
537532
pipeline_cache: Res<PipelineCache>,
533+
view_key_cache: Res<ViewKeyCache>,
538534
mut pipelines: ResMut<SpecializedRenderPipelines<RenderDebugOverlayPipeline>>,
539535
pipeline: Res<RenderDebugOverlayPipeline>,
540-
images: Res<RenderAssets<GpuImage>>,
541-
blue_noise: Res<Bluenoise>,
542-
views: Query<(
543-
Entity,
544-
&ViewTarget,
545-
&RenderDebugOverlay,
546-
&Msaa,
547-
Option<&bevy_core_pipeline::prepass::ViewPrepassTextures>,
548-
Has<bevy_core_pipeline::oit::OrderIndependentTransparencySettings>,
549-
Has<bevy_pbr::ExtractedAtmosphere>,
550-
)>,
536+
views: Query<(Entity, &ExtractedView, &RenderDebugOverlay)>,
551537
) {
552-
for (entity, target, config, msaa, prepass_textures, has_oit, has_atmosphere) in &views {
538+
for (entity, view, config) in &views {
553539
if !config.enabled {
554540
continue;
555541
}
556-
557-
let mut view_layout_key = MeshPipelineViewLayoutKey::from(*msaa)
558-
| MeshPipelineViewLayoutKey::from(prepass_textures);
559-
560-
if has_oit {
561-
view_layout_key |= MeshPipelineViewLayoutKey::OIT_ENABLED;
562-
}
563-
if has_atmosphere {
564-
view_layout_key |= MeshPipelineViewLayoutKey::ATMOSPHERE;
565-
}
566-
567-
if let Some(gpu_image) = images.get(&blue_noise.texture)
568-
&& gpu_image.texture.depth_or_array_layers() > 1
569-
{
570-
view_layout_key |= MeshPipelineViewLayoutKey::STBN;
571-
}
542+
let Some(view_key) = view_key_cache.get(&view.retained_view_entity) else {
543+
continue;
544+
};
572545

573546
let pipeline_id = pipelines.specialize(
574547
&pipeline_cache,
575548
&pipeline,
576549
RenderDebugOverlayPipelineKey {
577550
mode: config.mode,
578-
view_layout_key,
579-
target_format: target.main_texture_format(),
551+
view_layout_key: (*view_key).into(),
552+
target_format: view.target_format,
580553
},
581554
);
582555

@@ -631,15 +604,6 @@ fn render_debug_overlay(
631604
&RenderDebugOverlayPipelineId,
632605
&RenderDebugOverlayUniformOffset,
633606
&MeshViewBindGroup,
634-
&ViewUniformOffset,
635-
&ViewLightsUniformOffset,
636-
&ViewFogUniformOffset,
637-
&ViewLightProbesUniformOffset,
638-
&ViewScreenSpaceReflectionsUniformOffset,
639-
&ViewContactShadowsUniformOffset,
640-
&ViewEnvironmentMapUniformOffset,
641-
Has<bevy_core_pipeline::oit::OrderIndependentTransparencySettings>,
642-
Option<&OrderIndependentTransparencySettingsOffset>,
643607
Option<&ViewDepthPyramid>,
644608
)>,
645609
pipeline_cache: Res<PipelineCache>,
@@ -648,23 +612,8 @@ fn render_debug_overlay(
648612
fallback_image: Res<FallbackImage>,
649613
mut ctx: RenderContext,
650614
) {
651-
let (
652-
target,
653-
config,
654-
pipeline_id,
655-
uniform_offset,
656-
mesh_view_bind_group,
657-
view_uniform_offset,
658-
view_lights_offset,
659-
view_fog_offset,
660-
view_light_probes_offset,
661-
view_ssr_offset,
662-
view_contact_shadows_offset,
663-
view_environment_map_offset,
664-
has_oit,
665-
view_oit_offset,
666-
depth_pyramid,
667-
) = view.into_inner();
615+
let (target, config, pipeline_id, uniform_offset, mesh_view_bind_group, depth_pyramid) =
616+
view.into_inner();
668617

669618
if !config.enabled {
670619
return;
@@ -719,20 +668,11 @@ fn render_debug_overlay(
719668

720669
render_pass.set_pipeline(pipeline);
721670

722-
let mut dynamic_offsets = vec![
723-
view_uniform_offset.offset,
724-
view_lights_offset.offset,
725-
view_fog_offset.offset,
726-
**view_light_probes_offset,
727-
**view_ssr_offset,
728-
**view_contact_shadows_offset,
729-
**view_environment_map_offset,
730-
];
731-
if has_oit && let Some(view_oit_offset) = view_oit_offset {
732-
dynamic_offsets.push(view_oit_offset.offset);
733-
}
734-
735-
render_pass.set_bind_group(0, &mesh_view_bind_group.main, &dynamic_offsets);
671+
render_pass.set_bind_group(
672+
0,
673+
&mesh_view_bind_group.main,
674+
&mesh_view_bind_group.main_offsets,
675+
);
736676
render_pass.set_bind_group(1, &debug_bind_group, &[uniform_offset.offset]);
737677

738678
render_pass.draw(0..3, 0..1);

crates/bevy_gizmos_render/src/pipeline_3d.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,7 @@ impl Specializer<RenderPipeline> for LineGizmoPipelineSpecializer {
136136
key: Self::Key,
137137
descriptor: &mut RenderPipelineDescriptor,
138138
) -> Result<Canonical<Self::Key>, BevyError> {
139-
let view_layout = self
140-
.mesh_pipeline
141-
.get_view_layout(key.view_key.into())
142-
.clone();
139+
let view_layout = self.mesh_pipeline.get_view_layout(key.view_key.into());
143140

144141
descriptor.set_layout(0, view_layout.main_layout.clone());
145142
descriptor.vertex.buffers = line_gizmo_vertex_buffer_layouts(key.strip);
@@ -207,10 +204,7 @@ impl SpecializedRenderPipeline for LineJointGizmoPipeline {
207204

208205
let format = key.view_key.target_format();
209206

210-
let view_layout = self
211-
.mesh_pipeline
212-
.get_view_layout(key.view_key.into())
213-
.clone();
207+
let view_layout = self.mesh_pipeline.get_view_layout(key.view_key.into());
214208
let layout = vec![view_layout.main_layout.clone(), self.uniform_layout.clone()];
215209

216210
if key.joints == GizmoLineJoint::None {

crates/bevy_pbr/src/contact_shadows.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use bevy_render::{
2020
view::ExtractedView,
2121
GpuResourceAppExt, Render, RenderApp, RenderSystems,
2222
};
23-
use bevy_utils::default;
2423

2524
/// Enables contact shadows for a camera.
2625
pub struct ContactShadowsPlugin;
@@ -59,7 +58,7 @@ impl Default for ContactShadows {
5958
}
6059

6160
/// A version of [`ContactShadows`] for upload to the GPU.
62-
#[derive(Clone, Copy, Component, ShaderType, Default)]
61+
#[derive(Clone, Copy, ShaderType, Default)]
6362
pub struct ContactShadowsUniform {
6463
pub linear_steps: u32,
6564
pub thickness: f32,
@@ -81,7 +80,7 @@ impl From<ContactShadows> for ContactShadowsUniform {
8180
}
8281

8382
impl SyncComponent for ContactShadows {
84-
type Target = Self;
83+
type Target = (Self, ViewContactShadowsUniformOffset);
8584
}
8685

8786
impl ExtractComponent for ContactShadows {
@@ -118,29 +117,25 @@ impl Plugin for ContactShadowsPlugin {
118117

119118
fn prepare_contact_shadows_settings(
120119
mut commands: Commands,
121-
views: Query<(Entity, Option<&ContactShadows>), With<ExtractedView>>,
120+
views: Query<(Entity, &ContactShadows), With<ExtractedView>>,
122121
mut contact_shadows_buffer: ResMut<ContactShadowsBuffer>,
123122
render_device: Res<RenderDevice>,
124123
render_queue: Res<RenderQueue>,
125124
) {
126-
contact_shadows_buffer.0.clear();
125+
let Some(mut writer) =
126+
contact_shadows_buffer
127+
.0
128+
.get_writer(views.iter().len(), &render_device, &render_queue)
129+
else {
130+
return;
131+
};
127132
for (entity, settings) in &views {
128-
let uniform = if let Some(settings) = settings {
129-
ContactShadowsUniform::from(*settings)
130-
} else {
131-
ContactShadowsUniform {
132-
linear_steps: 0,
133-
..default()
134-
}
135-
};
136-
let offset = contact_shadows_buffer.0.push(&uniform);
133+
let uniform = ContactShadowsUniform::from(*settings);
134+
let offset = writer.write(&uniform);
137135
commands
138136
.entity(entity)
139137
.insert(ViewContactShadowsUniformOffset(offset));
140138
}
141-
contact_shadows_buffer
142-
.0
143-
.write_buffer(&render_device, &render_queue);
144139
}
145140

146141
/// A component that stores the offset within the [`ContactShadowsBuffer`] for

0 commit comments

Comments
 (0)