Skip to content

Commit f969c62

Browse files
mockersfcart
andcommitted
Fix wasm examples (#4967)
# Objective Fix #4958 There was 4 issues: - this is not true in WASM and on macOS: https://github.com/bevyengine/bevy/blob/f28b92120920f387020f3b3e858f0e7039b9c07e/examples/3d/split_screen.rs#L90 - ~~I made sure the system was running at least once~~ - I'm sending the event on window creation - in webgl, setting a viewport has impacts on other render passes - only in webgl and when there is a custom viewport, I added a render pass without a custom viewport - shaderdef NO_ARRAY_TEXTURES_SUPPORT was not used by the 2d pipeline - webgl feature was used but not declared in bevy_sprite, I added it to the Cargo.toml - shaderdef NO_STORAGE_BUFFERS_SUPPORT was not used by the 2d pipeline - I added it based on the BufferBindingType The last commit changes the two last fixes to add the shaderdefs in the shader cache directly instead of needing to do it in each pipeline Co-authored-by: Carter Anderson <[email protected]>
1 parent 772d152 commit f969c62

File tree

9 files changed

+107
-59
lines changed

9 files changed

+107
-59
lines changed

crates/bevy_core_pipeline/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ keywords = ["bevy"]
1414

1515
[features]
1616
trace = []
17+
webgl = []
1718

1819
[dependencies]
1920
# bevy

crates/bevy_core_pipeline/src/core_2d/main_pass_2d_node.rs

+52-26
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use bevy_render::{
1111
renderer::RenderContext,
1212
view::{ExtractedView, ViewTarget},
1313
};
14+
#[cfg(feature = "trace")]
15+
use bevy_utils::tracing::info_span;
1416

1517
pub struct MainPass2dNode {
1618
query: QueryState<
@@ -57,37 +59,61 @@ impl Node for MainPass2dNode {
5759
// no target
5860
return Ok(());
5961
};
62+
{
63+
#[cfg(feature = "trace")]
64+
let _main_pass_2d = info_span!("main_pass_2d").entered();
65+
let pass_descriptor = RenderPassDescriptor {
66+
label: Some("main_pass_2d"),
67+
color_attachments: &[target.get_color_attachment(Operations {
68+
load: match camera_2d.clear_color {
69+
ClearColorConfig::Default => {
70+
LoadOp::Clear(world.resource::<ClearColor>().0.into())
71+
}
72+
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
73+
ClearColorConfig::None => LoadOp::Load,
74+
},
75+
store: true,
76+
})],
77+
depth_stencil_attachment: None,
78+
};
6079

61-
let pass_descriptor = RenderPassDescriptor {
62-
label: Some("main_pass_2d"),
63-
color_attachments: &[target.get_color_attachment(Operations {
64-
load: match camera_2d.clear_color {
65-
ClearColorConfig::Default => {
66-
LoadOp::Clear(world.resource::<ClearColor>().0.into())
67-
}
68-
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
69-
ClearColorConfig::None => LoadOp::Load,
70-
},
71-
store: true,
72-
})],
73-
depth_stencil_attachment: None,
74-
};
75-
76-
let draw_functions = world.resource::<DrawFunctions<Transparent2d>>();
80+
let draw_functions = world.resource::<DrawFunctions<Transparent2d>>();
7781

78-
let render_pass = render_context
79-
.command_encoder
80-
.begin_render_pass(&pass_descriptor);
82+
let render_pass = render_context
83+
.command_encoder
84+
.begin_render_pass(&pass_descriptor);
8185

82-
let mut draw_functions = draw_functions.write();
83-
let mut tracked_pass = TrackedRenderPass::new(render_pass);
84-
if let Some(viewport) = camera.viewport.as_ref() {
85-
tracked_pass.set_camera_viewport(viewport);
86+
let mut draw_functions = draw_functions.write();
87+
let mut tracked_pass = TrackedRenderPass::new(render_pass);
88+
if let Some(viewport) = camera.viewport.as_ref() {
89+
tracked_pass.set_camera_viewport(viewport);
90+
}
91+
for item in &transparent_phase.items {
92+
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
93+
draw_function.draw(world, &mut tracked_pass, view_entity, item);
94+
}
8695
}
87-
for item in &transparent_phase.items {
88-
let draw_function = draw_functions.get_mut(item.draw_function).unwrap();
89-
draw_function.draw(world, &mut tracked_pass, view_entity, item);
96+
97+
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
98+
// reset for the next render pass so add an empty render pass without a custom viewport
99+
#[cfg(feature = "webgl")]
100+
if camera.viewport.is_some() {
101+
#[cfg(feature = "trace")]
102+
let _reset_viewport_pass_2d = info_span!("reset_viewport_pass_2d").entered();
103+
let pass_descriptor = RenderPassDescriptor {
104+
label: Some("reset_viewport_pass_2d"),
105+
color_attachments: &[target.get_color_attachment(Operations {
106+
load: LoadOp::Load,
107+
store: true,
108+
})],
109+
depth_stencil_attachment: None,
110+
};
111+
112+
render_context
113+
.command_encoder
114+
.begin_render_pass(&pass_descriptor);
90115
}
116+
91117
Ok(())
92118
}
93119
}

crates/bevy_core_pipeline/src/core_3d/main_pass_3d_node.rs

+20
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,26 @@ impl Node for MainPass3dNode {
194194
}
195195
}
196196

197+
// WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't
198+
// reset for the next render pass so add an empty render pass without a custom viewport
199+
#[cfg(feature = "webgl")]
200+
if camera.viewport.is_some() {
201+
#[cfg(feature = "trace")]
202+
let _reset_viewport_pass_3d = info_span!("reset_viewport_pass_3d").entered();
203+
let pass_descriptor = RenderPassDescriptor {
204+
label: Some("reset_viewport_pass_3d"),
205+
color_attachments: &[target.get_color_attachment(Operations {
206+
load: LoadOp::Load,
207+
store: true,
208+
})],
209+
depth_stencil_attachment: None,
210+
};
211+
212+
render_context
213+
.command_encoder
214+
.begin_render_pass(&pass_descriptor);
215+
}
216+
197217
Ok(())
198218
}
199219
}

