diff --git a/crates/horizon-client/src/game/options.rs b/crates/horizon-client/src/game/options.rs index 7ac4ae98b..a71494075 100644 --- a/crates/horizon-client/src/game/options.rs +++ b/crates/horizon-client/src/game/options.rs @@ -273,6 +273,7 @@ impl Game<'_> { s.horizon.hdr, s.horizon.hdr_paper_white as f32, s.horizon.hdr_peak as f32, + &Self::options_path().with_file_name(horizon_client::graphics::HDR_MARKER), ); } // Window.updateFullscreenIfChanged: only a changed option asks the diff --git a/crates/horizon-client/src/gfx.rs b/crates/horizon-client/src/gfx.rs index ad1fd0561..69449f67f 100644 --- a/crates/horizon-client/src/gfx.rs +++ b/crates/horizon-client/src/gfx.rs @@ -537,6 +537,9 @@ pub struct Renderer { hdr: Option, /// The HDR output the window's surface can present. hdr_output: Option, + /// The marker file of an HDR output that has not presented a frame yet + /// (`graphics::HDR_MARKER`). + hdr_marker: Option, /// The shader pack's post-processing, and the dimension (legacy id) it was loaded for. pack_post: Option<(i32, Option)>, /// The post passes of one of Horizon's own shader packs; never beside `pack_post`'s. @@ -2642,6 +2645,7 @@ impl Renderer { world_post, hdr: None, hdr_output, + hdr_marker: None, pack_post: None, native: None, pass_timing: pack_timing::PassTiming::logging(), @@ -3200,9 +3204,17 @@ impl Renderer { } /// HDR output (Horizon setting): HDR10 or scRGB at `paper_white` nits, the world's /// highlights expanded up to `peak` nits. Off where the surface can't present it. - pub fn set_hdr(&mut self, on: bool, paper_white: f32, peak: f32) { + pub fn set_hdr(&mut self, on: bool, paper_white: f32, peak: f32, marker: &std::path::Path) { let output = self.hdr_output.filter(|_| on && self.surface.is_some()); if output.is_some() != self.hdr.is_some() { + // If the game dies before HDR output shows a frame, the marker is still there at + // the next start, which then comes up with HDR off. + if output.is_some() { + let _ = std::fs::write(marker, "HDR output was being switched on\n"); + self.hdr_marker = Some(marker.to_owned()); + } else if let Some(marker) = self.hdr_marker.take() { + let _ = std::fs::remove_file(marker); + } let format = self.config.format.remove_srgb_suffix(); self.hdr = output.map(|output| hdr::Hdr::new(&self.device, format, output)); self.configure_surface(); @@ -5229,6 +5241,12 @@ impl Renderer { startup_step(format_args!("presenting the first frame")); } self.queue.present(surface_frame); + if self.hdr.is_some() + && let Some(marker) = self.hdr_marker.take() + { + let _ = std::fs::remove_file(marker); + log::info!("Horizon renderer: HDR output presented its first frame"); + } if reconfigure && let Some(surface) = &self.surface { Self::configure( &self.device, diff --git a/crates/horizon-client/src/graphics.rs b/crates/horizon-client/src/graphics.rs index fbf67f9ad..436c6afbb 100644 --- a/crates/horizon-client/src/graphics.rs +++ b/crates/horizon-client/src/graphics.rs @@ -5,6 +5,9 @@ use std::{fs, path::Path}; pub const FILE: &str = "horizon-graphics.txt"; +/// Written beside it before HDR output is switched on and removed once the first HDR frame is +/// presented. Found at the next start, it means HDR output took the game down, so HDR starts off. +pub const HDR_MARKER: &str = "horizon-hdr-pending"; /// Simple-level presets. `Custom` leaves every option as the player set it. #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] @@ -310,9 +313,17 @@ fn bool_text(v: bool) -> &'static str { } impl Graphics { pub fn load(dir: &Path) -> Self { - fs::read_to_string(dir.join(FILE)) + let mut g: Self = fs::read_to_string(dir.join(FILE)) .map(|t| Self::parse(&t)) - .unwrap_or_default() + .unwrap_or_default(); + if fs::remove_file(dir.join(HDR_MARKER)).is_ok() && g.hdr { + g.hdr = false; + g.save(dir); + log::warn!( + "the last start ended before HDR output showed a frame; HDR is off now (graphics option hdr, in {FILE})" + ); + } + g } pub fn parse(text: &str) -> Self { let mut g = Self::default();