Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions crates/bevy_render/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,47 @@ pub fn render_system(
{
let _span = info_span!("present_frames").entered();

world.resource_scope(|world, mut windows: Mut<ExtractedWindows>| {
let is_cpu = world
.get_resource::<RenderAdapterInfo>()
.is_some_and(|info| info.device_type == DeviceType::Cpu);

// Collect windows that need presenting BEFORE removing `ViewTarget`
let windows_to_present: Vec<Entity> = {
let views = state.get(world);
for (view_target, camera) in views.iter() {
if let Some(NormalizedRenderTarget::Window(window)) = camera.target
&& view_target.needs_present()
{
let Some(window) = windows.get_mut(&window.entity()) else {
continue;
};
window.present();
}
views
.iter()
.filter_map(|(view_target, camera)| {
if let Some(NormalizedRenderTarget::Window(window)) = camera.target
&& view_target.needs_present()
{
return Some(window.entity());
}
None
})
.collect()
};

// On software renderers (CPU device type), remove `ViewTarget` components to ensure
// the cloned `TextureView`s they hold are dropped. This prepares for surface
// reconfiguration on the next frame. (The original `swap_chain_texture_view` is
// dropped in `clear_view_attachments` which runs before `create_surfaces`.)
if is_cpu {
let view_entities: Vec<Entity> = world
.query_filtered::<Entity, With<ViewTarget>>()
.iter(world)
.collect();
for entity in view_entities {
world.entity_mut(entity).remove::<ViewTarget>();
}
});
}

// Present the windows that were marked for presentation
let mut windows = world.resource_mut::<ExtractedWindows>();
for window_entity in windows_to_present {
if let Some(window) = windows.get_mut(&window_entity) {
window.present();
}
}

#[cfg(feature = "tracing-tracy")]
tracing::event!(
Expand Down
22 changes: 19 additions & 3 deletions crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{
render_asset::RenderAssets,
render_phase::ViewRangefinder3d,
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
renderer::{RenderDevice, RenderQueue},
renderer::{RenderAdapterInfo, RenderDevice, RenderQueue},
sync_world::MainEntity,
texture::{
CachedTexture, ColorAttachment, DepthAttachment, GpuImage, ManualTextureViews,
Expand Down Expand Up @@ -1035,9 +1035,25 @@ pub fn prepare_view_attachments(
}
}

/// Clears the view target [`OutputColorAttachment`]s.
pub fn clear_view_attachments(mut view_target_attachments: ResMut<ViewTargetAttachments>) {
/// Clears the view target [`OutputColorAttachment`]s and drops texture views for windows
/// that need reconfiguration on software renderers.
pub fn clear_view_attachments(
mut view_target_attachments: ResMut<ViewTargetAttachments>,
mut windows: ResMut<ExtractedWindows>,
render_adapter_info: Res<RenderAdapterInfo>,
) {
view_target_attachments.clear();

// On software renderers (CPU device type), drop `swap_chain_texture_view` for windows
// that need reconfiguration. This must happen BEFORE `create_surfaces` runs, otherwise
// wgpu/DX12 will error with "surface is in use" when trying to resize.
if render_adapter_info.device_type == wgpu::DeviceType::Cpu {
for window in windows.values_mut() {
if window.size_changed || window.present_mode_changed {
drop(window.swap_chain_texture_view.take());
}
}
}
}

pub fn prepare_view_targets(
Expand Down