mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
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 https://github.com/bevyengine/bevy/issues/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.
This commit is contained in:
parent
9bad607df9
commit
55493a823e
1 changed files with 55 additions and 40 deletions
|
@ -43,7 +43,8 @@ impl Plugin for WindowRenderPlugin {
|
|||
.init_resource::<ExtractedWindows>()
|
||||
.init_resource::<WindowSurfaces>()
|
||||
.add_systems(ExtractSchedule, extract_windows)
|
||||
.add_systems(Render, prepare_windows.in_set(RenderSet::ManageViews));
|
||||
.add_systems(Render, prepare_windows.in_set(RenderSet::PrepareAssets))
|
||||
.add_systems(Render, create_surfaces.in_set(RenderSet::ManageViews));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,7 +214,7 @@ impl WindowSurfaces {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates and (re)configures window surfaces, and obtains a swapchain texture for rendering.
|
||||
/// (re)configures window surfaces, and obtains a swapchain texture for rendering.
|
||||
///
|
||||
/// NOTE: `get_current_texture` in `prepare_windows` can take a long time if the GPU workload is
|
||||
/// the performance bottleneck. This can be seen in profiles as multiple prepare-set systems all
|
||||
|
@ -236,55 +237,21 @@ impl WindowSurfaces {
|
|||
/// later.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn prepare_windows(
|
||||
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
|
||||
// which is necessary for some OS's
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: Option<NonSend<NonSendMarker>>,
|
||||
mut windows: ResMut<ExtractedWindows>,
|
||||
mut window_surfaces: ResMut<WindowSurfaces>,
|
||||
render_device: Res<RenderDevice>,
|
||||
render_instance: Res<RenderInstance>,
|
||||
render_adapter: Res<RenderAdapter>,
|
||||
screenshot_pipeline: Res<ScreenshotToScreenPipeline>,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<ScreenshotToScreenPipeline>>,
|
||||
mut msaa: ResMut<Msaa>,
|
||||
#[cfg(target_os = "linux")] render_instance: Res<RenderInstance>,
|
||||
) {
|
||||
for window in windows.windows.values_mut() {
|
||||
let window_surfaces = window_surfaces.deref_mut();
|
||||
let surface_data = window_surfaces
|
||||
.surfaces
|
||||
.entry(window.entity)
|
||||
.or_insert_with(|| {
|
||||
let surface_target = SurfaceTargetUnsafe::RawHandle {
|
||||
raw_display_handle: window.handle.display_handle,
|
||||
raw_window_handle: window.handle.window_handle,
|
||||
let Some(surface_data) = window_surfaces.surfaces.get(&window.entity) else {
|
||||
continue;
|
||||
};
|
||||
// SAFETY: The window handles in ExtractedWindows will always be valid objects to create surfaces on
|
||||
let surface = unsafe {
|
||||
// NOTE: On some OSes this MUST be called from the main thread.
|
||||
// As of wgpu 0.15, only fallible if the given window is a HTML canvas and obtaining a WebGPU or WebGL2 context fails.
|
||||
render_instance
|
||||
.create_surface_unsafe(surface_target)
|
||||
.expect("Failed to create wgpu surface")
|
||||
};
|
||||
let caps = surface.get_capabilities(&render_adapter);
|
||||
let formats = caps.formats;
|
||||
// For future HDR output support, we'll need to request a format that supports HDR,
|
||||
// but as of wgpu 0.15 that is not yet supported.
|
||||
// Prefer sRGB formats for surfaces, but fall back to first available format if no sRGB formats are available.
|
||||
let mut format = *formats.first().expect("No supported formats for surface");
|
||||
for available_format in formats {
|
||||
// Rgba8UnormSrgb and Bgra8UnormSrgb and the only sRGB formats wgpu exposes that we can use for surfaces.
|
||||
if available_format == TextureFormat::Rgba8UnormSrgb
|
||||
|| available_format == TextureFormat::Bgra8UnormSrgb
|
||||
{
|
||||
format = available_format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceData { surface, format }
|
||||
});
|
||||
|
||||
let surface_configuration = wgpu::SurfaceConfiguration {
|
||||
format: surface_data.format,
|
||||
|
@ -451,3 +418,51 @@ pub fn prepare_windows(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates window surfaces.
|
||||
pub fn create_surfaces(
|
||||
// By accessing a NonSend resource, we tell the scheduler to put this system on the main thread,
|
||||
// which is necessary for some OS's
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))] _marker: Option<NonSend<NonSendMarker>>,
|
||||
windows: Res<ExtractedWindows>,
|
||||
mut window_surfaces: ResMut<WindowSurfaces>,
|
||||
render_instance: Res<RenderInstance>,
|
||||
render_adapter: Res<RenderAdapter>,
|
||||
) {
|
||||
for window in windows.windows.values() {
|
||||
window_surfaces
|
||||
.surfaces
|
||||
.entry(window.entity)
|
||||
.or_insert_with(|| {
|
||||
let surface_target = SurfaceTargetUnsafe::RawHandle {
|
||||
raw_display_handle: window.handle.display_handle,
|
||||
raw_window_handle: window.handle.window_handle,
|
||||
};
|
||||
// SAFETY: The window handles in ExtractedWindows will always be valid objects to create surfaces on
|
||||
let surface = unsafe {
|
||||
// NOTE: On some OSes this MUST be called from the main thread.
|
||||
// As of wgpu 0.15, only fallible if the given window is a HTML canvas and obtaining a WebGPU or WebGL2 context fails.
|
||||
render_instance
|
||||
.create_surface_unsafe(surface_target)
|
||||
.expect("Failed to create wgpu surface")
|
||||
};
|
||||
let caps = surface.get_capabilities(&render_adapter);
|
||||
let formats = caps.formats;
|
||||
// For future HDR output support, we'll need to request a format that supports HDR,
|
||||
// but as of wgpu 0.15 that is not yet supported.
|
||||
// Prefer sRGB formats for surfaces, but fall back to first available format if no sRGB formats are available.
|
||||
let mut format = *formats.first().expect("No supported formats for surface");
|
||||
for available_format in formats {
|
||||
// Rgba8UnormSrgb and Bgra8UnormSrgb and the only sRGB formats wgpu exposes that we can use for surfaces.
|
||||
if available_format == TextureFormat::Rgba8UnormSrgb
|
||||
|| available_format == TextureFormat::Bgra8UnormSrgb
|
||||
{
|
||||
format = available_format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceData { surface, format }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue