mirror of
https://github.com/daniel-lynch/ovrplugin-openxr-shim.git
synced 2026-10-06 04:04:09 +02:00
Initial public release: OVRPlugin→OpenXR interoperability shim
An independent reimplementation of Meta's libOVRPlugin ABI on top of OpenXR, so VrApi-era Meta Quest VR titles can run on non-Meta OpenXR runtimes (Monado, Steam Frame) instead of being locked to Meta hardware. Original code only — no Meta/Epic/Capcom binaries, headers, or assets. Includes a desktop harness that drives the shim against Monado headless. Scope/legal: interoperability; entitlement handling is out of scope. See README for the legal/scope section and docs/ for the research trail and design notes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D6sFYGXZPsq3v7xtcDES6g
This commit is contained in:
commit
a72a79ad29
57 files changed
+9304
No files matched your search
@@ -0,0 +1,54 @@
|
||||
# libOVRPlugin.so shim (OVRPlugin v1.51 -> OpenXR)
|
||||
|
||||
Drop-in replacement for RE4 VR's libOVRPlugin.so that re-exports the ovrp_* symbols
|
||||
backed by OpenXR (Monado) instead of Meta's libvrapi.so. See ../HOST.md, ../SHIM-SCOPE.md.
|
||||
|
||||
## Layout
|
||||
- include/ovrplugin_shim.h — OVRPlugin v1.51 C ABI (types + core protos; self-checking
|
||||
_Static_asserts on binary-verified struct sizes).
|
||||
- gen_stubs.sh — generates src/stubs.c from ../analysis/shim_surface.txt.
|
||||
- src/stubs.c (generated) — 224 stubs: 101 Unsupported(-1004), 32 no-op Success(0),
|
||||
91 NotYetImplemented(-1005).
|
||||
- src/core.c — the 15 header-prototyped core fns (frame loop/init/poses/
|
||||
controller/system), currently TODO stubs returning -1005 with outputs zeroed.
|
||||
|
||||
## Build (host, for validation)
|
||||
```
|
||||
cc -std=c11 -Wall -shared -fPIC -fvisibility=hidden -Iinclude src/stubs.c src/core.c \
|
||||
-o build/libOVRPlugin.so
|
||||
```
|
||||
Status: builds; exports exactly 239 ovrp_ symbols (1:1 with shim_surface.txt, 0
|
||||
missing/extra); dlopen+dlsym verified. This is the SKELETON — it loads and resolves,
|
||||
it does not yet drive VR (core fns are TODO).
|
||||
|
||||
## Real target build (deployable) — TODO
|
||||
Must be aarch64 / Android (bionic) since it runs inside Lepton. Use the Android NDK:
|
||||
```
|
||||
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android29-clang \
|
||||
-std=c11 -shared -fPIC -fvisibility=hidden -Iinclude src/stubs.c src/core.c \
|
||||
-o build/arm64/libOVRPlugin.so
|
||||
```
|
||||
(host build only proves the C + symbol coverage; NDK build is the artifact that
|
||||
replaces the real lib in the APK.)
|
||||
|
||||
## Modules (current)
|
||||
- include/ovrplugin_shim.h — OVRPlugin v1.51 ABI (types, structs, core protos).
|
||||
- src/stubs.c (generated) — 221 stubs (unsupported/no-op/TODO).
|
||||
- src/core.c — lifecycle + frame loop + poses (-> xr_runtime).
|
||||
- src/xr_runtime.{h,c} — OpenXR engine: session, frame loop, swapchains.
|
||||
- src/vk_session.c — Vulkan-typed: xrCreateSession binding + image enum.
|
||||
- src/layers.c — ovrp_SetupLayer / GetLayerTexture2 / StageCount.
|
||||
- tests/harness.c — Path B smoke test (see ../TESTING.md).
|
||||
Build adds: -Ithird_party/openxr -Ithird_party/vulkan, and src/{core,xr_runtime,
|
||||
vk_session,layers,stubs}.c. 20 OpenXR fns used; 239/239 ovrp_ exported.
|
||||
|
||||
## Done so far
|
||||
Session lifecycle, frame loop (xrWaitFrame/Begin/EndFrame), poses (xrLocateViews/
|
||||
Space), swapchains (xrCreateSwapchain from ovrpLayerDesc, acquire/wait/release,
|
||||
XrCompositionLayerProjection submit). Vulkan binding from Initialize5 args [VERIFIED].
|
||||
|
||||
## Next (see ../TESTING.md for the test plan)
|
||||
1. NDK arm64 build (host build is validation only).
|
||||
2. [ANDROID-TODO] JavaVM/activity -> XrInstanceCreateInfoAndroidKHR + xrInitializeLoaderKHR.
|
||||
3. Input action sets (controllers/hands); depth layer; GetVulkan*ExtensionsKHR mapping.
|
||||
4. Repack APK (real entitlement — you own it); test on Quest 2.
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# Cross-build the shim to Android arm64 (the deployable target — runs inside the
|
||||
# RE4 APK on Quest/Lepton). Host build is validation-only; this is the real artifact.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
SHIM="$ROOT/shim"
|
||||
NDK="${ANDROID_NDK:-$(ls -d "$ROOT"/tools/android-ndk-* 2>/dev/null | head -1)}"
|
||||
[ -n "${NDK:-}" ] && [ -d "$NDK" ] || { echo "NDK not found. Set \$ANDROID_NDK or run scripts/fetch_deps.sh"; exit 1; }
|
||||
TC="$(ls -d "$NDK"/toolchains/llvm/prebuilt/* 2>/dev/null | head -1)" # host tag (linux/darwin)
|
||||
CC="$TC/bin/aarch64-linux-android29-clang" # API 29 (Quest is Android 10+; app targetSdk=29)
|
||||
|
||||
[ -x "$CC" ] || { echo "NDK clang not found at $CC"; exit 1; }
|
||||
mkdir -p "$SHIM/build/arm64"
|
||||
|
||||
"$CC" -std=c11 -Wall -shared -fPIC -fvisibility=hidden \
|
||||
-I"$SHIM/include" -I"$SHIM/third_party/openxr" -I"$SHIM/third_party/vulkan" \
|
||||
"$SHIM/src/stubs.c" "$SHIM/src/core.c" "$SHIM/src/xr_runtime.c" \
|
||||
"$SHIM/src/vk_session.c" "$SHIM/src/layers.c" "$SHIM/src/android_init.c" "$SHIM/src/xr_input.c" \
|
||||
"$SHIM/src/passthru.c" \
|
||||
-llog \
|
||||
-o "$SHIM/build/arm64/libOVRPlugin.so"
|
||||
|
||||
# NOTE: entitlement handling is out of scope for this project. On Quest you own the title,
|
||||
# so the platform's real entitlement check runs unchanged (keep the original
|
||||
# libovrplatformloader.so). Running on hardware with no Meta backend requires a valid
|
||||
# entitlement by some other means, which is the user's responsibility and not part of this repo.
|
||||
|
||||
# the xr* symbols resolve against libopenxr_loader.so at runtime; declare the dep so
|
||||
# the dynamic linker loads it (bundle libopenxr_loader.so in the APK lib/arm64-v8a/).
|
||||
PATCHELF="$(command -v patchelf || true)"
|
||||
if [ -n "$PATCHELF" ]; then
|
||||
"$PATCHELF" --add-needed libopenxr_loader.so "$SHIM/build/arm64/libOVRPlugin.so"
|
||||
echo "added NEEDED libopenxr_loader.so"
|
||||
else
|
||||
echo "WARN: patchelf not found — add 'libopenxr_loader.so' as NEEDED before packaging"
|
||||
fi
|
||||
echo "built: $SHIM/build/arm64/libOVRPlugin.so"
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env bash
|
||||
# build_host.sh — desktop (x86_64 Linux) build of the shim + the OpenXR test harness.
|
||||
# Mirrors build_android.sh but targets the host so the OpenXR path can be driven against
|
||||
# Monado's simulated HMD on a PC (see tools/desktop-harness/). NOT the shipping artifact —
|
||||
# that's build_android.sh (arm64). Needs: a C compiler, libvulkan, and the OpenXR loader
|
||||
# (Debian: libvulkan-dev libopenxr-loader1 libopenxr-dev). Run tools/desktop-harness/run.sh
|
||||
# after this to launch it headless against monado-service.
|
||||
set -euo pipefail
|
||||
SHIM="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT="$(cd "$SHIM/.." && pwd)"
|
||||
OUT="$ROOT/build/host"
|
||||
mkdir -p "$OUT"
|
||||
|
||||
CC="${CC:-cc}"
|
||||
# _GNU_SOURCE: glibc gates dladdr/CLOCK_MONOTONIC behind it (the NDK exposes them by default).
|
||||
INC="-I$SHIM/include -I$SHIM/third_party/openxr -I$SHIM/third_party/vulkan"
|
||||
CFLAGS="-std=c11 -Wall -D_GNU_SOURCE -fPIC -O2 -g $INC"
|
||||
|
||||
echo "== compiling shim sources (host) =="
|
||||
OBJS=()
|
||||
for f in "$SHIM"/src/*.c; do
|
||||
o="$OUT/$(basename "${f%.c}").o"
|
||||
"$CC" $CFLAGS -c "$f" -o "$o"
|
||||
OBJS+=("$o")
|
||||
done
|
||||
|
||||
# The shim's xr* calls resolve against the system OpenXR loader; Vulkan against libvulkan.
|
||||
# Detect the loader via ldconfig, falling back to a direct file probe (ldconfig reads
|
||||
# /etc/ld.so.cache, which some sandboxes block -> false negative).
|
||||
have_loader() {
|
||||
ldconfig -p 2>/dev/null | grep -q libopenxr_loader && return 0
|
||||
for d in /usr/lib /usr/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu /usr/local/lib; do
|
||||
[ -e "$d/libopenxr_loader.so" ] || [ -e "$d/libopenxr_loader.so.1" ] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
if ! have_loader; then
|
||||
echo "WARN: libopenxr_loader not found — install libopenxr-loader1 libopenxr-dev to link/run."
|
||||
echo " (objects built OK; skipping the .so + harness link.)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "== linking libOVRPlugin.so (host) =="
|
||||
"$CC" -shared -o "$OUT/libOVRPlugin.so" "${OBJS[@]}" -lopenxr_loader -lvulkan -lpthread -ldl
|
||||
echo "built: $OUT/libOVRPlugin.so"
|
||||
|
||||
echo "== building harness =="
|
||||
"$CC" -std=c11 -Wall -D_GNU_SOURCE -O2 -g -I"$SHIM/include" -I"$SHIM/third_party/vulkan" \
|
||||
"$ROOT/tools/desktop-harness/harness.c" \
|
||||
-o "$OUT/harness" \
|
||||
-L"$OUT" -lOVRPlugin -lvulkan -lm -Wl,-rpath,"$OUT"
|
||||
echo "built: $OUT/harness"
|
||||
echo
|
||||
echo "run it headless against Monado: tools/desktop-harness/run.sh"
|
||||
Executable
+68
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
# Generate shim/src/stubs.c from analysis/shim_surface.txt.
|
||||
# Each ovrp_ function gets a stub returning a sensible ovrpResult, classified by
|
||||
# name per SHIM-SCOPE.md buckets. Functions prototyped in the header (real sigs)
|
||||
# are SKIPPED here and live in core.c instead.
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
# Use the ORIGINAL lib's FULL export set (438) so the shim is a complete drop-in:
|
||||
# any dlsym of any ovrp_ resolves, even the 199 RE4 doesn't reference.
|
||||
SURF="$ROOT/analysis/all_exports.txt"
|
||||
OUT="$ROOT/shim/src/stubs.c"
|
||||
mkdir -p "$ROOT/shim/src"
|
||||
|
||||
# functions with real prototypes in ovrplugin_shim.h -> handled in core.c
|
||||
HEADER_FNS=" ovrp_GetNodePoseState3 ovrp_GetNodePoseStateRaw ovrp_GetControllerState4 \
|
||||
ovrp_PreInitialize3 ovrp_Initialize5 ovrp_Shutdown2 ovrp_Update3 ovrp_WaitToBeginFrame \
|
||||
ovrp_BeginFrame4 ovrp_EndFrame4 ovrp_GetPredictedDisplayTime ovrp_GetSystemHeadsetType2 \
|
||||
ovrp_GetTrackingOriginType2 ovrp_SetTrackingOriginType2 ovrp_RecenterTrackingOrigin2 \
|
||||
ovrp_SetupLayer ovrp_GetLayerTextureStageCount ovrp_GetLayerTexture2 \
|
||||
ovrp_GetInstanceExtensionsVk ovrp_GetDeviceExtensionsVk \
|
||||
ovrp_GetInitialized ovrp_GetSystemDisplayFrequency2 \
|
||||
ovrp_GetAppHasVrFocus2 ovrp_GetAppShouldQuit2 ovrp_GetUserPresent2 \
|
||||
ovrp_GetAppShouldRecenter2 ovrp_GetAppShouldRecreateDistortionWindow2 \
|
||||
ovrp_GetSystemMultiViewSupported2 ovrp_GetAppHasInputFocus ovrp_SetupDistortionWindow3 \
|
||||
ovrp_CalculateEyeLayerDesc2 ovrp_CalculateEyeViewportRect ovrp_GetMixedRealityInitialized ovrp_CalculateLayerDesc ovrp_GetNodePresent2 ovrp_GetNodeOrientationValid ovrp_GetNodePositionValid ovrp_GetNodeOrientationTracked2 ovrp_GetNodePositionTracked2 ovrp_SetControllerVibration2 \
|
||||
ovrp_GetTiledMultiResSupported ovrp_GetTiledMultiResLevel ovrp_SetTiledMultiResLevel \
|
||||
ovrp_GetTiledMultiResDynamic ovrp_SetTiledMultiResDynamic ovrp_GetGPUFrameTime \
|
||||
ovrp_DestroyLayer ovrp_GetNodeFrustum2 ovrp_SetSystemCpuLevel2 ovrp_SetSystemGpuLevel2 \
|
||||
ovrp_IsPerfMetricsSupported ovrp_GetPerfMetricsFloat ovrp_GetPerfMetricsInt \
|
||||
ovrp_GetAdaptiveGpuPerformanceScale2 \
|
||||
ovrp_DestroyDistortionWindow2 ovrp_SetupDisplayObjects2 ovrp_SetReorientHMDOnControllerRecenter \
|
||||
ovrp_SetClientColorDesc ovrp_SetAppEngineInfo2 ovrp_SetAppCPUPriority2 ovrp_InitializeMixedReality \
|
||||
ovrp_GetViewportStencil ovrp_GetSystemRecommendedMSAALevel2 ovrp_GetLocalTrackingSpaceRecenterCount \
|
||||
ovrp_GetLayerTextureFoveation ovrp_GetControllerHapticsDesc2 "
|
||||
# NB: the trailing 12 are game-called () stubs now owned by passthru.c — they keep their
|
||||
# original return constant when passthru is off, and tail-call the real lib when it's on.
|
||||
|
||||
{
|
||||
echo '/* AUTO-GENERATED by gen_stubs.sh from analysis/shim_surface.txt. Do not edit by hand. */'
|
||||
echo '#include "ovrplugin_shim.h"'
|
||||
echo '#include "log.h"'
|
||||
echo
|
||||
echo '/* Stub policy:'
|
||||
echo ' * -1004 Unsupported : features we will not implement (MRC/camera/perf/boundary/hands)'
|
||||
echo ' * 0 Success (no-op) : config setters we can safely accept-and-ignore for now'
|
||||
echo ' * -1005 NotYetImplemented : real work still owed (getters/etc. the game needs)'
|
||||
echo ' * Empty () = unspecified args: stub ignores args, returns constant in result reg. */'
|
||||
echo
|
||||
n_unsup=0; n_noop=0; n_todo=0; n_skip=0
|
||||
while read -r fn; do
|
||||
[ -z "$fn" ] && continue
|
||||
case " $HEADER_FNS " in *" $fn "*) n_skip=$((n_skip+1)); continue;; esac
|
||||
if echo "$fn" | grep -qE 'Media_|CameraDevice|ExternalCamera|HandState|Skeleton|GetMesh|HandTracking|HandNode|PerfMetric|GPUUtil|GPUFrameTime|ASW|TiledMultiRes|Boundary'; then
|
||||
ret="ovrpFailure_Unsupported"; n_unsup=$((n_unsup+1))
|
||||
elif echo "$fn" | grep -qE '^ovrp_Set[A-Z]|^ovrp_Reset|^ovrp_Recenter|^ovrp_SendEvent|^ovrp_Destroy|^ovrp_Override'; then
|
||||
ret="ovrpSuccess"; n_noop=$((n_noop+1))
|
||||
else
|
||||
ret="ovrpFailure_NotYetImplemented"; n_todo=$((n_todo+1))
|
||||
fi
|
||||
printf 'OVRP_EXPORT ovrpResult %s() { static int o; if(!o){o=1;XRRLOG("stub %s -> %s");} return %s; }\n' "$fn" "$fn" "$ret" "$ret"
|
||||
done < "$SURF"
|
||||
echo
|
||||
echo "/* generated: unsup=$n_unsup noop=$n_noop todo=$n_todo skipped(core)=$n_skip */"
|
||||
} > "$OUT"
|
||||
|
||||
echo "wrote $OUT"
|
||||
grep -c '^OVRP_EXPORT' "$OUT" | xargs echo "stub functions:"
|
||||
tail -1 "$OUT"
|
||||
@@ -0,0 +1,290 @@
|
||||
/* ovrplugin_shim.h — OVRPlugin (v1.51) C ABI for the RE4 VR -> OpenXR shim.
|
||||
*
|
||||
* Goal: a drop-in replacement libOVRPlugin.so that re-exports the ovrp_* symbols
|
||||
* RE4 VR (com.Armature.VR4, OVRPlugin 1.51 / pkg 19.0.0.449.531) calls, backed by
|
||||
* OpenXR (Monado) on Steam Frame instead of Meta's libvrapi.so.
|
||||
*
|
||||
* Provenance of each declaration:
|
||||
* [VERIFIED] struct size / arg shape confirmed from Ghidra decompilation of the
|
||||
* actual binary (see analysis/ovrp_decomp.txt, RE-NOTES.md).
|
||||
* [HEADER] taken from public OVRPlugin.cs @ v1.51; layout trusted because the
|
||||
* VERIFIED structs matched it byte-for-byte, but not independently
|
||||
* re-confirmed against this binary yet.
|
||||
* [TODO] signature not yet finalized — placeholder, do not trust arg list.
|
||||
*
|
||||
* Status: scaffold. Base types + the fully-confirmed functions are real; the rest
|
||||
* of the ~239-function surface (analysis/shim_surface.txt) is still to be filled.
|
||||
*/
|
||||
#ifndef OVRPLUGIN_SHIM_H
|
||||
#define OVRPLUGIN_SHIM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The real lib's exported ovrp_* are thin thunks; we just need matching symbols
|
||||
* with default visibility so the game's dlsym resolves to us. */
|
||||
#define OVRP_EXPORT __attribute__((visibility("default")))
|
||||
|
||||
/* ------------------------------------------------------------------ result --- */
|
||||
/* ovrpResult is a signed 32-bit int; success >= 0, failure < 0.
|
||||
* Codes below VERIFIED from return constants in the decompiled binary:
|
||||
* -1001 (0xfffffc17), -1002 (0xfffffc16), -1003 (0xfffffc15). */
|
||||
typedef int32_t ovrpResult;
|
||||
#define ovrpSuccess 0
|
||||
#define ovrpSuccess_EventUnavailable 1
|
||||
#define ovrpFailure -1000
|
||||
#define ovrpFailure_InvalidParameter -1001 /* [VERIFIED] */
|
||||
#define ovrpFailure_NotInitialized -1002 /* [VERIFIED] */
|
||||
#define ovrpFailure_InvalidOperation -1003 /* [VERIFIED] */
|
||||
#define ovrpFailure_Unsupported -1004
|
||||
#define ovrpFailure_NotYetImplemented -1005
|
||||
#define ovrpFailure_OperationFailed -1006
|
||||
#define ovrpFailure_InsufficientSize -1007
|
||||
#define ovrpFailure_DataIsInvalid -1008
|
||||
#define ovrpFailure_DeprecatedOperation -1009
|
||||
#define OVRP_SUCCESS(r) ((r) >= 0)
|
||||
|
||||
typedef enum { ovrpBool_False = 0, ovrpBool_True = 1 } ovrpBool;
|
||||
|
||||
/* -------------------------------------------------------------- math types --- */
|
||||
typedef struct { float x, y; } ovrpVector2f;
|
||||
typedef struct { int32_t x, y; } ovrpVector2i;
|
||||
typedef struct { int32_t w, h; } ovrpSizei;
|
||||
typedef struct { ovrpVector2i Pos; ovrpSizei Size; } ovrpRecti;
|
||||
typedef struct { float x, y, z; } ovrpVector3f;
|
||||
typedef struct { float x, y, z, w; } ovrpVector4f;
|
||||
typedef struct { float x, y, z, w; } ovrpQuatf;
|
||||
typedef struct { float w, h; } ovrpSizef;
|
||||
typedef struct { ovrpVector2f Pos; ovrpSizef Size; } ovrpRectf;
|
||||
typedef struct { float UpTan, DownTan, LeftTan, RightTan; } ovrpFovf;
|
||||
typedef struct { float zNear, zFar; ovrpFovf Fov; } ovrpFrustum2f;
|
||||
|
||||
typedef struct { ovrpQuatf Orientation; ovrpVector3f Position; } ovrpPosef; /* 28 */
|
||||
|
||||
typedef struct {
|
||||
ovrpPosef Pose;
|
||||
ovrpVector3f Velocity;
|
||||
ovrpVector3f Acceleration;
|
||||
ovrpVector3f AngularVelocity;
|
||||
ovrpVector3f AngularAcceleration;
|
||||
double Time;
|
||||
} ovrpPoseStatef; /* 88 */
|
||||
|
||||
/* binary-verified sizes — header is wrong if these fail */
|
||||
_Static_assert(sizeof(ovrpPosef) == 28, "ovrpPosef must be 28 bytes");
|
||||
_Static_assert(sizeof(ovrpPoseStatef) == 88, "ovrpPoseStatef must be 0x58=88 [VERIFIED]");
|
||||
|
||||
/* --------------------------------------------------------------- enums ------- */
|
||||
typedef enum {
|
||||
ovrpNode_None = -1, ovrpNode_EyeLeft = 0, ovrpNode_EyeRight = 1,
|
||||
ovrpNode_EyeCenter = 2, ovrpNode_HandLeft = 3, ovrpNode_HandRight = 4,
|
||||
ovrpNode_TrackerZero = 5, ovrpNode_TrackerOne = 6, ovrpNode_TrackerTwo = 7,
|
||||
ovrpNode_TrackerThree = 8, ovrpNode_Head = 9, ovrpNode_DeviceObjectZero = 10,
|
||||
ovrpNode_EnumSize = 0x7fffffff
|
||||
} ovrpNode;
|
||||
|
||||
typedef enum {
|
||||
ovrpStep_Render = -1, ovrpStep_Physics = 0, ovrpStep_EnumSize = 0x7fffffff
|
||||
} ovrpStep;
|
||||
|
||||
typedef enum {
|
||||
ovrpController_None = 0, ovrpController_LTouch = 0x01, ovrpController_RTouch = 0x02,
|
||||
ovrpController_Touch = 0x03, ovrpController_Remote = 0x04, ovrpController_Gamepad = 0x10,
|
||||
ovrpController_LTrackedRemote = 0x01000000, ovrpController_RTrackedRemote = 0x02000000,
|
||||
ovrpController_Touchpad = 0x08000000, ovrpController_Active = 0x80000000u,
|
||||
ovrpController_EnumSize = 0x7fffffff
|
||||
} ovrpController;
|
||||
|
||||
typedef enum {
|
||||
ovrpSystemHeadset_None = 0,
|
||||
/* mobile */
|
||||
ovrpSystemHeadset_Oculus_Quest = 8, ovrpSystemHeadset_Oculus_Quest_2 = 9,
|
||||
ovrpSystemHeadset_EnumSize = 0x7fffffff
|
||||
} ovrpSystemHeadset;
|
||||
|
||||
typedef enum {
|
||||
ovrpTrackingOrigin_EyeLevel = 0, ovrpTrackingOrigin_FloorLevel = 1,
|
||||
ovrpTrackingOrigin_Stage = 2, ovrpTrackingOrigin_EnumSize = 0x7fffffff
|
||||
} ovrpTrackingOrigin;
|
||||
|
||||
/* ----------------------------------------------------------- controller ------ */
|
||||
typedef struct {
|
||||
uint32_t ConnectedControllers;
|
||||
uint32_t Buttons;
|
||||
uint32_t Touches;
|
||||
uint32_t NearTouches;
|
||||
float LIndexTrigger, RIndexTrigger;
|
||||
float LHandTrigger, RHandTrigger;
|
||||
ovrpVector2f LThumbstick, RThumbstick;
|
||||
ovrpVector2f LTouchpad, RTouchpad;
|
||||
uint8_t LBatteryPercentRemaining, RBatteryPercentRemaining;
|
||||
uint8_t LRecenterCount, RRecenterCount;
|
||||
uint8_t Reserved[28];
|
||||
} ovrpControllerState4; /* 96 */
|
||||
_Static_assert(sizeof(ovrpControllerState4) == 96,
|
||||
"ovrpControllerState4 must be 0x60=96 [VERIFIED]");
|
||||
|
||||
/* ----------------------------------------------------------- layers ---------- */
|
||||
/* ovrpShape: Compositor::ImportLayerDesc switches on field +0x00. Cases
|
||||
* 0,1,2,4,5 verified as overlay shapes; case 3 = EyeFov (projection). [VERIFIED] */
|
||||
typedef enum {
|
||||
ovrpShape_Quad = 0, ovrpShape_Cylinder = 1, ovrpShape_Cubemap = 2,
|
||||
ovrpShape_EyeFov = 3, ovrpShape_OffcenterCubemap = 4, ovrpShape_Equirect = 5,
|
||||
ovrpShape_ReconstructionPassthrough = 7, ovrpShape_SurfaceProjectedPassthrough = 8,
|
||||
ovrpShape_Fisheye = 9, ovrpShape_EnumSize = 0xF
|
||||
} ovrpShape;
|
||||
typedef enum {
|
||||
ovrpLayout_Stereo = 0, ovrpLayout_Mono = 1, ovrpLayout_DoubleWide = 2,
|
||||
ovrpLayout_Array = 3, ovrpLayout_EnumSize = 0xF
|
||||
} ovrpLayout;
|
||||
typedef enum {
|
||||
ovrpTextureFormat_R8G8B8A8_sRGB = 0, ovrpTextureFormat_R8G8B8A8 = 1,
|
||||
ovrpTextureFormat_R16G16B16A16_FP = 2, ovrpTextureFormat_R11G11B10_FP = 3,
|
||||
ovrpTextureFormat_B8G8R8A8_sRGB = 4, ovrpTextureFormat_B8G8R8A8 = 5,
|
||||
ovrpTextureFormat_R5G6B5 = 11, ovrpTextureFormat_EnumSize = 0x7fffffff
|
||||
} ovrpTextureFormat;
|
||||
|
||||
/* ovrpLayerDesc — VERIFIED: Compositor::ImportLayerDesc memset's 0x7c=124 and
|
||||
* copies 0x68/0x6c/0x7c by version (base / +DepthFormat / +MotionVector). The
|
||||
* field layout below reproduces those three sizes exactly. */
|
||||
typedef struct {
|
||||
ovrpShape Shape; /* +0x00 switch field [VERIFIED] */
|
||||
ovrpLayout Layout; /* +0x04 */
|
||||
ovrpSizei TextureSize; /* +0x08 */
|
||||
int MipLevels; /* +0x10 */
|
||||
int SampleCount; /* +0x14 */
|
||||
ovrpTextureFormat Format; /* +0x18 */
|
||||
int LayerFlags; /* +0x1c (common header ends +0x20) */
|
||||
ovrpFovf Fov[2]; /* +0x20 */
|
||||
ovrpRectf VisibleRect[2]; /* +0x40 */
|
||||
ovrpSizei MaxViewportSize; /* +0x60 */
|
||||
ovrpTextureFormat DepthFormat; /* +0x68 (-> 0x6c = UE 4.25 EyeFov) */
|
||||
/* NOTE: the binary's internal union also supports a 124-byte variant with
|
||||
* MotionVector* fields, but UE 4.25's ovrpLayerDesc_EyeFov ends here (108).
|
||||
* We match UE's size so we never write past the caller's buffer. */
|
||||
} ovrpLayerDesc; /* 108 */
|
||||
typedef ovrpLayerDesc ovrpLayerDesc_EyeFov;
|
||||
_Static_assert(sizeof(ovrpLayerDesc) == 0x6c,
|
||||
"ovrpLayerDesc must be 0x6c=108 [UE 4.25 ovrpLayerDesc_EyeFov]");
|
||||
|
||||
/* ovrpLayerSubmit — VERIFIED 0x130=304 bytes (EndFrame4 allocs count*0x130).
|
||||
* Header fields are the public layout [HEADER]; the per-shape union tail is not
|
||||
* yet broken out -> reserved bytes to reach 304. [TODO] reverse ShapeData. */
|
||||
typedef struct {
|
||||
int LayerId; /* +0x00 */
|
||||
int TextureStage; /* +0x04 */
|
||||
ovrpRecti ViewportRect[2]; /* +0x08 */
|
||||
ovrpPosef Pose; /* +0x28 */
|
||||
int LayerSubmitFlags; /* +0x44 (ovrpLayerSubmitFlag_HeadLocked=1<<0) */
|
||||
ovrpVector4f ColorScale; /* +0x48 (added 1.31) */
|
||||
ovrpVector4f ColorOffset; /* +0x58 */
|
||||
int OverrideTextureRectMatrix; /* +0x68 (ovrpBool=int, added 1.34) */
|
||||
float TextureRectMatrix[16]; /* +0x6C (ovrpTextureRectMatrixf=64B) */
|
||||
int OverridePerLayerColorScaleAndOffset;/* +0xAC */
|
||||
ovrpSizef QuadSize; /* +0xB0 (ovrpLayerSubmit_Quad tail; world meters) */
|
||||
unsigned char _pad[0x130 - 0xB8]; /* reach the 304B union stride */
|
||||
} ovrpLayerSubmit; /* 304 */
|
||||
enum { ovrpLayerSubmitFlag_HeadLocked = (1 << 0) };
|
||||
_Static_assert(sizeof(ovrpLayerSubmit) == 0x130,
|
||||
"ovrpLayerSubmit must be 0x130=304 [VERIFIED EndFrame4 stride]");
|
||||
|
||||
/* =================================================================== API ===== */
|
||||
/* CONFIRMED (arg shape matched in Ghidra) */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePoseState3( /* [VERIFIED] 3 ints + out ptr */
|
||||
ovrpStep step, int frameIndex, ovrpNode nodeId, ovrpPoseStatef *outState);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePoseStateRaw( /* [VERIFIED] same shape, 0x58 */
|
||||
ovrpStep step, int frameIndex, ovrpNode nodeId, ovrpPoseStatef *outState);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerState4( /* [VERIFIED] mask + out 0x60 */
|
||||
ovrpController controllerMask, ovrpControllerState4 *outState);
|
||||
|
||||
/* CORE — frame loop / lifecycle [HEADER: from v1.51, arg list to re-verify] */
|
||||
/* ovrpRenderAPIType — apiType arg of Initialize5 */
|
||||
typedef enum {
|
||||
ovrpRenderAPI_None = 0, ovrpRenderAPI_OpenGL = 1, ovrpRenderAPI_Android_GLES = 2,
|
||||
ovrpRenderAPI_Vulkan = 4, ovrpRenderAPI_EnumSize = 0x7fffffff
|
||||
} ovrpRenderAPIType;
|
||||
typedef void (*ovrpLogCallback)(int level, const char *message);
|
||||
|
||||
OVRP_EXPORT ovrpResult ovrp_PreInitialize3(void *logCallback); /* [TODO] */
|
||||
/* [VERIFIED from UE OculusHMD.cpp InitializeSession()] exact arg order:
|
||||
* (apiType, logCallback, activity, VkInstance, VkPhysicalDevice, VkDevice,
|
||||
* VkQueue, flags, version). arg7 is a VkQueue handle, NOT a family index. */
|
||||
OVRP_EXPORT ovrpResult ovrp_Initialize5(
|
||||
ovrpRenderAPIType apiType, ovrpLogCallback logCallback, void *activity,
|
||||
void *vkInstance, void *vkPhysicalDevice, void *vkDevice, void *queue,
|
||||
unsigned int flags, const void *version); /* real 9th arg is const ovrpVersion& == a
|
||||
64-bit pointer; declaring it as a 32-bit int truncates it (crashes P4 passthru forward). */
|
||||
OVRP_EXPORT ovrpResult ovrp_Shutdown2(void);
|
||||
OVRP_EXPORT ovrpResult ovrp_Update3(ovrpStep step, int frameIndex, double predictedTime);
|
||||
OVRP_EXPORT ovrpResult ovrp_WaitToBeginFrame(int frameIndex);
|
||||
OVRP_EXPORT ovrpResult ovrp_BeginFrame4(int frameIndex, void *commandQueue); /* [HEADER] */
|
||||
OVRP_EXPORT ovrpResult ovrp_EndFrame4(int frameIndex,
|
||||
const ovrpLayerSubmit *const *layerSubmitPtr, int layerSubmitCount,
|
||||
void *commandQueue); /* [HEADER] */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetPredictedDisplayTime(int frameIndex, double *outTime);
|
||||
|
||||
/* CORE — system / eye params [HEADER] */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemHeadsetType2(ovrpSystemHeadset *outType);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingOriginType2(ovrpTrackingOrigin *outOrigin);
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingOriginType2(ovrpTrackingOrigin origin);
|
||||
OVRP_EXPORT ovrpResult ovrp_RecenterTrackingOrigin2(unsigned int flags);
|
||||
|
||||
/* DYNAMIC PERF — tiled multi-resolution (Oculus name for Fixed Foveated Rendering)
|
||||
* + GPU frame time. RE4 drives its own dynamic-perf loop through these; the shim
|
||||
* forwards the requested FFR level onto OpenXR XR_FB_foveation (see xr_runtime.c)
|
||||
* and answers GetGPUFrameTime with a measured frame-time estimate so the loop has
|
||||
* an input. Signatures verified against libOVRPlugin.so (analysis/endframe_impls.txt,
|
||||
* analysis/ovrp_decomp.txt): Get* take an out-pointer, Set* take a value. */
|
||||
typedef enum {
|
||||
ovrpTiledMultiResLevel_Off = 0,
|
||||
ovrpTiledMultiResLevel_LMSLow = 1,
|
||||
ovrpTiledMultiResLevel_LMSMedium = 2,
|
||||
ovrpTiledMultiResLevel_LMSHigh = 3,
|
||||
ovrpTiledMultiResLevel_LMSHighTop = 4,
|
||||
ovrpTiledMultiResLevel_EnumSize = 0x7fffffff
|
||||
} ovrpTiledMultiResLevel;
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResSupported(ovrpBool *outSupported);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResLevel(ovrpTiledMultiResLevel *outLevel);
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTiledMultiResLevel(ovrpTiledMultiResLevel level);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResDynamic(ovrpBool *outDynamic);
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTiledMultiResDynamic(ovrpBool isDynamic);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetGPUFrameTime(float *outGpuTimeMs);
|
||||
|
||||
/* Perf metrics. The game polls IsPerfMetricsSupported(metric) and, for supported
|
||||
* metrics, GetPerfMetrics{Float,Int}(metric, &out). Signatures verified against
|
||||
* libOVRPlugin.so (analysis/ovrp_decomp.txt): (uint metric, out-ptr). We answer per
|
||||
* metric truthfully (see xr_runtime.c) rather than stubbing the whole call Unsupported. */
|
||||
typedef enum {
|
||||
ovrpPerfMetrics_App_CpuTime_Float = 0,
|
||||
ovrpPerfMetrics_App_GpuTime_Float = 1,
|
||||
ovrpPerfMetrics_Compositor_CpuTime_Float = 3,
|
||||
ovrpPerfMetrics_Compositor_GpuTime_Float = 4,
|
||||
ovrpPerfMetrics_Compositor_DroppedFrameCount_Int = 5,
|
||||
ovrpPerfMetrics_System_GpuUtilPercentage_Float = 7,
|
||||
ovrpPerfMetrics_System_CpuUtilAveragePercentage_Float= 8,
|
||||
ovrpPerfMetrics_System_CpuUtilWorstPercentage_Float = 9,
|
||||
ovrpPerfMetrics_Device_CpuClockFrequencyInMHz_Float = 10,
|
||||
ovrpPerfMetrics_Device_GpuClockFrequencyInMHz_Float = 11,
|
||||
ovrpPerfMetrics_Device_CpuClockLevel_Int = 12,
|
||||
ovrpPerfMetrics_Device_GpuClockLevel_Int = 13,
|
||||
ovrpPerfMetrics_Count = 14,
|
||||
ovrpPerfMetrics_EnumSize = 0x7fffffff
|
||||
} ovrpPerfMetrics;
|
||||
OVRP_EXPORT ovrpResult ovrp_IsPerfMetricsSupported(ovrpPerfMetrics metric, ovrpBool *outSupported);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetPerfMetricsFloat(ovrpPerfMetrics metric, float *outValue);
|
||||
OVRP_EXPORT ovrpResult ovrp_GetPerfMetricsInt(ovrpPerfMetrics metric, int *outValue);
|
||||
|
||||
/* TODO: remaining ~225 of the 239-function surface; see analysis/shim_surface.txt.
|
||||
* Buckets (per SHIM-SCOPE.md): ~150 stub-to-constant (Media_, camera, perf,
|
||||
* boundary, handtracking, system-getters), ~45 mechanical (rest of tracking,
|
||||
* input, eye params), and the hard layer/swapchain set (SetupLayer,
|
||||
* CalculateEyeLayerDesc2, GetLayerTexture2) which need the 128-byte
|
||||
* ovrpLayerDesc reversed first. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* OVRPLUGIN_SHIM_H */
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef PASSTHRU_H
|
||||
#define PASSTHRU_H
|
||||
/* P4 passthru — run the REAL (SONAME-patched) libOVRPlugin inside our app and forward
|
||||
* every game-called export to it, so we can LOG native's per-eye poses/FOV/submit and
|
||||
* diff them against our clean-but-ghosting values. Gate: debug.re4vr.passthru=1.
|
||||
*
|
||||
* All-or-nothing: the real lib owns the WHOLE session, so every export the game calls
|
||||
* must forward (partial forwarding crashes mid-frame because state lives in the real
|
||||
* lib). Fully-prototyped exports (core.c/layers.c) forward via PT_FWD below; the handful
|
||||
* of no-arg () stubs the game also hits forward via signature-agnostic asm trampolines
|
||||
* in passthru.c. See HANDOFF-2026-06-27-native-parity.md. */
|
||||
|
||||
int pt_active(void); /* lazily inits on first call; 1 if real lib owns the session */
|
||||
void *pt_real(const char *name); /* dlsym from the real lib (NULL if !passthru or not found) */
|
||||
void pt_log_call(const char *name, long ret); /* rate-limited native call census (PTC log) */
|
||||
|
||||
/* Forward a fully-prototyped export to the real lib and return its result, caching the
|
||||
* resolved pointer per call site. Drop as the FIRST statement of each game-called export
|
||||
* in core.c / layers.c. Compiles to nothing reachable when passthru is off. Logs the
|
||||
* native return value (rate-limited) so we can diff the full call surface vs our shim. */
|
||||
#define PT_FWD(fn, ...) do { \
|
||||
if (pt_active()) { \
|
||||
static __typeof__(&fn) _pt_p; static int _pt_got; \
|
||||
if (!_pt_got) { _pt_p = (__typeof__(&fn))pt_real(#fn); _pt_got = 1; } \
|
||||
if (_pt_p) { \
|
||||
__typeof__(_pt_p(__VA_ARGS__)) _pt_r = _pt_p(__VA_ARGS__); \
|
||||
pt_log_call(#fn, (long)_pt_r); \
|
||||
return _pt_r; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* PASSTHRU_H */
|
||||
@@ -0,0 +1,103 @@
|
||||
/* android_init.c — Android OpenXR instance handshake.
|
||||
*
|
||||
* On Android the OpenXR loader must be primed with the JavaVM + a Context via
|
||||
* xrInitializeLoaderKHR BEFORE xrCreateInstance, and xrCreateInstance needs
|
||||
* XR_KHR_android_create_instance with XrInstanceCreateInfoAndroidKHR chained in.
|
||||
*
|
||||
* JavaVM: captured in JNI_OnLoad (called when the .so loads).
|
||||
* Activity/Context: preferred from ovrp_Initialize5 arg4; but PreInitialize3
|
||||
* creates the instance earlier, so we fall back to the Application context via
|
||||
* ActivityThread reflection. [VERIFY-ON-HW] whether Meta's runtime accepts the
|
||||
* Application context or wants the actual Activity.
|
||||
*
|
||||
* Host build: the #else stubs make this a no-op so xr_runtime.c is portable.
|
||||
*/
|
||||
#include "xr_runtime.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <jni.h>
|
||||
#define XR_USE_PLATFORM_ANDROID
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
static JavaVM *g_vm;
|
||||
static jobject g_context; /* global ref: Activity or Application context */
|
||||
static XrInstanceCreateInfoAndroidKHR g_androidCreate;
|
||||
|
||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
(void)reserved;
|
||||
g_vm = vm;
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
/* P4 passthru: the real (dlopen'd) libOVRPlugin captures the JavaVM in its own
|
||||
* JNI_OnLoad, which ART only invokes for System.loadLibrary — not for a native
|
||||
* dlopen. passthru.c hands this VM to the real lib's JNI_OnLoad so its VrApi path
|
||||
* doesn't deref a null VM in CompositorVRAPI::PreInitialize. */
|
||||
void *xrr_android_get_vm(void) { return g_vm; }
|
||||
|
||||
static JNIEnv *get_env(void) {
|
||||
JNIEnv *env = NULL;
|
||||
if (!g_vm) return NULL;
|
||||
if ((*g_vm)->GetEnv(g_vm, (void **)&env, JNI_VERSION_1_6) == JNI_OK) return env;
|
||||
if ((*g_vm)->AttachCurrentThread(g_vm, &env, NULL) == JNI_OK) return env;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* fallback: get the Application context via ActivityThread reflection */
|
||||
static jobject get_app_context(JNIEnv *env) {
|
||||
jclass at = (*env)->FindClass(env, "android/app/ActivityThread");
|
||||
if (!at) return NULL;
|
||||
jmethodID cur = (*env)->GetStaticMethodID(env, at,
|
||||
"currentActivityThread", "()Landroid/app/ActivityThread;");
|
||||
jobject atObj = (*env)->CallStaticObjectMethod(env, at, cur);
|
||||
if (!atObj) return NULL;
|
||||
jmethodID getApp = (*env)->GetMethodID(env, at,
|
||||
"getApplication", "()Landroid/app/Application;");
|
||||
jobject app = (*env)->CallObjectMethod(env, atObj, getApp);
|
||||
return app ? (*env)->NewGlobalRef(env, app) : NULL;
|
||||
}
|
||||
|
||||
static int g_realActivitySet;
|
||||
|
||||
void xrr_set_android_activity(void *activity) {
|
||||
JNIEnv *env = get_env();
|
||||
if (env && activity) {
|
||||
g_context = (*env)->NewGlobalRef(env, (jobject)activity);
|
||||
g_realActivitySet = 1; /* the real GameActivity, not the App context */
|
||||
}
|
||||
}
|
||||
int xrr_android_have_real_activity(void) { return g_realActivitySet; }
|
||||
|
||||
static jobject ensure_context(void) {
|
||||
if (g_context) return g_context;
|
||||
JNIEnv *env = get_env();
|
||||
if (env) g_context = get_app_context(env);
|
||||
return g_context;
|
||||
}
|
||||
|
||||
int xrr_android_init_loader(void) {
|
||||
PFN_xrInitializeLoaderKHR init = NULL;
|
||||
if (xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR",
|
||||
(PFN_xrVoidFunction *)&init) != XR_SUCCESS || !init)
|
||||
return 0;
|
||||
XrLoaderInitInfoAndroidKHR li = { XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR };
|
||||
li.applicationVM = g_vm;
|
||||
li.applicationContext = ensure_context();
|
||||
return XR_SUCCEEDED(init((XrLoaderInitInfoBaseHeaderKHR *)&li));
|
||||
}
|
||||
|
||||
void *xrr_android_instance_next(void) {
|
||||
g_androidCreate = (XrInstanceCreateInfoAndroidKHR){
|
||||
XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR };
|
||||
g_androidCreate.applicationVM = g_vm;
|
||||
g_androidCreate.applicationActivity = ensure_context();
|
||||
return &g_androidCreate;
|
||||
}
|
||||
|
||||
#else /* ----- host build: no-ops ----- */
|
||||
int xrr_android_init_loader(void) { return 1; }
|
||||
void *xrr_android_instance_next(void) { return 0; }
|
||||
void xrr_set_android_activity(void *a) { (void)a; }
|
||||
int xrr_android_have_real_activity(void) { return 0; }
|
||||
void *xrr_android_get_vm(void) { return 0; }
|
||||
#endif
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
/* core.c — the ovrp_* exports prototyped with real signatures in ovrplugin_shim.h:
|
||||
* lifecycle, frame loop, poses, tracking/perf config — all wired to OpenXR via xr_runtime.c.
|
||||
* (Session + Vulkan graphics binding are created in ovrp_Initialize5 -> xrr_init.)
|
||||
* Each export forwards to the real libOVRPlugin first when passthru is active (PT_FWD).
|
||||
*/
|
||||
#include "ovrplugin_shim.h"
|
||||
#include "xr_runtime.h"
|
||||
#include "passthru.h"
|
||||
#include "log.h"
|
||||
#include <string.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <sys/system_properties.h>
|
||||
#endif
|
||||
|
||||
#define TODO_RET ovrpFailure_NotYetImplemented
|
||||
|
||||
/* --- lifecycle ---------------------------------------------------------- */
|
||||
OVRP_EXPORT ovrpResult ovrp_PreInitialize3(void *garbage) {
|
||||
PT_FWD(ovrp_PreInitialize3, garbage); /* first pt_active() lazily loads the real lib */
|
||||
(void)garbage;
|
||||
XRRLOG("ovrp_PreInitialize3 called");
|
||||
ovrpResult r = xrr_pre_init();
|
||||
XRRLOG("ovrp_PreInitialize3 -> %d", r);
|
||||
return r;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_Initialize5(
|
||||
ovrpRenderAPIType apiType, ovrpLogCallback logCallback, void *activity,
|
||||
void *vkInstance, void *vkPhysicalDevice, void *vkDevice, void *queue,
|
||||
unsigned int flags, const void *version) { /* version = const ovrpVersion& (ptr) */
|
||||
PT_FWD(ovrp_Initialize5, apiType, logCallback, activity, vkInstance,
|
||||
vkPhysicalDevice, vkDevice, queue, flags, version);
|
||||
(void)apiType; (void)logCallback; (void)flags; (void)version;
|
||||
XRRLOG("ovrp_Initialize5: api=%d act=%p vkInst=%p vkPhys=%p vkDev=%p queue=%p fl=%u",
|
||||
apiType, activity, vkInstance, vkPhysicalDevice, vkDevice, queue, flags);
|
||||
xrr_set_android_activity(activity);
|
||||
xrr_vk_set_handles(vkDevice, queue, 0); /* for the end-of-frame flush barrier */
|
||||
/* OpenXR wants queueFamilyIndex+queueIndex; OVRPlugin gives a VkQueue we can't
|
||||
* decompose -> default family 0/index 0 (UE Vulkan on Quest uses graphics fam 0). */
|
||||
ovrpResult r = xrr_init(vkInstance, vkPhysicalDevice, vkDevice, 0);
|
||||
XRRLOG("ovrp_Initialize5 -> %d", r);
|
||||
return r;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_Shutdown2(void) {
|
||||
PT_FWD(ovrp_Shutdown2); xrr_shutdown(); return ovrpSuccess; }
|
||||
|
||||
/* --- frame loop --------------------------------------------------------- */
|
||||
OVRP_EXPORT ovrpResult ovrp_Update3(ovrpStep step, int frameIndex, double predictedTime) {
|
||||
PT_FWD(ovrp_Update3, step, frameIndex, predictedTime);
|
||||
(void)step; (void)frameIndex; (void)predictedTime;
|
||||
static int o; if (!o) { o = 1; XRRLOG("ovrp_Update3 first call"); }
|
||||
xrr_poll_events(); /* advance the session state machine */
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_WaitToBeginFrame(int frameIndex) {
|
||||
PT_FWD(ovrp_WaitToBeginFrame, frameIndex);
|
||||
ovrpResult r = xrr_wait_frame(frameIndex);
|
||||
static int o; if (!o) { o = 1; XRRLOG("ovrp_WaitToBeginFrame first call -> %d", r); }
|
||||
return r;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_BeginFrame4(int frameIndex, void *commandQueue) {
|
||||
PT_FWD(ovrp_BeginFrame4, frameIndex, commandQueue);
|
||||
(void)commandQueue;
|
||||
return xrr_begin_frame(frameIndex);
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_EndFrame4(int frameIndex,
|
||||
const ovrpLayerSubmit *const *layerSubmitPtr, int layerSubmitCount,
|
||||
void *commandQueue) {
|
||||
if (pt_active()) {
|
||||
static __typeof__(&ovrp_EndFrame4) _r; static int _g;
|
||||
if (!_g) { _r = (__typeof__(&ovrp_EndFrame4))pt_real("ovrp_EndFrame4"); _g = 1; }
|
||||
if (_r) {
|
||||
/* native per-layer submit: id, head-lock flag, world pose — diff vs ours */
|
||||
static int po = 0;
|
||||
if (po++ < 24 && layerSubmitPtr) {
|
||||
for (int i = 0; i < layerSubmitCount; i++) {
|
||||
const ovrpLayerSubmit *L = layerSubmitPtr[i];
|
||||
if (!L) continue;
|
||||
XRRLOG("PT EndFrame4 f=%d layer[%d/%d] id=%d flags=0x%x pos=(%.4f %.4f %.4f) quat=(%.4f %.4f %.4f %.4f)",
|
||||
frameIndex, i, layerSubmitCount, L->LayerId, L->LayerSubmitFlags,
|
||||
L->Pose.Position.x, L->Pose.Position.y, L->Pose.Position.z,
|
||||
L->Pose.Orientation.x, L->Pose.Orientation.y,
|
||||
L->Pose.Orientation.z, L->Pose.Orientation.w);
|
||||
}
|
||||
}
|
||||
return _r(frameIndex, layerSubmitPtr, layerSubmitCount, commandQueue);
|
||||
}
|
||||
}
|
||||
(void)commandQueue;
|
||||
static int o; if (!o) { o = 1; XRRLOG("ovrp_EndFrame4 first call (layers=%d)", layerSubmitCount); }
|
||||
return xrr_end_frame(frameIndex, layerSubmitPtr, layerSubmitCount);
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetPredictedDisplayTime(int frameIndex, double *outTime) {
|
||||
PT_FWD(ovrp_GetPredictedDisplayTime, frameIndex, outTime);
|
||||
(void)frameIndex;
|
||||
if (!outTime) return ovrpFailure_InvalidParameter;
|
||||
*outTime = xrr_predicted_display_time_s();
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* --- tracking / input --------------------------------------------------- */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePoseState3(ovrpStep step, int frameIndex,
|
||||
ovrpNode nodeId, ovrpPoseStatef *outState) {
|
||||
if (pt_active()) {
|
||||
static __typeof__(&ovrp_GetNodePoseState3) _r; static int _g;
|
||||
if (!_g) { _r = (__typeof__(&ovrp_GetNodePoseState3))pt_real("ovrp_GetNodePoseState3"); _g = 1; }
|
||||
if (_r) {
|
||||
ovrpResult rr = _r(step, frameIndex, nodeId, outState);
|
||||
/* native eye poses — the ghost diff target (cf. our STEREO/HEADvsEYE logs) */
|
||||
if (outState && (nodeId == ovrpNode_EyeLeft || nodeId == ovrpNode_EyeRight)) {
|
||||
static int po = 0;
|
||||
if (po++ < 16)
|
||||
XRRLOG("PT NodePoseState3 eye=%d pos=(%.4f %.4f %.4f) quat=(%.4f %.4f %.4f %.4f)",
|
||||
(int)nodeId, outState->Pose.Position.x, outState->Pose.Position.y,
|
||||
outState->Pose.Position.z, outState->Pose.Orientation.x,
|
||||
outState->Pose.Orientation.y, outState->Pose.Orientation.z,
|
||||
outState->Pose.Orientation.w);
|
||||
}
|
||||
return rr;
|
||||
}
|
||||
}
|
||||
(void)step; (void)frameIndex;
|
||||
return xrr_get_node_pose(nodeId, outState);
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePoseStateRaw(ovrpStep step, int frameIndex,
|
||||
ovrpNode nodeId, ovrpPoseStatef *outState) {
|
||||
PT_FWD(ovrp_GetNodePoseStateRaw, step, frameIndex, nodeId, outState);
|
||||
(void)step; (void)frameIndex;
|
||||
return xrr_get_node_pose(nodeId, outState);
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerState4(ovrpController controllerMask,
|
||||
ovrpControllerState4 *outState) {
|
||||
PT_FWD(ovrp_GetControllerState4, controllerMask, outState);
|
||||
if (!outState) return ovrpFailure_InvalidParameter;
|
||||
xrr_get_controller_state(controllerMask, outState);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* node presence/validity — the game gates controller-pose queries on these */
|
||||
OVRP_EXPORT ovrpResult ovrp_SetControllerVibration2(ovrpController mask,
|
||||
float frequency, float amplitude) {
|
||||
PT_FWD(ovrp_SetControllerVibration2, mask, frequency, amplitude);
|
||||
xrr_set_vibration(mask, frequency, amplitude);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePresent2(ovrpNode node, ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetNodePresent2, node, out);
|
||||
if (out) *out = xrr_node_present(node) ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeOrientationValid(ovrpNode node, ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetNodeOrientationValid, node, out);
|
||||
if (out) *out = xrr_node_valid(node) ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePositionValid(ovrpNode node, ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetNodePositionValid, node, out);
|
||||
if (out) *out = xrr_node_valid(node) ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeOrientationTracked2(ovrpNode node, ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetNodeOrientationTracked2, node, out);
|
||||
if (out) *out = xrr_node_valid(node) ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePositionTracked2(ovrpNode node, ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetNodePositionTracked2, node, out);
|
||||
if (out) *out = xrr_node_valid(node) ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* --- system / tracking config ------------------------------------------ */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemHeadsetType2(ovrpSystemHeadset *outType) {
|
||||
PT_FWD(ovrp_GetSystemHeadsetType2, outType);
|
||||
if (outType) *outType = ovrpSystemHeadset_Oculus_Quest_2;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* [VERIFIED from UE OculusHMD.cpp + disasm] ovrp_GetInitialized takes NO args and
|
||||
* returns ovrpBool DIRECTLY. My earlier (ovrpBool* out) signature wrote into x0
|
||||
* (which still held `this`), corrupting FOculusHMD's vtable -> null virtual crash.
|
||||
* Return false until the SESSION exists so FOculusHMD::InitDevice proceeds into
|
||||
* InitializeSession() (which calls ovrp_Initialize5 to create it). */
|
||||
OVRP_EXPORT ovrpBool ovrp_GetInitialized(void) {
|
||||
PT_FWD(ovrp_GetInitialized);
|
||||
/* called every frame, many times — don't log (it rolls the logcat buffer) */
|
||||
return (g_xr.session != XR_NULL_HANDLE) ? ovrpBool_True : ovrpBool_False;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemDisplayFrequency2(float *outFreq) {
|
||||
PT_FWD(ovrp_GetSystemDisplayFrequency2, outFreq);
|
||||
if (outFreq) *outFreq = 72.0f; /* Quest 2 default refresh */
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* per-frame app-state getters the loading loop polls (all (ovrpBool* out)->result) */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppHasVrFocus2(ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetAppHasVrFocus2, out);
|
||||
if (out) *out = ovrpBool_True; return ovrpSuccess; /* we have focus */
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppShouldQuit2(ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetAppShouldQuit2, out);
|
||||
if (out) *out = ovrpBool_False; return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserPresent2(ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetUserPresent2, out);
|
||||
if (out) *out = ovrpBool_True; return ovrpSuccess; /* headset worn */
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppShouldRecenter2(ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetAppShouldRecenter2, out);
|
||||
if (out) *out = ovrpBool_False; return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppShouldRecreateDistortionWindow2(ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetAppShouldRecreateDistortionWindow2, out);
|
||||
if (out) *out = ovrpBool_False; return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemMultiViewSupported2(ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetSystemMultiViewSupported2, out);
|
||||
if (out) *out = ovrpBool_True; return ovrpSuccess; /* Quest supports multiview */
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppHasInputFocus(ovrpBool *out) {
|
||||
PT_FWD(ovrp_GetAppHasInputFocus, out);
|
||||
if (out) *out = ovrpBool_True; return ovrpSuccess;
|
||||
}
|
||||
/* the OpenXR session IS our display; nothing extra to set up */
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupDistortionWindow3(unsigned int flags) {
|
||||
PT_FWD(ovrp_SetupDistortionWindow3, flags);
|
||||
(void)flags; return ovrpSuccess;
|
||||
}
|
||||
/* like GetInitialized, this returns ovrpBool DIRECTLY (no out-param) */
|
||||
OVRP_EXPORT ovrpBool ovrp_GetMixedRealityInitialized(void) {
|
||||
PT_FWD(ovrp_GetMixedRealityInitialized);
|
||||
return ovrpBool_False; /* MR not used */
|
||||
}
|
||||
/* [VERIFIED: UE builds the eye projection matrix from this FOV — OculusHMD.cpp
|
||||
* line ~2369 uses Fov.{Left,Right,Up,Down}Tan]. Must match the FOV we composite
|
||||
* with (g_xr.views[].fov), or the image is reprojected to the wrong frustum. */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeFrustum2(ovrpNode node, ovrpFrustum2f *out) {
|
||||
if (pt_active()) {
|
||||
static __typeof__(&ovrp_GetNodeFrustum2) _r; static int _g;
|
||||
if (!_g) { _r = (__typeof__(&ovrp_GetNodeFrustum2))pt_real("ovrp_GetNodeFrustum2"); _g = 1; }
|
||||
if (_r) {
|
||||
ovrpResult rr = _r(node, out);
|
||||
if (out) { static int po = 0;
|
||||
if (po++ < 8)
|
||||
XRRLOG("PT GetNodeFrustum2 node=%d -> Fov U=%.3f D=%.3f L=%.3f R=%.3f zN=%.3f zF=%.1f",
|
||||
node, out->Fov.UpTan, out->Fov.DownTan, out->Fov.LeftTan,
|
||||
out->Fov.RightTan, out->zNear, out->zFar);
|
||||
}
|
||||
return rr;
|
||||
}
|
||||
}
|
||||
if (!out) return ovrpFailure_InvalidParameter;
|
||||
int eye = (node == ovrpNode_EyeRight) ? 1 : 0; /* EyeLeft/EyeCenter -> 0 */
|
||||
out->zNear = 0.01f;
|
||||
out->zFar = 1000.0f;
|
||||
xrr_eye_fov_tangents(eye, &out->Fov.UpTan, &out->Fov.DownTan,
|
||||
&out->Fov.LeftTan, &out->Fov.RightTan);
|
||||
static int o = 0;
|
||||
if (o++ < 4) XRRLOG("GetNodeFrustum2 node=%d -> Fov U=%.3f D=%.3f L=%.3f R=%.3f",
|
||||
node, out->Fov.UpTan, out->Fov.DownTan, out->Fov.LeftTan, out->Fov.RightTan);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingOriginType2(ovrpTrackingOrigin *outOrigin) {
|
||||
PT_FWD(ovrp_GetTrackingOriginType2, outOrigin);
|
||||
if (outOrigin)
|
||||
*outOrigin = xrr_get_tracking_origin() ? ovrpTrackingOrigin_FloorLevel
|
||||
: ovrpTrackingOrigin_EyeLevel;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingOriginType2(ovrpTrackingOrigin origin) {
|
||||
PT_FWD(ovrp_SetTrackingOriginType2, origin);
|
||||
/* roomscale games request FloorLevel/Stage; honor it so the floor height (and
|
||||
* thus body-anchored inventory) is correct. */
|
||||
XRRLOG("ovrp_SetTrackingOriginType2(%d) -> %s", (int)origin,
|
||||
origin != ovrpTrackingOrigin_EyeLevel ? "floor" : "eye");
|
||||
xrr_set_tracking_origin(origin != ovrpTrackingOrigin_EyeLevel);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_RecenterTrackingOrigin2(unsigned int flags) {
|
||||
PT_FWD(ovrp_RecenterTrackingOrigin2, flags);
|
||||
(void)flags; return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* Perf levels: the game asks for CPU/GPU clock levels under load. We used to no-op
|
||||
* these, letting the device underclock while CPU-bound -> frame drops. Forward them
|
||||
* to XR_EXT_performance_settings so clocks boost. (real sig: one int level) */
|
||||
OVRP_EXPORT ovrpResult ovrp_SetSystemCpuLevel2(int level) {
|
||||
PT_FWD(ovrp_SetSystemCpuLevel2, level);
|
||||
xrr_set_perf_level(0, level); return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_SetSystemGpuLevel2(int level) {
|
||||
PT_FWD(ovrp_SetSystemGpuLevel2, level);
|
||||
xrr_set_perf_level(1, level); return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* Dynamic perf: tiled multi-res (FFR) + GPU frame time. Previously stubbed as
|
||||
* Unsupported, which disabled RE4's own GPU-load mitigation. We now report FFR
|
||||
* supported, forward the game's Set* requests onto OpenXR foveation (xr_runtime.c),
|
||||
* and feed GetGPUFrameTime so the game's scaler has an input. */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResSupported(ovrpBool *outSupported) {
|
||||
PT_FWD(ovrp_GetTiledMultiResSupported, outSupported);
|
||||
if (!outSupported) return ovrpFailure_InvalidParameter;
|
||||
*outSupported = xrr_foveation_supported() ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResLevel(ovrpTiledMultiResLevel *outLevel) {
|
||||
PT_FWD(ovrp_GetTiledMultiResLevel, outLevel);
|
||||
if (!outLevel) return ovrpFailure_InvalidParameter;
|
||||
*outLevel = (ovrpTiledMultiResLevel)xrr_get_tiled_multires_level();
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTiledMultiResLevel(ovrpTiledMultiResLevel level) {
|
||||
PT_FWD(ovrp_SetTiledMultiResLevel, level);
|
||||
xrr_set_tiled_multires_level((int)level);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTiledMultiResDynamic(ovrpBool *outDynamic) {
|
||||
PT_FWD(ovrp_GetTiledMultiResDynamic, outDynamic);
|
||||
if (!outDynamic) return ovrpFailure_InvalidParameter;
|
||||
*outDynamic = xrr_get_tiled_multires_dynamic() ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTiledMultiResDynamic(ovrpBool isDynamic) {
|
||||
PT_FWD(ovrp_SetTiledMultiResDynamic, isDynamic);
|
||||
xrr_set_tiled_multires_dynamic(isDynamic != ovrpBool_False);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetGPUFrameTime(float *outGpuTimeMs) {
|
||||
PT_FWD(ovrp_GetGPUFrameTime, outGpuTimeMs);
|
||||
if (!outGpuTimeMs) return ovrpFailure_InvalidParameter;
|
||||
*outGpuTimeMs = xrr_gpu_frame_time_ms();
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* Lever A — dynamic resolution. Previously stubbed Unsupported, leaving the game's preset
|
||||
* scale=1.0 (full res always). We return scale<1 under GPU pressure; the game self-downscales
|
||||
* its eye buffer (resolution = baseDensity * sqrt(scale)). See xr_runtime.c / game-perf-RE.md. */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAdaptiveGpuPerformanceScale2(float *outScale) {
|
||||
PT_FWD(ovrp_GetAdaptiveGpuPerformanceScale2, outScale);
|
||||
if (!outScale) return ovrpFailure_InvalidParameter;
|
||||
*outScale = xrr_adaptive_gpu_scale();
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* Perf metrics: per-metric support + read. Previously the whole call returned
|
||||
* Unsupported, which the game (correctly) treats as "no perf metrics at all" and may
|
||||
* gate its adaptive systems on. We answer per metric truthfully instead. */
|
||||
OVRP_EXPORT ovrpResult ovrp_IsPerfMetricsSupported(ovrpPerfMetrics metric, ovrpBool *outSupported) {
|
||||
PT_FWD(ovrp_IsPerfMetricsSupported, metric, outSupported);
|
||||
if (!outSupported) return ovrpFailure_InvalidParameter;
|
||||
*outSupported = xrr_perf_metric_supported((int)metric) ? ovrpBool_True : ovrpBool_False;
|
||||
return ovrpSuccess;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetPerfMetricsFloat(ovrpPerfMetrics metric, float *outValue) {
|
||||
PT_FWD(ovrp_GetPerfMetricsFloat, metric, outValue);
|
||||
if (!outValue) return ovrpFailure_InvalidParameter;
|
||||
return xrr_perf_metric_float((int)metric, outValue) ? ovrpSuccess : ovrpFailure_Unsupported;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetPerfMetricsInt(ovrpPerfMetrics metric, int *outValue) {
|
||||
PT_FWD(ovrp_GetPerfMetricsInt, metric, outValue);
|
||||
if (!outValue) return ovrpFailure_InvalidParameter;
|
||||
return xrr_perf_metric_int((int)metric, outValue) ? ovrpSuccess : ovrpFailure_Unsupported;
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/* layers.c — ovrp_* layer/swapchain functions, backed by xr_runtime swapchains.
|
||||
* SetupLayer creates an XrSwapchain from the (reversed) ovrpLayerDesc; the app
|
||||
* gets the per-stage VkImage handles via GetLayerTexture2 and wraps them in its
|
||||
* RHI. Depth swapchains + foveation (FFR) are created in xr_runtime's setup_layer.
|
||||
*/
|
||||
#include "ovrplugin_shim.h"
|
||||
#include "xr_runtime.h"
|
||||
#include "passthru.h"
|
||||
#include "log.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* [VERIFIED arg order from UE OculusHMD.cpp]: (layout, textureScale, mipLevels,
|
||||
* sampleCount, colorFormat, depthFormat, layerFlags, out). Fills the EyeFov layer
|
||||
* desc UE uses to create the eye swapchain (-> ovrp_SetupLayer). */
|
||||
OVRP_EXPORT ovrpResult ovrp_CalculateEyeLayerDesc2(
|
||||
ovrpLayout layout, float textureScale, int mipLevels, int sampleCount,
|
||||
ovrpTextureFormat colorFormat, ovrpTextureFormat depthFormat,
|
||||
int layerFlags, ovrpLayerDesc *out) {
|
||||
if (pt_active()) {
|
||||
static __typeof__(&ovrp_CalculateEyeLayerDesc2) _r; static int _g;
|
||||
if (!_g) { _r = (__typeof__(&ovrp_CalculateEyeLayerDesc2))pt_real("ovrp_CalculateEyeLayerDesc2"); _g = 1; }
|
||||
if (_r) {
|
||||
ovrpResult rr = _r(layout, textureScale, mipLevels, sampleCount,
|
||||
colorFormat, depthFormat, layerFlags, out);
|
||||
if (out) { static int po = 0;
|
||||
if (po++ < 4)
|
||||
XRRLOG("PT EyeLayerDesc2 %dx%d FovL(U%.3f D%.3f L%.3f R%.3f) FovR(U%.3f D%.3f L%.3f R%.3f)",
|
||||
out->TextureSize.w, out->TextureSize.h,
|
||||
out->Fov[0].UpTan, out->Fov[0].DownTan, out->Fov[0].LeftTan, out->Fov[0].RightTan,
|
||||
out->Fov[1].UpTan, out->Fov[1].DownTan, out->Fov[1].LeftTan, out->Fov[1].RightTan);
|
||||
}
|
||||
return rr;
|
||||
}
|
||||
}
|
||||
if (!out) return ovrpFailure_InvalidParameter;
|
||||
uint32_t w, h;
|
||||
xrr_recommended_eye_size(&w, &h);
|
||||
/* UE asks ~1.2x supersample (1728x1900). debug.re4vr.sscap=1 caps it to 1.0x to
|
||||
* free GPU/bandwidth (the copy-ring copies fewer pixels too); the ghosting is a
|
||||
* frame-drop/serialization issue not pixel count, but this is a cheap lever to
|
||||
* stack with the perf/copy-ring fixes. Default off (full res for sharpness). */
|
||||
if (textureScale > 1.0f) {
|
||||
static int cap = -1;
|
||||
if (cap < 0) {
|
||||
#ifdef __ANDROID__
|
||||
char s[92] = {0};
|
||||
extern int __system_property_get(const char*, char*);
|
||||
cap = (__system_property_get("debug.re4vr.sscap", s) > 0 && s[0] == '1') ? 1 : 0;
|
||||
#else
|
||||
cap = 0;
|
||||
#endif
|
||||
XRRLOG("supersample cap: %s (debug.re4vr.sscap), UE asked scale=%.2f", cap ? "1.0x" : "off", textureScale);
|
||||
}
|
||||
if (cap) textureScale = 1.0f;
|
||||
}
|
||||
if (textureScale > 0.0f) { w = (uint32_t)(w * textureScale); h = (uint32_t)(h * textureScale); }
|
||||
|
||||
/* Aggressive resolution lever (debug.re4vr.resscale = percent of the size above;
|
||||
* default 100). Below 100 shrinks the eye buffer further to keep UE under GPU budget
|
||||
* so it stops TRUNCATING frames -> black (the load-gated UE frame-drop; RenderDoc:
|
||||
* 28 draws vs ~198 normal, resolved eye = pure black). Read once at layer setup. */
|
||||
{
|
||||
static int rs = -1;
|
||||
if (rs < 0) {
|
||||
#ifdef __ANDROID__
|
||||
char s[92] = {0};
|
||||
extern int __system_property_get(const char*, char*);
|
||||
rs = (__system_property_get("debug.re4vr.resscale", s) > 0) ? atoi(s) : 100;
|
||||
#else
|
||||
rs = 100;
|
||||
#endif
|
||||
if (rs < 25) rs = 25;
|
||||
if (rs > 200) rs = 200;
|
||||
XRRLOG("resscale: %d%% (debug.re4vr.resscale)", rs);
|
||||
}
|
||||
if (rs != 100) { w = (uint32_t)((uint64_t)w * rs / 100); h = (uint32_t)((uint64_t)h * rs / 100); }
|
||||
}
|
||||
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->Shape = ovrpShape_EyeFov;
|
||||
out->Layout = layout;
|
||||
out->TextureSize.w = (int)w;
|
||||
out->TextureSize.h = (int)h;
|
||||
out->MipLevels = mipLevels > 0 ? mipLevels : 1;
|
||||
out->SampleCount = sampleCount > 0 ? sampleCount : 1;
|
||||
out->Format = colorFormat;
|
||||
out->LayerFlags = layerFlags;
|
||||
for (int e = 0; e < 2; e++) {
|
||||
/* real per-eye FOV so the layer desc matches GetNodeFrustum2 + our submit */
|
||||
xrr_eye_fov_tangents(e, &out->Fov[e].UpTan, &out->Fov[e].DownTan,
|
||||
&out->Fov[e].LeftTan, &out->Fov[e].RightTan);
|
||||
out->VisibleRect[e].Pos.x = 0.0f; out->VisibleRect[e].Pos.y = 0.0f;
|
||||
out->VisibleRect[e].Size.w = (float)w; out->VisibleRect[e].Size.h = (float)h;
|
||||
}
|
||||
out->MaxViewportSize.w = (int)w;
|
||||
out->MaxViewportSize.h = (int)h;
|
||||
out->DepthFormat = depthFormat;
|
||||
{ /* log only when the parameters change — called every frame otherwise */
|
||||
static int pw, ph, pl = -1, pf = -1;
|
||||
if ((int)layout != pl || (int)w != pw || (int)h != ph || (int)colorFormat != pf) {
|
||||
XRRLOG("CalculateEyeLayerDesc2: layout=%d %ux%u fmt=%d depth=%d flags=%d",
|
||||
layout, w, h, colorFormat, depthFormat, layerFlags);
|
||||
pl = layout; pw = (int)w; ph = (int)h; pf = colorFormat;
|
||||
}
|
||||
}
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* [from UE: CalculateEyeViewportRect(EyeLayerDesc, eye, scale, &vpRect)]. desc is
|
||||
* passed by value (>16B -> indirect, so a pointer in x0). Array layout: each eye
|
||||
* is a full array layer, so the viewport is the full (scaled) texture rect. */
|
||||
OVRP_EXPORT ovrpResult ovrp_CalculateEyeViewportRect(const ovrpLayerDesc *desc,
|
||||
int eye, float scale, ovrpRecti *out) {
|
||||
PT_FWD(ovrp_CalculateEyeViewportRect, desc, eye, scale, out);
|
||||
(void)eye;
|
||||
if (!desc || !out) return ovrpFailure_InvalidParameter;
|
||||
out->Pos.x = 0; out->Pos.y = 0;
|
||||
out->Size.w = (int)(desc->TextureSize.w * scale);
|
||||
out->Size.h = (int)(desc->TextureSize.h * scale);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* [from OVR_Plugin.h] non-eye layer desc (quad/cylinder/etc, e.g. the splash).
|
||||
* textureSize is const-ref => a pointer. Fills the common header; UE fills the
|
||||
* shape-specific tail. Stubbing this left the desc zeroed -> SetupLayer 0x0 -> fail. */
|
||||
OVRP_EXPORT ovrpResult ovrp_CalculateLayerDesc(ovrpShape shape, ovrpLayout layout,
|
||||
const ovrpSizei *textureSize, int mipLevels, int sampleCount,
|
||||
ovrpTextureFormat format, int layerFlags, ovrpLayerDesc *out) {
|
||||
PT_FWD(ovrp_CalculateLayerDesc, shape, layout, textureSize, mipLevels, sampleCount, format, layerFlags, out);
|
||||
if (!out || !textureSize) return ovrpFailure_InvalidParameter;
|
||||
out->Shape = shape;
|
||||
out->Layout = layout;
|
||||
out->TextureSize = *textureSize;
|
||||
out->MipLevels = mipLevels > 0 ? mipLevels : 1;
|
||||
out->SampleCount = sampleCount > 0 ? sampleCount : 1;
|
||||
out->Format = format;
|
||||
out->LayerFlags = layerFlags;
|
||||
XRRLOG("CalculateLayerDesc: shape=%d layout=%d %dx%d fmt=%d",
|
||||
shape, layout, textureSize->w, textureSize->h, format);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupLayer(void *device, ovrpLayerDesc *desc,
|
||||
int *outLayerId) {
|
||||
PT_FWD(ovrp_SetupLayer, device, desc, outLayerId);
|
||||
(void)device; /* the Vulkan device is already bound to the XrSession */
|
||||
return xrr_setup_layer(desc, outLayerId);
|
||||
}
|
||||
|
||||
/* [VERIFIED from UE OculusHMD.cpp: FOculusHMD::DestroyLayer(uint32 LayerId)] */
|
||||
OVRP_EXPORT ovrpResult ovrp_DestroyLayer(int layerId) {
|
||||
PT_FWD(ovrp_DestroyLayer, layerId);
|
||||
xrr_destroy_layer(layerId);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
OVRP_EXPORT ovrpResult ovrp_GetLayerTextureStageCount(int layerId, int *outCount) {
|
||||
PT_FWD(ovrp_GetLayerTextureStageCount, layerId, outCount);
|
||||
if (!outCount) return ovrpFailure_InvalidParameter;
|
||||
*outCount = xrr_layer_stage_count(layerId);
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
/* (layerId, stage, eyeId, &colorTexHandle, &depthTexHandle); either out may be
|
||||
* NULL. Handles are VkImage as uint64 [VERIFIED 5-arg shape from decompile]. */
|
||||
OVRP_EXPORT ovrpResult ovrp_GetLayerTexture2(int layerId, int stage, int eyeId,
|
||||
uint64_t *outColorTex, uint64_t *outDepthTex) {
|
||||
PT_FWD(ovrp_GetLayerTexture2, layerId, stage, eyeId, outColorTex, outDepthTex);
|
||||
if (!outColorTex && !outDepthTex) return ovrpFailure_InvalidParameter;
|
||||
return xrr_get_layer_texture(layerId, stage, eyeId, outColorTex, outDepthTex);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/* log.h — XRRLOG goes to logcat (tag "xrr") on Android, stderr on host.
|
||||
* grep it on-device: adb logcat | grep -i xrr */
|
||||
#ifndef XRR_LOG_H
|
||||
#define XRR_LOG_H
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#define XRRLOG(...) __android_log_print(ANDROID_LOG_INFO, "xrr", __VA_ARGS__)
|
||||
#define XRRERR(...) __android_log_print(ANDROID_LOG_ERROR, "xrr", __VA_ARGS__)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define XRRLOG(...) do { fprintf(stderr, "[xrr] " __VA_ARGS__); fputc('\n', stderr); } while (0)
|
||||
#define XRRERR(...) do { fprintf(stderr, "[xrr] ERR " __VA_ARGS__); fputc('\n', stderr); } while (0)
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/* passthru.c — P4 native-parity forwarding. See passthru.h. Loads the real, SONAME-
|
||||
* patched libOVRPlugin_real.so (deps incl. libvrapi ride along in the APK) and hands
|
||||
* the whole OVRPlugin session to it when debug.re4vr.passthru=1, so we can capture
|
||||
* native's per-eye poses/FOV/submit for the ghost diff. */
|
||||
#include "ovrplugin_shim.h"
|
||||
#include "passthru.h"
|
||||
#include "xr_runtime.h"
|
||||
#include "log.h"
|
||||
#include <dlfcn.h>
|
||||
#ifdef __ANDROID__
|
||||
#include <sys/system_properties.h>
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
/* The asm trampolines read this flag directly; hidden visibility keeps the load a
|
||||
* direct adrp/ldr (no GOT, no interposition). */
|
||||
__attribute__((visibility("hidden"))) int g_pt_active = 0;
|
||||
static void *g_pt_handle = 0;
|
||||
|
||||
/* ---- signature-agnostic stub forwarders --------------------------------------------
|
||||
* A few exports the game calls live only as no-arg () stubs in stubs.c (two aren't even
|
||||
* in OVR_Plugin.h, so we have no C signature to forward through). A naked arm64 tail-call
|
||||
* trampoline forwards them verbatim: it never touches the arg registers (x0-x7/v0-v7/x8),
|
||||
* so it works for ANY signature. Passthru off (or symbol missing) -> falls through to the
|
||||
* SAME return constant the original autogen stub used (non-passthru behavior unchanged). */
|
||||
#if defined(__aarch64__)
|
||||
#define PT_STUB(N, CONST) \
|
||||
__attribute__((visibility("hidden"))) void *g_pt_real_##N = 0; \
|
||||
__attribute__((naked, visibility("default"))) ovrpResult ovrp_##N(void) { \
|
||||
__asm__ volatile( \
|
||||
"adrp x16, g_pt_active\n\t" \
|
||||
"ldr w17, [x16, :lo12:g_pt_active]\n\t" \
|
||||
"cbz w17, 1f\n\t" \
|
||||
"adrp x16, g_pt_real_" #N "\n\t" \
|
||||
"ldr x16, [x16, :lo12:g_pt_real_" #N "]\n\t" \
|
||||
"cbz x16, 1f\n\t" \
|
||||
"br x16\n\t" \
|
||||
"1:\n\t" \
|
||||
"mov w0, #" #CONST "\n\t" \
|
||||
"ret\n\t"); \
|
||||
}
|
||||
#else /* host validation build: plain stub, no forwarding */
|
||||
#define PT_STUB(N, CONST) \
|
||||
void *g_pt_real_##N = 0; \
|
||||
ovrpResult ovrp_##N(void) { return (ovrpResult)(CONST); }
|
||||
#endif
|
||||
|
||||
/* The game-called () stubs (confirmed in device log). CONST = the constant the original
|
||||
* autogen stub returned -> non-passthru path is byte-identical. These names are removed
|
||||
* from stubs.c via gen_stubs.sh HEADER_FNS so there's no duplicate symbol. */
|
||||
PT_STUB(DestroyDistortionWindow2, 0) /* ovrpSuccess */
|
||||
PT_STUB(SetupDisplayObjects2, -1005) /* ovrpFailure_NotYetImplemented */
|
||||
PT_STUB(SetReorientHMDOnControllerRecenter, 0)
|
||||
PT_STUB(SetClientColorDesc, 0)
|
||||
PT_STUB(SetAppEngineInfo2, 0)
|
||||
PT_STUB(SetAppCPUPriority2, 0)
|
||||
PT_STUB(InitializeMixedReality, -1005)
|
||||
PT_STUB(GetViewportStencil, -1005)
|
||||
PT_STUB(GetSystemRecommendedMSAALevel2, -1005)
|
||||
PT_STUB(GetLocalTrackingSpaceRecenterCount, -1005)
|
||||
PT_STUB(GetLayerTextureFoveation, -1005)
|
||||
PT_STUB(GetControllerHapticsDesc2, -1005)
|
||||
|
||||
static void pt_first_use(void) {
|
||||
static int done = 0;
|
||||
if (done) return;
|
||||
done = 1;
|
||||
#ifdef __ANDROID__
|
||||
char s[PROP_VALUE_MAX] = {0};
|
||||
if (__system_property_get("debug.re4vr.passthru", s) <= 0 || s[0] != '1') return;
|
||||
void *h = dlopen("libOVRPlugin_real.so", RTLD_NOW | RTLD_LOCAL);
|
||||
if (!h) { XRRLOG("PASSTHRU: dlopen real libOVRPlugin FAILED: %s", dlerror()); return; }
|
||||
g_pt_handle = h;
|
||||
|
||||
/* ART only calls JNI_OnLoad for System.loadLibrary, not a native dlopen — so the
|
||||
* real lib's cached JavaVM is null and its VrApi PreInitialize derefs it (SIGSEGV in
|
||||
* CompositorVRAPI::PreInitialize). Replicate the loadLibrary handshake by hand. */
|
||||
jint (*real_jni_onload)(JavaVM *, void *) =
|
||||
(jint (*)(JavaVM *, void *))dlsym(h, "JNI_OnLoad");
|
||||
JavaVM *vm = (JavaVM *)xrr_android_get_vm();
|
||||
if (real_jni_onload && vm) {
|
||||
jint v = real_jni_onload(vm, 0);
|
||||
XRRLOG("PASSTHRU: primed real JNI_OnLoad(vm=%p) -> 0x%x", (void *)vm, v);
|
||||
} else {
|
||||
XRRLOG("PASSTHRU: WARN no real JNI_OnLoad/vm (onload=%p vm=%p) — PreInitialize may crash",
|
||||
(void *)real_jni_onload, (void *)vm);
|
||||
}
|
||||
#define PT_RESOLVE(N) g_pt_real_##N = dlsym(h, "ovrp_" #N)
|
||||
PT_RESOLVE(DestroyDistortionWindow2);
|
||||
PT_RESOLVE(SetupDisplayObjects2);
|
||||
PT_RESOLVE(SetReorientHMDOnControllerRecenter);
|
||||
PT_RESOLVE(SetClientColorDesc);
|
||||
PT_RESOLVE(SetAppEngineInfo2);
|
||||
PT_RESOLVE(SetAppCPUPriority2);
|
||||
PT_RESOLVE(InitializeMixedReality);
|
||||
PT_RESOLVE(GetViewportStencil);
|
||||
PT_RESOLVE(GetSystemRecommendedMSAALevel2);
|
||||
PT_RESOLVE(GetLocalTrackingSpaceRecenterCount);
|
||||
PT_RESOLVE(GetLayerTextureFoveation);
|
||||
PT_RESOLVE(GetControllerHapticsDesc2);
|
||||
#undef PT_RESOLVE
|
||||
g_pt_active = 1; /* set last: trampolines must not forward until the table is built */
|
||||
XRRLOG("PASSTHRU: ACTIVE — real libOVRPlugin owns the session (h=%p). Shim OpenXR path disabled.", h);
|
||||
#endif
|
||||
}
|
||||
|
||||
int pt_active(void) { pt_first_use(); return g_pt_active; }
|
||||
void *pt_real(const char *name) { return g_pt_handle ? dlsym(g_pt_handle, name) : 0; }
|
||||
|
||||
/* Rate-limited native call census. Keyed by the string-literal pointer (each PT_FWD call
|
||||
* site passes a stable literal), so per-function. Logs the first 3 calls then every 1200th
|
||||
* — enough to capture the full set of game-called exports + native's return for each,
|
||||
* without flooding on the per-frame getters. Diff `PTC` lines vs our shim's returns. */
|
||||
void pt_log_call(const char *name, long ret) {
|
||||
enum { MAXN = 320 };
|
||||
static const char *seen[MAXN];
|
||||
static unsigned cnt[MAXN];
|
||||
static int n = 0;
|
||||
int i;
|
||||
for (i = 0; i < n; i++) if (seen[i] == name) break;
|
||||
if (i == n) {
|
||||
if (n >= MAXN) return;
|
||||
seen[n] = name; cnt[n] = 0; i = n; n++;
|
||||
}
|
||||
unsigned c = ++cnt[i];
|
||||
if (c <= 3 || (c % 1200) == 0)
|
||||
XRRLOG("PTC %s -> %ld (#%u)", name, ret, c);
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/* AUTO-GENERATED by gen_stubs.sh from analysis/shim_surface.txt. Do not edit by hand. */
|
||||
#include "ovrplugin_shim.h"
|
||||
#include "log.h"
|
||||
|
||||
/* Stub policy:
|
||||
* -1004 Unsupported : features we will not implement (MRC/camera/perf/boundary/hands)
|
||||
* 0 Success (no-op) : config setters we can safely accept-and-ignore for now
|
||||
* -1005 NotYetImplemented : real work still owed (getters/etc. the game needs)
|
||||
* Empty () = unspecified args: stub ignores args, returns constant in result reg. */
|
||||
|
||||
OVRP_EXPORT ovrpResult ovrp_AddCustomMetadata() { static int o; if(!o){o=1;XRRLOG("stub ovrp_AddCustomMetadata -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_AutoThreadScheduling() { static int o; if(!o){o=1;XRRLOG("stub ovrp_AutoThreadScheduling -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_BeginFrame() { static int o; if(!o){o=1;XRRLOG("stub ovrp_BeginFrame -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_BeginFrame2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_BeginFrame2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_BeginFrame3() { static int o; if(!o){o=1;XRRLOG("stub ovrp_BeginFrame3 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_CalculateEyeLayerDesc() { static int o; if(!o){o=1;XRRLOG("stub ovrp_CalculateEyeLayerDesc -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_CalculateEyeLayerDesc3() { static int o; if(!o){o=1;XRRLOG("stub ovrp_CalculateEyeLayerDesc3 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_CalculateEyePreviewRect() { static int o; if(!o){o=1;XRRLOG("stub ovrp_CalculateEyePreviewRect -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_CloseCameraDevice() { static int o; if(!o){o=1;XRRLOG("stub ovrp_CloseCameraDevice -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ConvertPoseToCameraSpace() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ConvertPoseToCameraSpace -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_DestroyDistortionWindow() { static int o; if(!o){o=1;XRRLOG("stub ovrp_DestroyDistortionWindow -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_DestroyEyeTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_DestroyEyeTexture -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_DestroyMirrorTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_DestroyMirrorTexture -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_DestroyMirrorTexture2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_DestroyMirrorTexture2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_DismissHSW() { static int o; if(!o){o=1;XRRLOG("stub ovrp_DismissHSW -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_DoesCameraDeviceSupportDepth() { static int o; if(!o){o=1;XRRLOG("stub ovrp_DoesCameraDeviceSupportDepth -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EndEye() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EndEye -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EndEye2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EndEye2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EndFrame() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EndFrame -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EndFrame2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EndFrame2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EndFrame3() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EndFrame3 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EnqueueDestroyLayer() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EnqueueDestroyLayer -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EnqueueSetupLayer() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EnqueueSetupLayer -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EnqueueSetupLayer2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EnqueueSetupLayer2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EnqueueSubmitLayer() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EnqueueSubmitLayer -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EnqueueSubmitLayer2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EnqueueSubmitLayer2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EnumerateAllCameraDevices() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EnumerateAllCameraDevices -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_EnumerateAvailableCameraDevices() { static int o; if(!o){o=1;XRRLOG("stub ovrp_EnumerateAvailableCameraDevices -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetActiveController() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetActiveController -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetActiveController2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetActiveController2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAdapterId() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAdapterId -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAdaptiveGpuPerformanceScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAdaptiveGpuPerformanceScale -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppAsymmetricFov() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppAsymmetricFov -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppChromaticCorrection() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppChromaticCorrection -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppCPUPriority() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppCPUPriority -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppCPUPriority2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppCPUPriority2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppCpuStartToGpuEndTime() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppCpuStartToGpuEndTime -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppCpuStartToGpuEndTime2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppCpuStartToGpuEndTime2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppFramerate() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppFramerate -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppFramerate2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppFramerate2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppHasSystemOverlayPresent() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppHasSystemOverlayPresent -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppHasVrFocus() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppHasVrFocus -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppLatencyTimings() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppLatencyTimings -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppLatencyTimings2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppLatencyTimings2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppMonoscopic() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppMonoscopic -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppPerfStats() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppPerfStats -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppPerfStats2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppPerfStats2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppShouldQuit() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppShouldQuit -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppShouldRecenter() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppShouldRecenter -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppShouldRecreateDistortionWindow() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppShouldRecreateDistortionWindow -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAppSRGB() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAppSRGB -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetASWAdaptiveMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetASWAdaptiveMode -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetASWDepthScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetASWDepthScale -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetASWEnable() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetASWEnable -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetASWVelocityScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetASWVelocityScale -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioInDeviceId() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioInDeviceId -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioInDeviceId2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioInDeviceId2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioInId() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioInId -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioInId2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioInId2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioOutDeviceId() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioOutDeviceId -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioOutDeviceId2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioOutDeviceId2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioOutId() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioOutId -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetAudioOutId2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetAudioOutId2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBatteryStatus() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBatteryStatus -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryConfigured() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryConfigured -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryConfigured2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryConfigured2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryDimensions() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryDimensions -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryDimensions2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryDimensions2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryGeometry() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryGeometry -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryGeometry2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryGeometry2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryGeometry3() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryGeometry3 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryVisible() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryVisible -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBoundaryVisible2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBoundaryVisible2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetBufferCount() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetBufferCount -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceColorFrameBgraPixels() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDeviceColorFrameBgraPixels -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceColorFrameSize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDeviceColorFrameSize -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceDepthConfidencePixels() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDeviceDepthConfidencePixels -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceDepthFramePixels() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDeviceDepthFramePixels -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceDepthFrameSize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDeviceDepthFrameSize -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceDepthSensingMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDeviceDepthSensingMode -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDeviceIntrinsicsParameters() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDeviceIntrinsicsParameters -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCameraDevicePreferredDepthQuality() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCameraDevicePreferredDepthQuality -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCaps() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCaps -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCaps2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCaps2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetConnectedControllers() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetConnectedControllers -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetConnectedControllers2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetConnectedControllers2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerHapticsDesc() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetControllerHapticsDesc -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerHapticsState() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetControllerHapticsState -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerHapticsState2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetControllerHapticsState2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerState() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetControllerState -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerState2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetControllerState2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetControllerState3() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetControllerState3 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetCurrentTrackingTransformPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetCurrentTrackingTransformPose -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetDepthCompositingSupported() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetDepthCompositingSupported -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetDesiredEyeTextureFormat() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetDesiredEyeTextureFormat -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetDisplayAdapterId() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetDisplayAdapterId -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetDisplayAdapterId2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetDisplayAdapterId2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetDominantHand() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetDominantHand -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetExternalCameraCalibrationRawPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetExternalCameraCalibrationRawPose -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetExternalCameraCount() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetExternalCameraCount -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetExternalCameraExtrinsics() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetExternalCameraExtrinsics -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetExternalCameraIntrinsics() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetExternalCameraIntrinsics -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetExternalCameraName() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetExternalCameraName -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetExternalCameraPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetExternalCameraPose -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeAcceleration() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeAcceleration -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeFovLayerId() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeFovLayerId -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeFrustum() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeFrustum -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeOcclusionMesh() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeOcclusionMesh -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeOcclusionMeshEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeOcclusionMeshEnabled -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyePixelsPerTanAngleAtCenter() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyePixelsPerTanAngleAtCenter -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyePixelsPerTanAngleAtCenter2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyePixelsPerTanAngleAtCenter2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyePose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyePose -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyePreviewRect() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyePreviewRect -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeRecommendedResolutionScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeRecommendedResolutionScale -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureArrayEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureArrayEnabled -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureArraySupported() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureArraySupported -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureArraySupported2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureArraySupported2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureFlippedY() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureFlippedY -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureScale -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureShared() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureShared -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureSize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureSize -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeTextureStageCount() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeTextureStageCount -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeVelocity() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeVelocity -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetEyeViewportScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetEyeViewportScale -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetFloat() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetFloat -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetGPUUtilLevel() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetGPUUtilLevel -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetGPUUtilSupported() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetGPUUtilSupported -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHandNodePoseStateLatency() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHandNodePoseStateLatency -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHandState() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHandState -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHandState2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHandState2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHandTrackingEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHandTrackingEnabled -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHeadphonesPresent() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHeadphonesPresent -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHeadPoseModifier() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHeadPoseModifier -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHmdColorDesc() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHmdColorDesc -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHmdToEyeOffset() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHmdToEyeOffset -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetHmdToEyeOffset2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetHmdToEyeOffset2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetInputState() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetInputState -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetLayerAndroidSurfaceObject() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetLayerAndroidSurfaceObject -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetLayerOcclusionMesh() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetLayerOcclusionMesh -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetLayerTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetLayerTexture -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetLayerTexturePtr() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetLayerTexturePtr -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetLayerTextureSpaceWarp() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetLayerTextureSpaceWarp -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetMesh() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetMesh -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNativePointer() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNativePointer -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNativeSDKPointer() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNativeSDKPointer -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNativeSDKPointer2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNativeSDKPointer2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNativeSDKVersion() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNativeSDKVersion -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNativeSDKVersion2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNativeSDKVersion2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeAcceleration() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodeAcceleration -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeAcceleration2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodeAcceleration2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeFrustum() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodeFrustum -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeOrientationTracked() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodeOrientationTracked -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodePose -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePose2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodePose2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePoseState() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodePoseState -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePoseState2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodePoseState2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePositionTracked() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodePositionTracked -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodePresent() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodePresent -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeVelocity() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodeVelocity -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetNodeVelocity2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetNodeVelocity2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetReorientHMDOnControllerRecenter() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetReorientHMDOnControllerRecenter -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSkeleton() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSkeleton -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetStatus() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetStatus -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetStatus2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetStatus2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetString() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetString -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryLevel() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemBatteryLevel -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryLevel2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemBatteryLevel2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryStatus() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemBatteryStatus -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryStatus2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemBatteryStatus2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryTemperature() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemBatteryTemperature -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemBatteryTemperature2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemBatteryTemperature2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemCpuLevel() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemCpuLevel -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemCpuLevel2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemCpuLevel2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemDisplayAvailableFrequencies() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemDisplayAvailableFrequencies -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemDisplayFrequency() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemDisplayFrequency -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemGpuLevel() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemGpuLevel -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemGpuLevel2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemGpuLevel2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemHeadphonesPresent() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemHeadphonesPresent -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemHeadphonesPresent2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemHeadphonesPresent2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemHeadsetType() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemHeadsetType -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemHmd3DofModeEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemHmd3DofModeEnabled -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemMultiViewSupported() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemMultiViewSupported -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemPowerSavingMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemPowerSavingMode -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemPowerSavingMode2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemPowerSavingMode2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemProductName() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemProductName -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemProductName2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemProductName2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemRecommendedMSAALevel() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemRecommendedMSAALevel -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemRegion() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemRegion -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemRegion2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemRegion2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemVolume() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemVolume -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemVolume2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemVolume2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemVSyncCount() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemVSyncCount -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetSystemVSyncCount2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetSystemVSyncCount2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTimeInSeconds() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTimeInSeconds -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackerFrustum() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackerFrustum -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackerPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackerPose -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingCalibratedOrigin() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingCalibratedOrigin -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingCalibratedOrigin2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingCalibratedOrigin2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingIPDEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingIPDEnabled -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingIPDEnabled2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingIPDEnabled2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingOrientationEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingOrientationEnabled -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingOrientationEnabled2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingOrientationEnabled2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingOrientationSupported() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingOrientationSupported -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingOrientationSupported2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingOrientationSupported2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingOriginType() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingOriginType -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingPositionEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingPositionEnabled -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingPositionEnabled2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingPositionEnabled2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingPositionSupported() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingPositionSupported -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingPositionSupported2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingPositionSupported2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingTransformRawPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingTransformRawPose -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetTrackingTransformRelativePose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetTrackingTransformRelativePose -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUseOverriddenExternalCameraFov() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUseOverriddenExternalCameraFov -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUseOverriddenExternalCameraStaticPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUseOverriddenExternalCameraStaticPose -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserEyeDepth() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserEyeDepth -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserEyeHeight() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserEyeHeight -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserEyeHeight2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserEyeHeight2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserIPD() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserIPD -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserIPD2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserIPD2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserNeckEyeDistance() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserNeckEyeDistance -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserNeckEyeDistance2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserNeckEyeDistance2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetUserPresent() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetUserPresent -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetVersion() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetVersion -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetVersion2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetVersion2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_GetVrApiPropertyInt() { static int o; if(!o){o=1;XRRLOG("stub ovrp_GetVrApiPropertyInt -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_HasCameraDeviceOpened2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_HasCameraDeviceOpened2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Initialize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Initialize -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Initialize2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Initialize2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Initialize3() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Initialize3 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Initialize4() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Initialize4 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_IsCameraDeviceAvailable2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_IsCameraDeviceAvailable2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_IsCameraDeviceColorFrameAvailable2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_IsCameraDeviceColorFrameAvailable2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_IsCameraDeviceDepthFrameAvailable() { static int o; if(!o){o=1;XRRLOG("stub ovrp_IsCameraDeviceDepthFrameAvailable -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_IsRequestingASWData() { static int o; if(!o){o=1;XRRLOG("stub ovrp_IsRequestingASWData -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_CreateCustomCameraAnchor() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_CreateCustomCameraAnchor -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_DestroyCustomCameraAnchor() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_DestroyCustomCameraAnchor -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrame() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_EncodeMrcFrame -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrameDualTexturesWithPoseTime() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_EncodeMrcFrameDualTexturesWithPoseTime -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrameWithDualTextures() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_EncodeMrcFrameWithDualTextures -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_EncodeMrcFrameWithPoseTime() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_EncodeMrcFrameWithPoseTime -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_EnumerateCameraAnchorHandles() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_EnumerateCameraAnchorHandles -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetCameraAnchorHandle() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetCameraAnchorHandle -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetCameraAnchorName() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetCameraAnchorName -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetCameraAnchorType() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetCameraAnchorType -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetCameraMinMaxDistance() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetCameraMinMaxDistance -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetCurrentCameraAnchorHandle() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetCurrentCameraAnchorHandle -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetCustomCameraAnchorPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetCustomCameraAnchorPose -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetInitialized() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetInitialized -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetMrcActivationMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetMrcActivationMode -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetMrcAudioSampleRate() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetMrcAudioSampleRate -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetMrcFrameImageFlipped() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetMrcFrameImageFlipped -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetMrcFrameInverseAlpha() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetMrcFrameInverseAlpha -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetMrcFrameSize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetMrcFrameSize -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_GetMrcInputVideoBufferType() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_GetMrcInputVideoBufferType -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_Initialize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_Initialize -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_IsMrcActivated() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_IsMrcActivated -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_IsMrcEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_IsMrcEnabled -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetAvailableQueueIndexVulkan() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetAvailableQueueIndexVulkan -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetCameraMinMaxDistance() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetCameraMinMaxDistance -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetCustomCameraAnchorPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetCustomCameraAnchorPose -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetHeadsetControllerPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetHeadsetControllerPose -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetMrcActivationMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetMrcActivationMode -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetMrcAudioSampleRate() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetMrcAudioSampleRate -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetMrcFrameImageFlipped() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetMrcFrameImageFlipped -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetMrcFrameInverseAlpha() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetMrcFrameInverseAlpha -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetMrcFrameSize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetMrcFrameSize -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SetMrcInputVideoBufferType() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SetMrcInputVideoBufferType -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_Shutdown() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_Shutdown -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_SyncMrcFrame() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_SyncMrcFrame -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_Update() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_Update -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Media_UseMrcDebugCamera() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Media_UseMrcDebugCamera -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_OpenCameraDevice() { static int o; if(!o){o=1;XRRLOG("stub ovrp_OpenCameraDevice -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_OverrideExternalCameraFov() { static int o; if(!o){o=1;XRRLOG("stub ovrp_OverrideExternalCameraFov -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_OverrideExternalCameraStaticPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_OverrideExternalCameraStaticPose -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_PreInitialize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_PreInitialize -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_PreInitialize2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_PreInitialize2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_RecenterPose() { static int o; if(!o){o=1;XRRLOG("stub ovrp_RecenterPose -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_RecenterTrackingOrigin() { static int o; if(!o){o=1;XRRLOG("stub ovrp_RecenterTrackingOrigin -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_RecreateEyeTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_RecreateEyeTexture -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ReleaseEyeTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ReleaseEyeTexture -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ResetAppPerfStats() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ResetAppPerfStats -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ResetAppPerfStats2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ResetAppPerfStats2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ResetDefaultExternalCamera() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ResetDefaultExternalCamera -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SendEvent() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SendEvent -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SendEvent2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SendEvent2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetAppAsymmetricFov() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetAppAsymmetricFov -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetAppChromaticCorrection() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetAppChromaticCorrection -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetAppCPUPriority() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetAppCPUPriority -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetAppEngineInfo() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetAppEngineInfo -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetAppIgnoreVrFocus() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetAppIgnoreVrFocus -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetAppMonoscopic() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetAppMonoscopic -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetAppSRGB() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetAppSRGB -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetASWAdaptiveMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetASWAdaptiveMode -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetASWEnable() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetASWEnable -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetBoundaryVisible() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetBoundaryVisible -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetBoundaryVisible2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetBoundaryVisible2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetCameraDeviceDepthSensingMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetCameraDeviceDepthSensingMode -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetCameraDevicePreferredColorFrameSize() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetCameraDevicePreferredColorFrameSize -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetCameraDevicePreferredDepthQuality() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetCameraDevicePreferredDepthQuality -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetCaps() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetCaps -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetColorScaleAndOffset() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetColorScaleAndOffset -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetControllerHaptics() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetControllerHaptics -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetControllerHaptics2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetControllerHaptics2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetControllerVibration() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetControllerVibration -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetDefaultExternalCamera() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetDefaultExternalCamera -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetDepthCompositingInfo() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetDepthCompositingInfo -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetDepthProjInfo() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetDepthProjInfo -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetDesiredEyeTextureFormat() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetDesiredEyeTextureFormat -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetDeveloperMode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetDeveloperMode -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetExternalCameraProperties() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetExternalCameraProperties -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetEyeOcclusionMeshEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetEyeOcclusionMeshEnabled -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetEyeTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetEyeTexture -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetEyeTextureArrayEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetEyeTextureArrayEnabled -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetEyeTextureFlippedY() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetEyeTextureFlippedY -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetEyeTextureScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetEyeTextureScale -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetEyeTextureShared() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetEyeTextureShared -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetEyeViewportScale() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetEyeViewportScale -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetFloat() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetFloat -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetHandNodePoseStateLatency() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetHandNodePoseStateLatency -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetHeadPoseModifier() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetHeadPoseModifier -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetInhibitSystemUX() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetInhibitSystemUX -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetInhibitSystemUX2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetInhibitSystemUX2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetNodePositionTracked() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetNodePositionTracked -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetNodePositionTracked2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetNodePositionTracked2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetOctilinearInfo() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetOctilinearInfo -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetOverlayQuad() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetOverlayQuad -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetOverlayQuad2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetOverlayQuad2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetOverlayQuad3() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetOverlayQuad3 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetRemoteHandedness() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetRemoteHandedness -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetSystemCpuLevel() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetSystemCpuLevel -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetSystemDisplayFrequency() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetSystemDisplayFrequency -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetSystemGpuLevel() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetSystemGpuLevel -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetSystemVSyncCount() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetSystemVSyncCount -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetSystemVSyncCount2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetSystemVSyncCount2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetThreadPerformance() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetThreadPerformance -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingCalibratedOrigin2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingCalibratedOrigin2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingIPDEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingIPDEnabled -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingIPDEnabled2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingIPDEnabled2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingOrientationEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingOrientationEnabled -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingOrientationEnabled2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingOrientationEnabled2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingOriginType() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingOriginType -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingPositionEnabled() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingPositionEnabled -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetTrackingPositionEnabled2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetTrackingPositionEnabled2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupDisplayObjects() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupDisplayObjects -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupDistortionWindow() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupDistortionWindow -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupDistortionWindow2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupDistortionWindow2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupEyeTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupEyeTexture -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupEyeTexture2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupEyeTexture2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupLayerDepth() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupLayerDepth -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupMirrorTexture() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupMirrorTexture -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetupMirrorTexture2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetupMirrorTexture2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetUserEyeDepth() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetUserEyeDepth -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetUserEyeHeight() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetUserEyeHeight -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetUserEyeHeight2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetUserEyeHeight2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetUserIPD() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetUserIPD -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetUserIPD2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetUserIPD2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetUserNeckEyeDistance() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetUserNeckEyeDistance -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetUserNeckEyeDistance2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetUserNeckEyeDistance2 -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetVrApiPropertyFloat() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetVrApiPropertyFloat -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_SetVrApiPropertyInt() { static int o; if(!o){o=1;XRRLOG("stub ovrp_SetVrApiPropertyInt -> ovrpSuccess");} return ovrpSuccess; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ShowSystemUI() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ShowSystemUI -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ShowSystemUI2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ShowSystemUI2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ShowUI() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ShowUI -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Shutdown() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Shutdown -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_ShutdownMixedReality() { static int o; if(!o){o=1;XRRLOG("stub ovrp_ShutdownMixedReality -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_TestBoundaryNode() { static int o; if(!o){o=1;XRRLOG("stub ovrp_TestBoundaryNode -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_TestBoundaryNode2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_TestBoundaryNode2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_TestBoundaryPoint() { static int o; if(!o){o=1;XRRLOG("stub ovrp_TestBoundaryPoint -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_TestBoundaryPoint2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_TestBoundaryPoint2 -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Update() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Update -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_Update2() { static int o; if(!o){o=1;XRRLOG("stub ovrp_Update2 -> ovrpFailure_NotYetImplemented");} return ovrpFailure_NotYetImplemented; }
|
||||
OVRP_EXPORT ovrpResult ovrp_UpdateCameraDevices() { static int o; if(!o){o=1;XRRLOG("stub ovrp_UpdateCameraDevices -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
OVRP_EXPORT ovrpResult ovrp_UpdateExternalCamera() { static int o; if(!o){o=1;XRRLOG("stub ovrp_UpdateExternalCamera -> ovrpFailure_Unsupported");} return ovrpFailure_Unsupported; }
|
||||
|
||||
/* generated: unsup=103 noop=67 todo=202 skipped(core)=66 */
|
||||
@@ -0,0 +1,932 @@
|
||||
/* vk_session.c — Vulkan-typed half of the OpenXR handshake. Uses XR_KHR_vulkan_enable
|
||||
* (v1) because OVRPlugin's model is "the app creates the VkInstance/Device" (handles
|
||||
* arrive via ovrp_Initialize5 args 5-8) and asks us which extensions to enable via
|
||||
* ovrp_GetInstance/DeviceExtensionsVk — that's exactly the v1 get-extensions flow.
|
||||
*/
|
||||
#include <vulkan/vulkan.h>
|
||||
#define XR_USE_GRAPHICS_API_VULKAN
|
||||
#include <openxr/openxr_platform.h>
|
||||
#include "xr_runtime.h"
|
||||
#include "passthru.h"
|
||||
#include "log.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
/* fetch a KHR_vulkan_enable extension entry point by name */
|
||||
static PFN_xrVoidFunction get_xr(const char *name) {
|
||||
PFN_xrVoidFunction fn = NULL;
|
||||
if (g_xr.instance != XR_NULL_HANDLE)
|
||||
xrGetInstanceProcAddr(g_xr.instance, name, &fn);
|
||||
return fn;
|
||||
}
|
||||
|
||||
/* UE's Vulkan handles (from ovrp_Initialize5), used by both the graphics binding
|
||||
* and the end-of-frame flush barrier. */
|
||||
static VkDevice s_dev;
|
||||
static VkQueue s_queue;
|
||||
static uint32_t s_qfam;
|
||||
static VkPhysicalDevice s_phys; /* for memory-type selection (texture readback) */
|
||||
static VkInstance s_inst; /* to load instance-level entry points */
|
||||
|
||||
void xrr_vk_set_handles(void *device, void *queue, unsigned int family) {
|
||||
s_dev = (VkDevice)device; s_queue = (VkQueue)queue; s_qfam = family;
|
||||
}
|
||||
|
||||
/* libvulkan + its proc-addr loaders, opened ONCE. Previously every Vulkan helper dlopen'd
|
||||
* libvulkan.so per call (xrr_vk_frame_luma did it per frame), leaking a dl handle each time.
|
||||
* Returns 1 if vkGetDeviceProcAddr is available; fills gdpa/gipa (either may be NULL-arg). */
|
||||
static void *s_vklib;
|
||||
static PFN_vkGetDeviceProcAddr s_gdpa;
|
||||
static PFN_vkGetInstanceProcAddr s_gipa;
|
||||
static int vk_loaders(PFN_vkGetDeviceProcAddr *gdpa, PFN_vkGetInstanceProcAddr *gipa) {
|
||||
if (!s_vklib) {
|
||||
s_vklib = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||
if (s_vklib) {
|
||||
s_gdpa = (PFN_vkGetDeviceProcAddr)dlsym(s_vklib, "vkGetDeviceProcAddr");
|
||||
s_gipa = (PFN_vkGetInstanceProcAddr)dlsym(s_vklib, "vkGetInstanceProcAddr");
|
||||
}
|
||||
}
|
||||
if (gdpa) *gdpa = s_gdpa;
|
||||
if (gipa) *gipa = s_gipa;
|
||||
return s_gdpa != NULL;
|
||||
}
|
||||
|
||||
/* The OpenXR runtime synchronizes its compositor against the queue named in the
|
||||
* graphics binding. We only have UE's VkQueue handle, so scan (family,index) to
|
||||
* find which one it is — a wrong queueIndex means the runtime waits on an idle
|
||||
* queue and composites before UE finishes -> black unless we hard-wait ourselves. */
|
||||
static PFN_vkGetDeviceQueue load_get_device_queue(VkDevice dev) {
|
||||
PFN_vkGetDeviceProcAddr gdpa; vk_loaders(&gdpa, NULL);
|
||||
return gdpa ? (PFN_vkGetDeviceQueue)gdpa(dev, "vkGetDeviceQueue") : NULL;
|
||||
}
|
||||
static void detect_ue_queue(VkDevice dev, uint32_t *family, uint32_t *index) {
|
||||
*family = 0; *index = 0;
|
||||
if (!s_queue) return;
|
||||
PFN_vkGetDeviceQueue gdq = load_get_device_queue(dev);
|
||||
if (!gdq) { XRRLOG("queue detect: no vkGetDeviceQueue"); return; }
|
||||
for (uint32_t f = 0; f < 4; f++)
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
VkQueue q = VK_NULL_HANDLE;
|
||||
gdq(dev, f, i, &q);
|
||||
if (q == s_queue) {
|
||||
*family = f; *index = i;
|
||||
XRRLOG("queue detect: UE queue is family=%u index=%u", f, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
XRRLOG("queue detect: UE queue not matched, defaulting 0/0");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------- app-side extension queries -- */
|
||||
/* [VERIFIED from real Compositor::GetInstanceExtensionsVk] ABI is:
|
||||
* ovrp_Get*ExtensionsVk(const char** outArray, int* inoutCount)
|
||||
* outArray = caller's array of char*, filled with `count` POINTERS to extension
|
||||
* name strings (memcpy count<<3 bytes); inoutCount IN=capacity(entries), OUT=count;
|
||||
* returns -1007 if capacity<count; NULL outArray = size query. UE iterates the
|
||||
* result as char*[] (my single-buffer version made it deref chars as ptrs ->
|
||||
* strcmp segfault). We split xrGetVulkan*ExtensionsKHR's space list into ptrs. */
|
||||
#define XRR_MAX_EXTS 64
|
||||
static char s_extBuf[2][4096]; /* [0]=instance [1]=device */
|
||||
static const char *s_extPtrs[2][XRR_MAX_EXTS];
|
||||
static int s_extCount[2] = { -1, -1 };
|
||||
|
||||
static int build_ext_list(int forDevice) {
|
||||
if (s_extCount[forDevice] >= 0) return s_extCount[forDevice]; /* cached */
|
||||
const char *fname = forDevice ? "xrGetVulkanDeviceExtensionsKHR"
|
||||
: "xrGetVulkanInstanceExtensionsKHR";
|
||||
union { PFN_xrGetVulkanInstanceExtensionsKHR i;
|
||||
PFN_xrGetVulkanDeviceExtensionsKHR d;
|
||||
PFN_xrVoidFunction v; } fn;
|
||||
fn.v = get_xr(fname);
|
||||
if (!fn.v) return -1;
|
||||
char *buf = s_extBuf[forDevice];
|
||||
uint32_t got = 0;
|
||||
XrResult r = forDevice
|
||||
? fn.d(g_xr.instance, g_xr.systemId, 4096, &got, buf)
|
||||
: fn.i(g_xr.instance, g_xr.systemId, 4096, &got, buf);
|
||||
if (XR_FAILED(r) || got == 0) { XRRERR("%s failed: %d", fname, (int)r); return -1; }
|
||||
buf[got < 4096 ? got : 4095] = '\0';
|
||||
/* split the space-separated string in place into pointers */
|
||||
int n = 0;
|
||||
char *p = buf;
|
||||
while (*p && n < XRR_MAX_EXTS) {
|
||||
s_extPtrs[forDevice][n++] = p;
|
||||
char *sp = p;
|
||||
while (*sp && *sp != ' ') sp++;
|
||||
if (*sp == ' ') { *sp = '\0'; p = sp + 1; } else break;
|
||||
}
|
||||
s_extCount[forDevice] = n;
|
||||
return n;
|
||||
}
|
||||
|
||||
static ovrpResult get_vk_exts(int forDevice, const char **outArray, int *inoutCount) {
|
||||
if (!inoutCount) return ovrpFailure_InvalidParameter;
|
||||
if (g_xr.instance == XR_NULL_HANDLE || g_xr.systemId == XR_NULL_SYSTEM_ID)
|
||||
return ovrpFailure_InvalidOperation;
|
||||
int count = build_ext_list(forDevice);
|
||||
if (count < 0) return ovrpFailure_Unsupported;
|
||||
int cap = *inoutCount;
|
||||
*inoutCount = count; /* always report the count */
|
||||
if (outArray) {
|
||||
if (cap < count) return ovrpFailure_InsufficientSize; /* -1007 */
|
||||
memcpy(outArray, s_extPtrs[forDevice], (size_t)count * sizeof(char *));
|
||||
}
|
||||
return ovrpSuccess;
|
||||
}
|
||||
|
||||
OVRP_EXPORT ovrpResult ovrp_GetInstanceExtensionsVk(const char **outArray, int *inoutCount) {
|
||||
PT_FWD(ovrp_GetInstanceExtensionsVk, outArray, inoutCount); /* real vrapi extensions */
|
||||
ovrpResult res = get_vk_exts(0, outArray, inoutCount);
|
||||
XRRLOG("GetInstanceExtensionsVk -> %d (count=%d, fill=%d)", res,
|
||||
inoutCount ? *inoutCount : -1, outArray != NULL);
|
||||
return res;
|
||||
}
|
||||
OVRP_EXPORT ovrpResult ovrp_GetDeviceExtensionsVk(const char **outArray, int *inoutCount) {
|
||||
PT_FWD(ovrp_GetDeviceExtensionsVk, outArray, inoutCount); /* real vrapi extensions */
|
||||
ovrpResult res = get_vk_exts(1, outArray, inoutCount);
|
||||
XRRLOG("GetDeviceExtensionsVk -> %d (count=%d, fill=%d)", res,
|
||||
inoutCount ? *inoutCount : -1, outArray != NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- session creation -- */
|
||||
int xrr_create_session_vulkan(void *vkInstance, void *vkPhysicalDevice,
|
||||
void *vkDevice, unsigned int queueFamilyIndex) {
|
||||
if (g_xr.instance == XR_NULL_HANDLE || g_xr.systemId == XR_NULL_SYSTEM_ID)
|
||||
return 0;
|
||||
|
||||
/* required before session creation per XR_KHR_vulkan_enable */
|
||||
union { PFN_xrGetVulkanGraphicsRequirementsKHR f; PFN_xrVoidFunction v; } req;
|
||||
req.v = get_xr("xrGetVulkanGraphicsRequirementsKHR");
|
||||
XRRLOG("vk_session: reqProc=%p", (void *)req.v);
|
||||
if (req.f) {
|
||||
XrGraphicsRequirementsVulkanKHR gr = { XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR };
|
||||
XrResult rr = req.f(g_xr.instance, g_xr.systemId, &gr);
|
||||
XRRLOG("vk_session: GraphicsRequirements rc=%d minApi=0x%llx maxApi=0x%llx",
|
||||
(int)rr, (unsigned long long)gr.minApiVersionSupported,
|
||||
(unsigned long long)gr.maxApiVersionSupported);
|
||||
}
|
||||
/* runtime may require we query the graphics device too */
|
||||
union { PFN_xrGetVulkanGraphicsDeviceKHR f; PFN_xrVoidFunction v; } gd;
|
||||
gd.v = get_xr("xrGetVulkanGraphicsDeviceKHR");
|
||||
if (gd.f) {
|
||||
VkPhysicalDevice want = VK_NULL_HANDLE;
|
||||
XrResult dr = gd.f(g_xr.instance, g_xr.systemId, (VkInstance)vkInstance, &want);
|
||||
XRRLOG("vk_session: GraphicsDevice rc=%d want=%p got=%p match=%d", (int)dr,
|
||||
(void *)want, vkPhysicalDevice, want == (VkPhysicalDevice)vkPhysicalDevice);
|
||||
}
|
||||
|
||||
s_phys = (VkPhysicalDevice)vkPhysicalDevice;
|
||||
s_inst = (VkInstance)vkInstance;
|
||||
uint32_t qfam = queueFamilyIndex, qidx = 0;
|
||||
detect_ue_queue((VkDevice)vkDevice, &qfam, &qidx);
|
||||
s_qfam = qfam; /* the flush command pool must use the same family */
|
||||
|
||||
XrGraphicsBindingVulkanKHR binding = { XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR };
|
||||
binding.instance = (VkInstance)vkInstance;
|
||||
binding.physicalDevice = (VkPhysicalDevice)vkPhysicalDevice;
|
||||
binding.device = (VkDevice)vkDevice;
|
||||
binding.queueFamilyIndex = qfam;
|
||||
binding.queueIndex = qidx;
|
||||
XRRLOG("vk_session: binding inst=%p phys=%p dev=%p queue fam=%u idx=%u",
|
||||
vkInstance, vkPhysicalDevice, vkDevice, qfam, qidx);
|
||||
|
||||
XrSessionCreateInfo sci = { XR_TYPE_SESSION_CREATE_INFO };
|
||||
sci.next = &binding;
|
||||
sci.systemId = g_xr.systemId;
|
||||
XrResult r = xrCreateSession(g_xr.instance, &sci, &g_xr.session);
|
||||
if (XR_FAILED(r)) {
|
||||
XRRERR("xrCreateSession(Vulkan) failed: %d", (int)r);
|
||||
g_xr.session = XR_NULL_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
XRRLOG("vk_session: xrCreateSession OK session=%p", (void *)g_xr.session);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Enumerate a swapchain's VkImages, returned as opaque uint64 handles. */
|
||||
/* ---------------------------------------------------- tile-memory flush ----- *
|
||||
* On Quest's tiler GPU, UE renders the eye into tile memory and relies on the
|
||||
* compositor's submit to resolve it to main memory. We hand the image straight to
|
||||
* the OpenXR compositor, so without an explicit barrier the compositor reads stale
|
||||
* main-memory contents -> black / tearing / ghosting. This records+submits a
|
||||
* pipeline barrier (COLOR_ATTACHMENT_WRITE -> MEMORY_READ) to force the resolve.
|
||||
* Submitted on UE's own VkQueue from end_frame (same RHI thread) so there is no
|
||||
* concurrent queue access.
|
||||
*
|
||||
* Split submit/wait: xrr_vk_flush_submit records+submits the barrier and returns a
|
||||
* ring token WITHOUT blocking; xrr_vk_flush_wait(token) blocks on that submit's
|
||||
* fence. The frame loop submits frame N's flush then waits frame N-1's, so the
|
||||
* wait is off the critical path (the GPU finished it during this frame's work) ->
|
||||
* xrEndFrame lands on schedule and the compositor stops reprojecting every frame.
|
||||
* Ring is sized for >=1 full frame of in-flight tokens (every layer submits per
|
||||
* frame, and a token is now waited a frame later). */
|
||||
#define XRR_FLUSH_RING (XRR_MAX_LAYERS * 2)
|
||||
static int s_vkReady, s_vkFailed;
|
||||
static VkCommandPool s_pool;
|
||||
static VkCommandBuffer s_cmd[XRR_FLUSH_RING];
|
||||
static VkFence s_fence[XRR_FLUSH_RING];
|
||||
static int s_ring;
|
||||
static PFN_vkCreateCommandPool p_CreatePool;
|
||||
static PFN_vkAllocateCommandBuffers p_AllocCmd;
|
||||
static PFN_vkBeginCommandBuffer p_BeginCmd;
|
||||
static PFN_vkCmdPipelineBarrier p_Barrier;
|
||||
static PFN_vkEndCommandBuffer p_EndCmd;
|
||||
static PFN_vkQueueSubmit p_Submit;
|
||||
static PFN_vkResetCommandBuffer p_ResetCmd;
|
||||
static PFN_vkCreateFence p_CreateFence;
|
||||
static PFN_vkWaitForFences p_WaitFences;
|
||||
static PFN_vkResetFences p_ResetFences;
|
||||
static PFN_vkGetFenceStatus p_FenceStatus;
|
||||
static PFN_vkQueueWaitIdle p_QueueWaitIdle;
|
||||
static PFN_vkDeviceWaitIdle p_DeviceWaitIdle;
|
||||
|
||||
static int vk_lazy_init(void) {
|
||||
if (s_vkReady) return 1;
|
||||
if (s_vkFailed) return 0;
|
||||
if (!s_dev || !s_queue) return 0;
|
||||
PFN_vkGetDeviceProcAddr gdpa; vk_loaders(&gdpa, NULL);
|
||||
if (!gdpa) { s_vkFailed = 1; XRRERR("vk flush: no vkGetDeviceProcAddr"); return 0; }
|
||||
#define LOAD(p, n) p = (PFN_##n)gdpa(s_dev, #n); if (!p) { s_vkFailed = 1; XRRERR("vk flush: missing " #n); return 0; }
|
||||
LOAD(p_CreatePool, vkCreateCommandPool)
|
||||
LOAD(p_AllocCmd, vkAllocateCommandBuffers)
|
||||
LOAD(p_BeginCmd, vkBeginCommandBuffer)
|
||||
LOAD(p_Barrier, vkCmdPipelineBarrier)
|
||||
LOAD(p_EndCmd, vkEndCommandBuffer)
|
||||
LOAD(p_Submit, vkQueueSubmit)
|
||||
LOAD(p_ResetCmd, vkResetCommandBuffer)
|
||||
LOAD(p_CreateFence, vkCreateFence)
|
||||
LOAD(p_WaitFences, vkWaitForFences)
|
||||
LOAD(p_ResetFences, vkResetFences)
|
||||
LOAD(p_FenceStatus, vkGetFenceStatus)
|
||||
LOAD(p_QueueWaitIdle, vkQueueWaitIdle)
|
||||
LOAD(p_DeviceWaitIdle, vkDeviceWaitIdle)
|
||||
#undef LOAD
|
||||
VkCommandPoolCreateInfo pci = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
|
||||
pci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
pci.queueFamilyIndex = s_qfam;
|
||||
if (p_CreatePool(s_dev, &pci, NULL, &s_pool) != VK_SUCCESS) { s_vkFailed = 1; return 0; }
|
||||
VkCommandBufferAllocateInfo ai = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
|
||||
ai.commandPool = s_pool; ai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
ai.commandBufferCount = XRR_FLUSH_RING;
|
||||
if (p_AllocCmd(s_dev, &ai, s_cmd) != VK_SUCCESS) { s_vkFailed = 1; return 0; }
|
||||
for (int i = 0; i < XRR_FLUSH_RING; i++) {
|
||||
VkFenceCreateInfo fi = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
|
||||
fi.flags = VK_FENCE_CREATE_SIGNALED_BIT; /* first use sees it ready */
|
||||
if (p_CreateFence(s_dev, &fi, NULL, &s_fence[i]) != VK_SUCCESS) { s_vkFailed = 1; return 0; }
|
||||
}
|
||||
s_vkReady = 1;
|
||||
XRRLOG("vk flush: barrier ring ready (qfam=%u)", s_qfam);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Is the barrier ring up (handles bound + entry points loaded)? Lets the frame
|
||||
* loop fall back to a synchronous present until Vulkan is ready, then engage the
|
||||
* pipeline. Idempotent (vk_lazy_init only runs the setup once). */
|
||||
int xrr_vk_flush_ready(void) { return vk_lazy_init(); }
|
||||
|
||||
/* Record + submit the tile-memory flush barrier for `image` WITHOUT waiting.
|
||||
* Returns a ring token to pass to xrr_vk_flush_wait, or -1 if Vulkan isn't ready.
|
||||
* isDepth selects the depth-stencil aspect/layout/access (depth swapchains resolve
|
||||
* the same way but a color barrier on a depth image is invalid). */
|
||||
int xrr_vk_flush_submit_ex(uint64_t image, unsigned int arrayLayers, int isDepth) {
|
||||
if (!vk_lazy_init()) return -1;
|
||||
int idx = s_ring++ % XRR_FLUSH_RING;
|
||||
/* this slot's previous submit must be done before we re-record it (its fence
|
||||
* was already waited at present time a frame ago, so this is ~instant) */
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 100000000 /*100ms*/);
|
||||
p_ResetFences(s_dev, 1, &s_fence[idx]);
|
||||
p_ResetCmd(s_cmd[idx], 0);
|
||||
VkCommandBufferBeginInfo bi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
p_BeginCmd(s_cmd[idx], &bi);
|
||||
VkImageMemoryBarrier b = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
b.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
b.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b.image = (VkImage)(uintptr_t)image;
|
||||
b.subresourceRange.levelCount = 1;
|
||||
b.subresourceRange.layerCount = arrayLayers ? arrayLayers : 1;
|
||||
VkPipelineStageFlags srcStage;
|
||||
if (isDepth) {
|
||||
b.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
b.oldLayout = b.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
} else {
|
||||
b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
b.oldLayout = b.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
}
|
||||
p_Barrier(s_cmd[idx], srcStage,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &b);
|
||||
p_EndCmd(s_cmd[idx]);
|
||||
VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
si.commandBufferCount = 1; si.pCommandBuffers = &s_cmd[idx];
|
||||
if (p_Submit(s_queue, 1, &si, s_fence[idx]) != VK_SUCCESS) return -1;
|
||||
return idx;
|
||||
}
|
||||
/* color-image convenience wrapper (the common case) */
|
||||
int xrr_vk_flush_submit(uint64_t image, unsigned int arrayLayers) {
|
||||
return xrr_vk_flush_submit_ex(image, arrayLayers, 0);
|
||||
}
|
||||
|
||||
/* Block until the flush submitted under `token` has completed. The Meta runtime
|
||||
* does NOT synchronize its compositor against our submit, so the image must be
|
||||
* fully resolved before we release it to the compositor (else it reads
|
||||
* unresolved/invisible writes = black). Called a frame after submit, so the GPU
|
||||
* has already finished -> this returns immediately and never stalls the submit. */
|
||||
void xrr_vk_flush_wait(int token) {
|
||||
if (token < 0 || !s_vkReady) return;
|
||||
p_WaitFences(s_dev, 1, &s_fence[token], VK_TRUE, 100000000);
|
||||
}
|
||||
|
||||
/* Probe (debug.re4vr.qwait): drain UE's VkQueue so any submitted render completes
|
||||
* before we resolve/present. Distinguishes "UE submitted-but-incomplete" (this turns
|
||||
* the black image correct) from "UE hadn't submitted yet" (still black -> ordering
|
||||
* bug). A hard stall; diagnostic only. */
|
||||
void xrr_vk_queue_wait_idle(void) {
|
||||
if (!vk_lazy_init() || !p_QueueWaitIdle || !s_queue) return;
|
||||
p_QueueWaitIdle(s_queue);
|
||||
}
|
||||
|
||||
/* Full GPU completion across ALL queues. UE submits the eye render on its own queue(s)
|
||||
* (two seen: s_queue + a second), so draining s_queue alone misses it. Used at the
|
||||
* deferred present (which already runs AFTER UE's eye submit) to guarantee the render is
|
||||
* COMPLETE before we release+composite — the production form of what the dump's fence-wait
|
||||
* did. Heavier than a targeted fence wait; refine to the eye-render fence once confirmed. */
|
||||
void xrr_vk_device_wait_idle(void) {
|
||||
if (!vk_lazy_init() || !p_DeviceWaitIdle || !s_dev) return;
|
||||
p_DeviceWaitIdle(s_dev);
|
||||
}
|
||||
|
||||
/* ---- UE vkQueueSubmit hook (render-submit race fix) ----------------------- *
|
||||
* RE finding: UE 4.25 submits the eye render through the
|
||||
* FVulkan RHI's global PFN VulkanDynamicAPI::vkQueueSubmit AFTER ovrp_EndFrame4 on the
|
||||
* RHI thread (proven by the qwait no-op). We patch that global to a trampoline so the
|
||||
* shim observes the exact submit and can order present after it (present-on-submit, in
|
||||
* xr_runtime.c). The symbol is an EXPORTED BSS global, so dlsym gives its real runtime
|
||||
* address (robust to load bias) and the slot is writable (no mprotect). Our own resolve
|
||||
* barrier uses p_Submit (a distinct driver pointer), so it never re-enters this hook. */
|
||||
static PFN_vkQueueSubmit s_realQueueSubmit;
|
||||
static void **s_ueSubmitSlot;
|
||||
static int s_hookInstalled;
|
||||
|
||||
static VKAPI_ATTR VkResult VKAPI_CALL ue_submit_trampoline(
|
||||
VkQueue queue, uint32_t count, const VkSubmitInfo *pSubmits, VkFence fence) {
|
||||
VkResult r = s_realQueueSubmit(queue, count, pSubmits, fence); /* real submit first */
|
||||
/* notify after it's on the queue, so a same-queue barrier orders FIFO after it */
|
||||
xrr_on_ue_submit((uint64_t)(uintptr_t)queue, (uint64_t)(uintptr_t)fence, queue == s_queue);
|
||||
return r;
|
||||
}
|
||||
|
||||
int xrr_install_submit_hook(void) {
|
||||
if (s_hookInstalled) return 1;
|
||||
void *h = dlopen("libUE4.so", RTLD_NOLOAD | RTLD_NOW);
|
||||
if (!h) { XRRERR("submithook: libUE4.so not loaded"); return 0; }
|
||||
void **slot = (void **)dlsym(h, "_ZN16VulkanDynamicAPI13vkQueueSubmitE");
|
||||
if (!slot || !*slot) {
|
||||
XRRERR("submithook: global vkQueueSubmit slot=%p val=%p (RHI not up yet?)",
|
||||
(void *)slot, slot ? *slot : NULL);
|
||||
return 0;
|
||||
}
|
||||
/* sanity: the live value must look like a real vkQueueSubmit, not garbage */
|
||||
Dl_info di; const char *snm = "?", *fnm = "?";
|
||||
if (dladdr(*slot, &di)) { if (di.dli_sname) snm = di.dli_sname; if (di.dli_fname) fnm = di.dli_fname; }
|
||||
XRRLOG("submithook: UE vkQueueSubmit slot=%p -> %p (%s in %s)", (void *)slot, *slot, snm, fnm);
|
||||
if (*slot == (void *)&ue_submit_trampoline) { s_hookInstalled = 1; return 1; } /* already ours */
|
||||
s_realQueueSubmit = (PFN_vkQueueSubmit)*slot;
|
||||
s_ueSubmitSlot = slot;
|
||||
*slot = (void *)&ue_submit_trampoline; /* patch the global */
|
||||
s_hookInstalled = 1;
|
||||
XRRLOG("submithook: INSTALLED (real=%p tramp=%p, s_queue=%p)",
|
||||
(void *)s_realQueueSubmit, (void *)&ue_submit_trampoline, (void *)s_queue);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------- one-shot texture readback -- *
|
||||
* Copy one array layer of an eye swapchain image to a host buffer and dump a
|
||||
* downsampled PPM, so we can SEE whether UE's rendered eye texture is itself
|
||||
* doubled (=> game/UE render) or clean (=> the compositor adds the dupe). Slow &
|
||||
* synchronous — gated behind debug.re4vr.dump, fired once. */
|
||||
static PFN_vkGetPhysicalDeviceMemoryProperties p_MemProps;
|
||||
static PFN_vkCreateBuffer p_CreateBuf;
|
||||
static PFN_vkGetBufferMemoryRequirements p_BufReq;
|
||||
static PFN_vkAllocateMemory p_AllocMem;
|
||||
static PFN_vkBindBufferMemory p_BindBuf;
|
||||
static PFN_vkMapMemory p_MapMem;
|
||||
static PFN_vkCmdCopyImageToBuffer p_Copy2Buf;
|
||||
static PFN_vkDestroyBuffer p_DestroyBuf;
|
||||
static PFN_vkFreeMemory p_FreeMem;
|
||||
|
||||
static int dump_lazy(PFN_vkGetDeviceProcAddr gdpa) {
|
||||
#define DL(p,n) if(!p){ p=(PFN_##n)gdpa(s_dev,#n); if(!p){XRRERR("dump: missing " #n); return 0;} }
|
||||
DL(p_CreateBuf, vkCreateBuffer) DL(p_BufReq, vkGetBufferMemoryRequirements)
|
||||
DL(p_AllocMem, vkAllocateMemory) DL(p_BindBuf, vkBindBufferMemory)
|
||||
DL(p_MapMem, vkMapMemory) DL(p_Copy2Buf, vkCmdCopyImageToBuffer)
|
||||
DL(p_DestroyBuf, vkDestroyBuffer) DL(p_FreeMem, vkFreeMemory)
|
||||
#undef DL
|
||||
return 1;
|
||||
}
|
||||
|
||||
void xrr_vk_dump_image(uint64_t image, unsigned int w, unsigned int h,
|
||||
unsigned int arrayLayer, const char *path) {
|
||||
if (!vk_lazy_init() || !s_phys) { XRRERR("dump: not ready"); return; }
|
||||
PFN_vkGetDeviceProcAddr gdpa; PFN_vkGetInstanceProcAddr gipa; vk_loaders(&gdpa, &gipa);
|
||||
if (!gdpa || !dump_lazy(gdpa)) return;
|
||||
if (!p_MemProps) p_MemProps = (gipa && s_inst) ? (PFN_vkGetPhysicalDeviceMemoryProperties)
|
||||
gipa(s_inst, "vkGetPhysicalDeviceMemoryProperties") : NULL;
|
||||
if (!p_MemProps) { XRRERR("dump: no MemProps (inst=%p)", (void*)s_inst); return; }
|
||||
|
||||
VkDeviceSize sz = (VkDeviceSize)w * h * 4;
|
||||
VkBufferCreateInfo bci = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bci.size = sz; bci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VkBuffer buf = VK_NULL_HANDLE;
|
||||
if (p_CreateBuf(s_dev, &bci, NULL, &buf) != VK_SUCCESS) { XRRERR("dump: CreateBuffer"); return; }
|
||||
VkMemoryRequirements mr; p_BufReq(s_dev, buf, &mr);
|
||||
VkPhysicalDeviceMemoryProperties mp; p_MemProps(s_phys, &mp);
|
||||
uint32_t mt = UINT32_MAX;
|
||||
for (uint32_t i = 0; i < mp.memoryTypeCount; i++)
|
||||
if ((mr.memoryTypeBits & (1u<<i)) &&
|
||||
(mp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
|
||||
(mp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { mt = i; break; }
|
||||
if (mt == UINT32_MAX) { XRRERR("dump: no host-visible mem"); p_DestroyBuf(s_dev,buf,NULL); return; }
|
||||
VkMemoryAllocateInfo mai = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
mai.allocationSize = mr.size; mai.memoryTypeIndex = mt;
|
||||
VkDeviceMemory mem = VK_NULL_HANDLE;
|
||||
if (p_AllocMem(s_dev, &mai, NULL, &mem) != VK_SUCCESS) { XRRERR("dump: AllocMem"); p_DestroyBuf(s_dev,buf,NULL); return; }
|
||||
p_BindBuf(s_dev, buf, mem, 0);
|
||||
|
||||
int idx = s_ring++ % XRR_FLUSH_RING;
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 100000000);
|
||||
p_ResetFences(s_dev, 1, &s_fence[idx]);
|
||||
p_ResetCmd(s_cmd[idx], 0);
|
||||
VkCommandBufferBeginInfo cbi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
cbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
p_BeginCmd(s_cmd[idx], &cbi);
|
||||
VkImageMemoryBarrier b = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
b.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b.image = (VkImage)(uintptr_t)image;
|
||||
b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
b.subresourceRange.levelCount = 1; b.subresourceRange.baseArrayLayer = arrayLayer;
|
||||
b.subresourceRange.layerCount = 1;
|
||||
p_Barrier(s_cmd[idx], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &b);
|
||||
VkBufferImageCopy rgn; memset(&rgn, 0, sizeof(rgn));
|
||||
rgn.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
rgn.imageSubresource.mipLevel = 0;
|
||||
rgn.imageSubresource.baseArrayLayer = arrayLayer;
|
||||
rgn.imageSubresource.layerCount = 1;
|
||||
rgn.imageExtent.width = w; rgn.imageExtent.height = h; rgn.imageExtent.depth = 1;
|
||||
p_Copy2Buf(s_cmd[idx], (VkImage)(uintptr_t)image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buf, 1, &rgn);
|
||||
/* restore layout so the compositor/UE is unaffected */
|
||||
b.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
p_Barrier(s_cmd[idx], VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &b);
|
||||
p_EndCmd(s_cmd[idx]);
|
||||
VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
si.commandBufferCount = 1; si.pCommandBuffers = &s_cmd[idx];
|
||||
if (p_Submit(s_queue, 1, &si, s_fence[idx]) != VK_SUCCESS) { XRRERR("dump: submit"); goto cleanup; }
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 1000000000);
|
||||
|
||||
{ /* downsample to <=256 wide PPM (P6). Format is RGBA8; take RGB. */
|
||||
uint8_t *px = NULL;
|
||||
if (p_MapMem(s_dev, mem, 0, sz, 0, (void**)&px) != VK_SUCCESS || !px) { XRRERR("dump: map"); goto cleanup; }
|
||||
unsigned step = (w > 256) ? (w / 256) : 1;
|
||||
unsigned ow = w / step, oh = h / step;
|
||||
FILE *f = fopen(path, "wb");
|
||||
if (!f) { XRRERR("dump: fopen %s failed (errno path?)", path); goto cleanup; }
|
||||
fprintf(f, "P6\n%u %u\n255\n", ow, oh);
|
||||
for (unsigned y = 0; y < oh; y++)
|
||||
for (unsigned x = 0; x < ow; x++) {
|
||||
uint8_t *p = px + ((size_t)(y*step)*w + (x*step)) * 4;
|
||||
fwrite(p, 1, 3, f);
|
||||
}
|
||||
fclose(f);
|
||||
XRRLOG("dump: wrote %s (%ux%u from %ux%u layer=%u)", path, ow, oh, w, h, arrayLayer);
|
||||
}
|
||||
cleanup:
|
||||
p_FreeMem(s_dev, mem, NULL);
|
||||
p_DestroyBuf(s_dev, buf, NULL);
|
||||
}
|
||||
|
||||
/* ---- frame-counter barcode overlay (debug.re4vr.barcode) -------------------
|
||||
* Stamp a black/white binary barcode of `value` (the frameIndex we already log) into
|
||||
* the top-left of the eye image AFTER UE's render is resolved, so it appears on EVERY
|
||||
* frame including truncated/black ones. Lets a Meta Cast recording be aligned
|
||||
* frame-exactly to the FRAME/SKIPBLACK logs: read the bits on a black flash -> frameIndex
|
||||
* -> grep the log. Black/white survives cast-video compression; subtle color encoding
|
||||
* does not. Validation-only; gated off by default. A persistent host-visible staging
|
||||
* buffer is filled on the CPU each frame and copied in (no per-frame alloc). */
|
||||
#define BC_BITS 16 /* frameIndex low 16 bits (~15 min @72Hz before wrap) */
|
||||
#define BC_CELLS (BC_BITS + 1) /* +1 leading anchor cell (always white = strip locator) */
|
||||
#define BC_CELL_W 24
|
||||
#define BC_CELL_H 28
|
||||
#define BC_GUTTER 2 /* black gap framing each cell so bits never merge */
|
||||
#define BC_W (BC_CELLS * BC_CELL_W)
|
||||
#define BC_H (BC_CELL_H + 2 * BC_GUTTER)
|
||||
|
||||
static PFN_vkCmdCopyBufferToImage p_Copy2Img;
|
||||
static VkBuffer s_bcBuf;
|
||||
static VkDeviceMemory s_bcMem;
|
||||
static uint8_t *s_bcPx; /* persistent mapping of the staging buffer */
|
||||
|
||||
/* lazily create + map the persistent staging buffer and load the copy PFN. */
|
||||
static int barcode_lazy(PFN_vkGetDeviceProcAddr gdpa) {
|
||||
#define BL(p,n) if(!p){ p=(PFN_##n)gdpa(s_dev,#n); if(!p){XRRERR("barcode: missing " #n); return 0;} }
|
||||
BL(p_CreateBuf, vkCreateBuffer) BL(p_BufReq, vkGetBufferMemoryRequirements)
|
||||
BL(p_AllocMem, vkAllocateMemory) BL(p_BindBuf, vkBindBufferMemory)
|
||||
BL(p_MapMem, vkMapMemory) BL(p_Copy2Img, vkCmdCopyBufferToImage)
|
||||
#undef BL
|
||||
if (s_bcBuf) return 1;
|
||||
VkDeviceSize sz = (VkDeviceSize)BC_W * BC_H * 4;
|
||||
VkBufferCreateInfo bci = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bci.size = sz; bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
if (p_CreateBuf(s_dev, &bci, NULL, &s_bcBuf) != VK_SUCCESS) { XRRERR("barcode: CreateBuffer"); return 0; }
|
||||
VkMemoryRequirements mr; p_BufReq(s_dev, s_bcBuf, &mr);
|
||||
VkPhysicalDeviceMemoryProperties mp; p_MemProps(s_phys, &mp);
|
||||
uint32_t mt = UINT32_MAX;
|
||||
for (uint32_t i = 0; i < mp.memoryTypeCount; i++)
|
||||
if ((mr.memoryTypeBits & (1u<<i)) &&
|
||||
(mp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
|
||||
(mp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { mt = i; break; }
|
||||
if (mt == UINT32_MAX) { XRRERR("barcode: no host-visible mem"); return 0; }
|
||||
VkMemoryAllocateInfo mai = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
mai.allocationSize = mr.size; mai.memoryTypeIndex = mt;
|
||||
if (p_AllocMem(s_dev, &mai, NULL, &s_bcMem) != VK_SUCCESS) { XRRERR("barcode: AllocMem"); return 0; }
|
||||
p_BindBuf(s_dev, s_bcBuf, s_bcMem, 0);
|
||||
if (p_MapMem(s_dev, s_bcMem, 0, sz, 0, (void**)&s_bcPx) != VK_SUCCESS || !s_bcPx) {
|
||||
XRRERR("barcode: map"); s_bcPx = NULL; return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ---- cheap per-frame black detector (debug.re4vr.lumagate) -----------------
|
||||
* Sample a few full-width rows of the ALREADY-RESOLVED eye image and return the max
|
||||
* luminance (0..255). A truncated/black frame reads ~0 across all rows; any lit scene has
|
||||
* bright pixels somewhere on a sampled row -> high max. Unlike the onset-only post-hitch
|
||||
* flag, this is PER-FRAME so it covers the whole sustained-black tail. The dump's
|
||||
* observer-effect concern doesn't apply: the sync path already flush_waits the resolve, and
|
||||
* the black is real content (UE renders empty) — we just read what's there. Call AFTER the
|
||||
* resolve wait and BEFORE the barcode stamp (so the strip's white cells don't pollute it). */
|
||||
#define LUMA_ROWS 5
|
||||
static VkBuffer s_luBuf;
|
||||
static VkDeviceMemory s_luMem;
|
||||
static uint8_t *s_luPx;
|
||||
static unsigned s_luCap; /* bytes allocated */
|
||||
|
||||
int xrr_vk_frame_luma(uint64_t image, unsigned int w, unsigned int h, unsigned int arrayLayer) {
|
||||
if (!vk_lazy_init() || !s_phys) return -1;
|
||||
PFN_vkGetDeviceProcAddr gdpa; PFN_vkGetInstanceProcAddr gipa; vk_loaders(&gdpa, &gipa);
|
||||
if (!gdpa || !dump_lazy(gdpa)) return -1; /* dump_lazy loads CreateBuf/Copy2Buf/Map/etc */
|
||||
if (!p_MemProps) p_MemProps = (gipa && s_inst) ? (PFN_vkGetPhysicalDeviceMemoryProperties)
|
||||
gipa(s_inst, "vkGetPhysicalDeviceMemoryProperties") : NULL;
|
||||
if (!p_MemProps) return -1;
|
||||
|
||||
unsigned need = LUMA_ROWS * w * 4;
|
||||
if (!s_luBuf || need > s_luCap) {
|
||||
if (s_luBuf) { p_DestroyBuf(s_dev, s_luBuf, NULL); p_FreeMem(s_dev, s_luMem, NULL); s_luBuf = VK_NULL_HANDLE; s_luPx = NULL; }
|
||||
VkBufferCreateInfo bci = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
|
||||
bci.size = need; bci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
if (p_CreateBuf(s_dev, &bci, NULL, &s_luBuf) != VK_SUCCESS) { XRRERR("luma: CreateBuffer"); return -1; }
|
||||
VkMemoryRequirements mr; p_BufReq(s_dev, s_luBuf, &mr);
|
||||
VkPhysicalDeviceMemoryProperties mp; p_MemProps(s_phys, &mp);
|
||||
uint32_t mt = UINT32_MAX;
|
||||
for (uint32_t i = 0; i < mp.memoryTypeCount; i++)
|
||||
if ((mr.memoryTypeBits & (1u<<i)) &&
|
||||
(mp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
|
||||
(mp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { mt = i; break; }
|
||||
if (mt == UINT32_MAX) { XRRERR("luma: no host-visible mem"); return -1; }
|
||||
VkMemoryAllocateInfo mai = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
mai.allocationSize = mr.size; mai.memoryTypeIndex = mt;
|
||||
if (p_AllocMem(s_dev, &mai, NULL, &s_luMem) != VK_SUCCESS) { XRRERR("luma: AllocMem"); return -1; }
|
||||
p_BindBuf(s_dev, s_luBuf, s_luMem, 0);
|
||||
if (p_MapMem(s_dev, s_luMem, 0, need, 0, (void**)&s_luPx) != VK_SUCCESS || !s_luPx) { XRRERR("luma: map"); s_luPx = NULL; return -1; }
|
||||
s_luCap = need;
|
||||
}
|
||||
|
||||
int idx = s_ring++ % XRR_FLUSH_RING;
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 100000000);
|
||||
p_ResetFences(s_dev, 1, &s_fence[idx]);
|
||||
p_ResetCmd(s_cmd[idx], 0);
|
||||
VkCommandBufferBeginInfo cbi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
cbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
p_BeginCmd(s_cmd[idx], &cbi);
|
||||
VkImageMemoryBarrier b = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; b.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b.image = (VkImage)(uintptr_t)image; b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
b.subresourceRange.levelCount = 1; b.subresourceRange.baseArrayLayer = arrayLayer; b.subresourceRange.layerCount = 1;
|
||||
p_Barrier(s_cmd[idx], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,0,NULL,0,NULL,1,&b);
|
||||
/* sample LUMA_ROWS rows spread down the frame (skip y~0.30h where the barcode sits). */
|
||||
VkBufferImageCopy rgn[LUMA_ROWS]; memset(rgn, 0, sizeof(rgn));
|
||||
const float fy[LUMA_ROWS] = { 0.15f, 0.40f, 0.55f, 0.70f, 0.85f };
|
||||
for (int i = 0; i < LUMA_ROWS; i++) {
|
||||
rgn[i].bufferOffset = (VkDeviceSize)i * w * 4;
|
||||
rgn[i].bufferRowLength = w; rgn[i].bufferImageHeight = 1;
|
||||
rgn[i].imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
rgn[i].imageSubresource.baseArrayLayer = arrayLayer; rgn[i].imageSubresource.layerCount = 1;
|
||||
rgn[i].imageOffset.y = (int)(h * fy[i]);
|
||||
rgn[i].imageExtent.width = w; rgn[i].imageExtent.height = 1; rgn[i].imageExtent.depth = 1;
|
||||
}
|
||||
p_Copy2Buf(s_cmd[idx], (VkImage)(uintptr_t)image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, s_luBuf, LUMA_ROWS, rgn);
|
||||
b.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
p_Barrier(s_cmd[idx], VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,0,NULL,0,NULL,1,&b);
|
||||
p_EndCmd(s_cmd[idx]);
|
||||
VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
si.commandBufferCount = 1; si.pCommandBuffers = &s_cmd[idx];
|
||||
if (p_Submit(s_queue, 1, &si, s_fence[idx]) != VK_SUCCESS) { XRRERR("luma: submit"); return -1; }
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 100000000);
|
||||
/* max luminance over the sampled pixels (RGBA8; max channel is enough for "any light"). */
|
||||
int mx = 0; unsigned npx = LUMA_ROWS * w;
|
||||
for (unsigned i = 0; i < npx; i++) {
|
||||
uint8_t *p = s_luPx + (size_t)i * 4;
|
||||
int m = p[0]; if (p[1] > m) m = p[1]; if (p[2] > m) m = p[2];
|
||||
if (m > mx) mx = m;
|
||||
}
|
||||
return mx;
|
||||
}
|
||||
|
||||
void xrr_vk_stamp_barcode(uint64_t image, unsigned int w, unsigned int h,
|
||||
unsigned int arrayLayer, unsigned int value, int flagged) {
|
||||
if (!vk_lazy_init() || !s_phys) return;
|
||||
PFN_vkGetDeviceProcAddr gdpa; PFN_vkGetInstanceProcAddr gipa; vk_loaders(&gdpa, &gipa);
|
||||
if (!gdpa) return;
|
||||
if (!p_MemProps) p_MemProps = (gipa && s_inst) ? (PFN_vkGetPhysicalDeviceMemoryProperties)
|
||||
gipa(s_inst, "vkGetPhysicalDeviceMemoryProperties") : NULL;
|
||||
if (!p_MemProps) { XRRERR("barcode: no MemProps"); return; }
|
||||
if (!barcode_lazy(gdpa) || !s_bcPx) return;
|
||||
|
||||
/* paint the strip on the CPU as a GRAY ruler (so all 17 cell positions stay visible on
|
||||
* ANY frame background, incl. pure black) with each cell BLACK(0) or WHITE(1) on top,
|
||||
* gray gutters framing them. anchor cell c=0 = always white (strip locator); cells 1..16
|
||||
* = bits of `value`, LSB at cell 1. Three levels (black/gray/white) survive cast-video
|
||||
* compression. RGBA8 — these grays are channel-equal so RGBA/BGRA/sRGB don't matter. */
|
||||
const uint32_t BLACK = 0xFF000000u, WHITE = 0xFFFFFFFFu, GRAY = 0xFF808080u;
|
||||
/* RED when this frame is a flagged LIKELY-TRUNCATED candidate, else gray. (If the
|
||||
* swapchain is BGRA the red reads as blue — still clearly != gray, so the flag is
|
||||
* unambiguous either way.) Lets the recording show flag-vs-black by eye. */
|
||||
const uint32_t REDBG = 0xFF0000FFu;
|
||||
uint32_t bg = flagged ? REDBG : GRAY;
|
||||
uint32_t *px = (uint32_t*)s_bcPx;
|
||||
for (unsigned i = 0; i < (unsigned)(BC_W * BC_H); i++) px[i] = bg;
|
||||
for (unsigned c = 0; c < BC_CELLS; c++) {
|
||||
int on = (c == 0) ? 1 : (int)((value >> (c - 1)) & 1u);
|
||||
uint32_t col = on ? WHITE : BLACK;
|
||||
unsigned x0 = c * BC_CELL_W + BC_GUTTER, x1 = (c + 1) * BC_CELL_W - BC_GUTTER;
|
||||
for (unsigned y = BC_GUTTER; y < BC_GUTTER + BC_CELL_H; y++)
|
||||
for (unsigned x = x0; x < x1; x++) px[y * BC_W + x] = col;
|
||||
}
|
||||
|
||||
int idx = s_ring++ % XRR_FLUSH_RING;
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 100000000);
|
||||
p_ResetFences(s_dev, 1, &s_fence[idx]);
|
||||
p_ResetCmd(s_cmd[idx], 0);
|
||||
VkCommandBufferBeginInfo cbi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
cbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
p_BeginCmd(s_cmd[idx], &cbi);
|
||||
/* eye color images live in COLOR_ATTACHMENT_OPTIMAL here (same assumption as the
|
||||
* resolve path); flip the layer to TRANSFER_DST, copy the strip, flip back. */
|
||||
VkImageMemoryBarrier b = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b.image = (VkImage)(uintptr_t)image;
|
||||
b.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
b.subresourceRange.levelCount = 1; b.subresourceRange.baseArrayLayer = arrayLayer;
|
||||
b.subresourceRange.layerCount = 1;
|
||||
p_Barrier(s_cmd[idx], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &b);
|
||||
VkBufferImageCopy rgn; memset(&rgn, 0, sizeof(rgn));
|
||||
rgn.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
rgn.imageSubresource.mipLevel = 0;
|
||||
rgn.imageSubresource.baseArrayLayer = arrayLayer;
|
||||
rgn.imageSubresource.layerCount = 1;
|
||||
/* upper-center: the Meta Cast crops the eye render to 16:9 (top/bottom letterboxed
|
||||
* off), and the extreme FOV corner is unviewable in-headset — so (0,0) is invisible.
|
||||
* Center horizontally; place ~30% down, inside the cast's visible band. */
|
||||
rgn.imageOffset.x = (w > BC_W) ? (int)((w - BC_W) / 2) : 0;
|
||||
rgn.imageOffset.y = (h > BC_H) ? (int)(h * 30 / 100) : 0;
|
||||
rgn.imageExtent.width = BC_W; rgn.imageExtent.height = BC_H; rgn.imageExtent.depth = 1;
|
||||
p_Copy2Img(s_cmd[idx], s_bcBuf, (VkImage)(uintptr_t)image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &rgn);
|
||||
b.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
b.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
p_Barrier(s_cmd[idx], VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &b);
|
||||
p_EndCmd(s_cmd[idx]);
|
||||
VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
si.commandBufferCount = 1; si.pCommandBuffers = &s_cmd[idx];
|
||||
if (p_Submit(s_queue, 1, &si, s_fence[idx]) != VK_SUCCESS) { XRRERR("barcode: submit"); return; }
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 100000000); /* tiny copy; done before release */
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- shim-owned copy ring ----- *
|
||||
* UE renders into these shim images (handed to it via GetLayerTexture2) on its own
|
||||
* stage cadence; each frame we copy shimImages[TextureStage] into the freshly
|
||||
* acquired OpenXR image. The copy both resolves tile memory AND lets the frame loop
|
||||
* pipeline it (wait the PREVIOUS frame's copy, already done) so the CPU never blocks
|
||||
* on the current frame's GPU -> breaks the flush-wait serialization. Decoupled from
|
||||
* UE's stage so no stage-coupling break. Gated by debug.re4vr.copyring (off default). */
|
||||
static PFN_vkCreateImage p_CreateImage;
|
||||
static PFN_vkGetImageMemoryRequirements p_ImgReq;
|
||||
static PFN_vkBindImageMemory p_BindImg;
|
||||
static PFN_vkDestroyImage p_DestroyImage;
|
||||
static PFN_vkCmdCopyImage p_CopyImg;
|
||||
|
||||
static int copyring_lazy(PFN_vkGetDeviceProcAddr gdpa) {
|
||||
#define CL(p,n) if(!p){ p=(PFN_##n)gdpa(s_dev,#n); if(!p){XRRERR("copyring: missing " #n); return 0;} }
|
||||
CL(p_CreateImage, vkCreateImage) CL(p_ImgReq, vkGetImageMemoryRequirements)
|
||||
CL(p_BindImg, vkBindImageMemory) CL(p_DestroyImage, vkDestroyImage)
|
||||
CL(p_CopyImg, vkCmdCopyImage)
|
||||
/* memory PFNs reused from dump path */
|
||||
CL(p_AllocMem, vkAllocateMemory) CL(p_FreeMem, vkFreeMemory)
|
||||
#undef CL
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Allocate `count` device-local color images (matching the OpenXR eye swapchain) for
|
||||
* UE to render into. Returns image handles in out[], backing memory in outMem[]. */
|
||||
int xrr_vk_alloc_images_ex(uint64_t *out, uint64_t *outMem, int count,
|
||||
unsigned int w, unsigned int h, unsigned int arraySize,
|
||||
long long vkFormat, int isDepth) {
|
||||
if (!vk_lazy_init() || !s_phys) { XRRERR("copyring: vk not ready"); return 0; }
|
||||
PFN_vkGetDeviceProcAddr gdpa; PFN_vkGetInstanceProcAddr gipa; vk_loaders(&gdpa, &gipa);
|
||||
if (!gdpa || !copyring_lazy(gdpa)) return 0;
|
||||
if (!p_MemProps) p_MemProps = (gipa && s_inst) ? (PFN_vkGetPhysicalDeviceMemoryProperties)
|
||||
gipa(s_inst, "vkGetPhysicalDeviceMemoryProperties") : NULL;
|
||||
if (!p_MemProps) { XRRERR("copyring: no MemProps"); return 0; }
|
||||
VkPhysicalDeviceMemoryProperties mp; p_MemProps(s_phys, &mp);
|
||||
for (int i = 0; i < count; i++) {
|
||||
VkImageCreateInfo ici = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
|
||||
/* MUTABLE_FORMAT: UE renders the eye target through a linear (UNORM) image view
|
||||
* but samples/displays it as sRGB — that needs format-mutable views, which
|
||||
* OpenXR runtimes put on their swapchain images. Without it UE's gameplay
|
||||
* render path (linear view) fails -> black, while the title path works. */
|
||||
ici.flags = isDepth ? 0 : VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
ici.imageType = VK_IMAGE_TYPE_2D;
|
||||
ici.format = (VkFormat)vkFormat;
|
||||
ici.extent.width = w; ici.extent.height = h; ici.extent.depth = 1;
|
||||
ici.mipLevels = 1; ici.arrayLayers = arraySize ? arraySize : 1;
|
||||
ici.samples = VK_SAMPLE_COUNT_1_BIT; ici.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
/* Match the broad usage Meta gives its own swapchain images — UE's mobile
|
||||
* gameplay path uses the eye target as an INPUT_ATTACHMENT (subpass resolve)
|
||||
* and may clear it via transfer; a narrow usage makes gameplay render black
|
||||
* while the simpler title path still works. Depth hold-images (Lever C) use the
|
||||
* depth-stencil attachment usage instead so the layout transitions are valid. */
|
||||
ici.usage = isDepth
|
||||
? (VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)
|
||||
: (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
ici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VkImage img = VK_NULL_HANDLE;
|
||||
if (p_CreateImage(s_dev, &ici, NULL, &img) != VK_SUCCESS) { XRRERR("copyring: CreateImage %d", i); return 0; }
|
||||
VkMemoryRequirements mr; p_ImgReq(s_dev, img, &mr);
|
||||
uint32_t mt = UINT32_MAX;
|
||||
for (uint32_t k = 0; k < mp.memoryTypeCount; k++)
|
||||
if ((mr.memoryTypeBits & (1u<<k)) &&
|
||||
(mp.memoryTypes[k].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { mt = k; break; }
|
||||
if (mt == UINT32_MAX) { XRRERR("copyring: no device-local mem"); p_DestroyImage(s_dev,img,NULL); return 0; }
|
||||
VkMemoryAllocateInfo mai = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
|
||||
mai.allocationSize = mr.size; mai.memoryTypeIndex = mt;
|
||||
VkDeviceMemory mem = VK_NULL_HANDLE;
|
||||
if (p_AllocMem(s_dev, &mai, NULL, &mem) != VK_SUCCESS) { XRRERR("copyring: AllocMem %d", i); p_DestroyImage(s_dev,img,NULL); return 0; }
|
||||
p_BindImg(s_dev, img, mem, 0);
|
||||
out[i] = (uint64_t)(uintptr_t)img;
|
||||
outMem[i] = (uint64_t)(uintptr_t)mem;
|
||||
}
|
||||
XRRLOG("copyring: allocated %d shim images %ux%u array=%u fmt=%lld depth=%d", count, w, h, arraySize, vkFormat, isDepth);
|
||||
return 1;
|
||||
}
|
||||
/* color-image convenience wrapper (the common case) */
|
||||
int xrr_vk_alloc_images(uint64_t *out, uint64_t *outMem, int count,
|
||||
unsigned int w, unsigned int h, unsigned int arraySize,
|
||||
long long vkFormat) {
|
||||
return xrr_vk_alloc_images_ex(out, outMem, count, w, h, arraySize, vkFormat, 0);
|
||||
}
|
||||
|
||||
void xrr_vk_free_images(uint64_t *imgs, uint64_t *mem, int count) {
|
||||
if (!s_vkReady || !p_DestroyImage) return;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (imgs[i]) p_DestroyImage(s_dev, (VkImage)(uintptr_t)imgs[i], NULL);
|
||||
if (mem[i]) p_FreeMem(s_dev, (VkDeviceMemory)(uintptr_t)mem[i], NULL);
|
||||
imgs[i] = mem[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy image src -> dst (all array layers), resolving tile memory, WITHOUT waiting.
|
||||
* Returns a ring token for xrr_vk_flush_wait. Used bidirectionally (swapchain<->shim hold
|
||||
* image) for reproject save/restore. isDepth selects the depth aspect + depth-stencil
|
||||
* attachment layouts (Lever C depth-hold); both endpoints rest in *_ATTACHMENT_OPTIMAL so
|
||||
* the same barriers work either direction (dst content is discarded via UNDEFINED). */
|
||||
int xrr_vk_copy_submit_ex(uint64_t srcShim, uint64_t dstXr,
|
||||
unsigned int w, unsigned int h, unsigned int arrayLayers, int isDepth) {
|
||||
if (!vk_lazy_init() || !p_CopyImg) return -1;
|
||||
int idx = s_ring++ % XRR_FLUSH_RING;
|
||||
p_WaitFences(s_dev, 1, &s_fence[idx], VK_TRUE, 100000000);
|
||||
p_ResetFences(s_dev, 1, &s_fence[idx]);
|
||||
p_ResetCmd(s_cmd[idx], 0);
|
||||
VkCommandBufferBeginInfo bi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
|
||||
bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
p_BeginCmd(s_cmd[idx], &bi);
|
||||
uint32_t layers = arrayLayers ? arrayLayers : 1;
|
||||
VkImage src = (VkImage)(uintptr_t)srcShim, dst = (VkImage)(uintptr_t)dstXr;
|
||||
VkImageAspectFlags aspect = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
VkImageLayout attachLayout = isDepth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
VkAccessFlags attachWrite = isDepth ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||
: VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
VkPipelineStageFlags attachStage = isDepth
|
||||
? (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)
|
||||
: VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
VkImageMemoryBarrier b[2]; memset(b, 0, sizeof(b));
|
||||
for (int i = 0; i < 2; i++) {
|
||||
b[i].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
b[i].srcQueueFamilyIndex = b[i].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
b[i].subresourceRange.aspectMask = aspect;
|
||||
b[i].subresourceRange.levelCount = 1;
|
||||
b[i].subresourceRange.layerCount = layers;
|
||||
}
|
||||
/* src: *_ATTACHMENT -> TRANSFER_SRC ; dst: UNDEFINED -> TRANSFER_DST */
|
||||
b[0].srcAccessMask = attachWrite; b[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
b[0].oldLayout = attachLayout; b[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
b[0].image = src;
|
||||
b[1].srcAccessMask = 0; b[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
b[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; b[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||
b[1].image = dst;
|
||||
p_Barrier(s_cmd[idx], attachStage | VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, b);
|
||||
VkImageCopy rgn; memset(&rgn, 0, sizeof(rgn));
|
||||
rgn.srcSubresource.aspectMask = aspect; rgn.srcSubresource.layerCount = layers;
|
||||
rgn.dstSubresource.aspectMask = aspect; rgn.dstSubresource.layerCount = layers;
|
||||
rgn.extent.width = w; rgn.extent.height = h; rgn.extent.depth = 1;
|
||||
p_CopyImg(s_cmd[idx], src, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &rgn);
|
||||
/* dst: TRANSFER_DST -> *_ATTACHMENT (compositor/UE reads) ; src: TRANSFER_SRC -> *_ATTACHMENT (reuse) */
|
||||
b[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; b[0].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
b[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b[0].newLayout = attachLayout;
|
||||
b[0].image = dst;
|
||||
b[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; b[1].dstAccessMask = attachWrite;
|
||||
b[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; b[1].newLayout = attachLayout;
|
||||
b[1].image = src;
|
||||
p_Barrier(s_cmd[idx], VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
attachStage | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||
0, 0, NULL, 0, NULL, 2, b);
|
||||
p_EndCmd(s_cmd[idx]);
|
||||
VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
|
||||
si.commandBufferCount = 1; si.pCommandBuffers = &s_cmd[idx];
|
||||
if (p_Submit(s_queue, 1, &si, s_fence[idx]) != VK_SUCCESS) return -1;
|
||||
return idx;
|
||||
}
|
||||
/* color-image convenience wrapper (the common case) */
|
||||
int xrr_vk_copy_submit(uint64_t srcShim, uint64_t dstXr,
|
||||
unsigned int w, unsigned int h, unsigned int arrayLayers) {
|
||||
return xrr_vk_copy_submit_ex(srcShim, dstXr, w, h, arrayLayers, 0);
|
||||
}
|
||||
|
||||
uint32_t xrr_vk_enumerate_images(XrSwapchain sc, uint64_t *out, uint32_t max) {
|
||||
uint32_t n = 0;
|
||||
if (xrEnumerateSwapchainImages(sc, 0, &n, NULL) != XR_SUCCESS) return 0;
|
||||
if (n > max) n = max;
|
||||
XrSwapchainImageVulkanKHR imgs[XRR_MAX_IMAGES];
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
imgs[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
|
||||
imgs[i].next = NULL;
|
||||
}
|
||||
uint32_t got = 0;
|
||||
if (xrEnumerateSwapchainImages(sc, n, &got,
|
||||
(XrSwapchainImageBaseHeader *)imgs) != XR_SUCCESS)
|
||||
return 0;
|
||||
for (uint32_t i = 0; i < got; i++)
|
||||
out[i] = (uint64_t)(uintptr_t)imgs[i].image;
|
||||
return got;
|
||||
}
|
||||
|
||||
/* Reset shim Vulkan state so a post-Shutdown2 re-init (new VkDevice from a fresh ovrp_Initialize5)
|
||||
* rebuilds the command pool/fences/staging buffers instead of reusing handles from the dead device.
|
||||
* Called from xrr_shutdown under g_xrlock. Objects from the old device are left to the driver/process
|
||||
* to reclaim — destroying them needs PFNs we don't load, and Shutdown2 is normally process-exit. */
|
||||
void xrr_vk_teardown(void) {
|
||||
s_vkReady = 0; s_vkFailed = 0;
|
||||
s_pool = VK_NULL_HANDLE;
|
||||
for (int i = 0; i < XRR_FLUSH_RING; i++) { s_cmd[i] = VK_NULL_HANDLE; s_fence[i] = VK_NULL_HANDLE; }
|
||||
s_bcBuf = VK_NULL_HANDLE; s_bcMem = VK_NULL_HANDLE; s_bcPx = NULL;
|
||||
s_luBuf = VK_NULL_HANDLE; s_luMem = VK_NULL_HANDLE; s_luPx = NULL; s_luCap = 0;
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/* xr_input.c — OpenXR action-based input mapped to ovrpControllerState4 + hand poses.
|
||||
* Bindings target /interaction_profiles/oculus/touch_controller. ovrpButton bitmask
|
||||
* values are [VERIFIED from OVR_Plugin_Types.h]. */
|
||||
#include "xr_runtime.h"
|
||||
#include "log.h"
|
||||
#include <string.h>
|
||||
|
||||
/* ovrpButton bits */
|
||||
#define OVRP_BTN_A 0x00000001
|
||||
#define OVRP_BTN_B 0x00000002
|
||||
#define OVRP_BTN_X 0x00000100
|
||||
#define OVRP_BTN_Y 0x00000200
|
||||
#define OVRP_BTN_START 0x00100000 /* left menu */
|
||||
#define OVRP_BTN_LTHUMB 0x00000400
|
||||
#define OVRP_BTN_RTHUMB 0x00000004
|
||||
|
||||
static XrActionSet s_set;
|
||||
static XrAction a_A, a_B, a_X, a_Y, a_menu, a_lstickc, a_rstickc;
|
||||
static XrAction a_ltrig, a_rtrig, a_lgrip, a_rgrip, a_lstick, a_rstick;
|
||||
static XrAction a_lpose, a_rpose;
|
||||
static XrAction a_lhaptic, a_rhaptic;
|
||||
static XrSpace s_lspace, s_rspace;
|
||||
|
||||
static struct {
|
||||
uint32_t buttons;
|
||||
float ltrig, rtrig, lgrip, rgrip;
|
||||
ovrpVector2f lstick, rstick;
|
||||
XrPosef lpose, rpose; int lvalid, rvalid;
|
||||
} s_in;
|
||||
|
||||
static XrAction mk(XrActionType t, const char *n) {
|
||||
XrActionCreateInfo ci = { XR_TYPE_ACTION_CREATE_INFO };
|
||||
ci.actionType = t;
|
||||
strncpy(ci.actionName, n, XR_MAX_ACTION_NAME_SIZE - 1);
|
||||
strncpy(ci.localizedActionName, n, XR_MAX_LOCALIZED_ACTION_NAME_SIZE - 1);
|
||||
XrAction a = XR_NULL_HANDLE;
|
||||
xrCreateAction(s_set, &ci, &a);
|
||||
return a;
|
||||
}
|
||||
|
||||
int xrr_input_init(void) {
|
||||
if (g_xr.instance == XR_NULL_HANDLE || g_xr.session == XR_NULL_HANDLE) return 0;
|
||||
XrActionSetCreateInfo asci = { XR_TYPE_ACTION_SET_CREATE_INFO };
|
||||
strcpy(asci.actionSetName, "gameplay");
|
||||
strcpy(asci.localizedActionSetName, "gameplay");
|
||||
if (xrCreateActionSet(g_xr.instance, &asci, &s_set) != XR_SUCCESS) return 0;
|
||||
|
||||
a_A = mk(XR_ACTION_TYPE_BOOLEAN_INPUT, "a_btn");
|
||||
a_B = mk(XR_ACTION_TYPE_BOOLEAN_INPUT, "b_btn");
|
||||
a_X = mk(XR_ACTION_TYPE_BOOLEAN_INPUT, "x_btn");
|
||||
a_Y = mk(XR_ACTION_TYPE_BOOLEAN_INPUT, "y_btn");
|
||||
a_menu = mk(XR_ACTION_TYPE_BOOLEAN_INPUT, "menu_btn");
|
||||
a_lstickc = mk(XR_ACTION_TYPE_BOOLEAN_INPUT, "lstick_click");
|
||||
a_rstickc = mk(XR_ACTION_TYPE_BOOLEAN_INPUT, "rstick_click");
|
||||
a_ltrig = mk(XR_ACTION_TYPE_FLOAT_INPUT, "ltrigger");
|
||||
a_rtrig = mk(XR_ACTION_TYPE_FLOAT_INPUT, "rtrigger");
|
||||
a_lgrip = mk(XR_ACTION_TYPE_FLOAT_INPUT, "lgrip");
|
||||
a_rgrip = mk(XR_ACTION_TYPE_FLOAT_INPUT, "rgrip");
|
||||
a_lstick = mk(XR_ACTION_TYPE_VECTOR2F_INPUT, "lstick");
|
||||
a_rstick = mk(XR_ACTION_TYPE_VECTOR2F_INPUT, "rstick");
|
||||
a_lpose = mk(XR_ACTION_TYPE_POSE_INPUT, "lpose");
|
||||
a_rpose = mk(XR_ACTION_TYPE_POSE_INPUT, "rpose");
|
||||
a_lhaptic = mk(XR_ACTION_TYPE_VIBRATION_OUTPUT, "lhaptic");
|
||||
a_rhaptic = mk(XR_ACTION_TYPE_VIBRATION_OUTPUT, "rhaptic");
|
||||
|
||||
XrActionSuggestedBinding b[32]; int n = 0; XrPath p;
|
||||
#define BIND(act, path) do { if (xrStringToPath(g_xr.instance, path, &p) == XR_SUCCESS) \
|
||||
{ b[n].action = (act); b[n].binding = p; n++; } } while (0)
|
||||
BIND(a_A, "/user/hand/right/input/a/click");
|
||||
BIND(a_B, "/user/hand/right/input/b/click");
|
||||
BIND(a_X, "/user/hand/left/input/x/click");
|
||||
BIND(a_Y, "/user/hand/left/input/y/click");
|
||||
BIND(a_menu, "/user/hand/left/input/menu/click");
|
||||
BIND(a_lstickc, "/user/hand/left/input/thumbstick/click");
|
||||
BIND(a_rstickc, "/user/hand/right/input/thumbstick/click");
|
||||
BIND(a_ltrig, "/user/hand/left/input/trigger/value");
|
||||
BIND(a_rtrig, "/user/hand/right/input/trigger/value");
|
||||
BIND(a_lgrip, "/user/hand/left/input/squeeze/value");
|
||||
BIND(a_rgrip, "/user/hand/right/input/squeeze/value");
|
||||
BIND(a_lstick, "/user/hand/left/input/thumbstick");
|
||||
BIND(a_rstick, "/user/hand/right/input/thumbstick");
|
||||
BIND(a_lpose, "/user/hand/left/input/aim/pose");
|
||||
BIND(a_rpose, "/user/hand/right/input/aim/pose");
|
||||
BIND(a_lhaptic, "/user/hand/left/output/haptic");
|
||||
BIND(a_rhaptic, "/user/hand/right/output/haptic");
|
||||
|
||||
XrPath profile;
|
||||
xrStringToPath(g_xr.instance, "/interaction_profiles/oculus/touch_controller", &profile);
|
||||
XrInteractionProfileSuggestedBinding sb = { XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING };
|
||||
sb.interactionProfile = profile;
|
||||
sb.suggestedBindings = b;
|
||||
sb.countSuggestedBindings = n;
|
||||
if (xrSuggestInteractionProfileBindings(g_xr.instance, &sb) != XR_SUCCESS)
|
||||
XRRERR("suggest bindings failed");
|
||||
|
||||
XrActionSpaceCreateInfo spci = { XR_TYPE_ACTION_SPACE_CREATE_INFO };
|
||||
spci.poseInActionSpace.orientation.w = 1.0f;
|
||||
spci.action = a_lpose; xrCreateActionSpace(g_xr.session, &spci, &s_lspace);
|
||||
spci.action = a_rpose; xrCreateActionSpace(g_xr.session, &spci, &s_rspace);
|
||||
|
||||
XrSessionActionSetsAttachInfo at = { XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO };
|
||||
at.countActionSets = 1; at.actionSets = &s_set;
|
||||
if (xrAttachSessionActionSets(g_xr.session, &at) != XR_SUCCESS) {
|
||||
XRRERR("attach action sets failed"); return 0;
|
||||
}
|
||||
XRRLOG("input: action set attached (%d bindings)", n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bget(XrAction a) {
|
||||
XrActionStateGetInfo gi = { XR_TYPE_ACTION_STATE_GET_INFO }; gi.action = a;
|
||||
XrActionStateBoolean st = { XR_TYPE_ACTION_STATE_BOOLEAN };
|
||||
xrGetActionStateBoolean(g_xr.session, &gi, &st);
|
||||
return st.isActive && st.currentState;
|
||||
}
|
||||
static float fget(XrAction a) {
|
||||
XrActionStateGetInfo gi = { XR_TYPE_ACTION_STATE_GET_INFO }; gi.action = a;
|
||||
XrActionStateFloat st = { XR_TYPE_ACTION_STATE_FLOAT };
|
||||
xrGetActionStateFloat(g_xr.session, &gi, &st);
|
||||
return st.isActive ? st.currentState : 0.0f;
|
||||
}
|
||||
static ovrpVector2f v2get(XrAction a) {
|
||||
XrActionStateGetInfo gi = { XR_TYPE_ACTION_STATE_GET_INFO }; gi.action = a;
|
||||
XrActionStateVector2f st = { XR_TYPE_ACTION_STATE_VECTOR2F };
|
||||
xrGetActionStateVector2f(g_xr.session, &gi, &st);
|
||||
ovrpVector2f v = { 0, 0 };
|
||||
if (st.isActive) { v.x = st.currentState.x; v.y = st.currentState.y; }
|
||||
return v;
|
||||
}
|
||||
|
||||
void xrr_input_sync(void) {
|
||||
if (s_set == XR_NULL_HANDLE || !g_xr.running) return;
|
||||
XrActiveActionSet aas = { s_set, XR_NULL_PATH };
|
||||
XrActionsSyncInfo si = { XR_TYPE_ACTIONS_SYNC_INFO };
|
||||
si.countActiveActionSets = 1; si.activeActionSets = &aas;
|
||||
XrResult sr = xrSyncActions(g_xr.session, &si);
|
||||
static int dbg = 0;
|
||||
if (sr != XR_SUCCESS && dbg < 3) { dbg++; XRRLOG("xrSyncActions rc=%d", (int)sr); }
|
||||
if (XR_FAILED(sr)) return;
|
||||
|
||||
uint32_t btn = 0;
|
||||
if (bget(a_A)) btn |= OVRP_BTN_A;
|
||||
if (bget(a_B)) btn |= OVRP_BTN_B;
|
||||
if (bget(a_X)) btn |= OVRP_BTN_X;
|
||||
if (bget(a_Y)) btn |= OVRP_BTN_Y;
|
||||
if (bget(a_menu)) btn |= OVRP_BTN_START;
|
||||
if (bget(a_lstickc)) btn |= OVRP_BTN_LTHUMB;
|
||||
if (bget(a_rstickc)) btn |= OVRP_BTN_RTHUMB;
|
||||
s_in.buttons = btn;
|
||||
s_in.ltrig = fget(a_ltrig); s_in.rtrig = fget(a_rtrig);
|
||||
s_in.lgrip = fget(a_lgrip); s_in.rgrip = fget(a_rgrip);
|
||||
s_in.lstick = v2get(a_lstick); s_in.rstick = v2get(a_rstick);
|
||||
|
||||
XrSpaceLocation loc = { XR_TYPE_SPACE_LOCATION };
|
||||
XrResult lr = xrLocateSpace(s_lspace, g_xr.appSpace, g_xr.frameState.predictedDisplayTime, &loc);
|
||||
if (lr == XR_SUCCESS && (loc.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)) {
|
||||
s_in.lpose = loc.pose; s_in.lvalid = 1;
|
||||
}
|
||||
XrSpaceLocation rloc = { XR_TYPE_SPACE_LOCATION };
|
||||
XrResult rr = xrLocateSpace(s_rspace, g_xr.appSpace, g_xr.frameState.predictedDisplayTime, &rloc);
|
||||
if (rr == XR_SUCCESS && (rloc.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT)) {
|
||||
s_in.rpose = rloc.pose; s_in.rvalid = 1;
|
||||
}
|
||||
static int pd = 0;
|
||||
if (pd < 4) { pd++;
|
||||
XRRLOG("input poses: L rc=%d flags=0x%x pos=(%.2f,%.2f,%.2f) | R rc=%d flags=0x%x pos=(%.2f,%.2f,%.2f)",
|
||||
(int)lr, (unsigned)loc.locationFlags, loc.pose.position.x, loc.pose.position.y, loc.pose.position.z,
|
||||
(int)rr, (unsigned)rloc.locationFlags, rloc.pose.position.x, rloc.pose.position.y, rloc.pose.position.z);
|
||||
}
|
||||
}
|
||||
|
||||
/* ovrp_SetControllerVibration2(mask, freq, amplitude) -> xrApplyHapticFeedback.
|
||||
* amplitude 0 stops; >0 starts a short pulse (game re-issues for sustained rumble). */
|
||||
void xrr_set_vibration(unsigned int mask, float frequency, float amplitude) {
|
||||
if (s_set == XR_NULL_HANDLE || !g_xr.running) return;
|
||||
XrHapticVibration hv = { XR_TYPE_HAPTIC_VIBRATION };
|
||||
hv.amplitude = amplitude < 0 ? 0 : (amplitude > 1 ? 1 : amplitude);
|
||||
hv.frequency = frequency > 0.0f ? frequency : XR_FREQUENCY_UNSPECIFIED;
|
||||
hv.duration = 300000000; /* 0.3 s; replaced/stopped by the next call */
|
||||
XrHapticActionInfo hai = { XR_TYPE_HAPTIC_ACTION_INFO };
|
||||
for (int side = 0; side < 2; side++) {
|
||||
if (!(mask & (side == 0 ? 0x01u : 0x02u))) continue;
|
||||
hai.action = side == 0 ? a_lhaptic : a_rhaptic;
|
||||
if (amplitude > 0.0f)
|
||||
xrApplyHapticFeedback(g_xr.session, &hai, (const XrHapticBaseHeader *)&hv);
|
||||
else
|
||||
xrStopHapticFeedback(g_xr.session, &hai);
|
||||
}
|
||||
}
|
||||
|
||||
void xrr_get_controller_state(unsigned int mask, ovrpControllerState4 *out) {
|
||||
(void)mask;
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->ConnectedControllers = 0x01 | 0x02 | 0x80000000u; /* LTouch|RTouch|Active */
|
||||
out->Buttons = s_in.buttons;
|
||||
out->LIndexTrigger = s_in.ltrig; out->RIndexTrigger = s_in.rtrig;
|
||||
out->LHandTrigger = s_in.lgrip; out->RHandTrigger = s_in.rgrip;
|
||||
out->LThumbstick = s_in.lstick; out->RThumbstick = s_in.rstick;
|
||||
}
|
||||
|
||||
/* node presence/validity — the game gates pose queries on these. Reporting the
|
||||
* controllers as present+tracked is what makes it actually ASK for hand poses. */
|
||||
int xrr_node_present(int node) {
|
||||
switch (node) {
|
||||
case ovrpNode_Head: case ovrpNode_EyeLeft: case ovrpNode_EyeRight:
|
||||
case ovrpNode_EyeCenter: case ovrpNode_HandLeft: case ovrpNode_HandRight:
|
||||
return 1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
int xrr_node_valid(int node) {
|
||||
switch (node) {
|
||||
case ovrpNode_Head: case ovrpNode_EyeLeft: case ovrpNode_EyeRight:
|
||||
case ovrpNode_EyeCenter:
|
||||
return g_xr.running ? 1 : 0;
|
||||
case ovrpNode_HandLeft: return s_in.lvalid;
|
||||
case ovrpNode_HandRight: return s_in.rvalid;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int xrr_get_hand_pose(int node, ovrpPoseStatef *out) {
|
||||
const XrPosef *p = NULL;
|
||||
if (node == ovrpNode_HandLeft && s_in.lvalid) p = &s_in.lpose;
|
||||
if (node == ovrpNode_HandRight && s_in.rvalid) p = &s_in.rpose;
|
||||
if (!p) return 0;
|
||||
ovrp_pose_from_xr(p, &out->Pose);
|
||||
return 1;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,195 @@
|
||||
/* xr_runtime.h — OpenXR session + frame-loop engine behind the ovrp_* frame fns.
|
||||
* Core OpenXR only (no graphics-API headers); the Vulkan graphics binding +
|
||||
* swapchains are handled separately once the ovrp_Initialize5 handshake is
|
||||
* reversed. This module owns the instance/system/session/spaces + frame pacing. */
|
||||
#ifndef XR_RUNTIME_H
|
||||
#define XR_RUNTIME_H
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include "ovrplugin_shim.h"
|
||||
|
||||
#define XRR_MAX_LAYERS 16
|
||||
#define XRR_MAX_IMAGES 8
|
||||
|
||||
typedef struct {
|
||||
XrSwapchain swapchain; /* color */
|
||||
XrSwapchain depthSwapchain; /* optional (SetupLayerDepth) */
|
||||
uint32_t imageCount; /* = stage count */
|
||||
uint32_t width, height, arraySize;
|
||||
int64_t colorFormat;
|
||||
int64_t depthFormat; /* 0 = no depth swapchain */
|
||||
uint64_t colorImages[XRR_MAX_IMAGES]; /* VkImage handles -> app */
|
||||
uint64_t depthImages[XRR_MAX_IMAGES];
|
||||
/* copy-ring: shim color images UE renders into (decoupled from OpenXR swapchain) */
|
||||
uint64_t shimImages[XRR_MAX_IMAGES];
|
||||
uint64_t shimMem[XRR_MAX_IMAGES];
|
||||
int shimCount; /* >0 = copy-ring active for this layer */
|
||||
uint32_t acquiredIndex; /* this frame's acquired (render) image */
|
||||
uint32_t depthAcquiredIndex;
|
||||
int depthAcquired; /* paired depth image held this frame */
|
||||
int imageAcquired; /* this frame's render image is held */
|
||||
/* render-ahead pipeline: the image rendered LAST frame is held one extra
|
||||
* frame so its tile-memory flush completes off the critical path. */
|
||||
int presentPending; /* holding last frame's image to present */
|
||||
int presentToken; /* its flush fence token (xrr_vk_flush_*) */
|
||||
uint32_t presentIndex; /* its swapchain index (diagnostics) */
|
||||
/* present-on-submit (debug.re4vr.submithook=2): image held from this frame's
|
||||
* acquire until UE's eye-render vkQueueSubmit fires, then resolved+released. */
|
||||
int deferColor; /* color image awaiting deferred present */
|
||||
int deferDepth; /* depth image awaiting deferred present */
|
||||
uint32_t deferColorIndex; /* held color swapchain index */
|
||||
uint32_t deferDepthIndex; /* held depth swapchain index */
|
||||
int active;
|
||||
int isEyeFov; /* projection vs overlay */
|
||||
int layout; /* ovrpLayout (Array vs side-by-side) */
|
||||
} XrLayer;
|
||||
|
||||
typedef struct {
|
||||
XrInstance instance;
|
||||
XrSystemId systemId;
|
||||
XrSession session;
|
||||
XrSpace appSpace; /* LOCAL or STAGE — tracking origin */
|
||||
XrSpace viewSpace; /* VIEW — head pose */
|
||||
XrSessionState sessionState;
|
||||
XrViewConfigurationType viewConfigType;
|
||||
|
||||
/* per-frame state from the last xrWaitFrame */
|
||||
XrFrameState frameState;
|
||||
XrView views[2]; /* located eye views */
|
||||
uint32_t viewCount;
|
||||
int running; /* xrBeginSession done */
|
||||
int inFrame; /* between BeginFrame and EndFrame */
|
||||
|
||||
XrLayer layers[XRR_MAX_LAYERS];
|
||||
int layerCount;
|
||||
} XrRuntime;
|
||||
|
||||
extern XrRuntime g_xr;
|
||||
|
||||
/* lifecycle (ovrp_PreInitialize3 / ovrp_Initialize5 / ovrp_Shutdown2) */
|
||||
ovrpResult xrr_pre_init(void); /* create instance + pick system */
|
||||
/* create session from the app's Vulkan handles (Initialize5 args 5-8) + spaces */
|
||||
ovrpResult xrr_init(void *vkInstance, void *vkPhysicalDevice, void *vkDevice,
|
||||
unsigned int queueFamilyIndex);
|
||||
void xrr_shutdown(void);
|
||||
|
||||
/* defined in vk_session.c (Vulkan-typed, kept out of this core-only header) */
|
||||
int xrr_create_session_vulkan(void *vkInstance, void *vkPhysicalDevice,
|
||||
void *vkDevice, unsigned int queueFamilyIndex);
|
||||
|
||||
/* frame loop */
|
||||
void xrr_poll_events(void); /* session state machine */
|
||||
ovrpResult xrr_wait_frame(int frameIndex); /* xrWaitFrame + locate views */
|
||||
ovrpResult xrr_begin_frame(int frameIndex); /* xrBeginFrame */
|
||||
ovrpResult xrr_end_frame(int frameIndex,
|
||||
const ovrpLayerSubmit *const *layers, int layerCount);
|
||||
double xrr_predicted_display_time_s(void); /* seconds */
|
||||
|
||||
/* pose query (ovrp_GetNodePoseState3) */
|
||||
ovrpResult xrr_get_node_pose(ovrpNode node, ovrpPoseStatef *out);
|
||||
void xrr_eye_fov_tangents(int eye, float *up, float *down, float *left, float *right);
|
||||
|
||||
/* layers / swapchains (ovrp_SetupLayer / GetLayerTextureStageCount / GetLayerTexture2) */
|
||||
ovrpResult xrr_setup_layer(const ovrpLayerDesc *desc, int *outLayerId);
|
||||
void xrr_destroy_layer(int layerId);
|
||||
ovrpResult xrr_setup_layer_depth(int layerId, const ovrpLayerDesc *depthDesc);
|
||||
int xrr_layer_stage_count(int layerId);
|
||||
ovrpResult xrr_get_layer_texture(int layerId, int stage, int eye,
|
||||
uint64_t *outColor, uint64_t *outDepth);
|
||||
/* defined in vk_session.c — enumerate swapchain VkImages as uint64 handles */
|
||||
uint32_t xrr_vk_enumerate_images(XrSwapchain sc, uint64_t *out, uint32_t max);
|
||||
|
||||
/* recommended per-eye render size from the view configuration */
|
||||
void xrr_recommended_eye_size(uint32_t *w, uint32_t *h);
|
||||
|
||||
/* tracking origin (xr_runtime.c) — 1 = floor (STAGE), 0 = eye level (LOCAL) */
|
||||
void xrr_set_tracking_origin(int floor);
|
||||
int xrr_get_tracking_origin(void);
|
||||
/* apply the game's CPU/GPU perf-level request via XR_EXT_performance_settings */
|
||||
void xrr_set_perf_level(int isGpu, int level);
|
||||
|
||||
/* game dynamic-perf bridge (xr_runtime.c <- core.c ovrp_*TiledMultiRes* / GPUFrameTime).
|
||||
* Forwards RE4's own FFR scaling onto XR_FB_foveation and feeds it a GPU-time estimate. */
|
||||
int xrr_foveation_supported(void); /* GetTiledMultiResSupported */
|
||||
void xrr_set_tiled_multires_level(int ovrpLevel);/* SetTiledMultiResLevel (0..4)*/
|
||||
int xrr_get_tiled_multires_level(void); /* GetTiledMultiResLevel */
|
||||
void xrr_set_tiled_multires_dynamic(int on); /* SetTiledMultiResDynamic */
|
||||
int xrr_get_tiled_multires_dynamic(void); /* GetTiledMultiResDynamic */
|
||||
float xrr_gpu_frame_time_ms(void); /* GetGPUFrameTime source (ms) */
|
||||
float xrr_adaptive_gpu_scale(void); /* GetAdaptiveGpuPerformanceScale2 (Lever A) */
|
||||
/* perf metrics (ovrp_IsPerfMetricsSupported / GetPerfMetrics{Float,Int}); metric =
|
||||
* ovrpPerfMetrics id. *_supported returns 1/0; getters return 1+write *out, else 0. */
|
||||
int xrr_perf_metric_supported(int metric);
|
||||
int xrr_perf_metric_float(int metric, float *out);
|
||||
int xrr_perf_metric_int(int metric, int *out);
|
||||
|
||||
/* render-submit race fix (debug.re4vr.submithook). xrr_install_submit_hook patches UE's
|
||||
* global VulkanDynamicAPI::vkQueueSubmit to a trampoline (vk_session.c); the trampoline
|
||||
* calls xrr_on_ue_submit after each UE submit so present can be ordered after UE's
|
||||
* eye-render submit. isRenderQueue = UE submitted to the shim's graphics queue. */
|
||||
int xrr_install_submit_hook(void);
|
||||
void xrr_on_ue_submit(uint64_t queue, uint64_t fence, int isRenderQueue);
|
||||
|
||||
/* Vulkan barrier infra (vk_session.c) — flush UE's tile-memory render to main
|
||||
* memory before the OpenXR compositor reads the swapchain image. */
|
||||
void xrr_vk_set_handles(void *device, void *queue, unsigned int family);
|
||||
void xrr_vk_teardown(void); /* reset shim Vulkan state for clean re-init (called from shutdown) */
|
||||
/* render-ahead flush: submit the barrier without blocking (returns a ring token,
|
||||
* or -1 if Vulkan isn't ready), wait it a frame later, ready() probes the ring. */
|
||||
int xrr_vk_flush_submit(uint64_t image, unsigned int arrayLayers);
|
||||
int xrr_vk_flush_submit_ex(uint64_t image, unsigned int arrayLayers, int isDepth);
|
||||
void xrr_vk_flush_wait(int token);
|
||||
/* Block until UE's VkQueue is fully idle (vkQueueWaitIdle). Diagnostic probe for the
|
||||
* render-submit race: forces all queue work to complete before we resolve/present. */
|
||||
void xrr_vk_queue_wait_idle(void);
|
||||
void xrr_vk_device_wait_idle(void);
|
||||
/* copy-ring (vk_session.c): shim images UE renders into + pipelined resolve-copy */
|
||||
int xrr_vk_alloc_images(uint64_t *out, uint64_t *outMem, int count,
|
||||
unsigned int w, unsigned int h, unsigned int arraySize, long long vkFormat);
|
||||
int xrr_vk_alloc_images_ex(uint64_t *out, uint64_t *outMem, int count,
|
||||
unsigned int w, unsigned int h, unsigned int arraySize, long long vkFormat, int isDepth);
|
||||
void xrr_vk_free_images(uint64_t *imgs, uint64_t *mem, int count);
|
||||
int xrr_vk_copy_submit(uint64_t srcShim, uint64_t dstXr,
|
||||
unsigned int w, unsigned int h, unsigned int arrayLayers);
|
||||
int xrr_vk_copy_submit_ex(uint64_t srcShim, uint64_t dstXr,
|
||||
unsigned int w, unsigned int h, unsigned int arrayLayers, int isDepth);
|
||||
int xrr_vk_flush_ready(void);
|
||||
/* one-shot debug readback of one array layer to a downsampled PPM (debug.re4vr.dump) */
|
||||
void xrr_vk_dump_image(uint64_t image, unsigned int w, unsigned int h,
|
||||
unsigned int arrayLayer, const char *path);
|
||||
/* stamp a black/white binary barcode of `value` (the frameIndex) into the top-left of
|
||||
* one array layer, AFTER UE's resolve, so it rides on every frame incl. black ones —
|
||||
* frame-exact video<->log correlation (debug.re4vr.barcode). Validation-only. */
|
||||
void xrr_vk_stamp_barcode(uint64_t image, unsigned int w, unsigned int h,
|
||||
unsigned int arrayLayer, unsigned int value, int flagged);
|
||||
/* per-frame black detector: max luminance (0..255) over a few rows of the resolved eye
|
||||
* image; ~0 => truncated/black frame. Covers the whole black tail (debug.re4vr.lumagate). */
|
||||
int xrr_vk_frame_luma(uint64_t image, unsigned int w, unsigned int h, unsigned int arrayLayer);
|
||||
|
||||
/* input (xr_input.c) — OpenXR action sets -> ovrpControllerState4 + hand poses */
|
||||
int xrr_input_init(void);
|
||||
void xrr_input_sync(void);
|
||||
void xrr_get_controller_state(unsigned int mask, ovrpControllerState4 *out);
|
||||
int xrr_get_hand_pose(int node, ovrpPoseStatef *out);
|
||||
int xrr_node_present(int node);
|
||||
int xrr_node_valid(int node);
|
||||
void xrr_set_vibration(unsigned int mask, float frequency, float amplitude);
|
||||
|
||||
/* Android instance handshake (android_init.c). No-ops on the host build so the
|
||||
* same xr_runtime.c serves both. JavaVM is captured via JNI_OnLoad; the activity
|
||||
* comes from Initialize5 arg4, with an Application-context reflection fallback. */
|
||||
int xrr_android_init_loader(void); /* xrInitializeLoaderKHR (vm+context) */
|
||||
void *xrr_android_instance_next(void); /* &XrInstanceCreateInfoAndroidKHR | NULL */
|
||||
void xrr_set_android_activity(void *activity);
|
||||
int xrr_android_have_real_activity(void);
|
||||
void *xrr_android_get_vm(void); /* JavaVM* captured in JNI_OnLoad (NULL on host) */
|
||||
|
||||
/* helpers */
|
||||
static inline void ovrp_pose_from_xr(const XrPosef *in, ovrpPosef *out) {
|
||||
out->Orientation.x = in->orientation.x; out->Orientation.y = in->orientation.y;
|
||||
out->Orientation.z = in->orientation.z; out->Orientation.w = in->orientation.w;
|
||||
out->Position.x = in->position.x; out->Position.y = in->position.y;
|
||||
out->Position.z = in->position.z;
|
||||
}
|
||||
|
||||
#endif /* XR_RUNTIME_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/* harness.c — drives the ovrp_* sequence against a real OpenXR runtime
|
||||
* (Path B: Monado simulated/headless). Smoke-tests the shim's OpenXR usage
|
||||
* without RE4 or a headset. See ../../TESTING.md.
|
||||
*
|
||||
* Build (inside a Linux env with an OpenXR loader):
|
||||
* cc -std=c11 -I../include -I../third_party/openxr harness.c \
|
||||
* ../src/stubs.c ../src/core.c ../src/xr_runtime.c ../src/vk_session.c \
|
||||
* ../src/layers.c -lopenxr_loader -o harness
|
||||
* XR_RUNTIME_JSON=/path/openxr_monado-dev.json ./harness
|
||||
*
|
||||
* NOTE: Initialize5 -> xrCreateSession needs real Vulkan handles. For a first
|
||||
* smoke test we stop after PreInitialize3 (instance+system create) unless real
|
||||
* VkInstance/Device handles are provided. Set WITH_VK=1 + fill the handles to go
|
||||
* further once a headless Vulkan device is available.
|
||||
*/
|
||||
#include "ovrplugin_shim.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define CHECK(expr) do { \
|
||||
ovrpResult _r = (expr); \
|
||||
printf(" %-34s -> %d %s\n", #expr, _r, OVRP_SUCCESS(_r) ? "OK" : "(fail)"); \
|
||||
} while (0)
|
||||
|
||||
int main(void) {
|
||||
printf("== ovrp shim smoke test ==\n");
|
||||
|
||||
printf("[lifecycle]\n");
|
||||
CHECK(ovrp_PreInitialize3(NULL)); /* xrCreateInstance + xrGetSystem */
|
||||
|
||||
/* Session creation needs real Vulkan handles; pass NULLs and expect failure
|
||||
* until a headless Vulkan device is wired (see TESTING.md Path B note). */
|
||||
printf("[init — expect fail without Vulkan handles]\n");
|
||||
CHECK(ovrp_Initialize5(ovrpRenderAPI_Vulkan, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, 0, 0));
|
||||
|
||||
printf("[frame loop — will report not-ready until session exists]\n");
|
||||
for (int f = 0; f < 3; f++) {
|
||||
ovrp_Update3(ovrpStep_Render, f, 0.0);
|
||||
ovrp_WaitToBeginFrame(f);
|
||||
ovrp_BeginFrame4(f, NULL);
|
||||
ovrpPoseStatef head;
|
||||
ovrp_GetNodePoseState3(ovrpStep_Render, f, ovrpNode_Head, &head);
|
||||
double t = 0; ovrp_GetPredictedDisplayTime(f, &t);
|
||||
ovrp_EndFrame4(f, NULL, 0, NULL);
|
||||
printf(" frame %d: head.w=%.3f t=%.6f\n", f, head.Pose.Orientation.w, t);
|
||||
}
|
||||
|
||||
printf("[shutdown]\n");
|
||||
CHECK(ovrp_Shutdown2());
|
||||
printf("== done ==\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user