Repository navigation
Conversation
NOT TESTED
Co-authored-by: Uwie <Uwie>
Co-authored-by: HttpAnimations <shawndouglasyt@gmail.com>
bob
) * vr: capture the microphone for voice chat on Build 2998 On the vr branch Roblox 2.736.1408 joins voice chat and plays other players, but never opens a microphone: its FmodAudioDevice capture methods have no working host path, and main's native capture (537828a "Fix vc") is pinned to 2.738 RVAs. Port main's NativeInputCapture and interpose the FmodAudioDevice capture slots for Build 2998. 2.738 inserted two device-list slots (7 and 11), so the capture methods sit at {4, 11..15} here instead of {4, 13..17}. The input-device slots {8, 9, 10, 16}, checked against main's input RVAs for this image, anchor that layout before anything is patched, and each capture slot must be a distinct method next to the input-device code. The voice sink is called through its own vtable after checking that the vtable and its PCM entry point lie in libroblox, and the retained shared_ptr is released through the libc++ control-block ABI, so no further Build 2998 RVAs are needed. If any check fails, capture stays off and the output routes still work. MOCKTAIL_NATIVE_INPUT_CAPTURE=0 turns the capture interposition off, and audio.input_device: disabled reports no microphone to Roblox. * Requested fix at PR 181
Also fix openxr shit
…ore FMOD profile functions
SteamVR (vrclient.so) binds its Vulkan renderer to the lifetime of the XrInstance. When Roblox destroys the LuaApp Vulkan device and creates a second VkInstance/VkDevice for UGC experiences, reusing the original XrInstance causes SteamVR to dereference freed device handles in xrEndFrame. Tear down and recreate the XrInstance whenever a new guest Vulkan instance is initialized, resetting session state, spaces, and controller actions.
# Conflicts: # stubs/libandroid_stub.cc
…ark mode vr.frame_rate_limit / MOCKTAIL_VR_FRAME_RATE_LIMIT replaces graphics.frame_rate_limit while VR is active and takes the same values. It defaults to unlimited so xrWaitFrame paces Roblox at the headset refresh rate instead of Roblox's own 60 FPS cap. MOCKTAIL_VR_RENDER_SCALE scales the runtime's recommended eye extent. SteamVR's recommendation for a Quest 2 at 90 Hz (2244x2352 per eye) missed the 11.1 ms budget and halved the rate to 45 FPS. MOCKTAIL_VR_UNPACED=1 stops guest frames from blocking in xrWaitFrame: the open XR frame spans several guest frames and is submitted once per display period, for measuring maximum render rate.
When Roblox asks for a keyboard (showKeyboard), a world-locked panel opens below eye level as an OpenXR quad layer. Controllers point at keys and the trigger types; text and key presses go through the same platform events as the desktop keyboard, so the focused TextBox edits identically. The layout is US QWERTY without the function row or Ctrl/Alt, with one-shot Shift, Caps Lock, Tab, Backspace auto-repeat, Enter and Close. A trigger aimed at the panel is withheld from Roblox so a key press is not also a click. A text field above the keys mirrors the focused TextBox, whose desktop overlay never reaches the eye images. MOCKTAIL_VR_KEYBOARD=0 turns it off.
Mark the 3092 profile experimental. It still runs when selected with --roblox-lib, but it no longer becomes the preferred update target for every x86_64 user, so the shipped payload metadata (2998) is again the preferred profile. Select the 2998 entry by Build ID in the partial-input profile test instead of relying on manifest order, and drop the shipped 3092 entry before the test re-identifies 2998 as 3092. Align the example config's VR build wording with the bootstrap template.
VR now stays off at runtime in every build until --vr or vr.enabled: true, so a normal launch on a VR-capable build never tries to reach an OpenXR runtime and no longer exits when none is running. MOCKTAIL_ENABLE_VR defaults to AUTO: OpenXR support is built when the third_party/OpenXR-SDK submodule is present and skipped with a notice otherwise, so source packages that do not fetch submodules (Nix, AUR) keep building. ON still requires the submodule. mocktail-vr-probe is only built and installed in VR builds. CI gains an x86_64 job that builds and tests with MOCKTAIL_ENABLE_VR=OFF. The config docs and README describe the new defaults.
An explicit --vr on a Roblox build without VR support now exits with the build's version and Build ID, the builds VR supports, and how to select one (--roblox-lib). When VR is only enabled in the config, the launch continues without VR and logs the same details. The bridge's own Install error names both as well. The verified build contracts carry their version labels and move to namespace scope so they can be listed.
Queue and device-idle locks in the Vulkan adapter are now taken only after an armed OpenXR backend calls mocktail_vulkan_enable_queue_sharing(). The guest synchronizes its own queue use; only the runtime and the eye copies add a second user. Without VR, and in builds without it, submits and presents take no locks. FFlagDebugEnableVREmulator is only written when VR is active, so a user's own fflags.json value is no longer overridden on every launch. Config loading is back after the single-instance lock and the support bundle guard. A non-VR build still rejects --vr before creating any data or state directories, from the command line alone; a vr.enabled config in such a build is rejected once the config is loaded.
- Every frame error, including the swapchain-image and copy-fence timeouts, now tears the session down recoverably instead of ending XR output for the rest of the run. - Session recovery backs off (1, 2, 4, 8 s) and recreates the XrInstance after an instance-loss event, an instance/runtime failure, or three failed attempts, so VR returns after SteamVR or WiVRn restarts instead of retrying forever. - While no XR session runs (headset idle, session not READY, recovering) presents are paced at 60 Hz outside the backend lock instead of running unthrottled. - A PrepareHostPresent failure that consumed nothing (copy resources unavailable, failed fence reset or submit) presents normally instead of failing the guest's vkQueuePresentKHR; only device loss is propagated. - A runtime/guest GPU mismatch falls back to the plain host device and keeps the game running without headset output, naming both GPUs. - A failed EGL attach on the GLES path no longer makes window init fail; the game runs without headset output and the bind is not retried.
- Once the guest eye format is known, the eye swapchains are recreated once in the format that keeps its bytes: the eye format, else its UNORM/SRGB sibling (raw copy), else the other channel order with the same sRGB-ness (a blit that only swizzles). Mixed order-and-gamma cases no longer go through a gamma-converting blit; if only that remains, it is logged. - The desktop mirror segment is created with O_EXCL after removing our own stale segment (a crashed run's leftover), and must be private to this user before eye images are written to it. - A new frame_mutex_ is held for the whole XR frame cycle and by every path that can destroy the session (taken before mutex_). That lets the cycle release mutex_ while it blocks in xrWaitFrame, so guest render-thread hooks no longer wait out the runtime's pacing. Swapchain-image and fence waits stay under mutex_; they return promptly unless the GPU or compositor stalls, and they run while guest eye bindings are copied.
…reads - MOCKTAIL_VR_HAND_POSE_SOURCE=grip now rotates hand records from the grip pose. base_ori started as the identity quaternion, so the norm check never fell back to it and hand rotation was dropped. - Hand records cancel the engine's stored hand pitch (read from hand_pitch_storage_rva by the pointer hook, 20 until read) instead of a hard-coded 20, so they agree with the pointer ray. - Shutdown never rewrites the aim-pointer prologue while guest threads may be executing it; the jump stays and only forwards once the bridge is gone, and a later activation reuses it. - Guest hooks count themselves in flight before loading the bridge pointer; Shutdown unpublishes the bridge and waits for in-flight calls to drain, so no hook keeps a pointer to a destroyed bridge. - Roblox's original state and eye getters are kept for the process lifetime. A hook reached with no bridge, including after a failed vtable restore, forwards to them instead of returning an unfilled state buffer. Restoring the vtable no longer depends on the pointer hook. - The activation log names the vtable slots in the right order.
- Remove the MOCKTAIL_VR_TEST_SESSION_LOSS_AFTER fault injection; nothing used it. - The scripted head pose and the eye evidence dumper only work in builds configured with -DMOCKTAIL_VR_DIAGNOSTICS=ON (default OFF); release builds ignore their environment variables. - Remove FindFmodInputCaptureProfile and HasExpectedFmodInputCaptureVtable (only their own tests called them) and the never-defined PrepareCaptureLocked declaration; the audio bridge files match upstream again. - docs/VR.md lists every MOCKTAIL_VR_* variable with its default, linked from the README.
…he content folder
…ds still in a hook
…ession - Implement RobloxHapticProtocolBridge for MessageBus HapticProtocol (SupportsHaptics, GetMotors, SetMotorState, UpdateSingletonVibration). - Wire bridge into RobloxExperienceComposition and direct game runtime. - Call JNI NativeGLInterface.nativeUpdateMobileHapticsState during startup and game completion. - Enable FFlagKeepHapticsOnMobileWhenGamepadConnected and FFlagVRHaptics in VR client settings overrides to bypass gamepad haptic suppression in libroblox. - Directly activate KeepHaptics and VRHaptics fast flag bytes in memory within RobloxVrDeviceBridge::Activate for builds 2998 and 3222. - Check xrApplyHapticFeedback result code and add diagnostic logging.
…ting - Register HapticProtocol and report motors only when MOCKTAIL_VR_ENABLED is on. - Drop the per-message [haptic] dispatch log; log each OpenXR haptic result once per hand. - Write a fast flag only when its name pointer matches the expected name. - Remove the state-sync fallback that dlsym can never resolve.
… of pinning it The Vulkan adapter exports vk* symbols globally, so a runtime loaded again after it bound its Vulkan calls to the adapter and deadlocked the join. Pinning avoided the reload but left SteamVR with its old VkInstance, which aborted the join with "vkGetInstanceProcAddr: Invalid instance". Later instances now load the runtime libraries with RTLD_DEEPBIND and let them unload with their instance.
…m them The Android client drops HapticService:SetMotor on the Gamepad1 LeftHand and RightHand motors: its haptics backend only consumes Large and Small. VR games such as VR Hands drive those motors, so they never vibrated. - Interpose HapticService::SetMotor through its reflection descriptor, call the original, and forward Gamepad1 LeftHand/RightHand to OpenXR. The descriptor and the engine's intensity reader are found by pattern at load, for both the 2998 (tuple span) and 3222 (shared tuple) reader ABIs. The held level renews a 50 ms lease every presented frame. - Report the hand motors at x = -1/+1 in GetMotors. Positional HapticEffects aim at a hand there with a 0.5 radius (VOXEL DESTRUCT 2 does), so at +-0.2 every effect mixed to zero. - Play SetMotorState buffers sample by sample with trailing silence trimmed. Roblox sends 100 x 25 ms look-ahead buffers; taking the peak for the whole buffer turned a short bump into 2.5 s at full strength. - Stop vibrating from the DebugDeviceVR haptic slot. The engine pulls it every frame but with each mix buffer's first sample, held about a second, so it duplicated the buffers as a long buzz. - Enable SupportGenericHapticsOnVR and FixRegisterMotors with the other haptic flags.
# Conflicts: # FAQ.md
The 3092 table had the address of another field in the same registration, so the flag never turned on.
MOCKTAIL_VR_PERF now reports how long the CPU waits in the desktop mirror and in present preparation, and the time between presents, so per-frame stalls outside the XR frame cycle show up in the numbers.
Every frame the CPU waited for the GPU to finish Roblox's whole frame in the desktop mirror, then again for the eye copy, so CPU and GPU work never overlapped. The mirror blit now consumes the guest's present semaphores and signals a per-image semaphore that the present waits on. Present preparation hands remaining waits to the GPU the same way. Eye copies are submitted from a small ring of command buffers and fences and rely on queue order, so the CPU only waits when the GPU is three frames behind or the guest destroys an image a copy still reads. On Monado at 120 Hz with 1280x1440 eyes this removed 2 to 5 ms of waiting per frame and kept the frame rate at 118 to 119 fps instead of 103 to 118. Also free the copy resources when the guest device goes away without a session, so a later device never reuses stale handles.
…sses The frame cycle read the pose source, evidence and mirror settings from the environment every frame. Read them once. Check the thread-local eye request before taking the backend lock, so render passes that are not eye passes do not contend with the frame cycle.
Move the empty wait-and-signal batch into internal::ChainPresentDependencies, like WaitForPresentDependencies, and test that it waits on every present semaphore, signals the replacement, never blocks the CPU, and leaves a failed submit to the guest.
…iting With the eye copies no longer waited for, MOCKTAIL_VR_MIRROR_SHM made the CPU wait for the whole frame before publishing, which cut the frame rate from 117 to 82 fps at 120 Hz. Publish each readback at the next copy, when the GPU has finished it. The external viewer sees each frame one frame later.
vr.mode in config.yaml picks how Nightcap starts: off on the desktop, on in VR, auto in VR only when this user's SteamVR is running and its OpenXR runtime reports a headset. auto never starts SteamVR, and asks its runtime from a short-lived copy of the process so the runtime's libraries do not load before the VR backend arms. vr.enabled still works as on/off, and --vr or --no-vr still override the file for one launch.
Without a headset SteamVR refuses the OpenXR client at xrCreateInstance (VRInitError_Driver_WirelessHmdNotConnected) instead of reporting no system, so say that it usually means no headset is connected. Describe vr.mode in the README, docs/VR.md and the changelog.
Roblox's mouse lock and the RMB camera drag put the window into relative mouse mode with a grab, which locked the cursor inside it while the headset was in use. In VR the controllers aim and the window only mirrors the left eye, so the pointer is never captured and the system cursor stays visible.
Roblox's VR debug device renders both eyes into single-sample textures, so edges were jagged in the headset. When the eyes go to the runtime's swapchain, an FXAA draw now replaces the plain copy. It samples the eye directly, and re-encodes for sRGB swapchains so the guest's bytes round-trip exactly. Anything it cannot set up falls back to the copy. vr.anti_aliasing (fxaa, the default, or off) controls it. The SPIR-V is generated from shaders/vr by scripts/generate_vr_shaders.py and checked in, so builds need no shader compiler; a test checks it against the sources when glslc is installed. On a Quest 2 through SteamVR at 90 Hz (2244x2352 per eye) frame times did not change. Captured output keeps 97 to 98 percent of pixels byte-identical and the average brightness unchanged, and smooths the edges.
Collaborator
Author
|
opened on wrong repo sorry lol |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings the
vrbranch intomain. VR stays opt-in: non-VR launches keep their original paths, and the build works without the OpenXR submodule.VR runtime
vr.modewithon,offandauto, and a clear reason whenautofinds no headsetInput
Roblox builds
Docs and tests
docs/VR.mdcovers setup, supported builds and every VR variable; the FAQ points to it