Skip to content

Commit

Permalink
configure_surface needs to be on the main thread on iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
mockersf committed Feb 27, 2024
1 parent 2fbb4c6 commit bb815fa
Showing 1 changed file with 66 additions and 49 deletions.
115 changes: 66 additions & 49 deletions crates/bevy_render/src/view/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use std::{
sync::PoisonError,
};
use wgpu::{
BufferUsages, SurfaceTargetUnsafe, TextureFormat, TextureUsages, TextureViewDescriptor,
BufferUsages, SurfaceConfiguration, SurfaceTargetUnsafe, TextureFormat, TextureUsages,
TextureViewDescriptor,
};

pub mod screenshot;
Expand All @@ -42,7 +43,7 @@ impl Plugin for WindowRenderPlugin {
.add_systems(
Render,
create_surfaces
.run_if(need_new_surfaces)
.run_if(need_surface_configuration)
.before(prepare_windows),
)
.add_systems(Render, prepare_windows.in_set(RenderSet::ManageViews));
Expand Down Expand Up @@ -198,7 +199,7 @@ fn extract_windows(
struct SurfaceData {
// TODO: what lifetime should this be?
surface: wgpu::Surface<'static>,
format: TextureFormat,
configuration: SurfaceConfiguration,
}

#[derive(Resource, Default)]
Expand Down Expand Up @@ -254,45 +255,12 @@ pub fn prepare_windows(
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 should be removed once https://github.com/bevyengine/bevy/issues/7194 lands and we're doing proper
// feature detection for MSAA.
// 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
.get_texture_format_features(surface_configuration.format)
.get_texture_format_features(surface_data.configuration.format)
.flags;

if !sample_flags.sample_count_supported(msaa.samples()) {
Expand Down Expand Up @@ -340,7 +308,6 @@ pub fn prepare_windows(

let surface = &surface_data.surface;
if not_already_configured || window.size_changed || window.present_mode_changed {
render_device.configure_surface(surface, &surface_configuration);
let frame = surface
.get_current_texture()
.expect("Error configuring surface");
Expand All @@ -351,7 +318,7 @@ pub fn prepare_windows(
window.set_swapchain_texture(frame);
}
Err(wgpu::SurfaceError::Outdated) => {
render_device.configure_surface(surface, &surface_configuration);
render_device.configure_surface(surface, &surface_data.configuration);
let frame = surface
.get_current_texture()
.expect("Error reconfiguring surface");
Expand All @@ -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() {
let texture = render_device.create_texture(&wgpu::TextureDescriptor {
label: Some("screenshot-capture-rendertarget"),
size: wgpu::Extent3d {
width: surface_configuration.width,
height: surface_configuration.height,
width: surface_data.configuration.width,
height: surface_data.configuration.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: surface_configuration.format.add_srgb_suffix(),
format: surface_data.configuration.format.add_srgb_suffix(),
usage: TextureUsages::RENDER_ATTACHMENT
| TextureUsages::COPY_SRC
| TextureUsages::TEXTURE_BINDING,
Expand All @@ -394,7 +361,7 @@ pub fn prepare_windows(
size: screenshot::get_aligned_size(
window.physical_width,
window.physical_height,
surface_data.format.pixel_size() as u32,
surface_data.configuration.format.pixel_size() as u32,
) as u64,
usage: BufferUsages::MAP_READ | BufferUsages::COPY_DST,
mapped_at_creation: false,
Expand All @@ -407,7 +374,7 @@ pub fn prepare_windows(
let pipeline_id = pipelines.specialize(
&pipeline_cache,
&screenshot_pipeline,
surface_configuration.format,
surface_data.configuration.format,
);
window.swap_chain_texture_view = Some(texture_view);
window.screenshot_memory = Some(ScreenshotPreparedState {
Expand All @@ -420,12 +387,15 @@ pub fn prepare_windows(
}
}

pub fn need_new_surfaces(
pub fn need_surface_configuration(
windows: Res<ExtractedWindows>,
window_surfaces: Res<WindowSurfaces>,
) -> bool {
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;
}
}
Expand All @@ -443,9 +413,10 @@ pub fn create_surfaces(
mut window_surfaces: ResMut<WindowSurfaces>,
render_instance: Res<RenderInstance>,
render_adapter: Res<RenderAdapter>,
render_device: Res<RenderDevice>,
) {
for window in windows.windows.values() {
window_surfaces
let data = window_surfaces
.surfaces
.entry(window.entity)
.or_insert_with(|| {
Expand Down Expand Up @@ -477,7 +448,53 @@ 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 {
render_device.configure_surface(&data.surface, &data.configuration);
}
}
}

0 comments on commit bb815fa

Please sign in to comment.