compositor: only release swapchain image in Submit if one was acquired - #431
Open
shakespear-dev wants to merge 1 commit into
Open
shakespear-dev wants to merge 1 commit into
shakespear-dev wants to merge 1 commit into
Conversation
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.
Fixes a panic in
IVRCompositor::Submitthat kills the game on startup:How I hit it
Serious Sam VR: The First Encounter (Steam 552450) under Proton, WiVRn, Quest 3, Linux, AMD GPU. The game shows "xrizer crashed" on every launch, before the menu. Same result with the v0.5 release and with the current nightly (0989a7f). In the log the panic always comes right after the first game texture arrives:
The full log excerpt with the backtrace is at the bottom of this description.
This looks like the same crash as #364 (Serious Sam Fusion, also WiVRn): same panic text at the same point in the log. That issue was closed after a reinstall made it go away, without a code change.
Why it happens
FrameController::submit_implreleases the swapchain image as soon as both eyes have been submitted, whenever a swapchain exists. It does not check that an image was actually acquired.begin_frame, a few lines above, guards the very same release withself.image_acquired.The unguarded release is reached when the first
Submitarrives while no frame is begun:Submitfinds no frame controller and callsinitialize_real_session, which restarts the session for the game's texture.FrameController::newcreates the swapchain from the texture info but acquires nothing (image_acquired: false).post_session_restartreplays the previous frame state. ForWaitedit only callsmaybe_wait_frame;begin_frame, the only place that acquires an image, does not run.submit_implcallsrelease_image()on a swapchain with nothing acquired, and the openxr crate asserts.In the usual implicit-timing flow the previous state is
Begun, sobegin_frameruns during the restart and acquires an image. That is why most games never see this.Steps to reproduce
Without a headset, on
main: apply only the test from this PR and runIt sets explicit timing, calls
WaitGetPoses, then submits both eyes withoutSubmitExplicitTimingData. It fails with the same message at the same place (openxr-0.21.1/src/swapchain.rs:107), right after "Received game texture, restarted session with new data".With a headset: launch Serious Sam VR: TFE through xrizer; it panics before the menu.
One caveat: my logs from the game were at INFO level, so I have not confirmed that the game takes exactly this call sequence (explicit timing without
SubmitExplicitTimingData). The test is a sequence that provably reaches the same unguarded release; the game's panic message, backtrace and position in the log match it.The fix
Release only when an image was acquired, the same condition
begin_frameuses:The frame that was submitted without being begun is dropped, as before:
PostPresentHandoffskips it because the state is notBegun, and the nextWaitGetPosestakes the existing "discard frame" path, wherebegin_frameacquires an image normally. The second half of the test checks that the following frame goesBegun->Ended. Nothing changes for apps that begin their frames properly, sinceimage_acquiredis already true for them at this point.With this change the game starts, reaches the menu and plays; I finished a level with it.
cargo test,cargo +nightly miri test,cargo fmt --checkandcargo clippy --workspace --all-targetspass locally.xrizer log from the crashing run (stock nightly, 0989a7f)