Skip to content

Commit 0fe1393

Browse files
authored
feat(xr-tools): fix linker, try creating headless session (#136)
Makes xr-tools actually work properly
1 parent 0a9761d commit 0fe1393

File tree

9 files changed

+151
-38
lines changed

9 files changed

+151
-38
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ for the application binaries, because they are not yet usable by end-users. You
8282
still need to set up monado, for which you should consult the [linux VR
8383
wiki][lvra]
8484

85+
### Windows
86+
87+
- Install llvm: `winget install -i --id=LLVM.LLVM -e`. Be sure to select the
88+
option to set the PATH for all users. Then, set the `LIBCLANG_PATH` to
89+
`C:\Program Files\LLVM\bin` or whatever the base path was that you installed.
90+
Note: in addition to needing libclang, we use lld-link.exe instead of link.exe
91+
because it plays slightly nicer with Linux -> Windows cross compilation.
92+
8593
[workspace inheritance]: https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table
8694
[vscode fmt]: https://stackoverflow.com/a/54665086
8795
[rustrover fmt]: https://www.jetbrains.com/help/rust/rustfmt.html#rustfmt-on-save

Cargo.lock

Lines changed: 24 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ bevy = "0.17"
1919
openxr = "0.21.0"
2020
clap = { version = "4.5.54", features = ["derive"] }
2121
tracing = "0.1.44"
22-
tracing-subscriber = "0.3.22"
22+
tracing-subscriber = { version = "0.3.22", features = ["env-filter"] }
2323
owo-colors = "4.2.3"
2424

2525
# nx dependencies
2626
nx-core.path = "internal/core"
2727

28+
[patch.crates-io.openxr]
29+
git = "https://github.com/Ralith/openxrs"
30+
rev = "193b76ac2cb5eeefb78f5f7d8ab7b76a805c546f" # TODO: use crates once released.
31+
2832
[profile.release]
2933
lto = true
3034
codegen-units = 1

apps/xr-tools/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "nx-xr-tools"
2+
name = "xr-tools"
33
version = "0.0.0"
44
description = "Miscellaneous XR Tools"
55

@@ -12,7 +12,7 @@ rust-version.workspace = true
1212
workspace = true
1313

1414
[dependencies]
15-
openxr = { workspace = true, features = ["linked"] }
15+
openxr = { workspace = true, features = ["static"] }
1616
clap.workspace = true
1717
color-eyre.workspace = true
1818
tracing.workspace = true

apps/xr-tools/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ mod openxr;
33
use clap::Parser;
44
use color_eyre::Result;
55
use tracing::info;
6+
use tracing_subscriber::EnvFilter;
67

78
#[derive(Parser, Debug)]
89
#[clap(about)]
@@ -21,6 +22,7 @@ impl Args {
2122
fn main() -> Result<()> {
2223
color_eyre::install()?;
2324
tracing_subscriber::fmt()
25+
.with_env_filter(EnvFilter::from_default_env())
2426
.with_writer(std::io::stderr)
2527
.init();
2628
let args = Args::parse();

apps/xr-tools/src/openxr.rs

Lines changed: 107 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use clap::Parser;
22
use color_eyre::{Result, eyre::Context, owo_colors::OwoColorize};
3-
use tracing::debug;
3+
use openxr::{
4+
ApplicationInfo, ExtensionSet, FormFactor, FrameStream, FrameWaiter, Graphics,
5+
Headless, Session, headless::SessionCreateInfo as HeadlessSessionCreateInfo,
6+
};
7+
use tracing::{debug, error, info};
48

59
#[derive(Debug, Parser)]
610
pub struct Args {
@@ -20,30 +24,120 @@ struct InfoArgs {}
2024

2125
impl InfoArgs {
2226
fn run(self, entry: ::openxr::Entry) -> Result<()> {
23-
println!("{}", "layers:".bold());
24-
for layer in entry
27+
let mut layers = entry
2528
.enumerate_layers()
26-
.wrap_err("failed to enumerate layers")?
27-
{
28-
println!("layer: {layer:?}");
29+
.wrap_err("failed to enumerate layers")?;
30+
layers.sort_by_key(|l| l.layer_name.to_owned());
31+
println!("{}", "layers:".bold());
32+
for layer in layers {
33+
let name = &layer.layer_name;
34+
println!(
35+
"- {} v{}: spec version: {}, desc: {}",
36+
name, layer.layer_version, layer.spec_version, layer.description
37+
);
38+
39+
let extensions =
40+
entry.enumerate_layer_extensions(name).wrap_err_with(|| {
41+
format!("failed to enumerate layer extensions for layer {name}")
42+
})?;
43+
let mut extension_names: Vec<_> = extensions
44+
.names()
45+
.into_iter()
46+
.map(String::from_utf8_lossy)
47+
.collect();
48+
extension_names.sort();
49+
for ext_name in extension_names {
50+
println!(" - {ext_name}");
51+
}
2952
}
3053

31-
let extensions = entry
54+
let supported_extensions = entry
3255
.enumerate_extensions()
3356
.wrap_err("failed to enumerate extensions")?;
57+
let mut names: Vec<_> = supported_extensions
58+
.names()
59+
.into_iter()
60+
.map(String::from_utf8_lossy)
61+
.collect();
62+
names.sort();
3463
println!("{}", "extensions:".bold());
35-
for name in extensions.names() {
36-
let name = std::ffi::CStr::from_bytes_with_nul(name)
37-
.wrap_err("encountered name that was not a CStr")?;
38-
let name = std::str::from_utf8(name.to_bytes())
39-
.wrap_err("encountered name that was not UTF-8")?;
40-
println!("{name}");
64+
for name in names {
65+
println!("- {name}");
66+
}
67+
68+
let mut requested_extensions = ExtensionSet::default();
69+
requested_extensions.mnd_headless = supported_extensions.mnd_headless;
70+
let mk_instance = move |ext| {
71+
entry
72+
.create_instance(
73+
&ApplicationInfo {
74+
application_name: "xr-tools",
75+
..Default::default()
76+
},
77+
&ext,
78+
&[],
79+
)
80+
.wrap_err("failed to create openxr instance")
81+
};
82+
83+
let instance = match mk_instance(requested_extensions.clone()) {
84+
Ok(i) => i,
85+
Err(err) => {
86+
error!("failed to create instance with headless extension: {err}");
87+
info!("attempting again but this time with no extensions");
88+
requested_extensions = ExtensionSet::default();
89+
mk_instance(requested_extensions.clone())?
90+
}
91+
};
92+
debug!("created openxr instance");
93+
94+
let runtime_properties = instance
95+
.properties()
96+
.wrap_err("failed to get runtime properties from instance")?;
97+
println!(
98+
"{} {}, {} {}",
99+
"runtime:".bold(),
100+
runtime_properties.runtime_name,
101+
"version:".bold(),
102+
runtime_properties.runtime_version
103+
);
104+
105+
let hmd_system_id = instance
106+
.system(FormFactor::HEAD_MOUNTED_DISPLAY)
107+
.wrap_err("failed to get SystemID for HEAD_MOUNTED_DISPLAY form factor")?;
108+
let hmd_properties = instance
109+
.system_properties(hmd_system_id)
110+
.wrap_err("failed to get system properties for HMD")?;
111+
println!("{hmd_properties:#?}");
112+
113+
// SAFETY: Headless sessions have no special safety requirements
114+
if requested_extensions.mnd_headless {
115+
info!("press enter key to open xr session with headless graphics...");
116+
std::io::stdin().read_line(&mut String::new()).unwrap();
117+
let (session, frame_waiter, frame_stream) = unsafe {
118+
instance.create_session::<Headless>(
119+
hmd_system_id,
120+
&HeadlessSessionCreateInfo {},
121+
)
122+
}
123+
.wrap_err("failed to create headless session")?;
124+
debug!("created headless session");
125+
do_session(session, frame_waiter, frame_stream)?;
41126
}
42127

43128
Ok(())
44129
}
45130
}
46131

132+
fn do_session<G: Graphics>(
133+
_session: Session<G>,
134+
_frame_waiter: FrameWaiter,
135+
_frame_stream: FrameStream<G>,
136+
) -> Result<()> {
137+
// TODO: Query devices
138+
Ok(())
139+
}
140+
47141
impl Args {
48142
pub fn run(self) -> Result<()> {
49143
let entry = if self.static_loader {

deny.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,5 @@ unknown-git = "deny"
6464
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
6565
# please don't make this list any longer qwq
6666
allow-git = [
67-
"https://github.com/Schmarni-Dev/bevy-suis",
68-
"https://github.com/awtterpip/bevy_oxr",
69-
"https://github.com/unavi-xyz/bevy_vr_controller",
70-
"https://github.com/Schmarni-Dev/bevy_spatial_egui",
71-
"https://github.com/Schmarni-Dev/schminput"
67+
"https://github.com/Ralith/openxrs",
7268
]

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[toolchain]
22
channel = "1.92.0" # See workspace Cargo.toml
3-
components = ["rust-src", "rust-analyzer"]
3+
components = ["rust-src", "rust-analyzer", "rustfmt", "clippy"]
44
profile = "default"
55
targets = ["x86_64-pc-windows-msvc", "aarch64-apple-darwin", "aarch64-unknown-linux-gnu", "x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]

0 commit comments

Comments
 (0)