Skip to content

Commit 55493a8

Browse files
authored
Allow prepare_windows to run off main thread on all platforms (#11672)
# Objective - Allow prepare windows to run off of the main thread on all platforms. - Fixes #9964 on all platforms. ## Solution - Running `prepare_windows` on the main thread on apple platforms is only mandatory to create surface, which is only needed during window creation. Split that part into its own system that happens before `prepare_windows` - Tested on macOS and iOS --- ## Changelog - Allow prepare windows to run off main thread on all platforms.
1 parent 9bad607 commit 55493a8

File tree

1 file changed

+55
-40
lines changed
  • crates/bevy_render/src/view/window

1 file changed

+55
-40
lines changed

crates/bevy_render/src/view/window/mod.rs

+55-40
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ impl Plugin for WindowRenderPlugin {
4343
.init_resource::<ExtractedWindows>()
4444
.init_resource::<WindowSurfaces>()
4545
.add_systems(ExtractSchedule, extract_windows)
46-
.add_systems(Render, prepare_windows.in_set(RenderSet::ManageViews));
46+
.add_systems(Render, prepare_windows.in_set(RenderSet::PrepareAssets))
47+
.add_systems(Render, create_surfaces.in_set(RenderSet::ManageViews));
4748
}
4849
}
4950

@@ -213,7 +214,7 @@ impl WindowSurfaces {
213214
}
214215
}
215216

216-
/// Creates and (re)configures window surfaces, and obtains a swapchain texture for rendering.
217+
/// (re)configures window surfaces, and obtains a swapchain texture for rendering.
217218
///
218219
/// NOTE: `get_current_texture` in `prepare_windows` can take a long time if the GPU workload is
219220
/// the performance bottleneck. This can be seen in profiles as multiple prepare-set systems all
@@ -236,55 +237,21 @@ impl WindowSurfaces {
236237
/// later.
237238
#[allow(clippy::too_many_arguments)]
238239
pub fn prepare_windows(
239-
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
240-
// which is necessary for some OS's
241-
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: Option<NonSend<NonSendMarker>>,
242240
mut windows: ResMut<ExtractedWindows>,
243241
mut window_surfaces: ResMut<WindowSurfaces>,
244242
render_device: Res<RenderDevice>,
245-
render_instance: Res<RenderInstance>,
246243
render_adapter: Res<RenderAdapter>,
247244
screenshot_pipeline: Res<ScreenshotToScreenPipeline>,
248245
pipeline_cache: Res<PipelineCache>,
249246
mut pipelines: ResMut<SpecializedRenderPipelines<ScreenshotToScreenPipeline>>,
250247
mut msaa: ResMut<Msaa>,
248+
#[cfg(target_os = "linux")] render_instance: Res<RenderInstance>,
251249
) {
252250
for window in windows.windows.values_mut() {
253251
let window_surfaces = window_surfaces.deref_mut();
254-
let surface_data = window_surfaces
255-
.surfaces
256-
.entry(window.entity)
257-
.or_insert_with(|| {
258-
let surface_target = SurfaceTargetUnsafe::RawHandle {
259-
raw_display_handle: window.handle.display_handle,
260-
raw_window_handle: window.handle.window_handle,
261-
};
262-
// SAFETY: The window handles in ExtractedWindows will always be valid objects to create surfaces on
263-
let surface = unsafe {
264-
// NOTE: On some OSes this MUST be called from the main thread.
265-
// As of wgpu 0.15, only fallible if the given window is a HTML canvas and obtaining a WebGPU or WebGL2 context fails.
266-
render_instance
267-
.create_surface_unsafe(surface_target)
268-
.expect("Failed to create wgpu surface")
269-
};
270-
let caps = surface.get_capabilities(&render_adapter);
271-
let formats = caps.formats;
272-
// For future HDR output support, we'll need to request a format that supports HDR,
273-
// but as of wgpu 0.15 that is not yet supported.
274-
// Prefer sRGB formats for surfaces, but fall back to first available format if no sRGB formats are available.
275-
let mut format = *formats.first().expect("No supported formats for surface");
276-
for available_format in formats {
277-
// Rgba8UnormSrgb and Bgra8UnormSrgb and the only sRGB formats wgpu exposes that we can use for surfaces.
278-
if available_format == TextureFormat::Rgba8UnormSrgb
279-
|| available_format == TextureFormat::Bgra8UnormSrgb
280-
{
281-
format = available_format;
282-
break;
283-
}
284-
}
285-
286-
SurfaceData { surface, format }
287-
});
252+
let Some(surface_data) = window_surfaces.surfaces.get(&window.entity) else {
253+
continue;
254+
};
288255

289256
let surface_configuration = wgpu::SurfaceConfiguration {
290257
format: surface_data.format,
@@ -451,3 +418,51 @@ pub fn prepare_windows(
451418
}
452419
}
453420
}
421+
422+
/// Creates window surfaces.
423+
pub fn create_surfaces(
424+
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
425+
// which is necessary for some OS's
426+
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: Option<NonSend<NonSendMarker>>,
427+
windows: Res<ExtractedWindows>,
428+
mut window_surfaces: ResMut<WindowSurfaces>,
429+
render_instance: Res<RenderInstance>,
430+
render_adapter: Res<RenderAdapter>,
431+
) {
432+
for window in windows.windows.values() {
433+
window_surfaces
434+
.surfaces
435+
.entry(window.entity)
436+
.or_insert_with(|| {
437+
let surface_target = SurfaceTargetUnsafe::RawHandle {
438+
raw_display_handle: window.handle.display_handle,
439+
raw_window_handle: window.handle.window_handle,
440+
};
441+
// SAFETY: The window handles in ExtractedWindows will always be valid objects to create surfaces on
442+
let surface = unsafe {
443+
// NOTE: On some OSes this MUST be called from the main thread.
444+
// As of wgpu 0.15, only fallible if the given window is a HTML canvas and obtaining a WebGPU or WebGL2 context fails.
445+
render_instance
446+
.create_surface_unsafe(surface_target)
447+
.expect("Failed to create wgpu surface")
448+
};
449+
let caps = surface.get_capabilities(&render_adapter);
450+
let formats = caps.formats;
451+
// For future HDR output support, we'll need to request a format that supports HDR,
452+
// but as of wgpu 0.15 that is not yet supported.
453+
// Prefer sRGB formats for surfaces, but fall back to first available format if no sRGB formats are available.
454+
let mut format = *formats.first().expect("No supported formats for surface");
455+
for available_format in formats {
456+
// Rgba8UnormSrgb and Bgra8UnormSrgb and the only sRGB formats wgpu exposes that we can use for surfaces.
457+
if available_format == TextureFormat::Rgba8UnormSrgb
458+
|| available_format == TextureFormat::Bgra8UnormSrgb
459+
{
460+
format = available_format;
461+
break;
462+
}
463+
}
464+
465+
SurfaceData { surface, format }
466+
});
467+
}
468+
}

0 commit comments

Comments
 (0)