Repository navigation
Conversation
Adds a fourth rendering method that renders a single view from the point between the eyes and submits that image to both eyes every frame. It costs about as much as Synchronized Sequential, but both eyes get a new image each frame, so there is no halved refresh rate or ghosting. There is no stereo depth. Mono reuses the single view layout that AFR already uses, so is_using_afr() stays true for it. The new is_using_alternating_eyes() covers the places that depend on left/right frame parity, which mono skips. Horizontal Symmetric projection is forced (and Vertical Matched unless the user picked Symmetric) so both eyes share one frustum and the existing per eye view bounds crop the image at submit. Work that used to run only on the left or right pass (pose update, roomscale movement, aim rotation, UObjectHook attachments) now runs on the single mono pass. Tested on D3D12 with OpenXR (VDXR). The D3D11 and OpenVR paths compile but are untested.
|
nice work! I am looking to implement this as well as an additional separate option |
joeyhodge
added a commit
to joeyhodge/UEVR
that referenced
this pull request
Sep 26, 2026
Keep rendering IDs 0-4 intact and add Mono as ID 5. Retire GPU consumers before live mode transitions, gate fresh pose/projection/scene generations, retain per-image copy sources, and keep Native/Ghost/DIBR settings isolated. Pair the experimental frontend branch and add WARP copy, transition, geometry and profile tests. Adapted from Noniv's Mono proposal in praydog#442; implementation and validation details are in docs/mono-rendering.md.
joeyhodge
added a commit
to joeyhodge/UEVR
that referenced
this pull request
Sep 26, 2026
Keep rendering IDs 0-4 intact and add Mono as ID 5. Retire GPU consumers before live mode transitions, gate fresh pose/projection/scene generations, retain per-image copy sources, and keep Native/Ghost/DIBR settings isolated. Pair the experimental frontend branch and add WARP copy, transition, geometry and profile tests. Adapted from Noniv's Mono proposal in praydog#442; implementation and validation details are in docs/mono-rendering.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds "Mono" as a fourth option in the Rendering Method dropdown. It renders one view from the point between the eyes and sends that same image to both eyes every frame.
I wanted it for performance. Synchronized Sequential renders one eye per frame, but it only submits a finished stereo pair every second frame. When I tried it, the FPS shown in Virtual Desktop did not go up compared to Native Stereo and it felt choppy. Mono also renders one view per frame, but every frame goes to both eyes. What you give up is stereo depth: the world looks flat, like a very large screen wrapped around you. The UI still has depth because it goes to the compositor as its own quad layer.
In Clair Obscur: Expedition 33 (UE5, D3D12, OpenXR through Virtual Desktop's VDXR) I got roughly 70% more FPS than Native Stereo at the same settings.
The second reason is stereo bugs. Some games render certain effects for one eye only. In Clair Obscur: Expedition 33, fog is sometimes visible in one eye and not the other, and objects are occasionally lit in one eye only. The mismatch is uncomfortable to look at. Since Mono shows both eyes the same image, those differences go away.
How it works
Mono reuses the single view layout that the AFR methods already use, so
is_using_afr()is still true for it and the render target and swapchain setup is unchanged. I addedis_using_alternating_eyes()for the code that depends on left/right frame parity, and switched those call sites over so mono skips them.Both eyes have to share one frustum, so mono forces Horizontal Symmetric projection, and Vertical Matched if the user left vertical on default. The existing per eye view bounds then crop the shared image at submit. The eye offset is the average of the left and right offsets.
On submit, the D3D11 and D3D12 components already had a path that copies one frame to both eye swapchains when the same frame is presented twice. Mono takes that path every frame, with the right eye copy reading the left half of the backbuffer.
Some work only ran on the left pass (pose update) or the right pass (roomscale movement, aim rotation, UObjectHook attachment ticking). With a single pass per frame, mono runs all of it on that pass.
Testing
Tested by me: D3D12 with OpenXR (VDXR) on Quest 3, one game, played with Quest controllers. Switching between Native Stereo and Mono at runtime works.
Not tested: D3D11, OpenVR/SteamVR, 2D screen mode, and headsets with canted displays (Index, Pimax). Those paths compile, and I changed them the same way as the D3D12/OpenXR ones, but nobody has run them. On canted headsets the symmetric projection is probably not enough, since the two eyes do not share an orientation there.