88 Commits
Author SHA1 Message Date
DieMitchellandClaude Opus 5.5 4a4696de86 Remove foveation diagnostics and prepare v0.2.0 beta
Drop the pass-size logging and SHADPS4_VR_FOVEATION_TEST coarse mode used
to verify the map on the Frame, point the docs at v0.2.0, and record what
was verified on the headset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
steam-frame-v0.2.0
2026-10-11 22:13:56 +02:00
DieMitchellandClaude Opus 5.5 853a32b0a4 Foveate the per-eye scene pass instead of wide stereo passes
Astro Bot draws its scene one eye at a time (1200x1280 at preset 5), so
the side-by-side gate never matched it and the map only reached other
wide passes. known_title now publishes the scene's eye size; exactly
that pass gets a single-eye map.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:48:01 +02:00
DieMitchellandClaude Opus 5.5 5deb3c3edc Log foveation pass sizes and add a coarse-map test mode
Diagnostic for the Frame test: logs each distinct render-pass size once
with whether it can take the map, and SHADPS4_VR_FOVEATION_TEST=1 forces
4x4 everywhere so a driver ignoring the map is obvious.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:40:28 +02:00
DieMitchellandClaude Opus 5.5 d9d845345a Let the foveation map replace the pipeline shading rate
Pipelines had no fragment shading-rate state, so the combiners defaulted
to KEEP and the attached rate map never changed the shading rate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 21:31:16 +02:00
DieMitchell 1933d4bba3 Handle foveation image-view creation result 2026-10-11 15:04:20 +02:00
DieMitchell 14826294a2 Require single-sample support for rate bands 2026-10-11 14:48:52 +02:00
DieMitchell 8c2d54ccaa Include VMA after Vulkan platform setup 2026-10-11 14:45:34 +02:00
DieMitchell 8bac3b565d Include VMA mapping declarations 2026-10-11 14:33:55 +02:00
DieMitchell cbad4abb99 Drop unused upload allocation metadata 2026-10-11 14:33:45 +02:00
DieMitchell f1c075c140 Report active foveation maps 2026-10-11 14:31:06 +02:00
DieMitchell a6a4620e5a Remove stale optional feature-chain access 2026-10-11 14:30:07 +02:00
DieMitchell d2a6c56370 Clarify conditional render presets 2026-10-11 14:22:18 +02:00
DieMitchell 6b28216ade Keep gaze fallback logging to one warning 2026-10-11 14:20:49 +02:00
DieMitchell 8733d52476 Choose the foveation resolution for direct launches 2026-10-11 14:14:00 +02:00
DieMitchell 66740d71ba Use the gaze action subpath and gate layered passes 2026-10-11 14:13:18 +02:00
DieMitchell b164648378 Clarify foveation is branch-only 2026-10-11 14:12:29 +02:00
DieMitchell 48cbb739f5 Keep optional gaze extensions gated 2026-10-11 14:10:41 +02:00
DieMitchell cf1ae09e3d Fix shading-rate capability query 2026-10-11 14:08:13 +02:00
DieMitchell 8fc1593f01 Add opt-in eye-tracked foveation for Frame 2026-10-11 14:04:02 +02:00
DieMitchell 09d2afee7b Remove non-Frame project files 2026-10-10 23:23:50 +02:00
DieMitchell 54b1157e20 Add on-device installer using SteamOS devkit shortcut registration steam-frame-v0.1.2 2026-10-10 23:15:16 +02:00
DieMitchell d821d1e5b8 Clarify headset installation and Steam shortcut setup 2026-10-10 23:05:27 +02:00
DieMitchell 4fe067a1b0 Rewrite documentation for standalone AstroQuest-Frame 2026-10-10 23:02:17 +02:00
DieMitchell ed58f2617d Rename Steam Frame fork to AstroQuest-Frame 2026-10-10 22:57:32 +02:00
DieMitchell 9404a9295d Map Steam Frame D-pad and document right-stick gestures steam-frame-v0.1.1 2026-10-10 22:55:05 +02:00
DieMitchell 764e7664fc Add native Steam Frame ARM64 build and controller bindings steam-frame-v0.1.0 2026-10-10 22:52:43 +02:00
Jonathan Tate 3a75299ff5 Improve guest HR timer precision and cap local desktop mirror updates pc-vr-0.20-timer-mirror-20261008 2026-10-07 07:38:24 -04:00
Jonathan Tate d4e4e00192 Port pipeline cache repairs and precise late-frame recovery from elliotttate 2026-10-07 07:05:22 -04:00
Jonathan Tate 4b9479a086 Retain fixed FPS choices alongside default Full framerate option pc-vr-0.20-full-framerate-20261006 2026-10-06 23:05:15 -04:00
Jonathan Tate 8b42b96ef7 Default to full refresh and simplify launcher with two higher resolutions 2026-10-06 23:03:03 -04:00
Jonathan Tate ee87d8a087 Reduce Windows VR presentation wakeup jitter and completion polling delay 2026-10-06 22:48:52 -04:00
Jonathan Tate f54f39c328 Keep soccer animation budgets in console-frame units for game 1.00 pc-vr-0.20-soccer-timing-20261006 2026-10-06 18:56:58 -04:00
Jonathan Tate 2882350c07 Merge AstroQuest 0.20 while retaining PC VR performance fixes pc-vr-0.20-performance-20261006 2026-10-06 18:35:56 -04:00
bigmak94andClaude Opus 5.5 807ca1f377 0.20: the two things of world 2, and the README no longer says how games are got
Version 0.20 of the Quest app (versionCode 20) and of the PC package: the collisions at the
end of level 2-1 (Issue #16) and the squares in the lava's glow around the octopus, both in
the emulator and so the same on the headset and on the PC. The notes of both READMEs say
what was wrong and what was tried.

README: the answer to "How do I get the game onto my computer?" is that this project gives
no information on how to get games and that the repository does not include any game data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:41:36 +02:00
bigmak94andClaude Opus 5.5 368f8be8e7 A draw with one surface as two of its colour targets is made once for each: no squares in the lava's glow
Around the octopus of world 2 the glow of the lava had squares in it, lit and dark, that
came and went as he moved (seen on the PC in the headset, and on the monitor at the console's
size).

The game draws the rings that glow into a quarter-size buffer which it clears first and then
has bound twice for the ring draws: as target 0 with a write mask of red, green and blue and
blending on, and as target 1 with a write mask of alpha and blending off. The console's GPU
writes both to the same memory. In Vulkan the image was two attachments of one render pass,
which leaves undefined what it holds afterwards: read back right after the ring draws it
had the rings in some blocks of 4x8 texels and the cleared value in others, and was whole
right before them. (Making the GPU finish all its work before and after the image was
filled changed nothing, which is what ruled out the order of the work as the cause.)

Rasterizer::Draw now asks which of a draw's targets share a surface and makes the draw once
for every one of them, with the others left out of the pipeline as if nothing were bound
there. The shaders are the same. A draw that writes depth with a test that fails on equal
depth, or uses the stencil, would not come out the same twice: it is drawn as before, with a
line in the log.

Tried on the PC at the console's size through the challenge that has the same octopus: the
buffer read back after the ring draws had 34 to 73 hard edges on its grid of four texels
before and none after, over three passes each, and ten pictures of the fight have the glow
whole. Not yet seen in the headset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 20:25:22 +02:00
bigmak94andClaude Opus 5.5 8a909b0438 Collisions that the game moves land where it sends them: the invisible wall at the end of 2-1
Issue #16 (and seen on the PC): at the end of level 2-1 the hero stood in the air above the
last mound and ran into a wall that was not there, the island below had the same; its
collisions were most of a block above what was drawn.

The game moves the collision bodies of what moves by sending them to a place: the physics
library gives a body the speed that takes it there in one step, distance / time step, with
the time step of the step last taken, and the step that follows moves it by speed x the new
time step. On the console both are a sixtieth of a second. With the time step the emulator
gives the game, which follows what frames take, the body lands off by its way times the
difference between the two. What moves all the time is put right a frame later. What is sent
once is not: a level sleeps by sections, and a section that wakes sends all its bodies in one
frame from where they slept to where the level has moved since. The last two sections of 2-1
are woken at the top of a tree that carried them 17 units up while they slept, in a frame
that is long because of all that is new in it.

The function that has the library take a step wrote the new time step down and then stepped.
It is changed in place, in both versions of the game, to step with the time step that is
written down, the one every body was sent with, and to write the new one down after
(SHADPS4_TITLE_PHYSICS_STEP=0 leaves the game's own). The places are checked for what the
game has there before anything is written.

SHADPS4_TITLE_PHYSICS_WATCH=1 has the log tell every ten seconds how far the bodies sent
ended from where they were sent. On the PC, the scripted walk through the first level at
about 40 frames a second: with the game's own step, off by the way times the difference of
the two time steps (0.003 for a body sent 0.16 where they were 2% apart, 0.085 for one sent
0.19 across a hitch); with the change 0.0000 over 110,000 sends, in 1.00 and in 1.04.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 18:20:41 +02:00
bigmak94andClaude Opus 5.5 f5f4c2ccf5 On the PC the game's sound goes to Virtual Desktop's own device whenever that is in the system
The session after the last fix played from the PC's speakers again, with the headset
connected from the start: Virtual Desktop's sound device was there, but Windows preferred
the speakers (which the test of the last commit had caused: it chose them by hand, and
Windows keeps to the device chosen last), and Virtual Desktop's runtime names the device
Windows prefers, not its own.

- The device whose name ends with "(Virtual Desktop Audio)" is the headset's while it is in
  the system, which it is while Virtual Desktop streams to a headset: whatever Windows
  prefers and whatever the runtime in use (SteamVR names none). Its microphone likewise,
  while the playback device is there. SHADPS4_XR_STREAM_AUDIO names another ending.
- tools/audio-endpoint.ps1 preferred says which device Windows would play on if all were
  there, and pc-audio-default-test.sh makes that one the preferred one again when it is
  done, also where it is not there during the test.

Tried against a simulated headset with the monitor's device named as the streaming
program's: the game plays on it while Windows plays on the speakers. Not tried: with
Virtual Desktop itself, which needs the headset worn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 16:07:24 +02:00
bigmak94andClaude Opus 5.5 4270a553ab The game no longer stops when Windows changes its playback device, and its sound finds the headset that connects after the start
A session on the PC ended with "Unhandled Exception code 0xc0000005" in
SDL_GetAudioStreamDataAdjustGain, on the playback thread of Virtual Desktop's sound device,
a moment after the emulator had moved its ports "back" to the PC's speakers.

- Why the speakers: Virtual Desktop has its sound device only while it streams to the
  headset. Asked before that, its runtime names what Windows plays on, and the emulator asked
  once, at the start; it then held on to the speakers by name and took the sound back to them
  three seconds after Windows had moved it to the headset. The runtime is asked again now
  whenever a sound device comes or goes (OpenXrHost::AudioDevicesChanged, on the frame
  thread), and the ports go where it then says.
- Why that stopped the game: ports opened on "the default device" are moved by SDL when the
  system changes its default, and SDL 3.5.0 (SDL_DefaultAudioDeviceChanged) puts each moved
  port at the front of the new device's list without setting the back link of the one
  behind it; closing a moved port afterwards leaves the list pointing at freed memory, which
  the device's playback thread reads. The ports no longer play on "the default device":
  each is opened on the device the system plays on at that moment, as the device it is, and
  FollowDevice moves it when the system chooses another (after the three seconds it already
  waits for devices that come back).

tools/audio-endpoint.ps1 can say and set the device Windows plays on;
tools/pc-audio-default-test.sh changes it while the game plays, and back.

Tried: with the build before, that test stops the emulator (access violation); with this one
it plays on, the ports that are left to the system on the new device and back, the ones
named for a device staying there. The device test of 0.13 (a named device, and the default
device itself, taken out of Windows and put back: the level moves to the other device and
back). Against a simulated headset, whose runtime names another device once one went away:
the runtime is asked again and the ports follow. With SDL's dummy driver, as the headset's
build has it, the ports open as before. Not tried: Virtual Desktop's own device coming and
going, which needs the headset worn, and the Quest app (the headset was in use).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:53:09 +02:00
bigmak94andClaude Opus 5.5 747e525ec7 The PC's settings file tells of language= and turn=, and of controllers that take turns
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:24:17 +02:00
bigmak94andClaude Opus 5.5 d4094454ed 0.19: what players wrote elsewhere: the launcher's runtime check, the game's language, controllers that take turns on the PC, a view that turns by steps
From the project's thread on Reddit and the comments under the videos about it, all written
before 0.18. What 0.18 had not answered:

- The PC launcher asked for the Visual C++ runtime again and again, however often it was
  installed (one player cut the check out of the launcher to play). Started from a 32-bit
  program, "powershell" is the 32-bit one, to which Windows shows the 32-bit system folder
  under the 64-bit one's name, and vcruntime140_1.dll only exists in 64 bits. The launcher
  hands over to the 64-bit PowerShell first (which also puts the OpenXR runtime's registry
  entry where it looks), looks for the files where a 64-bit program finds them and next to
  the emulator, names the ones it misses, and its question can be answered with "start the
  game all the same". When the emulator ends with "DLL not found" it says what that is.
- The game was in English whatever the console's language should have been: the emulator's
  console was set to English and nothing offered another. SHADPS4_CONSOLE_LANGUAGE takes a
  language tag ("fr-FR", "pt_BR", "zh-Hans-CN") or the console's number
  (Common::ConsoleLanguageFromTag). The PC launcher passes the language Windows is shown in,
  or the one chosen in its window from the game's 28 (language=); the Quest app passes the
  headset's (language= for another).
- On the PC the headset's controllers did nothing while a gamepad was connected, even one
  that only lay there. Whichever was used last plays (Input::PadSource): a button or a stick
  of the headset's controllers takes over once the gamepad has said nothing for a quarter of
  a second, which leaves a gamepad that a streaming program makes of those controllers
  playing as before; the gamepad takes back with its first button, stick or touch. While the
  headset's controllers play, GameController leaves the gamepad's input aside, and the
  runtime believes a host that says where the controller is over a gamepad's sensors.
- Turning the view by steps, asked for by a player who cannot turn round where they sit:
  Runtime::TurnView turns the seat about the head (the head keeps its place in the title's
  world, the controller comes round, a reset of the view undoes it). Asked for with a button
  the game has no use for in play, held, and the right stick flicked to a side
  (Input::ViewTurn): L1 on a gamepad, the grip of the hand that does not hold the controller
  on the headset's own; from the Quest app as two new flags of the pad pose message. 30
  degrees a step (SHADPS4_VR_TURN, turn=). The Quest app's card names it.
- "Save Migration", a question in a box behind the game's window at the first start
  (reported from Linux, where the package's ready-made folder was not used): only asked
  where an older shadPS4 left something to move.

README: common questions (getting the game, headsets, controllers, SteamVR, why the picture
looks reprojected, language, Linux), and a player's recipe for Proton, as reported.

Tried: the unit tests (console_language_test, pad_source_test, pad_router_test with the
turn, launcher-test under 64-bit and 32-bit PowerShell, the launcher's hand-over from a
32-bit one); the game on the PC in French, Japanese and Arabic, and in English for a
language it lacks; against a simulated headset with a test gamepad and test presses of the
headset's controllers (SHADPS4_TEST_VIRTUAL_PRESS/_TURN, SHADPS4_XR_TEST_PRESS/_TURN): each
takes over from the other, the view turns by either, the picture turns and the head stays in
place; on a Quest 3 without wearing it: the language reaches the game, the self-test's new
HOST_TURN turns the view with a tracked and with an untracked controller alike, the card
shows its new line. Not tried: any of it worn, and Virtual Desktop's own gamepad emulation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 15:22:17 +02:00
bigmak94andClaude Opus 5.5 9ff3e43060 The PC package's own notes know of 1.04, of other headsets and of the touchpad's buttons
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:05:08 +02:00
bigmak94andClaude Opus 5.5 9bcfd747e9 README: what of 0.18's controllers has been played in a headset
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:03:03 +02:00
bigmak94andClaude Opus 5.5 22b89f16f4 Merge pull request #15 from ODevStudio: update packages marked PATCHGO are told from the game
The launcher took a package for the game's update by three of the marks an update can
carry; PATCHGO (0x00200000) is the fourth. By ODevStudio, who reduced their pull request to
this once main had the rest of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:02:29 +02:00
bigmak94andClaude Opus 5.5 9a2b8b8178 The touchpad's gestures on buttons, and a stick's finger the game can follow
The first worn try of the Quest app with the headset's own controllers ended at the
catapult of the first level: the right stick pulled back and let go did not shoot it. And
nothing told the player that the pad is pressed (the water cannon) by pressing that stick in.

Why the catapult failed: the game reads the pad once for every frame it draws (the newest of
the states it is handed), and takes the place it first finds the finger at for the start of
a pull. A stick is at its end within a few hundredths of a second, so the finger that
followed it there had, for the game, begun where it ended. By a model of the game's rule
(tools/tests/touch_game_model.h: read at 0xc04cc3, y = 1 - raw / 950, the catapult of
0x436fc0 wants more than 0.25 s and more than 0.4 of the pad) one fast pull in four failed
at 60 frames a second and two in three at 30, which is what the reports of Issue #2 say and
what the headset draws.

- Input::MovedFinger: a finger that stays where it lands until the game has seen it there,
  goes no faster than a finger flicks and counts as arrived once it was seen at its end.
- Input::StickFinger is built on it: the finger comes down behind the pad's middle, on the
  side the stick comes from, and is dragged to where the stick points.
- Input::PadGestures: what the game asks of the pad, done by buttons it has no use for in
  play (it only asks about them in a few menus, and is still told of them): the pad pressed
  while a button is held, a swipe forward for each press of another, a pull back that is
  held and let go with a third. On the headset's own controllers the trigger and the grip of
  the hand that holds the controller in the game and the other hand's trigger; on a gamepad
  without a touchpad R2, R1 and L2. In the Quest app's router, the PC host's code for the
  headset's controllers and the PC's gamepads.
- The Quest app shows a card over the game that names those buttons, when the game starts
  and whenever OPTIONS is pressed (the game's pause).
- SHADPS4_PAD_TOUCH_TRACE=1 has the log say what the game was given of the touchpad at each
  of its reads; input scripts can press the gesture buttons (gesture=press|swipe|pull); the
  Quest app's dry start pulls the right stick and presses R1.

Tried: the tests (stick_finger_test and pad_gestures_test against the model at 26 to 60
frames a second, pad_router_test); with the trace, in the game on the PC (62 reads a
second) and on a Quest 3 without wearing it (48 in its sandbox, 36 through the whole app):
a pull is given as 0.74 to 0.76 of the pad over 0.34 s and more, a swipe as 0.67 over a
dozen reads, a press for as long as it is held. Not tried: the catapult itself going off
(a script did not get through the level to it), and all of it worn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 13:42:32 +02:00
bigmak94andClaude Opus 5.5 ee4f9aa03f Quest app: the headset's own controllers play the game, and what other gamepads lack is made up for
The app was made for a DualSense and took everything else for a lesser one of those. Players
without one could play on the PC, with the headset's controllers, and not on the headset.

The headset's own controllers: the app reads them through the headset's runtime (OpenXR
actions, the layout the PC host has: A cross, B square, X circle, Y triangle and both
together to blow, grips L1/R1, triggers L2/R2, right stick the finger on the touchpad, left
menu button OPTIONS, both sticks in to reset the view), the right one is the controller in
the game with where it is and how it points, both shake with the game's rumble. The gamepad
the system makes of them for other apps is no longer taken for a gamepad: it says neither
where it is nor whether anybody holds it.

Which of the two: a small router (quest-host/cpp/pad_router.h) between the activity, which
hears of gamepads, and the session, which reads the controllers. The game is played with the
one used last. From a gamepad only a button under a thumb or a stick takes over, never a
trigger or a grip: while a gamepad is held it is hands the headset sees. What buttons mean
about the view besides (the first press of X takes the seat, OPTIONS held resets the view)
moved there from the activity, so that it is the same for both. The start-up menu takes
either; what confirmed it is not pressed in the game.

Gamepads that are not a PlayStation's:
- The right stick as the touchpad's finger is Input::StickFinger now, as on the PC: the
  finger lifts where the stick was let go, which the catapult at the end of a level needs.
  A button that presses the touchpad touches it in its middle.
- A gamepad without motion sensors followed the hands to where they were and kept pointing
  straight ahead. Now the hands turn and tilt it (quest-host/cpp/held_pad.h): the line
  between the palms is its sideways axis, the way the hands point is its tilt. The app says
  so with a new flag of the pad pose message (HeldInHands), and the emulator lets go of a
  controller that was a tracked device once it no longer is (it stayed where that device
  was last seen for as long as no motion sensor of its own spoke up).
- Motion sensors are only taken from PlayStation controllers: which way is up for one is
  each maker's own affair.
- A right stick on RX/RY, triggers that are only buttons, a Back button the system takes
  for its own "back".

For trying a build on a headset whose owner plays with the installed one:
quest-host/build.sh --test-package builds the app under another name, which installs next to
it; the test tools take ASTRO_PACKAGE. The self-test can report a controller the way a
session does (HOST_PAD) and keep pictures of it (HOST_SHOTS).

Tried on a Quest 3 without wearing it: the runtime takes the bindings, the app starts and
plays with a made-up gamepad, and in the game's picture the controller is where and how the
self-test says a tracked controller or hands around a gamepad are, and comes back when they
are lost. tools/tests/pad_router_test.cpp and held_pad_test.cpp try the rest on the PC.
Not tried: any of it worn, and no gamepad other than a DualSense.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 11:38:59 +02:00
ODevStudio d59cd0d370 Reduce PR to PATCHGO package rejection
Keep the maintainer's 1.04 build support, calibration and documentation from main. Retain the missing PATCHGO flag check and a regression fixture that is larger than the base package.
2026-10-06 11:01:35 +02:00
ODevStudio 664710034a Merge main and resolve PR 15 compatibility conflicts 2026-10-06 10:44:37 +02:00
bigmak94andClaude Opus 5.5 0d5bd58fe6 The microphone's loudness is not reported for a microphone that gave nothing at all
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:20:04 +02:00
bigmak94andClaude Opus 5.5 fb18b8d6bf 0.18: the game's version 1.04, SteamVR and other PC headsets, and what the reports on GitHub asked for
The first release since 0.13. For the Quest it brings the field-of-view menu of 0.14 to
0.17 and the game's version 1.04; for the PC the same and SteamVR support, spectator views,
a gamepad that can be moved where nothing tracks it, an easier catapult with a stick,
blowing with buttons, and the fixes for the two ways the game stopped as it started.
README-QUEST-VR.md and README-PC-VR.md tell each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:16:16 +02:00
bigmak94andClaude Opus 5.5 d96618af1d Quest app 0.14 to 0.17: a field-of-view menu at the start, counted from the headset's own view
Work of 2026-10-04, committed as it was (README-QUEST-VR.md tells each step):

- 0.14: every start shows a panel in the headset to choose how much of the field of view
  the game draws (left and right on the D-pad or the left stick, X to play). Less is the
  same pixels over fewer degrees, a sharper picture; the choice is remembered. Below all of
  it, each eye gets a soft-edged squircle border, drawn where the host copies the frame.
- 0.15: the percent is of the headset's own view, read from OpenXR before Play is offered
  and handed to the emulator before the game starts (SHADPS4_VR_HEADSET_FOV_TAN), 50 to 100.
- 0.16: the border sits around each eye's straight ahead, which a headset's uneven view
  does not have in the middle of the picture.
- 0.17: both eyes draw the same, even view around straight ahead that takes in the
  headset's own (SHADPS4_VR_FOV_SYMMETRIC), so that what one eye shows the other shows too
  when the view is narrowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 10:15:43 +02:00