diff --git a/native/shared/src/ffi_core/visual.rs b/native/shared/src/ffi_core/visual.rs index a2218b8..589de12 100644 --- a/native/shared/src/ffi_core/visual.rs +++ b/native/shared/src/ffi_core/visual.rs @@ -218,6 +218,14 @@ macro_rules! __bloom_ffi_visual { }) } + // bloom_set_present_mode [round-2 audit F6] + #[no_mangle] + pub extern "C" fn bloom_set_present_mode(mode: f64) { + $crate::ffi::guard("bloom_set_present_mode", move || { + engine().renderer.set_present_mode(mode as u32); + }) + } + // bloom_set_sun_shafts [source: macos] #[no_mangle] pub extern "C" fn bloom_set_sun_shafts(strength: f64, decay: f64, r: f64, g: f64, b: f64) { diff --git a/native/shared/src/renderer/mod.rs b/native/shared/src/renderer/mod.rs index ad66ec3..099d3e8 100644 --- a/native/shared/src/renderer/mod.rs +++ b/native/shared/src/renderer/mod.rs @@ -7851,6 +7851,28 @@ impl Renderer { self.grain_strength = strength.max(0.0); } + /// Present mode: 0 = Fifo (vsync), 1 = Mailbox (uncapped, no tearing), + /// 2 = Immediate (uncapped, tearing allowed). Round-2 audit F6: the + /// mode was hardcoded Fifo, which also made `set_target_fps` inert + /// (its sleep-based cap only engages when vsync is off). All three + /// modes are supported by DXGI on Windows; on other backends an + /// unsupported request falls back to Fifo at configure time. + pub fn set_present_mode(&mut self, mode: u32) { + let requested = match mode { + 1 => wgpu::PresentMode::Mailbox, + 2 => wgpu::PresentMode::Immediate, + _ => wgpu::PresentMode::Fifo, + }; + if self.surface_config.present_mode == requested { + return; + } + self.surface_config.present_mode = requested; + if let Some(surface) = &self.surface { + surface.configure(&self.device, &self.surface_config); + } + eprintln!("bloom: present mode = {:?}", requested); + } + /// Sun shaft (screen-space god ray) strength. 0 (default) = off. /// 0.4 = subtle haze, 1.0+ = obvious cinematic shafts. The /// shafts are sampled from the depth buffer along a screen-space diff --git a/package.json b/package.json index dfa63c0..7094c3a 100644 --- a/package.json +++ b/package.json @@ -1229,6 +1229,13 @@ ], "returns": "void" }, + { + "name": "bloom_set_present_mode", + "params": [ + "f64" + ], + "returns": "void" + }, { "name": "bloom_set_sun_shafts", "params": [ diff --git a/src/core/index.ts b/src/core/index.ts index f1be5fe..0c218e6 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -20,6 +20,7 @@ declare function bloom_set_fog(r: number, g: number, b: number, density: number, declare function bloom_set_chromatic_aberration(strength: number): void; declare function bloom_set_vignette(strength: number, softness: number): void; declare function bloom_set_film_grain(strength: number): void; +declare function bloom_set_present_mode(mode: number): void; declare function bloom_set_sun_shafts(strength: number, decay: number, r: number, g: number, b: number): void; declare function bloom_set_auto_exposure(on: number): void; declare function bloom_set_taa_enabled(on: number): void; @@ -265,6 +266,16 @@ export function setFilmGrain(strength: number): void { bloom_set_film_grain(strength); } +/** + * Swapchain present mode: 0 = Fifo (vsync, default), 1 = Mailbox + * (uncapped, no tearing), 2 = Immediate (uncapped, tearing allowed). + * With a non-vsync mode active, `setTargetFPS`'s sleep-based cap + * becomes effective — under Fifo it is inert by design. + */ +export function setPresentMode(mode: number): void { + bloom_set_present_mode(mode); +} + /** Screen-space sun shafts (god rays). strength 0 = off. */ export function setSunShafts(strength: number, decay: number, r: number, g: number, b: number): void { bloom_set_sun_shafts(strength, decay, r, g, b);