Files
questshock/android/app/src/main/AndroidManifest.xml
T
ml 2300d081c3
build / build (push) Successful in 2m12s
Add OpenXR bring-up: render the game as a floating quad in an immersive Quest session
- New android/app/src/main/cpp/xr_session.c (+.h): owns the OpenXR
  instance/session/local-space/swapchain and the per-frame
  xrWaitFrame/xrBeginFrame/xrEndFrame loop, submitting the game's
  existing flat render as a single head-tracked XrCompositionLayerQuad.
  No stereo rendering or controller input yet - that's steps B/C/D of
  the plan.
- 11-android-openxr-cmake.patch: links the OpenXR loader as a build
  dependency, staged into jniLibs the same way as gl4es/SDL2.
  build-image/Dockerfile and prepare-android-project.sh build and stage
  it.
- 12-android-openxr-present.patch: redirects OpenGL.cc's final present
  step (opengl_swap_and_restore / SDLDraw's software path) into the XR
  swapchain FBO instead of the window, on Android only. Two real gl4es
  bugs had to be worked around to get pixels on screen at all:
    - gl4es's own glBindFramebuffer errors on an FBO id it didn't create
      itself, even though the real driver-level bind succeeds - fixed by
      creating the swapchain FBO container via gl4es's own
      glGenFramebuffers/glBindFramebuffer, and only using the real
      (dlsym'd) driver call for attaching OpenXR's foreign swapchain
      texture, which gl4es's own attach can't handle.
    - gl4es's glBegin/glVertexAttrib/glVertex3f immediate-mode emulation
      only captures a fresh per-vertex value for attribute 0 (position,
      driven directly by glVertex3f) - custom attributes like this
      shader's texcoords/light are GLES2's *constant*-attribute API and
      applied once for the whole draw, not per vertex, silently
      collapsing the UI-overlay quad to a single sampled texel. Fixed by
      switching that one draw call to real vertex arrays
      (glVertexAttribPointer/glDrawArrays).
  Also flips the V texcoord to match SDL's top-down row order against
  GL's texture convention, and reuses a persistent texture object
  instead of a fresh gen/upload/delete every frame.
- AndroidManifest.xml: declares the immersive-HMD intent category and
  focus-aware metadata, drops the 2D-panel layout hint.
- README: documents the new OpenXR immersive mode.
2026-07-25 07:25:27 +02:00

70 lines
3.7 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto">
<!-- OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
<uses-feature android:name="android.hardware.usb.host" android:required="false" />
<!-- External mouse input events -->
<uses-feature android:name="android.hardware.type.pc" android:required="false" />
<!-- Immersive OpenXR app now (see android/app/src/main/cpp/xr_session.c),
not a 2D Home panel - vr.headtracking is what actually declares that
to Horizon OS. -->
<uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="true" />
<!-- Plain, unrestricted /sdcard access for the res/data,res/sound the
user drops in and the shaders/soundfont this app extracts there on
first run - see res/GET_ASSETS_QUEST.txt and QuestShockActivity.
requestLegacyExternalStorage below (paired with targetSdkVersion 29
in build.gradle) is what keeps this working instead of Android 11+
scoped storage. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:allowBackup="true"
android:requestLegacyExternalStorage="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:hardwareAccelerated="true" >
<!-- Tells Horizon OS this activity wants the compositor for itself
(immersive VR), not the Home 2D-panel path - required for an
OpenXR session to actually start. -->
<meta-data android:name="com.oculus.vr.focusaware" android:value="true" />
<activity android:name="de.ladkau.questshock.QuestShockActivity"
android:label="@string/app_name"
android:alwaysRetainTaskState="true"
android:launchMode="singleInstance"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:screenOrientation="landscape"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<!-- The vendor-neutral, Khronos-defined way to declare an
immersive OpenXR entry point (vs. e.g. Meta's own
com.oculus.intent.category.VR) - see this project's
"favor OpenXR" rule in the README. If Horizon OS still
launches this as a flat panel on-device, the next thing
to try is adding a com.oculus.supportedDevices meta-data
listing the target Quest models - not confirmed
necessary from static analysis alone. -->
<category android:name="org.khronos.openxr.intent.category.IMMERSIVE_HMD" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
</activity>
</application>
</manifest>