mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
configure_surface needs to be on the main thread on iOS (#12055)
# Objective - Bevy fails to change screen orientation on iOS ``` Main Thread Checker: UI API called on a background thread: -[UIView layer] PID: 37669, TID: 13872050, Thread name: Compute Task Pool (1), Queue name: com.apple.root.default-qos.overcommit, QoS: 0 Backtrace: 4 bevy_mobile_example 0x0000000102cf92b8 _ZN60_$LT$$LP$$RP$$u20$as$u20$objc..message..MessageArguments$GT$6invoke17h8944e3d8ee34f15fE + 64 5 bevy_mobile_example 0x0000000102c46358 _ZN4objc7message8platform15send_unverified17h667844cebe2d7931E + 132 6 bevy_mobile_example 0x0000000102bcbd6c _ZN8wgpu_hal5metal7surface100_$LT$impl$u20$wgpu_hal..Surface$LT$wgpu_hal..metal..Api$GT$$u20$for$u20$wgpu_hal..metal..Surface$GT$9configure17h8a6af0f24cec1328E + 1548 7 bevy_mobile_example 0x000000010279be50 _ZN9wgpu_core6device6global52_$LT$impl$u20$wgpu_core..global..Global$LT$G$GT$$GT$17surface_configure17h52709bbb3b3f0ff1E + 2792 8 bevy_mobile_example 0x000000010287aacc _ZN84_$LT$wgpu..backend..wgpu_core..ContextWgpuCore$u20$as$u20$wgpu..context..Context$GT$17surface_configure17h54077b9f040286a4E + 508 9 bevy_mobile_example 0x00000001028904b4 _ZN47_$LT$T$u20$as$u20$wgpu..context..DynContext$GT$17surface_configure17hfd6a0ac5a67a8f02E + 256 10 bevy_mobile_example 0x00000001028a1870 _ZN4wgpu7Surface9configure17h97bf7dbd54220473E + 148 11 bevy_mobile_example 0x0000000101fdc7cc _ZN11bevy_render8renderer13render_device12RenderDevice17configure_surface17h6853eab840b53e07E + 56 12 bevy_mobile_example 0x000000010228eb64 _ZN11bevy_render4view6window15prepare_windows17hf6f8b3c93ba189b8E + 3248 13 bevy_mobile_example 0x0000000102169eb8 _ZN4core3ops8function5FnMut8call_mut17h53ae762930afec98E + 192 14 bevy_mobile_example 0x0000000101e46a80 _ZN4core3ops8function5impls79_$LT$impl$u20$core..ops..function..FnMut$LT$A$GT$$u20$for$u20$$RF$mut$u20$F$GT$8call_mut17h5789c37c5983ce4cE + 208 15 bevy_mobile_example 0x0000000101e936e4 _ZN152_$LT$Func$u20$as$u20$bevy_ecs..system..function_system..SystemParamFunction$LT$fn$LP$F0$C$F1$C$F2$C$F3$C$F4$C$F5$C$F6$C$F7$RP$$u20$.$GT$$u20$Out$GT$$GT$3run10call_inner17h4ea44d3456146151E + 220 16 bevy_mobile_example 0x0000000101e4683c _ZN152_$LT$Func$u20$as$u20$bevy_ecs..system..function_system..SystemParamFunction$LT$fn$LP$F0$C$F1$C$F2$C$F3$C$F4$C$F5$C$F6$C$F7$RP$$u20$.$GT$$u20$Out$GT$$GT$3run17h6515ba9e61bb4d59E + 204 17 bevy_mobile_example 0x0000000101e7f99c _ZN120_$LT$bevy_ecs..system..function_system..FunctionSystem$LT$Marker$C$F$GT$$u20$as$u20$bevy_ecs..system..system..System$GT$10run_unsafe17h78999ea2add1da26E + 212 18 bevy_mobile_example 0x0000000103b4ef60 _ZN8bevy_ecs8schedule8executor14multi_threaded21MultiThreadedExecutor17spawn_system_task28_$u7b$$u7b$closure$u7d$$u7d$28_$u7b$$u7b$closure$u7d$$u7d$17hb2572f7968d8618eE + 48 19 bevy_mobile_example 0x0000000103b5bc9c _ZN4core3ops8function6FnOnce9call_once17h4cfa9d5c488566d4E + 16 20 bevy_mobile_example 0x0000000103b2d58c _ZN115_$LT$core..panic..unwind_safe..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$9call_once17he61d5557ff370a2cE + 40 21 bevy_mobile_example 0x0000000103b34548 _ZN3std9panicking3try7do_call17hb9ad087e1a06eb39E + 72 22 bevy_mobile_example 0x0000000103b351bc __rust_try + 32 23 bevy_mobile_example 0x0000000103b33a30 _ZN3std9panicking3try17hdebf82084f4342b0E + 76 24 bevy_mobile_example 0x0000000103c4aedc _ZN3std5panic12catch_unwind17h7e60b22a0a18032eE + 12 25 bevy_mobile_example 0x0000000103b4ea78 _ZN8bevy_ecs8schedule8executor14multi_threaded21MultiThreadedExecutor17spawn_system_task28_$u7b$$u7b$closure$u7d$$u7d$17h1af950387501b795E + 148 26 bevy_mobile_example 0x0000000103b2cfa0 _ZN100_$LT$core..panic..unwind_safe..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..future..future..Future$GT$4poll17h1258e4bf3dbe2fd8E + 48 ``` ## Solution - run surface configuration on the main thread on iOS ## Migration Guide System `need_new_surfaces` has been renamed `need_surface_configuration` and now also configure the surfaces on window creation or resizing
This commit is contained in:
parent
b8c58dedd9
commit
7caa026806
1 changed files with 76 additions and 49 deletions
|
@ -17,7 +17,8 @@ use std::{
|
||||||
sync::PoisonError,
|
sync::PoisonError,
|
||||||
};
|
};
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
BufferUsages, SurfaceTargetUnsafe, TextureFormat, TextureUsages, TextureViewDescriptor,
|
BufferUsages, SurfaceConfiguration, SurfaceTargetUnsafe, TextureFormat, TextureUsages,
|
||||||
|
TextureViewDescriptor,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod screenshot;
|
pub mod screenshot;
|
||||||
|
@ -42,7 +43,7 @@ impl Plugin for WindowRenderPlugin {
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Render,
|
Render,
|
||||||
create_surfaces
|
create_surfaces
|
||||||
.run_if(need_new_surfaces)
|
.run_if(need_surface_configuration)
|
||||||
.before(prepare_windows),
|
.before(prepare_windows),
|
||||||
)
|
)
|
||||||
.add_systems(Render, prepare_windows.in_set(RenderSet::ManageViews));
|
.add_systems(Render, prepare_windows.in_set(RenderSet::ManageViews));
|
||||||
|
@ -198,7 +199,7 @@ fn extract_windows(
|
||||||
struct SurfaceData {
|
struct SurfaceData {
|
||||||
// TODO: what lifetime should this be?
|
// TODO: what lifetime should this be?
|
||||||
surface: wgpu::Surface<'static>,
|
surface: wgpu::Surface<'static>,
|
||||||
format: TextureFormat,
|
configuration: SurfaceConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
|
@ -254,45 +255,12 @@ pub fn prepare_windows(
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let surface_configuration = wgpu::SurfaceConfiguration {
|
|
||||||
format: surface_data.format,
|
|
||||||
width: window.physical_width,
|
|
||||||
height: window.physical_height,
|
|
||||||
usage: TextureUsages::RENDER_ATTACHMENT,
|
|
||||||
present_mode: match window.present_mode {
|
|
||||||
PresentMode::Fifo => wgpu::PresentMode::Fifo,
|
|
||||||
PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed,
|
|
||||||
PresentMode::Mailbox => wgpu::PresentMode::Mailbox,
|
|
||||||
PresentMode::Immediate => wgpu::PresentMode::Immediate,
|
|
||||||
PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync,
|
|
||||||
PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync,
|
|
||||||
},
|
|
||||||
// TODO: Expose this as a setting somewhere
|
|
||||||
// 2 is wgpu's default/what we've been using so far.
|
|
||||||
// 1 is the minimum, but may cause lower framerates due to the cpu waiting for the gpu to finish
|
|
||||||
// all work for the previous frame before starting work on the next frame, which then means the gpu
|
|
||||||
// has to wait for the cpu to finish to start on the next frame.
|
|
||||||
desired_maximum_frame_latency: 2,
|
|
||||||
alpha_mode: match window.alpha_mode {
|
|
||||||
CompositeAlphaMode::Auto => wgpu::CompositeAlphaMode::Auto,
|
|
||||||
CompositeAlphaMode::Opaque => wgpu::CompositeAlphaMode::Opaque,
|
|
||||||
CompositeAlphaMode::PreMultiplied => wgpu::CompositeAlphaMode::PreMultiplied,
|
|
||||||
CompositeAlphaMode::PostMultiplied => wgpu::CompositeAlphaMode::PostMultiplied,
|
|
||||||
CompositeAlphaMode::Inherit => wgpu::CompositeAlphaMode::Inherit,
|
|
||||||
},
|
|
||||||
view_formats: if !surface_data.format.is_srgb() {
|
|
||||||
vec![surface_data.format.add_srgb_suffix()]
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is an ugly hack to work around drivers that don't support MSAA.
|
// This is an ugly hack to work around drivers that don't support MSAA.
|
||||||
// This should be removed once https://github.com/bevyengine/bevy/issues/7194 lands and we're doing proper
|
// This should be removed once https://github.com/bevyengine/bevy/issues/7194 lands and we're doing proper
|
||||||
// feature detection for MSAA.
|
// feature detection for MSAA.
|
||||||
// When removed, we can also remove the `.after(prepare_windows)` of `prepare_core_3d_depth_textures` and `prepare_prepass_textures`
|
// When removed, we can also remove the `.after(prepare_windows)` of `prepare_core_3d_depth_textures` and `prepare_prepass_textures`
|
||||||
let sample_flags = render_adapter
|
let sample_flags = render_adapter
|
||||||
.get_texture_format_features(surface_configuration.format)
|
.get_texture_format_features(surface_data.configuration.format)
|
||||||
.flags;
|
.flags;
|
||||||
|
|
||||||
if !sample_flags.sample_count_supported(msaa.samples()) {
|
if !sample_flags.sample_count_supported(msaa.samples()) {
|
||||||
|
@ -340,7 +308,6 @@ pub fn prepare_windows(
|
||||||
|
|
||||||
let surface = &surface_data.surface;
|
let surface = &surface_data.surface;
|
||||||
if not_already_configured || window.size_changed || window.present_mode_changed {
|
if not_already_configured || window.size_changed || window.present_mode_changed {
|
||||||
render_device.configure_surface(surface, &surface_configuration);
|
|
||||||
let frame = surface
|
let frame = surface
|
||||||
.get_current_texture()
|
.get_current_texture()
|
||||||
.expect("Error configuring surface");
|
.expect("Error configuring surface");
|
||||||
|
@ -351,7 +318,7 @@ pub fn prepare_windows(
|
||||||
window.set_swapchain_texture(frame);
|
window.set_swapchain_texture(frame);
|
||||||
}
|
}
|
||||||
Err(wgpu::SurfaceError::Outdated) => {
|
Err(wgpu::SurfaceError::Outdated) => {
|
||||||
render_device.configure_surface(surface, &surface_configuration);
|
render_device.configure_surface(surface, &surface_data.configuration);
|
||||||
let frame = surface
|
let frame = surface
|
||||||
.get_current_texture()
|
.get_current_texture()
|
||||||
.expect("Error reconfiguring surface");
|
.expect("Error reconfiguring surface");
|
||||||
|
@ -369,20 +336,20 @@ pub fn prepare_windows(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.swap_chain_texture_format = Some(surface_data.format);
|
window.swap_chain_texture_format = Some(surface_data.configuration.format);
|
||||||
|
|
||||||
if window.screenshot_func.is_some() {
|
if window.screenshot_func.is_some() {
|
||||||
let texture = render_device.create_texture(&wgpu::TextureDescriptor {
|
let texture = render_device.create_texture(&wgpu::TextureDescriptor {
|
||||||
label: Some("screenshot-capture-rendertarget"),
|
label: Some("screenshot-capture-rendertarget"),
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
width: surface_configuration.width,
|
width: surface_data.configuration.width,
|
||||||
height: surface_configuration.height,
|
height: surface_data.configuration.height,
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
},
|
},
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: surface_configuration.format.add_srgb_suffix(),
|
format: surface_data.configuration.format.add_srgb_suffix(),
|
||||||
usage: TextureUsages::RENDER_ATTACHMENT
|
usage: TextureUsages::RENDER_ATTACHMENT
|
||||||
| TextureUsages::COPY_SRC
|
| TextureUsages::COPY_SRC
|
||||||
| TextureUsages::TEXTURE_BINDING,
|
| TextureUsages::TEXTURE_BINDING,
|
||||||
|
@ -394,7 +361,7 @@ pub fn prepare_windows(
|
||||||
size: screenshot::get_aligned_size(
|
size: screenshot::get_aligned_size(
|
||||||
window.physical_width,
|
window.physical_width,
|
||||||
window.physical_height,
|
window.physical_height,
|
||||||
surface_data.format.pixel_size() as u32,
|
surface_data.configuration.format.pixel_size() as u32,
|
||||||
) as u64,
|
) as u64,
|
||||||
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
|
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
|
@ -407,7 +374,7 @@ pub fn prepare_windows(
|
||||||
let pipeline_id = pipelines.specialize(
|
let pipeline_id = pipelines.specialize(
|
||||||
&pipeline_cache,
|
&pipeline_cache,
|
||||||
&screenshot_pipeline,
|
&screenshot_pipeline,
|
||||||
surface_configuration.format,
|
surface_data.configuration.format,
|
||||||
);
|
);
|
||||||
window.swap_chain_texture_view = Some(texture_view);
|
window.swap_chain_texture_view = Some(texture_view);
|
||||||
window.screenshot_memory = Some(ScreenshotPreparedState {
|
window.screenshot_memory = Some(ScreenshotPreparedState {
|
||||||
|
@ -420,12 +387,15 @@ pub fn prepare_windows(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn need_new_surfaces(
|
pub fn need_surface_configuration(
|
||||||
windows: Res<ExtractedWindows>,
|
windows: Res<ExtractedWindows>,
|
||||||
window_surfaces: Res<WindowSurfaces>,
|
window_surfaces: Res<WindowSurfaces>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
for window in windows.windows.values() {
|
for window in windows.windows.values() {
|
||||||
if !window_surfaces.configured_windows.contains(&window.entity) {
|
if !window_surfaces.configured_windows.contains(&window.entity)
|
||||||
|
|| window.size_changed
|
||||||
|
|| window.present_mode_changed
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,9 +413,10 @@ pub fn create_surfaces(
|
||||||
mut window_surfaces: ResMut<WindowSurfaces>,
|
mut window_surfaces: ResMut<WindowSurfaces>,
|
||||||
render_instance: Res<RenderInstance>,
|
render_instance: Res<RenderInstance>,
|
||||||
render_adapter: Res<RenderAdapter>,
|
render_adapter: Res<RenderAdapter>,
|
||||||
|
render_device: Res<RenderDevice>,
|
||||||
) {
|
) {
|
||||||
for window in windows.windows.values() {
|
for window in windows.windows.values() {
|
||||||
window_surfaces
|
let data = window_surfaces
|
||||||
.surfaces
|
.surfaces
|
||||||
.entry(window.entity)
|
.entry(window.entity)
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
|
@ -477,7 +448,63 @@ pub fn create_surfaces(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceData { surface, format }
|
let configuration = wgpu::SurfaceConfiguration {
|
||||||
|
format,
|
||||||
|
width: window.physical_width,
|
||||||
|
height: window.physical_height,
|
||||||
|
usage: TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
present_mode: match window.present_mode {
|
||||||
|
PresentMode::Fifo => wgpu::PresentMode::Fifo,
|
||||||
|
PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed,
|
||||||
|
PresentMode::Mailbox => wgpu::PresentMode::Mailbox,
|
||||||
|
PresentMode::Immediate => wgpu::PresentMode::Immediate,
|
||||||
|
PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync,
|
||||||
|
PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync,
|
||||||
|
},
|
||||||
|
// TODO: Expose this as a setting somewhere
|
||||||
|
// 2 is wgpu's default/what we've been using so far.
|
||||||
|
// 1 is the minimum, but may cause lower framerates due to the cpu waiting for the gpu to finish
|
||||||
|
// all work for the previous frame before starting work on the next frame, which then means the gpu
|
||||||
|
// has to wait for the cpu to finish to start on the next frame.
|
||||||
|
desired_maximum_frame_latency: 2,
|
||||||
|
alpha_mode: match window.alpha_mode {
|
||||||
|
CompositeAlphaMode::Auto => wgpu::CompositeAlphaMode::Auto,
|
||||||
|
CompositeAlphaMode::Opaque => wgpu::CompositeAlphaMode::Opaque,
|
||||||
|
CompositeAlphaMode::PreMultiplied => {
|
||||||
|
wgpu::CompositeAlphaMode::PreMultiplied
|
||||||
|
}
|
||||||
|
CompositeAlphaMode::PostMultiplied => {
|
||||||
|
wgpu::CompositeAlphaMode::PostMultiplied
|
||||||
|
}
|
||||||
|
CompositeAlphaMode::Inherit => wgpu::CompositeAlphaMode::Inherit,
|
||||||
|
},
|
||||||
|
view_formats: if !format.is_srgb() {
|
||||||
|
vec![format.add_srgb_suffix()]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
render_device.configure_surface(&surface, &configuration);
|
||||||
|
|
||||||
|
SurfaceData {
|
||||||
|
surface,
|
||||||
|
configuration,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if window.size_changed || window.present_mode_changed {
|
||||||
|
data.configuration.width = window.physical_width;
|
||||||
|
data.configuration.height = window.physical_height;
|
||||||
|
data.configuration.present_mode = match window.present_mode {
|
||||||
|
PresentMode::Fifo => wgpu::PresentMode::Fifo,
|
||||||
|
PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed,
|
||||||
|
PresentMode::Mailbox => wgpu::PresentMode::Mailbox,
|
||||||
|
PresentMode::Immediate => wgpu::PresentMode::Immediate,
|
||||||
|
PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync,
|
||||||
|
PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync,
|
||||||
|
};
|
||||||
|
render_device.configure_surface(&data.surface, &data.configuration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue