- C 71.1%
- C++ 22.4%
- CMake 2.8%
- Python 1.9%
- Kotlin 0.6%
- Other 1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
In-headset screenshots (and quiet captures) came out dark and washed out, and could show stale or black content, while the debug-GUI desktop mirror of the very same left-eye scratch image looked right. Two causes in the capture block of comp_renderer_draw: - The readback blit sampled the scratch through its sRGB view, which decodes to linear, into an rgba8 UNORM storage image with no re-encode, so the PNG stored linear bytes. Sample through the UNORM view instead so the sRGB-encoded bytes stay untouched end to end. The debug-GUI readback sink keeps upstream's view. - The request was consumed after the frame was drawn. On a one-projection- layer fast-path frame the scratch image is skipped entirely, so the shot was whatever an older frame left there, or nothing. Claim the request before the render path is chosen and force the layer-squash path for that frame, as the finger-frame overlay already does. Verified with the simulated HMD and hello_xr: the old build produced an all-black capture, the new one the clear colour correctly encoded with no black columns; the quiet capture path is identical. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
| .github/workflows | ||
| .gitlab-ci | ||
| .reuse | ||
| cmake | ||
| dist/portable | ||
| doc | ||
| examples | ||
| gradle/wrapper | ||
| LICENSES | ||
| scripts | ||
| src | ||
| tests | ||
| .clang-format | ||
| .clang-tidy | ||
| .cmake-format.py | ||
| .editorconfig | ||
| .git-blame-ignore-revs | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| .mailmap | ||
| build.gradle | ||
| CMakeLists.txt | ||
| CMakePresets.json | ||
| CMakePresets.json.license | ||
| CompilerFlags.cmake | ||
| CONTRIBUTING.md | ||
| flake.lock | ||
| flake.nix | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| LICENSE | ||
| README.md | ||
| settings.gradle | ||
| vcpkg.json | ||
| vcpkg.json.license | ||
Monado - XR Runtime (XRT)
Quick Install (SteamVR Lighthouse + Envision)
# Build
cmake -B cbuild -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr \
-DXRT_BUILD_DRIVER_STEAMVR_LIGHTHOUSE=ON \
-DXRT_BUILD_DRIVER_SURVIVE=OFF \
-DXRT_BUILD_DRIVER_UDCAP=ON \
-DXRT_FEATURE_GESTURE_DETECTOR=OFF
cmake --build cbuild -j$(nproc)
# Install
sudo cmake --install cbuild
This fork adds UDCAP gloves support and device hotplug for the SteamVR
Lighthouse driver: controllers and trackers are discovered as they are powered
on — including after apps are already running — and appear to OpenXR clients
without a restart. Devices that power off stay listed (append-only, like
SteamVR) and are reported as disconnected, but keep their controller role until
a powered-on device can take it over, so in-game hands hold their last pose
instead of snapping back to the body. To have a powered-off device reported as
untracked instead, so apps can apply their own fallback, set
XRT_HOLD_POSE_WHEN_OFF=0 or flip the switch at runtime through libmonado. When
UDCAP gloves are active they hold the left/right controller roles until real
controllers are powered on, and take them back when the controllers are powered
off.
Note: the HMD must be connected at startup; only controllers, trackers and gloves hotplug. Gloves are picked up at startup only (start udcap-server before Monado).
In-headset screenshots
Capture the rendered view to a PNG from inside VR: hold the trigger and click
the system button on either controller. Images are saved to ~/Pictures/Monado
(created automatically) and a shutter sound plays on capture.
- Captures the left eye, undistorted and uncropped — crop to taste afterwards.
- On-demand and encoded off the render thread, so there is no frame-rate cost.
- A compositor feature: works when Monado is the runtime, not in SteamVR-compositor mode.
Environment overrides (set on whatever launches the Monado service):
MONADO_SCREENSHOT_DIR— output directory (default~/Pictures/Monado).MONADO_SCREENSHOT_SOUND_CMD— command used to play the shutter sound.MONADO_SCREENSHOT_NO_SOUND— set to mute the shutter sound.MONADO_SCREENSHOT_HEIGHT— capture height in pixels (default1080). Set0for full native render resolution. This resizes the shared mirror readback buffer, so larger values also enlarge the debug-GUI desktop mirror — only raise it if you don't mind that cost.
(kill -USR1 <monado-service pid> also triggers a capture — handy for testing
without controllers.)
Finger-frame gesture
Make a "frame" with both hands — thumb and index extended, the other three
fingers curled, the two hands forming opposite corners of a rectangle. Hold it
for the configured delay and a frame outline appears in the headset, previewing
the region about to be captured (it follows your hands, so you can recompose).
Then curl one index finger — left or right, like pressing a shutter — to
take the shot. It's saved cropped to the framed region (a viewfinder),
alongside the others in ~/Pictures/Monado. Driven by hand tracking, so it works
with UDCAP gloves or Valve Index controllers. Disabled by default; build with
-DXRT_FEATURE_GESTURE_DETECTOR=ON to enable it.
Settings live in ~/.config/monado/gestures.json, hot-reloaded while running
(built-in defaults are used if the file is absent):
{
"enabled": true,
"hold_ms": 2000,
"frame_feedback": true,
"debug": false
}
hold_ms is how long the frame must be held before the preview appears and
capture is armed (it no longer fires on its own — you trigger with an index
curl). Set frame_feedback to false to arm silently, without the in-headset
outline.
Controller freeze
Hold one app's controllers in place while every other app and overlay keeps tracking them live. The frozen app sees its hands stay where they were, with no effect on anything else. It is per client, addressed by client id.
Trigger it from libmonado (mnd_root_set_client_controller_freeze) or the
command line:
monado-ctl --freeze <client-id> # hold that client's controllers
monado-ctl --unfreeze <client-id> # resume live tracking
Run monado-ctl with no arguments to list clients and their ids. The symbol is
absent on stock Monado, so tools can detect support before showing freeze UI.
Powered-off controllers: hold or release
By default a controller or tracker that powers off (or loses its pose) keeps serving its last good pose, so in-game hands freeze in place. Switch that off to report it untracked instead, like upstream Monado, so the app can take over (an avatar's own idle or sleeping pose, for example). It applies to every app and takes effect at once, also for devices that are already off. The headset always holds.
monado-ctl --hold-pose=off # report powered-off controllers as untracked
monado-ctl --hold-pose=on # hold their last pose (default)
monado-ctl --hold-pose # print the current mode
libmonado: mnd_root_set_hold_pose_when_off / mnd_root_get_hold_pose_when_off.
The startup default comes from XRT_HOLD_POSE_WHEN_OFF (default true).
Device tracking state
mnd_root_get_device_tracking_state reports whether a device is connected
(powered on; for UDCAP gloves: radio link up) and whether its pose is fully
tracked, so a UI can grey out dead devices that stay in the device list. UDCAP
gloves also report their battery level now.
Device pose
mnd_root_get_device_pose (libmonado 1.10) returns where a device is right now,
in its tracking origin's space, so a tool can measure things like where the
headset sits on the floor.
Room setup without a restart
The SteamVR Lighthouse driver (steamvr_lh) applies SteamVR's room setup
(chaperone_info.vrchap, matched to a universe in lighthousedb.json) to every
pose. It now watches both files while running and re-applies the room setup when
either changes, so a floor calibration written while Monado runs takes effect at
once.
AI usage: The UDCAP, hotplug, in-headset screenshot, finger-frame gesture and controller-freeze, hold-pose, tracking-state, device-pose and room-setup-reload additions in this fork were developed with AI assistance (Anthropic's Claude), under human direction, testing, and review. Upstream Monado is unaffected.
- Main homepage and documentation: https://monado.freedesktop.org/
- Promotional homepage: https://monado.dev
- Maintained at https://gitlab.freedesktop.org/monado/monado
- Latest API documentation: https://monado.pages.freedesktop.org/monado
- Continuously-updated changelog of the default branch: https://monado.pages.freedesktop.org/monado/_c_h_a_n_g_e_l_o_g.html
Monado is an open source XR runtime delivering immersive experiences such as VR and AR on mobile, PC/desktop, and any other device (because gosh darn people come up with a lot of weird hardware). Monado aims to be a complete and conforming implementation of the OpenXR API made by Khronos. The project is primarily developed on GNU/Linux, but also runs on Android and Windows. "Monado" has no specific meaning and is just a name.
Monado source tree
src/xrt/include- headers that define the internal interfaces of Monado.src/xrt/compositor- code for doing distortion and driving the display hardware of a device.src/xrt/auxiliary- utilities and other larger components.src/xrt/drivers- hardware drivers.src/xrt/state_trackers/oxr- OpenXR API implementation.src/xrt/targets- glue code and build logic to produce final binaries.src/external- a small collection of external code and headers.
Getting Started
Dependencies include:
- CMake 3.13 or newer (Note Ubuntu 18.04 only has 3.10)
- Python 3.6 or newer
- Vulkan headers and loader - Fedora package
vulkan-loader-devel - OpenGL headers
- Eigen3 - Debian/Ubuntu package
libeigen3-dev - glslangValidator - Debian/Ubuntu package
glslang-tools, Fedora packageglslang. - libusb
- libudev - Debian/Ubuntu package
libudev-dev, Fedora packagesystemd-devel - Video 4 Linux - Debian/Ubuntu package
libv4l-dev.
Optional (but recommended) dependencies:
- libxcb and xcb-xrandr development packages
- OpenHMD 0.3.0 or newer (found using pkg-config)
Truly optional dependencies, useful for some drivers, app support, etc.:
- Doxygen - Debian/Ubuntu package
doxygenandgraphviz - Wayland development packages
- Xlib development packages
- libhidapi - Debian/Ubuntu package
libhidapi-dev - OpenCV
- libuvc - Debian/Ubuntu package
libuvc-dev - libjpeg
- libbluetooth - Debian/Ubuntu package
libbluetooth-dev - libsdl - Debian/Ubuntu package
libsdl2-dev
Experimental Windows support requires the Vulkan SDK and also needs or works best with the following vcpkg packages installed:
- pthreads eigen3 libusb hidapi zlib doxygen
If you have a recent vcpkg installed and use the appropriate
CMake toolchain file, the vcpkg manifest in the Monado repository will instruct
vcpkg to locally install the dependencies automatically. The Vulkan SDK
installer should set the VULKAN_SDK Windows environment variable to point
at the installation location (for example, C:/VulkanSDK/1.3.250.1), though
make sure you open a new terminal (or open the CMake GUI) after doing that
install to make sure it is available.
Monado has been tested on these distributions, but is expected to work on almost any modern distribution.
- Ubuntu 24.04, 22.04, 20.04, (18.04 may not be fully supported)
- Debian 11
bookworm, 10buster- Up-to-date package lists can be found in our CI config file,
.gitlab-ci.yml
- Up-to-date package lists can be found in our CI config file,
- Archlinux
These distributions include recent-enough versions of all the software to use direct mode, without using any external, third-party, or backported package sources.
See also Status of DRM Leases for more details on specific packages, versions, and commits.
Due to the lack of a OpenGL extension: GL_EXT_memory_object_fd on Intel's OpenGL driver, only the AMD radeonsi driver and the proprietary NVIDIA driver will work for OpenGL OpenXR clients. This is due to a requirement of the Compositor. Support status of the extension can be found on the mesamatrix website.
CMake
Build process is similar to other CMake builds, so something like the following will build it.
Go into the source directory, create a build directory, and change into it.
mkdir build
cd build
Then, invoke CMake to generate a project. Feel free to change the build type or generator ("Ninja" is fast and parallel) as you see fit.
cmake .. -DCMAKE_BUILD_TYPE=Debug -G "Unix Makefiles"
If you plan to install the runtime,
append something like -DCMAKE_INSTALL_PREFIX=~/.local
to specify the root of the install directory.
(The default install prefix is /usr/local.)
To build, the generic CMake build commands below will work on all systems,
though you can manually invoke your build tool (make, ninja, etc.) if you prefer.
The first command builds the runtime and docs,
and the second, which is optional, installs the runtime under ${CMAKE_INSTALL_PREFIX}.
cmake --build .
cmake --build . --target install
Alternately, if using Make, the following will build the runtime and docs, then install.
Replace make with ninja if you used the Ninja generator.
make
make install
Documentation can be browsed by opening doc/html/index.html in the build directory in a web browser.
Getting started using OpenXR with Monado
This implements the OpenXR API,
so to do anything with it, you'll need an application
that uses OpenXR, along with the OpenXR loader.
The OpenXR loader is a glue library that connects OpenXR applications to OpenXR runtimes such as Monado
It determines which runtime to use by looking for the config file active_runtime.json (either a symlink to
or a copy of a runtime manifest) in the usual XDG config paths
and processes environment variables such as XR_RUNTIME_JSON=/usr/share/openxr/0/openxr_monado.json.
It can also insert OpenXR API Layers without the application or the runtime having to do it.
You can use the hello_xr sample provided with the OpenXR SDK.
The OpenXR loader can be pointed to a runtime json file in a nonstandard location with the environment variable XR_RUNTIME_JSON. Example:
XR_RUNTIME_JSON=~/monado/build/openxr_monado-dev.json ./openxr-example
For ease of development Monado creates a runtime manifest file in its build directory using an absolute path to the
Monado runtime in the build directory called openxr_monado-dev.json. Pointing XR_RUNTIME_JSON to this
file allows using Monado after building, without installing.
Note that the loader can always find and load the runtime
if the path to the runtime library given in the json manifest is an absolute path,
but if a relative path like libopenxr_monado.so.0 is given,
then LD_LIBRARY_PATH must include the directory that contains libopenxr_monado.so.0.
The absolute path in openxr_monado-dev.json takes care of this for you.
Distribution packages for monado may provide the "active runtime" file /etc/xdg/openxr/1/active_runtime.json.
In this case the loader will automatically use Monado when starting an OpenXR application. This global configuration
can be overridden on a per user basis by creating ~/.config/openxr/1/active_runtime.json.
Direct mode
On AMD and Intel GPUs our direct mode code requires a connected HMD to have
the non-desktop xrandr property set to 1.
Only the most common HMDs have the needed quirks added to the linux kernel.
If you know that your HMD lacks the quirk you can run this command before or
after connecting the HMD and it will have it. Where HDMI-A-0 is the xrandr
output name where you plug the HMD in.
xrandr --output HDMI-A-0 --prop --set non-desktop 1
You can verify that it stuck with the command.
xrandr --prop
Running Vulkan Validation
To run Monado with Vulkan validation the loader's layer functionality can be used.
VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ./build/src/xrt/targets/service/monado-service
The same can be done when launching a Vulkan client.
If you want a backtrace to be produced at validation errors, create a vk_layer_settings.txt
file with the following content:
khronos_validation.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG,VK_DBG_LAYER_ACTION_BREAK
khronos_validation.report_flags = error,warn
khronos_validation.log_filename = stdout
Coding style and formatting
clang-format is used,
and a .clang-format config file is present in the repo
to allow your editor to use them.
To manually apply clang-format to every non-external source file in the tree,
run this command in the source dir with a sh-compatible shell
(Git for Windows git-bash should be OK):
scripts/format-project.sh
You can optionally put something like CLANG_FORMAT=clang-format-7 before that command
if your clang-format binary isn't named clang-format.
Note that you'll typically prefer to use something like git clang-format
to re-format only your changes, in case version differences in tools result in overall format changes.
The CI "style" job currently runs on Debian Bullseye, so it has clang-format-11.
Contributing, Code of Conduct
See CONTRIBUTING.md for details of contribution guidelines. GitLab Issues and
Merge Requests are the preferred way to discuss problems, suggest enhancements,
or submit changes for review. In case of a security issue, you should choose
the "confidential" option when using the GitLab issues page. For highest
security, you can send encrypted email (using GPG/OpenPGP) to Rylie Pavlik at
rylie.pavlik@collabora.com and using the associated key from
https://keys.openpgp.org/vks/v1/by-fingerprint/45207B2B1E53E1F2755FF63CC5A2D593A61DBC9D.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
We follow the standard freedesktop.org code of conduct, available at https://www.freedesktop.org/wiki/CodeOfConduct/, which is based on the Contributor Covenant.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting:
- First-line project contacts:
- Rylie Pavlik rylie.pavlik@collabora.com
- Frederic Plourde frederic.plourde@collabora.com
- Jakob Bornecrantz tbornecrantz@nvidia.com
- freedesktop.org contacts: see most recent list at https://www.freedesktop.org/wiki/CodeOfConduct/
Code of Conduct section excerpt adapted from the Contributor Covenant, version 1.4.1, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html, and from the freedesktop.org-specific version of that code, available at https://www.freedesktop.org/wiki/CodeOfConduct/, used under CC-BY-4.0.