crates/bevy_internal/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ x11 = ["bevy_winit/x11"]
5555
subpixel_glyph_atlas = ["bevy_text/subpixel_glyph_atlas"]
5656

5757
# Optimise for WebGL2
58-
webgl = ["bevy_pbr/webgl", "bevy_render/webgl"]
58+
webgl = ["bevy_core_pipeline/webgl", "bevy_pbr/webgl", "bevy_render/webgl"]
5959

6060
# enable systems that allow for automated testing on CI
6161
bevy_ci_testing = ["bevy_app/bevy_ci_testing", "bevy_render/ci_limits"]

crates/bevy_pbr/src/render/light.rs

-12
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ pub struct ShadowPipeline {
212212
pub skinned_mesh_layout: BindGroupLayout,
213213
pub point_light_sampler: Sampler,
214214
pub directional_light_sampler: Sampler,
215-
pub clustered_forward_buffer_binding_type: BufferBindingType,
216215
}
217216

218217
// TODO: this pattern for initializing the shaders / pipeline isn't ideal. this should be handled by the asset system
@@ -221,9 +220,6 @@ impl FromWorld for ShadowPipeline {
221220
let world = world.cell();
222221
let render_device = world.resource::<RenderDevice>();
223222

224-
let clustered_forward_buffer_binding_type = render_device
225-
.get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT);
226-
227223
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
228224
entries: &[
229225
// View
@@ -268,7 +264,6 @@ impl FromWorld for ShadowPipeline {
268264
compare: Some(CompareFunction::GreaterEqual),
269265
..Default::default()
270266
}),
271-
clustered_forward_buffer_binding_type,
272267
}
273268
}
274269
}
@@ -330,13 +325,6 @@ impl SpecializedMeshPipeline for ShadowPipeline {
330325
bind_group_layout.push(self.mesh_layout.clone());
331326
}
332327

333-
if !matches!(
334-
self.clustered_forward_buffer_binding_type,
335-
BufferBindingType::Storage { .. }
336-
) {
337-
shader_defs.push(String::from("NO_STORAGE_BUFFERS_SUPPORT"));
338-
}
339-
340328
let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;
341329

