use super::frame_policy::{FrameAction, FramePolicy};
use crate::ecs::StepResult;
use crate::gfx::backend::{FrameParams, RenderBackend};
use crate::gfx::ops::ReplayOutcome;
use crate::gfx::profile::RenderStats;
use crate::gfx::snapshot::{RenderSnapshot, SceneOp};
pub(crate) struct SubmitOutcome {
pub result: StepResult,
pub(crate) render_stats: Option<RenderStats>,
pub(crate) memory_pressure: bool,
pub replay: ReplayOutcome,
pub(crate) device_lost: bool,
}
impl SubmitOutcome {
fn stop() -> Self {
Self {
result: StepResult::Stop,
render_stats: None,
memory_pressure: false,
replay: ReplayOutcome::default(),
device_lost: false,
}
}
}
pub(crate) fn submit(
policy: &mut FramePolicy,
snap: &mut RenderSnapshot,
backend: &mut dyn RenderBackend,
) -> SubmitOutcome {
let replay = snap.ops.replay(backend);
backend.set_ui_cursor_hidden(snap.ui.cursor_hidden);
if let Some(on) = snap.ui.menu_mode {
backend.set_menu_mode(on);
}
if let Some(capture) = snap.ui.camera_capture {
backend.set_camera_capture(capture);
}
if backend.window_closed() {
tracing::info!("GraphicsSystem: window closed");
backend.wait_idle();
return SubmitOutcome {
replay,
..SubmitOutcome::stop()
};
}
if !snap.models.is_empty() {
backend.update_models(&snap.models);
}
for (skinned_index, joints) in snap.poses.iter() {
backend.update_skinned_pose(skinned_index, joints);
}
for (skinned_index, weights) in snap.morphs.iter() {
backend.update_morph_weights(skinned_index, weights);
}
if !snap.skinned_models.is_empty() {
backend.update_skinned_models(&snap.skinned_models);
}
for op in &snap.scene_ops {
match *op {
SceneOp::SetFade(fade) => backend.set_fade(fade),
SceneOp::Visibility { draw_idx, visible } => {
backend.update_visibility(draw_idx, visible)
}
}
}
backend.update_view(snap.frame.view);
let mut memory_pressure = false;
match backend.draw_frame(FrameParams {
elapsed: snap.frame.elapsed,
fov_y_radians: snap.frame.fov_y_radians,
near: snap.frame.near,
far: snap.frame.far,
cam_pos: snap.frame.cam_pos,
text_calls: &snap.text_calls,
lines: &snap.lines,
world_hidden: snap.frame.world_hidden,
view_mode: snap.frame.view_mode,
show: snap.frame.show,
}) {
Ok(()) => policy.frame_succeeded(),
Err(e) => {
memory_pressure = matches!(e, crate::gfx::error::RenderError::OutOfDeviceMemory(_));
match policy.on_frame_error(&e) {
FrameAction::SkipFrame => {}
FrameAction::Shutdown => {
backend.wait_idle();
return SubmitOutcome {
memory_pressure,
replay,
..SubmitOutcome::stop()
};
}
FrameAction::ShutdownDeviceLost => {
tracing::error!("GraphicsSystem: device lost, stopping: {}", e);
crate::crash::report_device_lost(&e.to_string());
return SubmitOutcome {
memory_pressure,
replay,
device_lost: true,
..SubmitOutcome::stop()
};
}
}
}
}
SubmitOutcome {
result: StepResult::Continue,
render_stats: Some(backend.render_stats()),
memory_pressure,
replay,
device_lost: false,
}
}