feat!: enable support for different openvr compatibility modules other than opencomposite
Some checks are pending
/ cargo-fmtcheck (push) Waiting to run
/ cargo-clippy (push) Waiting to run
/ cargo-test (push) Waiting to run
/ appimage (push) Waiting to run

This commit is contained in:
Gabriele Musco 2024-12-04 20:32:36 +01:00
parent 4ea0ce53b0
commit e685cf757d
13 changed files with 219 additions and 45 deletions

View file

@ -19,13 +19,15 @@ pub fn get_build_opencomposite_jobs(profile: &Profile, clean_build: bool) -> Vec
let git = Git {
repo: profile
.opencomposite_repo
.ovr_comp
.repo
.as_ref()
.unwrap_or(&"https://gitlab.com/znixian/OpenOVR.git".into())
.clone(),
dir: profile.opencomposite_path.clone(),
dir: profile.ovr_comp.path.clone(),
branch: profile
.opencomposite_branch
.ovr_comp
.branch
.as_ref()
.unwrap_or(&"openxr".into())
.clone(),
@ -33,14 +35,14 @@ pub fn get_build_opencomposite_jobs(profile: &Profile, clean_build: bool) -> Vec
jobs.extend(git.get_pre_build_jobs(profile.pull_on_build));
let build_dir = profile.opencomposite_path.join("build");
let build_dir = profile.ovr_comp.path.join("build");
let mut cmake_vars: HashMap<String, String> = HashMap::new();
cmake_vars.insert("CMAKE_EXPORT_COMPILE_COMMANDS".into(), "ON".into());
cmake_vars.insert("CMAKE_BUILD_TYPE".into(), "RelWithDebInfo".into());
let cmake = Cmake {
env: None,
vars: Some(cmake_vars),
source_dir: profile.opencomposite_path.clone(),
source_dir: profile.ovr_comp.path.clone(),
build_dir: build_dir.clone(),
};
if !Path::new(&build_dir).is_dir() || clean_build {

View file

@ -65,10 +65,42 @@ impl Config {
}
fn from_path(path: &Path) -> Self {
File::open(path)
let mut this: Self = File::open(path)
.ok()
.and_then(|file| serde_json::from_reader(BufReader::new(file)).ok())
.unwrap_or_default()
.unwrap_or_default();
let mut needs_save = false;
// remap legacy opencomposite data to new ovr_comp
#[allow(deprecated)]
for prof in this.user_profiles.iter_mut() {
if prof
.ovr_comp
.path
.file_name()
.unwrap_or_default()
.to_string_lossy()
== "__envision__fallbackovrcomp"
{
prof.ovr_comp.path = prof.opencomposite_path.clone();
needs_save = true;
}
if prof.opencomposite_repo.is_some() && prof.ovr_comp.repo.is_none() {
prof.ovr_comp.repo = prof.opencomposite_repo.take();
needs_save = true;
}
if prof.opencomposite_branch.is_some() && prof.ovr_comp.branch.is_none() {
prof.ovr_comp.branch = prof.opencomposite_branch.take();
needs_save = true;
}
}
if needs_save {
this.save_to_path(path).expect("Failed to save config");
}
this
}
fn save_to_path(&self, path: &Path) -> Result<(), serde_json::Error> {

View file

@ -98,7 +98,7 @@ pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths {
external_drivers: None,
jsonid: "vrpathreg".into(),
log: vec![datadir.join("Steam/logs")],
runtime: vec![profile.opencomposite_path.join("build")],
runtime: vec![profile.ovr_comp.path.join("build")],
version: 1,
}
}

View file

@ -17,6 +17,7 @@ use std::{
io::BufReader,
path::{Path, PathBuf},
slice::Iter,
str::FromStr,
};
use uuid::Uuid;
@ -258,6 +259,78 @@ impl Display for LighthouseDriver {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum OvrCompatibilityModuleType {
#[default]
Opencomposite,
}
impl Display for OvrCompatibilityModuleType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Opencomposite => "OpenComposite",
})
}
}
impl OvrCompatibilityModuleType {
pub fn iter() -> Iter<'static, Self> {
[Self::Opencomposite].iter()
}
}
impl FromStr for OvrCompatibilityModuleType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().trim() {
"opencomposite" => Ok(Self::Opencomposite),
_ => Err(format!("no match for ovr compatibility module `{s}`")),
}
}
}
impl From<u32> for OvrCompatibilityModuleType {
fn from(value: u32) -> Self {
match value {
0 => Self::Opencomposite,
_ => panic!("OvrCompatibilityModuleType index out of bounds"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ProfileOvrCompatibilityModule {
pub mod_type: OvrCompatibilityModuleType,
pub repo: Option<String>,
pub branch: Option<String>,
pub path: PathBuf,
}
impl ProfileOvrCompatibilityModule {
fn default_for_uuid(uuid: &str) -> Self {
let mod_type = OvrCompatibilityModuleType::default();
Self {
mod_type,
repo: None,
branch: None,
path: get_data_dir().join(uuid).join(mod_type.to_string()),
}
}
}
impl Default for ProfileOvrCompatibilityModule {
fn default() -> Self {
let mod_type = OvrCompatibilityModuleType::default();
Self {
mod_type,
repo: None,
branch: None,
path: get_data_dir().join("__envision__fallbackovrcomp"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Profile {
pub uuid: String,
@ -268,9 +341,15 @@ pub struct Profile {
pub xrservice_branch: Option<String>,
#[serde(default = "HashMap::<String, String>::default")]
pub xrservice_cmake_flags: HashMap<String, String>,
#[deprecated]
#[serde(default)]
pub opencomposite_path: PathBuf,
#[deprecated]
pub opencomposite_repo: Option<String>,
#[deprecated]
pub opencomposite_branch: Option<String>,
#[serde(default)]
pub ovr_comp: ProfileOvrCompatibilityModule,
pub features: ProfileFeatures,
pub environment: HashMap<String, String>,
/// Install prefix
@ -295,6 +374,7 @@ impl Display for Profile {
}
impl Default for Profile {
#[allow(deprecated)]
fn default() -> Self {
let uuid = Self::new_uuid();
let profile_dir = get_data_dir().join(&uuid);
@ -330,12 +410,13 @@ impl Default for Profile {
mercury_enabled: false,
},
environment: HashMap::new(),
prefix: get_data_dir().join("prefixes").join(&uuid),
prefix: Self::default_prefix_path(&uuid),
can_be_built: true,
pull_on_build: true,
opencomposite_path: profile_dir.join("opencomposite"),
opencomposite_repo: None,
opencomposite_branch: None,
ovr_comp: ProfileOvrCompatibilityModule::default_for_uuid(&uuid),
editable: true,
lighthouse_driver: LighthouseDriver::default(),
xrservice_launch_options: String::default(),
@ -347,6 +428,10 @@ impl Default for Profile {
}
impl Profile {
fn default_prefix_path(uuid: &str) -> PathBuf {
get_data_dir().join("prefixes").join(uuid)
}
pub fn xr_runtime_json_env_var(&self) -> String {
format!(
"XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"",
@ -424,8 +509,8 @@ impl Profile {
}
let uuid = Self::new_uuid();
let profile_dir = get_data_dir().join(&uuid);
#[allow(deprecated)]
let mut dup = Self {
uuid,
name: format!("Duplicate of {}", self.name),
xrservice_type: self.xrservice_type.clone(),
xrservice_repo: self.xrservice_repo.clone(),
@ -465,7 +550,16 @@ impl Profile {
opencomposite_path: profile_dir.join("opencomposite"),
skip_dependency_check: self.skip_dependency_check,
xrservice_launch_options: self.xrservice_launch_options.clone(),
..Default::default()
prefix: Self::default_prefix_path(&uuid),
ovr_comp: ProfileOvrCompatibilityModule {
mod_type: self.ovr_comp.mod_type,
repo: self.ovr_comp.repo.clone(),
branch: self.ovr_comp.branch.clone(),
path: profile_dir.join(self.ovr_comp.mod_type.to_string()),
},
can_be_built: self.can_be_built,
editable: true,
uuid,
};
if dup.environment.contains_key("LD_LIBRARY_PATH") {
dup.environment.insert(
@ -612,7 +706,10 @@ mod tests {
path::{Path, PathBuf},
};
use crate::profile::{ProfileFeature, ProfileFeatureType, ProfileFeatures, XRServiceType};
use crate::profile::{
OvrCompatibilityModuleType, ProfileFeature, ProfileFeatureType, ProfileFeatures,
ProfileOvrCompatibilityModule, XRServiceType,
};
use super::Profile;
@ -622,7 +719,7 @@ mod tests {
assert_eq!(profile.name, "Demo profile");
assert_eq!(profile.xrservice_path, PathBuf::from("/home/user/monado"));
assert_eq!(
profile.opencomposite_path,
profile.ovr_comp.path,
PathBuf::from("/home/user/opencomposite")
);
assert_eq!(profile.prefix, PathBuf::from("/home/user/envisionprefix"));
@ -653,7 +750,12 @@ mod tests {
name: "Demo profile".into(),
xrservice_path: PathBuf::from("/home/user/monado"),
xrservice_type: XRServiceType::Monado,
opencomposite_path: PathBuf::from("/home/user/opencomposite"),
ovr_comp: ProfileOvrCompatibilityModule {
path: PathBuf::from("/home/user/opencomposite"),
repo: None,
branch: None,
mod_type: OvrCompatibilityModuleType::default(),
},
features: ProfileFeatures {
libsurvive: ProfileFeature {
feature_type: ProfileFeatureType::Libsurvive,

View file

@ -1,7 +1,10 @@
use crate::{
constants::APP_NAME,
paths::{data_monado_path, data_opencomposite_path, get_data_dir},
profile::{prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeatures, XRServiceType},
profile::{
prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeatures,
ProfileOvrCompatibilityModule, XRServiceType,
},
};
use std::collections::HashMap;
@ -21,7 +24,10 @@ pub fn lighthouse_profile() -> Profile {
name: format!("Lighthouse Driver - {name} Default", name = APP_NAME),
xrservice_path: data_monado_path(),
xrservice_type: XRServiceType::Monado,
opencomposite_path: data_opencomposite_path(),
ovr_comp: ProfileOvrCompatibilityModule {
path: data_opencomposite_path(),
..Default::default()
},
features: ProfileFeatures::default(),
environment,
prefix,

View file

@ -3,7 +3,7 @@ use crate::{
paths::{data_monado_path, data_opencomposite_path, data_openhmd_path, get_data_dir},
profile::{
prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType,
ProfileFeatures, XRServiceType,
ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType,
},
};
use std::collections::HashMap;
@ -24,7 +24,10 @@ pub fn openhmd_profile() -> Profile {
name: format!("OpenHMD - {name} Default", name = APP_NAME),
xrservice_path: data_monado_path(),
xrservice_type: XRServiceType::Monado,
opencomposite_path: data_opencomposite_path(),
ovr_comp: ProfileOvrCompatibilityModule {
path: data_opencomposite_path(),
..Default::default()
},
features: ProfileFeatures {
openhmd: ProfileFeature {
feature_type: ProfileFeatureType::OpenHmd,

View file

@ -1,7 +1,7 @@
use crate::{
constants::APP_NAME,
paths::{data_monado_path, data_opencomposite_path, get_data_dir},
profile::{Profile, ProfileFeatures, XRServiceType},
profile::{Profile, ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType},
};
use std::collections::HashMap;
@ -25,7 +25,10 @@ pub fn simulated_profile() -> Profile {
name: format!("Simulated Driver - {name} Default", name = APP_NAME),
xrservice_path: data_monado_path(),
xrservice_type: XRServiceType::Monado,
opencomposite_path: data_opencomposite_path(),
ovr_comp: ProfileOvrCompatibilityModule {
path: data_opencomposite_path(),
..Default::default()
},
features: ProfileFeatures::default(),
environment,
prefix,

View file

@ -3,7 +3,7 @@ use crate::{
paths::{data_libsurvive_path, data_monado_path, data_opencomposite_path, get_data_dir},
profile::{
prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType,
ProfileFeatures, XRServiceType,
ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType,
},
};
use std::collections::HashMap;
@ -26,7 +26,10 @@ pub fn survive_profile() -> Profile {
name: format!("Survive - {name} Default", name = APP_NAME),
xrservice_path: data_monado_path(),
xrservice_type: XRServiceType::Monado,
opencomposite_path: data_opencomposite_path(),
ovr_comp: ProfileOvrCompatibilityModule {
path: data_opencomposite_path(),
..Default::default()
},
features: ProfileFeatures {
libsurvive: ProfileFeature {
feature_type: ProfileFeatureType::Libsurvive,

View file

@ -1,7 +1,10 @@
use crate::{
constants::APP_NAME,
paths::{data_opencomposite_path, data_wivrn_path, get_data_dir},
profile::{prepare_ld_library_path, Profile, ProfileFeatures, XRServiceType},
profile::{
prepare_ld_library_path, Profile, ProfileFeatures, ProfileOvrCompatibilityModule,
XRServiceType,
},
};
use std::collections::HashMap;
@ -18,7 +21,10 @@ pub fn wivrn_profile() -> Profile {
name: format!("WiVRn - {name} Default", name = APP_NAME),
xrservice_path: data_wivrn_path(),
xrservice_type: XRServiceType::Wivrn,
opencomposite_path: data_opencomposite_path(),
ovr_comp: ProfileOvrCompatibilityModule {
path: data_opencomposite_path(),
..Default::default()
},
features: ProfileFeatures {
..Default::default()
},

View file

@ -3,7 +3,7 @@ use crate::{
paths::{data_basalt_path, data_monado_path, data_opencomposite_path, get_data_dir},
profile::{
prepare_ld_library_path, LighthouseDriver, Profile, ProfileFeature, ProfileFeatureType,
ProfileFeatures, XRServiceType,
ProfileFeatures, ProfileOvrCompatibilityModule, XRServiceType,
},
};
use std::collections::HashMap;
@ -24,7 +24,10 @@ pub fn wmr_profile() -> Profile {
name: format!("WMR - {name} Default", name = APP_NAME),
xrservice_path: data_monado_path(),
xrservice_type: XRServiceType::Monado,
opencomposite_path: data_opencomposite_path(),
ovr_comp: ProfileOvrCompatibilityModule {
path: data_opencomposite_path(),
..Default::default()
},
features: ProfileFeatures {
basalt: ProfileFeature {
feature_type: ProfileFeatureType::Basalt,

View file

@ -36,7 +36,7 @@ use crate::{
linux_distro::LinuxDistro,
openxr_prober::is_openxr_ready,
paths::get_data_dir,
profile::{Profile, XRServiceType},
profile::{OvrCompatibilityModuleType, Profile, XRServiceType},
stateless_action,
steam_linux_runtime_injector::{
restore_runtime_entrypoint, set_runtime_entrypoint_launch_opts_from_profile,
@ -486,7 +486,11 @@ impl AsyncComponent for App {
XRServiceType::Wivrn => get_build_wivrn_jobs(&profile, clean_build),
});
}
jobs.extend(get_build_opencomposite_jobs(&profile, clean_build));
jobs.extend(match profile.ovr_comp.mod_type {
OvrCompatibilityModuleType::Opencomposite => {
get_build_opencomposite_jobs(&profile, clean_build)
}
});
let missing_deps = profile.missing_dependencies();
if !(self.skip_depcheck || profile.skip_dependency_check || missing_deps.is_empty())
{

View file

@ -6,7 +6,7 @@ use super::{
};
use crate::{
env_var_descriptions::ENV_VAR_DESCRIPTIONS_AS_PARAGRAPH,
profile::{LighthouseDriver, Profile, XRServiceType},
profile::{LighthouseDriver, OvrCompatibilityModuleType, Profile, XRServiceType},
};
use adw::prelude::*;
use gtk::glib::{self, clone};
@ -216,31 +216,43 @@ impl SimpleComponent for ProfileEditor {
),
},
add: model.xrservice_cmake_flags_rows.widget(),
add: opencompgrp = &adw::PreferencesGroup {
set_title: "OpenComposite",
set_description: Some("OpenVR driver built on top of OpenXR"),
add: ovr_comp_grp = &adw::PreferencesGroup {
set_title: "OpenVR Compatibility",
set_description: Some("OpenVR compatibility module, translates between OpenXR and OpenVR to run legacy OpenVR apps"),
add: &combo_row(
"OpenVR Module Type",
None,
model.profile.borrow().ovr_comp.mod_type.to_string().as_str(),
OvrCompatibilityModuleType::iter()
.map(OvrCompatibilityModuleType::to_string)
.collect::<Vec<String>>(),
clone!(#[strong] prof, move |row| {
prof.borrow_mut().ovr_comp.mod_type =
OvrCompatibilityModuleType::from(row.selected());
}),
),
add: &path_row(
"OpenComposite Path", None,
Some(model.profile.borrow().opencomposite_path.clone().to_string_lossy().to_string()),
"OpenVR Module Path", None,
Some(model.profile.borrow().ovr_comp.path.clone().to_string_lossy().to_string()),
Some(init.root_win.clone()),
clone!(#[strong] prof, move |n_path| {
prof.borrow_mut().opencomposite_path = n_path.unwrap_or_default().into();
prof.borrow_mut().ovr_comp.path = n_path.unwrap_or_default().into();
})
),
add: &entry_row(
"OpenComposite Repo",
model.profile.borrow().opencomposite_repo.clone().unwrap_or_default().as_str(),
"OpenVR Compatibility Repo",
model.profile.borrow().ovr_comp.repo.clone().unwrap_or_default().as_str(),
clone!(#[strong] prof, move |row| {
let n_val = row.text().to_string();
prof.borrow_mut().opencomposite_repo = (!n_val.is_empty()).then_some(n_val);
prof.borrow_mut().ovr_comp.repo = (!n_val.is_empty()).then_some(n_val);
})
),
add: &entry_row(
"OpenComposite Branch",
model.profile.borrow().opencomposite_branch.clone().unwrap_or_default().as_str(),
"OpenVR Compatibility Branch",
model.profile.borrow().ovr_comp.branch.clone().unwrap_or_default().as_str(),
clone!(#[strong] prof, move |row| {
let n_val = row.text().to_string();
prof.borrow_mut().opencomposite_branch = (!n_val.is_empty()).then_some(n_val);
prof.borrow_mut().ovr_comp.branch = (!n_val.is_empty()).then_some(n_val);
})
),
},

View file

@ -5,9 +5,7 @@
"xrservice_path": "/home/user/monado",
"xrservice_repo": null,
"xrservice_branch": null,
"opencomposite_path": "/home/user/opencomposite",
"opencomposite_repo": null,
"opencomposite_branch": null,
"ovr_comp": { "mod_type": "Opencomposite", "path": "/home/user/opencomposite", "repo": null, "branch": null },
"features": {
"libsurvive": {
"feature_type": "Libsurvive",
@ -34,4 +32,4 @@
"can_be_built": true,
"editable": true,
"pull_on_build": true
}
}