Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions payload/src/hooks/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ fn game_update_render(game: *mut Game, update_contexts: *mut UpdateContexts) {
// Apply the sun-shadow diagnostic override before the original runs, so this frame's
// sim-side CShadowManager::UpdateRender sees it and drives the engine's own SetEnabled path.
apply_sun_shadow_override(Config::lock_query(|c| c.stereo.disable_sun_shadows));
// Same discipline for the screen-space water-reflection override: applied here so the
// engine's water update and this frame's water draws both see it.
graphics_engine::scene::water::apply_ssr_override(Config::lock_query(|c| {
c.stereo.disable_screen_space_water_reflection
}));

// Apply a requested shader reload here, on the game thread before this frame's draws, so the
// PCF-patch hook re-creates the already-loaded shaders (injection is normally after the game
Expand Down
2 changes: 1 addition & 1 deletion payload/src/hooks/graphics_engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub mod shader;
mod single_pass;

mod post;
mod scene;
pub(crate) mod scene;
mod screen;

pub(crate) use post::post_effects;
Expand Down
60 changes: 59 additions & 1 deletion payload/src/hooks/graphics_engine/render_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::{
stereo_diff::op_total,
trace::{TraceEvent, TraceState, tracing_active},
},
hooks::graphics_engine::scene::water,
profiler::gpu::seam,
stereo::{STEREO_STATE, draw_index, is_second_eye},
vr::foveation::{FORCE_STENCIL_TEST, FoveationParams},
Expand Down Expand Up @@ -561,6 +562,12 @@ fn pre_draw(this: *mut RenderEngine, ctx: *mut HContext_t) -> u64 {
// rather than from the game thread, which runs concurrently with it once the frame tail is
// deferred.
crate::stereo::single_pass::begin_dispatch();
// The water-simulation once-per-frame latch resets at the same seam, for the same
// concurrency reason (see its doc comment).
water::begin_dispatch();
// Re-mirror the water reflection camera for this dispatch's eye before the reflection
// pre-passes (which the un-sharing below lets run per eye) read it.
water::apply_per_eye_reflection_camera();
let original = PRE_DRAW.get().unwrap();
let share_cfg =
Config::lock_query(|c| c.stereo.share_prepasses && c.stereo.restore_frame_counters);
Expand All @@ -569,14 +576,44 @@ fn pre_draw(this: *mut RenderEngine, ctx: *mut HContext_t) -> u64 {
// engine-owned, null-checked pass pointers; the `m_Enabled` flag write mirrors the shadow
// scheduler's own store in `commit_render_pass_settings`.
let disabled = unsafe { disable_shared_prepasses(this) };
unsafe { record_reflection_pass_count(this) };
let r = original.call(this, ctx);
unsafe { reenable_passes(&disabled) };
r
} else {
// SAFETY: as above, read-only.
unsafe { record_reflection_pass_count(this) };
original.call(this, ctx)
}
}

/// Record how many reflection-chain passes (the categories
/// [`RenderPassId::PRE_RP_REFLECTION_PRE`] through [`RenderPassId::PRE_RP_REFLECTION_POST`]) are
/// enabled for this dispatch's pre-pass loop, for the water diagnostics snapshot (issue #47): zero
/// on an eye that should have re-rendered them means the per-eye reflection re-render never ran.
///
/// # Safety
///
/// `this` must be the live render engine.
unsafe fn record_reflection_pass_count(this: *mut RenderEngine) {
let Some(engine) = (unsafe { this.as_ref() }) else {
return;
};
let mut enabled = 0;
for cat in
RenderPassId::PRE_RP_REFLECTION_PRE as usize..=RenderPassId::PRE_RP_REFLECTION_POST as usize
{
for &pass in unsafe { engine.m_RenderPasses[cat].as_slice() } {
if let Some(pass) = (unsafe { pass.as_ref() })
&& pass.m_StateFlags.contains(RenderPassState::m_Enabled)
{
enabled += 1;
}
}
}
water::record_reflection_passes_enabled(enabled);
}

/// The pre-pass categories ([`RenderPassId`] indices) that render identically for both eyes and whose
/// outputs persist for the whole frame, so eye 1 can reuse eye 0's output instead of re-running
/// them: the reflection chain (which also fixes the per-eye shadow flicker #31), the sun-shadow
Expand All @@ -593,6 +630,22 @@ const SHARED_PREPASS_CATEGORIES: &[(usize, usize)] = &[
),
];

/// The shared categories with the water planar-reflection chain carved out, used while
/// [`per_eye_water_reflection`](crate::stereo::config::StereoConfig::per_eye_water_reflection) is
/// on: those passes re-render on the second eye's dispatch from that eye's re-mirrored reflection
/// camera (see `scene::water::apply_per_eye_reflection_camera`), while the environment cube, cloud
/// shadows, and the shadow/water-sim block stay shared.
const SHARED_PREPASS_CATEGORIES_PER_EYE_REFLECTION: &[(usize, usize)] = &[
(
RenderPassId::PRE_RP_ENVREFLECTION as usize,
RenderPassId::PRE_RP_CLOUDSHADOWS as usize,
),
(
RenderPassId::PRE_RP_STATIC_SHADOW_0 as usize,
RenderPassId::PRE_RP_WATER_DISPLACEMENT_PRE as usize,
),
];

/// Clear [`RenderPassState::m_Enabled`] on every enabled pass in the shared pre-pass categories so
/// `PreDraw`'s loop skips them, returning the passes cleared so [`reenable_passes`] can restore them.
///
Expand All @@ -603,8 +656,13 @@ unsafe fn disable_shared_prepasses(this: *mut RenderEngine) -> Vec<*mut RenderPa
let Some(engine) = (unsafe { this.as_mut() }) else {
return Vec::new();
};
let categories = if Config::lock_query(|c| c.stereo.per_eye_water_reflection) {
SHARED_PREPASS_CATEGORIES_PER_EYE_REFLECTION
} else {
SHARED_PREPASS_CATEGORIES
};
let mut disabled = Vec::new();
for &(lo, hi) in SHARED_PREPASS_CATEGORIES {
for &(lo, hi) in categories {
for cat in lo..=hi {
for &pass in unsafe { engine.m_RenderPasses[cat].as_slice() } {
if let Some(pass) = (unsafe { pass.as_mut() })
Expand Down
4 changes: 4 additions & 0 deletions payload/src/hooks/graphics_engine/scene/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ pub mod terrain;
// The stereo relaxation of the volumetric-patch terrain's view-dependent hull culls (black terrain
// patch gaps).
pub(crate) mod terrain_cull;
// The legacy water blocks' per-eye screen-UV bias under the collapse.
pub(crate) mod water;

/// Bundle the world-geometry detours into one hook library.
pub(super) fn hook_library() -> HookLibrary {
HookLibrary::new()
.with_hook_library(render_block::hook_library())
.with_hook_library(culling::hook_library())
.with_hook_library(terrain::hook_library())
.with_hook_library(terrain_cull::hook_library())
.with_hook_library(water::hook_library())
}
Loading
Loading