342330
Ok(RenderPipelineDescriptor {

crates/bevy_pbr/src/render/mesh.rs

-15
Original file line numberDiff line numberDiff line change
@@ -582,18 +582,6 @@ impl SpecializedMeshPipeline for MeshPipeline {
582582
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(4));
583583
}
584584

585-
// TODO: consider exposing this in shaders in a more generally useful way, such as:
586-
// # if AVAILABLE_STORAGE_BUFFER_BINDINGS == 3
587-
// /* use storage buffers here */
588-
// # elif
589-
// /* use uniforms here */
590-
if !matches!(
591-
self.clustered_forward_buffer_binding_type,
592-
BufferBindingType::Storage { .. }
593-
) {
594-
shader_defs.push(String::from("NO_STORAGE_BUFFERS_SUPPORT"));
595-
}
596-
597585
let mut bind_group_layout = vec![self.view_layout.clone()];
598586
if layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
599587
&& layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
@@ -624,9 +612,6 @@ impl SpecializedMeshPipeline for MeshPipeline {
624612
depth_write_enabled = true;
625613
}
626614

627-
#[cfg(feature = "webgl")]
628-
shader_defs.push(String::from("NO_ARRAY_TEXTURES_SUPPORT"));
629-
630615
Ok(RenderPipelineDescriptor {
631616
vertex: VertexState {
632617
shader: MESH_SHADER_HANDLE.typed::<Shader>(),

crates/bevy_render/src/render_resource/pipeline_cache.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ use bevy_ecs::system::{Res, ResMut};
1515
use bevy_utils::{default, tracing::error, Entry, HashMap, HashSet};
1616
use std::{hash::Hash, iter::FusedIterator, mem, ops::Deref, sync::Arc};
1717
use thiserror::Error;
18-
use wgpu::{PipelineLayoutDescriptor, ShaderModule, VertexBufferLayout as RawVertexBufferLayout};
18+
use wgpu::{
19+
BufferBindingType, PipelineLayoutDescriptor, ShaderModule,
20+
VertexBufferLayout as RawVertexBufferLayout,
21+
};
1922

2023
enum PipelineDescriptor {
2124
RenderPipelineDescriptor(Box<RenderPipelineDescriptor>),
@@ -117,9 +120,26 @@ impl ShaderCache {
117120
let module = match data.processed_shaders.entry(shader_defs.to_vec()) {
118121
Entry::Occupied(entry) => entry.into_mut(),
119122
Entry::Vacant(entry) => {
123+
let mut shader_defs = shader_defs.to_vec();
124+
#[cfg(feature = "webgl")]
125+
shader_defs.push(String::from("NO_ARRAY_TEXTURES_SUPPORT"));
126+
127+
// TODO: 3 is the value from CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT declared in bevy_pbr
128+
// consider exposing this in shaders in a more generally useful way, such as:
129+
// # if AVAILABLE_STORAGE_BUFFER_BINDINGS == 3
130+
// /* use storage buffers here */
131+
// # elif
132+
// /* use uniforms here */
133+
if !matches!(
134+
render_device.get_supported_read_only_binding_type(3),
135+
BufferBindingType::Storage { .. }
136+
) {
137+
shader_defs.push(String::from("NO_STORAGE_BUFFERS_SUPPORT"));
138+
}
139+
120140
let processed = self.processor.process(
121141
shader,
122-
shader_defs,
142+
&shader_defs,
123143
&self.shaders,
124144
&self.import_path_shaders,
125145
)?;

crates/bevy_sprite/src/mesh2d/mesh.rs

-3
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,6 @@ impl SpecializedMeshPipeline for Mesh2dPipeline {
323323
vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(4));
324324
}
325325

326-
#[cfg(feature = "webgl")]
327-
shader_defs.push(String::from("NO_ARRAY_TEXTURES_SUPPORT"));
328-
329326
let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;
330327

331328
Ok(RenderPipelineDescriptor {

crates/bevy_winit/src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -637,12 +637,23 @@ fn handle_create_window_events(
637637
let mut windows = world.resource_mut::<Windows>();
638638
let create_window_events = world.resource::<Events<CreateWindow>>();
639639
let mut window_created_events = world.resource_mut::<Events<WindowCreated>>();
640+
#[cfg(not(any(target_os = "windows", target_feature = "x11")))]
641+
let mut window_resized_events = world.resource_mut::<Events<WindowResized>>();
640642
for create_window_event in create_window_event_reader.iter(&create_window_events) {
641643
let window = winit_windows.create_window(
642644
event_loop,
643645
create_window_event.id,
644646
&create_window_event.descriptor,
645647
);
648+
// This event is already sent on windows, x11, and xwayland.
649+
// TODO: we aren't yet sure about native wayland, so we might be able to exclude it,
650+
// but sending a duplicate event isn't problematic, as windows already does this.
651+
#[cfg(not(any(target_os = "windows", target_feature = "x11")))]
652+
window_resized_events.send(WindowResized {
653+
id: create_window_event.id,
654+
width: window.width(),
655+
height: window.height(),
656+
});
646657
windows.add(window);
647658
window_created_events.send(WindowCreated {
648659
id: create_window_event.id,

0 commit comments

Comments
 (0)