Add Meta Quest OpenXR VR support for Android#2
Conversation
|
Warning Review limit reached
Next review available in: 45 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (20)
📝 WalkthroughWalkthroughAdds a Meta Quest Android flavor with OpenXR and GLES3 support, Quest-specific packaging and startup behavior, Android VR rendering adaptations, local ADB/Docker tooling, and separate phone and Quest APK CI workflows. ChangesQuest Android VR flavor
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Developer
participant Gradle
participant CMake
participant PicaSim
participant OpenXRRuntime
participant Quest
Developer->>Gradle: assembleQuestDebug
Gradle->>CMake: Configure PICASIM_QUEST
CMake->>Gradle: Link GLESv3 and OpenXR loader
Gradle->>Quest: Install Quest APK
Quest->>PicaSim: Launch Quest activity
PicaSim->>OpenXRRuntime: CreateInstance()
OpenXRRuntime->>OpenXRRuntime: Create OpenGLES session
OpenXRRuntime->>Quest: Render VR frames
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
.github/workflows/github-release.yml (1)
159-164: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winInclude the Quest APK in GitHub releases.
The PR objectives mention updating the release workflows to "build flavor-specific APKs, upload renamed Quest artifacts". However, this workflow currently only builds and packages the
phoneflavor. If you intend to distribute the experimental Quest build via GitHub releases, you should addassembleQuestDebugand copy its APK here as well.📦 Proposed fix to include the Quest APK
- - name: Build debug APK + - name: Build debug APKs working-directory: android run: | - ./gradlew assemblePhoneDebug + ./gradlew assemblePhoneDebug assembleQuestDebug - - name: Rename APK + - name: Rename APKs run: | VERSION=$(grep -oE 'Version [0-9.]+' VERSIONS.txt | head -1 | sed 's/Version //') cp android/app/build/outputs/apk/phone/debug/app-phone-debug.apk "PicaSim-${VERSION}-android-debug.apk" + cp android/app/build/outputs/apk/quest/debug/app-quest-debug.apk "PicaSim-${VERSION}-quest-debug.apk" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: release-android - path: PicaSim-*-android-debug.apk + path: PicaSim-*-debug.apk retention-days: 1🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/github-release.yml around lines 159 - 164, Update the release workflow’s Android build and packaging steps around assemblePhoneDebug and the Rename APK step to also run assembleQuestDebug and copy the generated Quest debug APK into a clearly named PicaSim-${VERSION}-quest-android-debug.apk release artifact, while preserving the existing phone artifact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@android/app/build.gradle`:
- Around line 143-144: Update the quest flavor dependency declaration for
org.khronos.openxr:openxr_loader_for_android from version 1.1.49 to 1.1.60,
leaving its questImplementation configuration unchanged.
In `@QUEST.md`:
- Line 67: Update the hardware-testing status in QUEST.md to document the Quest
headset and build tested, reflecting that device testing exposed the
invisible-menu startup issue. Retain caveats for any Quest models or
configurations that remain untested.
In `@source/Framework/RenderManager.cpp`:
- Around line 697-704: Update the MSAA renderbuffer setup in the RenderManager
initialization path to use the same internal format selected by
OpenXRRuntime::CreateSwapchainsInternal, rather than always forcing
GL_SRGB8_ALPHA8 on Android. Expose or reuse the selected swapchain format so the
renderbuffer and swapchain attachment match for both GL_RGBA8 and
GL_SRGB8_ALPHA8, preserving the existing platform-specific setup.
---
Nitpick comments:
In @.github/workflows/github-release.yml:
- Around line 159-164: Update the release workflow’s Android build and packaging
steps around assemblePhoneDebug and the Rename APK step to also run
assembleQuestDebug and copy the generated Quest debug APK into a clearly named
PicaSim-${VERSION}-quest-android-debug.apk release artifact, while preserving
the existing phone artifact.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: efe706a8-5579-4839-a3f6-f7479da8e5a9
📒 Files selected for processing (15)
.github/workflows/android-build.yml.github/workflows/github-release.ymlCMakeLists.txtQUEST.mdandroid/app/build.gradleandroid/app/src/quest/AndroidManifest.xmlquest_run.shsource/Framework/RenderManager.cppsource/PicaSim/Main.cppsource/PicaSim/PicaSim.cppsource/Platform/OpenXRRuntime.cppsource/Platform/OpenXRRuntime.hsource/Platform/VRManager.cppsource/Platform/VRMenuRenderer.cppsource/Platform/Window.cpp
| // Khronos OpenXR loader (AAR with prefab support) — quest flavor only | ||
| questImplementation 'org.khronos.openxr:openxr_loader_for_android:1.1.49' |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
What is the latest stable version of the org.khronos.openxr:openxr_loader_for_android package on Maven Central?
💡 Result:
The latest stable version of the org.khronos.openxr:openxr_loader_for_android package available on Maven Central is 1.1.60 [1]. Although a hotfix version 1.1.59.1 was previously released [2], the 1.1.60 release, published on May 20, 2026, serves as a subsequent stable update containing support for a new multi-vendor extension along with various fixes and cleanups [1]. Users can include this version in their Android project's build.gradle file as follows: implementation 'org.khronos.openxr:openxr_loader_for_android:1.1.60' [1]
Citations:
- 1: chore(deps): bump org.khronos.openxr:openxr_loader_for_android from 1.1.49 to 1.1.60 in /android ReactVision/virocore#336
- 2: https://github.com/KhronosGroup/OpenXR-SDK-Source/releases/tag/release-1.1.59.1
Bump org.khronos.openxr:openxr_loader_for_android to 1.1.60
1.1.49 is behind the current stable Maven Central release.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@android/app/build.gradle` around lines 143 - 144, Update the quest flavor
dependency declaration for org.khronos.openxr:openxr_loader_for_android from
version 1.1.49 to 1.1.60, leaving its questImplementation configuration
unchanged.
|
|
||
| - **Experimental** — the build-system support is in place, but the rendering | ||
| path is still being ported to GLES3 for the Quest's OpenXR runtime. | ||
| - Not yet tested on real hardware. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Update the hardware-testing status.
“Not yet tested on real hardware” contradicts the PR history, which says Quest device testing exposed the invisible-menu startup issue. Document the tested headset/build and retain any untested-device caveats.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@QUEST.md` at line 67, Update the hardware-testing status in QUEST.md to
document the Quest headset and build tested, reflecting that device testing
exposed the invisible-menu startup issue. Retain caveats for any Quest models or
configurations that remain untested.
| #if defined(PICASIM_ANDROID) || defined(__ANDROID__) | ||
| // GLES3 requires the multisample resolve source and destination to | ||
| // have identical internal formats. The OpenXR runtime prefers an | ||
| // SRGB8_ALPHA8 swapchain (which Quest provides), so match it here. | ||
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaaSamples, GL_SRGB8_ALPHA8, eyeWidth, eyeHeight); | ||
| #else | ||
| glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaaSamples, GL_RGBA8, eyeWidth, eyeHeight); | ||
| #endif |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm the swapchain fallback and MSAA resolve sites remain coupled.
rg -n -C4 'selectedFormat|GL_SRGB8_ALPHA8|glRenderbufferStorageMultisample|glBlitFramebuffer' \
source/Platform/OpenXRRuntime.cpp source/Framework/RenderManager.cppRepository: RobertoD91/PicaSim
Length of output: 9518
🌐 Web query:
OpenGL ES 3.0 glBlitFramebuffer multisample resolve identical internal formats GL_INVALID_OPERATION official spec
💡 Result:
In OpenGL ES 3.0, the glBlitFramebuffer specification explicitly requires that if either the read or draw framebuffer is multisampled (i.e., SAMPLE_BUFFERS is greater than zero), the internal formats of the corresponding attachments must be identical [1][2][3]. If they are not identical, an GL_INVALID_OPERATION error is generated [1][2][3]. This restriction is a formal requirement of the OpenGL ES 3.0 specification for multisample resolve operations [1][2]. While later versions of the desktop OpenGL specification (starting with 4.4) were updated to relax this constraint and allow format conversion during multisample blits, the OpenGL ES 3.0 core specification retains the requirement that formats must be identical for multisample resolve operations to ensure conformance [4][1][2]. In addition to the identical format requirement, glBlitFramebuffer also mandates the following for multisample blits (when either the read or draw buffer is multisampled): * The source and destination rectangle dimensions (X0, Y0, X1, Y1) must be identical [1][2][3]. * If both framebuffers are multisampled, their sample counts (SAMPLES) must be identical [5][6][3]. Failure to meet these conditions—including the identical internal format requirement—will result in a GL_INVALID_OPERATION error [5][1][2][3].
Citations:
- 1: https://github.com/anholt/mesa/blob/master/src/mesa/main/blit.c
- 2: https://lists.freedesktop.org/archives/mesa-dev/2013-January/033003.html
- 3: https://registry.khronos.org/OpenGL/extensions/NV/NV_framebuffer_blit.txt
- 4: imirkin/mesa@4c7c9e4
- 5: https://www.khronos.org/opengl/wiki/GlBlitFramebuffer
- 6: https://man.archlinux.org/man/glBlitFramebuffer.3G.en.txt
Match the MSAA renderbuffer format to the selected swapchain format
OpenXRRuntime::CreateSwapchainsInternal can select GL_RGBA8, but the Android MSAA buffer is still created as GL_SRGB8_ALPHA8. In OpenGL ES 3.0, multisample blits require identical internal formats, so the resolve can fail with GL_INVALID_OPERATION when the fallback is used. Expose the chosen swapchain format or derive the renderbuffer format from the swapchain attachment.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@source/Framework/RenderManager.cpp` around lines 697 - 704, Update the MSAA
renderbuffer setup in the RenderManager initialization path to use the same
internal format selected by OpenXRRuntime::CreateSwapchainsInternal, rather than
always forcing GL_SRGB8_ALPHA8 on Android. Expose or reuse the selected
swapchain format so the renderbuffer and swapchain attachment match for both
GL_RGBA8 and GL_SRGB8_ALPHA8, preserving the existing platform-specific setup.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/android-build.yml (1)
63-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
printfinstead ofecho -nfor decoding base64 secrets.Different implementations of
echohandle the-nflag inconsistently, which can sometimes corrupt the decoded output or print-ndirectly into the stream.printfis POSIX-compliant and more reliable for handling base64 secrets.
.github/workflows/android-build.yml#L63-L63: replaceecho -n "$ANDROID_KEYSTORE_BASE64"withprintf "%s" "$ANDROID_KEYSTORE_BASE64"..github/workflows/github-release.yml#L165-L165: replaceecho -n "$ANDROID_KEYSTORE_BASE64"withprintf "%s" "$ANDROID_KEYSTORE_BASE64"..github/workflows/quest-build.yml#L62-L62: replaceecho -n "$ANDROID_KEYSTORE_BASE64"withprintf "%s" "$ANDROID_KEYSTORE_BASE64".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/android-build.yml at line 63, Replace echo -n with printf "%s" when piping ANDROID_KEYSTORE_BASE64 into base64 decoding in .github/workflows/android-build.yml:63-63, .github/workflows/github-release.yml:165-165, and .github/workflows/quest-build.yml:62-62; preserve the existing output paths and decoding flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In @.github/workflows/android-build.yml:
- Line 63: Replace echo -n with printf "%s" when piping ANDROID_KEYSTORE_BASE64
into base64 decoding in .github/workflows/android-build.yml:63-63,
.github/workflows/github-release.yml:165-165, and
.github/workflows/quest-build.yml:62-62; preserve the existing output paths and
decoding flow.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a6a1767f-70cf-4e5e-8588-be2cfde53ae2
📒 Files selected for processing (11)
.github/workflows/android-build.yml.github/workflows/github-release.yml.github/workflows/quest-build.ymlQUEST.mdandroid/app/build.gradleandroid/debug.keystoredocker/android-build.Dockerfilequest_docker_build.shquest_run.shsource/PicaSim/Main.cpptools/android_smoke_test.sh
🚧 Files skipped from review as they are similar to previous changes (2)
- quest_run.sh
- QUEST.md
Android gains phone/quest product flavors: phone is today's build, quest passes PICASIM_QUEST=ON to CMake, links the Khronos OpenXR Android loader (org.khronos.openxr:openxr_loader_for_android:1.1.49 via prefab, minSdk 29 for this flavor as the loader requires 24+) and merges a manifest overlay with the Quest metadata (vr.headtracking, com.oculus.intent.category.VR, supportedDevices, no orientation lock). CMake: new PICASIM_QUEST option; on Android it enables VR, finds the OpenXR prefab package, defines PICASIM_VR_SUPPORT/PICASIM_QUEST and links GLESv3 + openxr_loader. Non-quest Android keeps VR forced off. CI builds both flavors and uploads a separate quest APK artifact; APK paths updated for the flavored output layout. QUEST.md documents building, sideloading and input (RC transmitter as SDL gamepad, no VR controller support). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Quest: Android/OpenGL ES backend for the OpenXR runtime Adds the Android path to the OpenXR layer, all behind PICASIM_ANDROID with the Win32/desktop-GL path unchanged: - XR_USE_GRAPHICS_API_OPENGL_ES + XR_USE_PLATFORM_ANDROID, with EGL, GLES3 and JNI headers ahead of openxr_platform.h - one-time xrInitializeLoaderKHR with the JavaVM and activity obtained from SDL, before any other OpenXR call (mandatory on Android) - instance extensions XR_KHR_opengl_es_enable and XR_KHR_android_create_instance, with XrInstanceCreateInfoAndroidKHR chained into instance creation - session creation via XrGraphicsBindingOpenGLESAndroidKHR built from the current EGL display/context, with the EGLConfig recovered from the context's EGL_CONFIG_ID - swapchain images typed XrSwapchainImageOpenGLESKHR Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Quest: port the VR render path to OpenGL ES 3.0 The VR rendering code was written against desktop GL; this makes it compile and behave on an ES 3.0 context (Quest), with every change inert unless PICASIM_ANDROID/PICASIM_QUEST is defined: - Window: request an ES 3.0 context and GLES3 headers for the quest flavor (non-quest Android stays on ES 2.0) - glDepthRange -> glDepthRangef on GLES (double variant doesn't exist) - MSAA color renderbuffer uses GL_SRGB8_ALPHA8 on Android: GLES3 requires matching internal formats on multisample resolve blits and the swapchain prefers sRGB - panorama depth copy: GLES cannot glCopyTexImage2D depth, so it is replaced by a depth blit through a temporary FBO; depth texture allocated with GL_UNSIGNED_INT as GLES3 rejects DEPTH_COMPONENT24 + GL_FLOAT - desktop mirror-window rendering and per-eye mirror blits compiled out on Android (no mirror on device; swapping the invisible SDL surface could stall the XR frame loop), and the eye mirror FBOs are skipped entirely, saving GPU memory Known runtime follow-ups documented in QUEST.md territory: swapchain format fallback if the runtime lacks SRGB8_ALPHA8, and possible double sRGB encoding to tune in the swapchain choice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Quest: fix glad include in PicaSim.cpp for Android VR builds PicaSim.cpp's VR block included glad unconditionally; it had only ever compiled on Windows. Use GLES3 headers on Android like the rest of the VR path. First compile failure caught by CI on the quest flavor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Quest: enable VR at startup so menus render in the headset On-device testing showed the app healthy (assets extracted, GL up, OpenXR instance created on the Meta runtime) but stuck on the system loading interstitial: the menus were rendering to the invisible SDL surface with zero XR frames submitted. The menus already go through VRMenuRenderer, which is gated on mOptions.mEnableVR - default false and only togglable from the desktop settings UI. On the quest flavor, force it on at startup: the SDL window is invisible, the app only exists in VR. Also from the first device-test round: - quest_run.sh: one-step adb install + launch + PID-filtered logcat (drops the Quest system noise, keeps PicaSim/SDL/OpenXR output), saving to picasim_quest_run.log with a crash-report dump on Ctrl-C - CI names the quest APK com.rowlhouse.picasim-quest-v<version>-b<run> so sideloaded builds are identifiable Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Quest: skip menus at startup, stable debug signing, quest-only CI workflow [skip ci] Second device-test round: the XR session comes up and the menus render in the headset, so now the quest flavor goes straight to flying via the existing mFreeFlyOnStartup path (menu navigation needs a Bluetooth mouse for now and is a later step). Sideload fixes: - debug builds are now signed with a keystore committed to the repo (standard Android debug credentials): every CI runner used to generate its own debug key, so each new APK failed to install with INSTALL_FAILED_UPDATE_INCOMPATIBLE - CI passes -PpicasimBuildNumber=<run number>: versionCode becomes <2MMNNPP>000+build, strictly increasing across CI builds so updates install cleanly; quest_run.sh installs with -r -d (downgrade allowed for local builds) and auto-uninstalls on a signature mismatch quest-build.yml is a new workflow_dispatch-only workflow that builds just the quest flavor, to iterate on the port without burning CI minutes on the full multi-platform suite; combined with [skip ci] on work-in-progress pushes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Android CI: optional custom signing keystore via secrets [skip ci] Debug builds can now be signed with a user-provided key: the workflows (quest-build, android-build, github-release) decode ANDROID_KEYSTORE_BASE64 and export it with its credentials (ANDROID_KEYSTORE_PASSWORD/KEY_ALIAS/KEY_PASSWORD) as PICASIM_KEYSTORE_* environment variables, which build.gradle's debug signing config picks up. With any secret missing - e.g. on fork PRs, where secrets are unavailable - the build falls back to the debug keystore committed in android/, preserving the stable-signature behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Quest: local Docker build environment for fast iteration [skip ci] quest_docker_build.sh builds the APK in a container instead of waiting for CI: docker/android-build.Dockerfile bakes JDK 17 + Android SDK, NDK 27.0.12077973 (the version AGP actually resolves on CI) and cmake 3.22.1, with licenses pre-accepted so AGP can fetch anything else. Gradle caches persist in the picasim-gradle named volume and native build outputs live in the repo bind-mount, so incremental builds are fast. A host android/local.properties is shadowed inside the container so it can't point gradle at the host SDK path. Runs as linux/amd64 (the NDK has no linux/arm64 host toolchain); on Apple Silicon enable Rosetta emulation in Docker Desktop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX quest_run.sh: add -u/--uninstall option for clean installs [skip ci] ./quest_run.sh -u <apk> uninstalls the old app before installing (clean install, drops app data); ./quest_run.sh -u alone just uninstalls and exits. The automatic uninstall-on-signature-mismatch fallback stays. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX Quest: start with the powered trainer in the 3D field; fix emulator smoke test [skip ci] The quest flavor now always starts flying the Jackdaw (powered, with wheels) in RecreationGround3D - the same combination as the built-in powered-trainer scenario but with the full-3D environment instead of the panoramic one - until the menus are usable in the headset. The test-android job had been broken since its introduction: the android-emulator-runner action executes its script input line by line, so the multi-line polling loop died with a shell syntax error. The logic now lives in tools/android_smoke_test.sh, called as one line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX
a6a5382 to
8b08e0c
Compare
Summary
Adds OpenXR-based VR support for Meta Quest headsets (Quest 2/Pro/3) via a new Android Gradle product flavor. The regular Android build remains unchanged (phone flavor, VR off). This is an experimental feature—the build system is in place, but rendering is still being ported to GLES3.
Key Changes
Build System & Configuration
questGradle product flavor alongside existingphoneflavor; both use the same application ID so only one can be installed at a timeorg.khronos.openxr:openxr_loader_for_android:1.1.49) via Gradle prefab support, exposed to CMake asOpenXR::openxr_loader-DPICASIM_QUEST=ONto enable VR on Android; setsPICASIM_VR_SUPPORT=1,PICASIM_QUEST=1, and links GLESv3 in addition to GLESv2Android Manifest & Metadata
android/app/src/quest/AndroidManifest.xml) with:com.oculus.intent.category.VR)OpenXR Runtime Implementation (
OpenXRRuntime.cpp)CreateInstance(): Retrieves JavaVM and activity from SDL, initializes Android OpenXR loader viaxrInitializeLoaderKHRbefore any other OpenXR callsCreateInstance(): SelectsXR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAMEon Android vs.XR_KHR_OPENGL_ENABLE_EXTENSION_NAMEon desktop; includesXR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAMEin enabled extensionsCreateInstance(): Passes JavaVM and activity to runtime viaXrInstanceCreateInfoAndroidKHRchained structCreateSessionInternal(): Android path retrieves EGL display/context from SDL, finds matching EGLConfig viaGetEGLConfigForContext()helper, creates graphics binding withXrGraphicsBindingOpenGLESAndroidKHRXrSwapchainImageOpenGLESKHRon Android vs.XrSwapchainImageOpenGLKHRon desktopGraphics & Rendering (
RenderManager.cpp,Window.cpp,VRManager.cpp,VRMenuRenderer.cpp)glBlitFramebuffer,glRenderbufferStorageMultisample, sized internal formatsglDepthRangef()(float variant) on GLES,glDepthRange()on desktopGL_SRGB8_ALPHA8on Quest (matches OpenXR runtime preference) vs.GL_RGBA8on desktopGL_UNSIGNED_INTtype on GLES3 (required forGL_DEPTH_COMPONENT24) vs.GL_FLOATon desktopglBlitFramebufferon GLES3 (sinceglCopyTexImage2Dcannot copy from depth buffer) vs.glCopyTexImage2Don desktophttps://claude.ai/code/session_0123xeZJrveacZTdK8bCv7YX
Summary by CodeRabbit