From 67d738451cbc50354d05e5df482ab1475cd2f19a Mon Sep 17 00:00:00 2001 From: Stefan Maier <145186748+Cesarus85@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:48:27 +0200 Subject: [PATCH] Draw the eyes one by one by default; multiview only with debug.multiview On the Quest 3, in big online games (26-35 players), the picture was doubled and shifted from the start as the head turned, nauseating; with 48 bots it was not, and with the eyes drawn one by one it was not online either. Not the frame rate: one by one, online at 72 Hz, the compositor repeated as many frames and nothing was seen. The Steam Frame had the same doubling with multiview (2026-10-05) and draws them one by one since. So both now do by default; debug.multiview (was vr.multiview, and debug.multiview_steamvr) draws them at once, for finding what the shared pass draws wrongly. The refresh rate's steps take up the extra cost. Co-Authored-By: Claude Opus 5.5 --- port/android/VR_ROADMAP.md | 16 +++++++++++++++- port/linux/include/halo_vr.h | 2 +- port/linux/src/port_config.c | 13 ++++++------- port/linux/src/vr.c | 23 ++++++++++------------- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/port/android/VR_ROADMAP.md b/port/android/VR_ROADMAP.md index b26a0201..afe17685 100644 --- a/port/android/VR_ROADMAP.md +++ b/port/android/VR_ROADMAP.md @@ -17,7 +17,7 @@ named where code is taken over. | Area | What | | --- | --- | | Headsets | Quest 3; Steam Frame (Lepton): its controllers' layout, a Steam library tile that installs, starts, updates and quits the game, data kept in `~/Documents/RingfallMjolnirVR` | -| Rendering | Both eyes in one pass (multiview) on the Quest; one by one on SteamVR, where multiview's eyes did not fuse; lens flares at their depth in stereo; HUD, menus, scope, crosshair and names as layers of their own | +| Rendering | The eyes drawn one by one (both at once, multiview, only with `debug.multiview`: its eyes did not always fuse, see the open points); lens flares at their depth in stereo; HUD, menus, scope, crosshair and names as layers of their own | | Aiming | The weapon in the hand, its shots from the muzzle, laser and crosshair options | | Body | Physical crouch (`vr.crouch_limit`) beside the crouch button, leaning (`vr.lean_limit`), melee by swinging, grenades thrown with the left hand, two-handed weapons | | Vehicles | The Warthog's wheel turned with the hands, right trigger throttle, left brake; first-person seats; turrets with handles | @@ -518,6 +518,20 @@ see that nothing is missing or slower. ## Open points outside the order +- Multiview's doubled pictures (2026-10-16): on the developer's Quest 3, + doubled and shifted pictures from the start of big online games (26-35 + players) as the head turned, nauseating; none in a local game with 48 + bots; none online either with the eyes drawn one by one. Not the frame + rate: one by one, online at 72 Hz, the compositor repeated as many + frames (about 4 a second) and nothing was seen. Not the facing jumps + (respawns only) nor the camera (it moves every frame). Before: the + Steam Frame's (2026-10-05), each eye alone sharp. So the eyes are drawn + one by one by default now (`debug.multiview` for both at once). To do: + find what the shared pass draws wrongly online, e.g. by saving both + eyes' pictures in a big online game and comparing what is doubled + (sprites and effects projected by the game itself, `mv_depth`; programs + made on the shader worker; the sky rows), then turn it back on: it + halves the drawing's CPU cost. - Big online games (2026-10-16): doubled pictures on a 32-player server, none in a local game with 48 bots. Not the GPU (60–80 %): the ticks cost 3.3–4.6 ms as a client there (1.3–1.9 ms with bots or 16 players), so diff --git a/port/linux/include/halo_vr.h b/port/linux/include/halo_vr.h index c685c957..32111c8c 100644 --- a/port/linux/include/halo_vr.h +++ b/port/linux/include/halo_vr.h @@ -50,7 +50,7 @@ void halo_vr_eye_camera(int eye, const float game_position[3], /* copies the back buffer, just drawn for an eye, to that eye's image */ void halo_vr_capture_eye(int eye); -/* Both eyes in one draw (vr.multiview, where GL_OVR_multiview2 is): whether +/* Both eyes in one draw (debug.multiview, where GL_OVR_multiview2 is): whether this frame draws so; the camera between the eyes whose view takes in both (as halo_vr_eye_camera), which also starts drawing into both eyes' layers; and after the draw, the layers taken for the eyes' images. */ diff --git a/port/linux/src/port_config.c b/port/linux/src/port_config.c index 8bc1cfa6..0bf50f54 100644 --- a/port/linux/src/port_config.c +++ b/port/linux/src/port_config.c @@ -233,9 +233,6 @@ static const struct config_setting config_settings[] = "away from the player's body (walls are not checked)." }, { "vr.crouch_limit", _config_real, "0.9", "HALO_VR_CROUCH_LIMIT", _environment_value, _platform_android, "How far, in metres, the view follows your head down." }, - { "vr.multiview", _config_boolean, "true", "HALO_VR_MULTIVIEW", _environment_value, _platform_android, - "Draw both eyes in one pass (GL_OVR_multiview2), from between them: about\n" - "half the drawing's cost on the processor. false: one eye after the other." }, { "vr.log_performance", _config_boolean, "false", "HALO_VR_LOG_PERFORMANCE", _environment_value, _platform_android, "Log the frame rate and where the frame time goes every five seconds\n" "(adb logcat -s halo)." }, @@ -786,10 +783,12 @@ static const struct config_setting config_settings[] = "machines of twice it), to test the netcode as over the internet; 0 none." }, { "debug.network_loss", _config_real, "0.0", "HALO_NETWORK_LOSS", _environment_value, _platform_all, "Percent of datagrams received that are dropped, for the same; 0 none." }, - { "debug.multiview_steamvr", _config_boolean, "false", "HALO_MULTIVIEW_STEAMVR", _environment_value, - _platform_android, - "On SteamVR (the Steam Frame) the eyes are drawn one by one, whatever\n" - "vr.multiview says: true draws them at once there too, for testing." }, + { "debug.multiview", _config_boolean, "false", "HALO_MULTIVIEW", _environment_value, _platform_android, + "Draw both eyes in one pass (GL_OVR_multiview2), from between them: about\n" + "half the drawing's cost on the processor, but the eyes' pictures did not\n" + "always fuse (doubled as the head turned: on the Steam Frame now and then,\n" + "on the Quest 3 in big online games). Off, one eye after the other; on,\n" + "for finding why." }, { "debug.gl_thread", _config_integer, "-1", "HALO_GL_THREAD", _environment_value, _platform_android, "Mesa's GL thread (its drivers: the Steam Frame's): 1 on, 0 off, -1 as the\n" "driver chooses. Read when the app starts." }, diff --git a/port/linux/src/vr.c b/port/linux/src/vr.c index 1cbcdfa2..2ed0e5a4 100644 --- a/port/linux/src/vr.c +++ b/port/linux/src/vr.c @@ -138,7 +138,7 @@ static struct float seat_frame_yaw; int seat_frame_valid; float seat_turn; - int multiview; /* vr.multiview: both eyes in one draw */ + int multiview; /* debug.multiview: both eyes in one draw */ int multiview_logged; int multiview_logged_views; /* vr.foveation's level last logged (+1; 0: none yet) */ @@ -645,7 +645,7 @@ void halo_vr_initialize(void) vr.two_hand_reach = (float)config_real("vr.two_hand_reach"); vr.melee_swing_speed = (float)config_real("vr.melee_swing_speed"); vr.grenade_throw_speed = (float)config_real("vr.grenade_throw_speed"); - vr.multiview = config_boolean("vr.multiview"); + vr.multiview = config_boolean("debug.multiview"); vr.vehicle_first_person = config_boolean("vr.vehicle_first_person"); vr.vehicle_spawn = config_boolean("debug.vehicle_spawn"); vr.turret_handles = config_boolean("vr.turret_handles"); @@ -678,16 +678,13 @@ void halo_vr_initialize(void) vr.active = 1; platform_log("VR: %s, eyes %dx%d at %.0f Hz", vr.info.system_name, vr.info.eye_width, vr.info.eye_height, vr.info.refresh_rate); - /* SteamVR (the Steam Frame): each eye drawn apart. With both drawn at - once the eyes' pictures did not fuse, now and then: each alone was - sharp, the two together doubled as the head turned (2026-10-05), and - one by one costs it no more (its time goes to the driver either way). - debug.multiview_steamvr draws them at once there again, for finding why */ - if (vr.multiview && strstr(vr.info.system_name, "SteamVR") && !config_boolean("debug.multiview_steamvr")) - { - vr.multiview = 0; - platform_log("VR: SteamVR: the eyes drawn one by one (debug.multiview_steamvr)"); - } + /* Each eye drawn apart (debug.multiview draws both at once). At once, + the eyes' pictures did not always fuse: on the Steam Frame now and then + (each alone sharp, the two together doubled as the head turned, + 2026-10-05; one by one costs it no more there), and on the Quest 3 in + big online games (doubled from the start as the head turned, none with + 48 bots; one by one, none online either, 2026-10-16) */ + platform_log("VR: the eyes drawn %s (debug.multiview)", vr.multiview ? "at once" : "one by one"); } int halo_vr_active(void) @@ -2161,7 +2158,7 @@ float halo_vr_refresh_rate(void) return vr.active ? vr.info.refresh_rate : 0.0f; } -/* ---------- both eyes at once (vr.multiview) +/* ---------- both eyes at once (debug.multiview) The scene is drawn once, from a camera between the eyes whose view takes in both eyes' (with a margin, for what is near: the eyes stand apart), into two