Cache the QueryState used to drop swapchain TextureViews (#11781)

# Objective
While profiling around to validate the results of #9172, I noticed that
`present_frames` can take a significant amount of time. Digging into the
cause, it seems like we're creating a new `QueryState` from scratch
every frame. This involves scanning the entire World's metadata instead
of just updating its view of the world.

## Solution
Use a `SystemState` argument to cache the `QueryState` to avoid this
construction cost.

## Performance
Against `many_foxes`, this seems to cut the time spent in
`present_frames` by nearly almost 2x. Yellow is this PR, red is main.


![image](https://github.com/bevyengine/bevy/assets/3137680/2b02bbe0-6219-4255-958d-b690e37e7fba)
This commit is contained in:
James Liu 2024-02-08 16:34:04 -08:00 committed by GitHub
parent 0166db33f7
commit f26b438c22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -13,7 +13,7 @@ use crate::{
settings::{WgpuSettings, WgpuSettingsPriority},
view::{ExtractedWindows, ViewTarget},
};
use bevy_ecs::prelude::*;
use bevy_ecs::{prelude::*, system::SystemState};
use bevy_time::TimeSender;
use bevy_utils::Instant;
use std::sync::Arc;
@ -22,7 +22,7 @@ use wgpu::{
};
/// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame.
pub fn render_system(world: &mut World) {
pub fn render_system(world: &mut World, state: &mut SystemState<Query<Entity, With<ViewTarget>>>) {
world.resource_scope(|world, mut graph: Mut<RenderGraph>| {
graph.update(world);
});
@ -59,10 +59,7 @@ pub fn render_system(world: &mut World) {
// Remove ViewTarget components to ensure swap chain TextureViews are dropped.
// If all TextureViews aren't dropped before present, acquiring the next swap chain texture will fail.
let view_entities = world
.query_filtered::<Entity, With<ViewTarget>>()
.iter(world)
.collect::<Vec<_>>();
let view_entities = state.get(world).iter().collect::<Vec<_>>();
for view_entity in view_entities {
world.entity_mut(view_entity).remove::<ViewTarget>();
}