Repository navigation
Keep Quest decoded images alive across frame gaps - #42
Merged
demonixis merged 2 commits intoOct 4, 2026
Merged
Conversation
Owner
|
Thanks for this PR. Please resolve the conflict and I'll merge it |
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.
Problem and change
When
AcquireFrame()finds no new image, it has already deletedcurrentImage_.RenderFrame()then reuses the previous external texture even though its ImageReader slot has been returned to the decoder. An EGL texture reference does not keep that slot acquired. See the NDK image ownership contract.Acquire into a temporary image and validate its hardware buffer before replacing the held image. On replacement, the render-thread callback completes prior GPU reads with
glFinish()before returning the old image. Empty acquisition and hardware-buffer errors preserve the held image; the output counter is consumed only on a successful replacement. The existing three image slots leave the two-slot margin needed byacquireLatestImage().Related work
#22 also retains the displayed image when no queued frame is due. This patch addresses the current latest-image path, hardware-buffer acquisition failure, and the ordering of GPU completion and image release. Both PRs touch
AcquireFrame(); their signature and ownership changes will need reconciliation if both are merged.Validation
assembleDebug assembleRelease, arm64-v8a, Java 17, NDK 28.2.13676358, CMake 3.22.1.AcquireFrame()body: repeated empty acquisition, invalid hardware buffer, first acquisition, and successful replacement. Unmodified develop: 7 failed checks out of 120; this change: 120/120 passed.glFinish()wait. The fake completion callback checks call ordering, not real GPU completion.Reproduce the isolated checks
The standalone reproducer is kept on a separate fork branch so these small fixes do not introduce an Android mocking framework into the runtime suite. It compiles the actual affected function/branch bodies with fake Android APIs and a controlled clock under ASan/UBSan. It does not execute MediaCodec, GLES, or an OpenXR headset.
After downloading the script outside the checkout, run from this PR branch:
Base checked:
developatf72f2b20dd0c9e5a4c0b43ca7f9b0f65704aa1e6. The affected Android source files are identical onunstableata93418fea5f523107057c1903c6fe753d89da839.