mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
Run a clear pass on Windows without any Views (#3304)
Fixes #3043 `surface_texture.present()` will cause panics if no work is done on a given frame. "Views" are how we queue up work. Without any cameras, no work is produced. This adds a "clear pass" for windows without views, which ensures we clear windows (thus doing work) every frame. This is a "quick fix". It can be made much cleaner once we make "render targets" a concept and move some responsibilities around. Then we just clear the "render target" once instead of clearing "views". I _might_ have time to tackle that work prior to 0.6, but I doubt it. If "render targets" don't make it in to 0.6, they will be one of the first things I tackle after release.
This commit is contained in:
parent
172f4d6d78
commit
fe9b5003c5
1 changed files with 54 additions and 7 deletions
|
@ -1,15 +1,27 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::ClearColor;
|
use crate::ClearColor;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_render2::{
|
use bevy_render2::{
|
||||||
|
camera::ExtractedCamera,
|
||||||
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo},
|
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo},
|
||||||
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
|
render_resource::{
|
||||||
|
LoadOp, Operations, RenderPassColorAttachment, RenderPassDepthStencilAttachment,
|
||||||
|
RenderPassDescriptor,
|
||||||
|
},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
view::{ExtractedView, ExtractedWindows, ViewDepthTexture, ViewTarget},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ClearPassNode {
|
pub struct ClearPassNode {
|
||||||
query:
|
query: QueryState<
|
||||||
QueryState<(&'static ViewTarget, Option<&'static ViewDepthTexture>), With<ExtractedView>>,
|
(
|
||||||
|
&'static ViewTarget,
|
||||||
|
Option<&'static ViewDepthTexture>,
|
||||||
|
Option<&'static ExtractedCamera>,
|
||||||
|
),
|
||||||
|
With<ExtractedView>,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClearPassNode {
|
impl ClearPassNode {
|
||||||
|
@ -35,9 +47,17 @@ impl Node for ClearPassNode {
|
||||||
render_context: &mut RenderContext,
|
render_context: &mut RenderContext,
|
||||||
world: &World,
|
world: &World,
|
||||||
) -> Result<(), NodeRunError> {
|
) -> Result<(), NodeRunError> {
|
||||||
/* This gets all ViewTargets and ViewDepthTextures and clears its attachments */
|
let mut cleared_windows = HashSet::new();
|
||||||
for (target, depth) in self.query.iter_manual(world) {
|
let clear_color = world.get_resource::<ClearColor>().unwrap();
|
||||||
let clear_color = world.get_resource::<ClearColor>().unwrap();
|
|
||||||
|
// This gets all ViewTargets and ViewDepthTextures and clears its attachments
|
||||||
|
// TODO: This has the potential to clear the same target multiple times, if there
|
||||||
|
// are multiple views drawing to the same target. This should be fixed when we make
|
||||||
|
// clearing happen on "render targets" instead of "views" (see the TODO below for more context).
|
||||||
|
for (target, depth, camera) in self.query.iter_manual(world) {
|
||||||
|
if let Some(camera) = camera {
|
||||||
|
cleared_windows.insert(camera.window_id);
|
||||||
|
}
|
||||||
let pass_descriptor = RenderPassDescriptor {
|
let pass_descriptor = RenderPassDescriptor {
|
||||||
label: Some("clear_pass"),
|
label: Some("clear_pass"),
|
||||||
color_attachments: &[target.get_color_attachment(Operations {
|
color_attachments: &[target.get_color_attachment(Operations {
|
||||||
|
@ -59,6 +79,33 @@ impl Node for ClearPassNode {
|
||||||
.begin_render_pass(&pass_descriptor);
|
.begin_render_pass(&pass_descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This is a hack to ensure we don't call present() on frames without any work,
|
||||||
|
// which will cause panics. The real fix here is to clear "render targets" directly
|
||||||
|
// instead of "views". This should be removed once full RenderTargets are implemented.
|
||||||
|
let windows = world.get_resource::<ExtractedWindows>().unwrap();
|
||||||
|
for window in windows.values() {
|
||||||
|
// skip windows that have already been cleared
|
||||||
|
if cleared_windows.contains(&window.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let pass_descriptor = RenderPassDescriptor {
|
||||||
|
label: Some("clear_pass"),
|
||||||
|
color_attachments: &[RenderPassColorAttachment {
|
||||||
|
view: window.swap_chain_texture.as_ref().unwrap(),
|
||||||
|
resolve_target: None,
|
||||||
|
ops: Operations {
|
||||||
|
load: LoadOp::Clear(clear_color.0.into()),
|
||||||
|
store: true,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
render_context
|
||||||
|
.command_encoder
|
||||||
|
.begin_render_pass(&pass_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue