2021-05-09 03:50:54 -05:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
use pkg_config;
|
2020-06-06 15:00:49 -05:00
|
|
|
use std::{env, path::PathBuf};
|
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
fn get_ffmpeg_path() -> PathBuf {
|
|
|
|
let ffmpeg_path = alvr_filesystem::deps_dir()
|
|
|
|
.join(if cfg!(target_os = "linux") {
|
|
|
|
"linux"
|
|
|
|
} else {
|
|
|
|
"windows"
|
|
|
|
})
|
|
|
|
.join("ffmpeg");
|
|
|
|
|
|
|
|
if cfg!(target_os = "linux") {
|
|
|
|
ffmpeg_path.join("alvr_build")
|
2022-05-11 06:39:04 -05:00
|
|
|
} else {
|
2022-09-21 15:55:06 -05:00
|
|
|
ffmpeg_path
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "local_ffmpeg")]
|
|
|
|
fn do_ffmpeg_config(build: &mut cc::Build) {
|
|
|
|
let ffmpeg_path = get_ffmpeg_path();
|
2021-05-09 03:50:54 -05:00
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
assert!(ffmpeg_path.join("include").exists());
|
|
|
|
build.include(ffmpeg_path.join("include"));
|
|
|
|
|
|
|
|
#[cfg(all(feature = "gpl", target_os = "linux"))]
|
2021-05-09 03:50:54 -05:00
|
|
|
{
|
2022-09-21 15:55:06 -05:00
|
|
|
let ffmpeg_pkg_path = ffmpeg_path.join("lib").join("pkgconfig");
|
2022-05-11 05:36:16 -05:00
|
|
|
assert!(ffmpeg_pkg_path.exists());
|
2022-05-11 06:39:04 -05:00
|
|
|
|
2022-05-11 05:36:16 -05:00
|
|
|
let ffmpeg_pkg_path = ffmpeg_pkg_path.to_string_lossy().to_string();
|
|
|
|
env::set_var(
|
|
|
|
"PKG_CONFIG_PATH",
|
2022-05-11 06:39:04 -05:00
|
|
|
env::var("PKG_CONFIG_PATH").map_or(ffmpeg_pkg_path.clone(), |old| {
|
|
|
|
format!("{ffmpeg_pkg_path}:{old}")
|
|
|
|
}),
|
2022-05-11 05:36:16 -05:00
|
|
|
);
|
2021-05-09 03:50:54 -05:00
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
let pkg = pkg_config::Config::new().cargo_metadata(false).to_owned();
|
|
|
|
|
|
|
|
let avutil = pkg.probe("libavutil").unwrap();
|
|
|
|
let avfilter = pkg.probe("libavfilter").unwrap();
|
|
|
|
let avcodec = pkg.probe("libavcodec").unwrap();
|
|
|
|
let swscale = pkg.probe("libswscale").unwrap();
|
2021-05-09 03:50:54 -05:00
|
|
|
|
|
|
|
build
|
|
|
|
.define("AVCODEC_MAJOR", avcodec.version.split(".").next().unwrap())
|
|
|
|
.define("AVUTIL_MAJOR", avutil.version.split(".").next().unwrap())
|
|
|
|
.define(
|
|
|
|
"AVFILTER_MAJOR",
|
|
|
|
avfilter.version.split(".").next().unwrap(),
|
|
|
|
)
|
|
|
|
.define("SWSCALE_MAJOR", swscale.version.split(".").next().unwrap());
|
|
|
|
|
|
|
|
// activate dlopen for libav libraries
|
|
|
|
build
|
|
|
|
.define("LIBRARY_LOADER_AVCODEC_LOADER_H_DLOPEN", None)
|
|
|
|
.define("LIBRARY_LOADER_AVUTIL_LOADER_H_DLOPEN", None)
|
|
|
|
.define("LIBRARY_LOADER_AVFILTER_LOADER_H_DLOPEN", None)
|
|
|
|
.define("LIBRARY_LOADER_SWSCALE_LOADER_H_DLOPEN", None);
|
|
|
|
|
|
|
|
println!("cargo:rustc-link-lib=dl");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
fn do_ffmpeg_config_post() {
|
|
|
|
if cfg!(feature = "local_ffmpeg") {
|
|
|
|
// TODO: cfg!(feature = "gpl") - switch to static linking
|
|
|
|
let kind = if false { "static" } else { "dylib" };
|
2022-02-18 15:05:02 -06:00
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
let ffmpeg_path = get_ffmpeg_path();
|
|
|
|
let ffmpeg_lib_path = ffmpeg_path.join("lib");
|
|
|
|
assert!(ffmpeg_lib_path.exists());
|
2022-02-18 15:05:02 -06:00
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
println!(
|
|
|
|
"cargo:rustc-link-search=native={}",
|
|
|
|
ffmpeg_lib_path.to_string_lossy()
|
|
|
|
);
|
|
|
|
|
|
|
|
println!("cargo:rustc-link-lib={}=avutil", kind);
|
|
|
|
println!("cargo:rustc-link-lib={}=avfilter", kind);
|
|
|
|
println!("cargo:rustc-link-lib={}=avcodec", kind);
|
|
|
|
println!("cargo:rustc-link-lib={}=swscale", kind);
|
|
|
|
} else {
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
{
|
|
|
|
let pkg = pkg_config::Config::new().to_owned();
|
|
|
|
|
|
|
|
pkg.probe("libavutil").unwrap();
|
|
|
|
pkg.probe("libavfilter").unwrap();
|
|
|
|
pkg.probe("libavcodec").unwrap();
|
|
|
|
pkg.probe("libswscale").unwrap();
|
|
|
|
}
|
|
|
|
}
|
2022-02-18 15:05:02 -06:00
|
|
|
}
|
|
|
|
|
2020-06-06 15:00:49 -05:00
|
|
|
fn main() {
|
|
|
|
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
|
|
let cpp_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("cpp");
|
|
|
|
|
2021-03-14 14:00:25 -05:00
|
|
|
#[cfg(windows)]
|
|
|
|
let platform = "cpp/platform/win32";
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
let platform = "cpp/platform/linux";
|
2021-08-02 17:59:01 -05:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
let platform = "cpp/platform/macos";
|
2021-03-14 14:00:25 -05:00
|
|
|
|
|
|
|
let common_iter = walkdir::WalkDir::new("cpp")
|
2020-06-06 15:00:49 -05:00
|
|
|
.into_iter()
|
2021-03-14 14:00:25 -05:00
|
|
|
.filter_entry(|entry| entry.file_name() != "tools" && entry.file_name() != "platform");
|
|
|
|
|
|
|
|
let platform_iter = walkdir::WalkDir::new(platform).into_iter();
|
|
|
|
|
|
|
|
let cpp_paths = common_iter
|
|
|
|
.chain(platform_iter)
|
2020-06-06 15:00:49 -05:00
|
|
|
.filter_map(|maybe_entry| maybe_entry.ok())
|
|
|
|
.map(|entry| entry.into_path())
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
let source_files_paths = cpp_paths.iter().filter(|path| {
|
|
|
|
path.extension()
|
|
|
|
.filter(|ext| {
|
|
|
|
let ext_str = ext.to_string_lossy();
|
|
|
|
ext_str == "c" || ext_str == "cpp"
|
|
|
|
})
|
|
|
|
.is_some()
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut build = cc::Build::new();
|
|
|
|
build
|
|
|
|
.cpp(true)
|
|
|
|
.files(source_files_paths)
|
2021-03-14 14:00:25 -05:00
|
|
|
.flag_if_supported("-isystemcpp/openvr/headers") // silences many warnings from openvr headers
|
|
|
|
.flag_if_supported("-std=c++17")
|
2020-06-06 15:00:49 -05:00
|
|
|
.include("cpp/openvr/headers")
|
2021-03-14 14:00:25 -05:00
|
|
|
.include("cpp");
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
build
|
Vulkan based linux port (#604)
* Vulkan based linux port
This version replaces the "screen grab" version.
The mechanism is based on frame capture in vrcompositor process, which
are then shared with vrserver process, encoded there and transmitted to
the headset.
A vulkan layer is added to vrcompositor, this layer exposes the
VK_EXT_direct_mode_display, VK_EXT_acquire_xlib_display and some other
related vulkan functions. Functions implemented in the layer add one
display to the list naturally returned by the driver, this display
matches properties in ALVR settings (resolution and refresh rate), and
all functions required by SteamVR are implemented (xlib acquire,
properties enumeration, vsync event, swapchain creation).
The layer then connects to a socket owned by the server, submits the
VkImage creation parameters, and transfers file descriptors
corresponding to the images in the swapchain and associated semaphores.
The, on each frame, a packet is sent on the socket describing the image
that has been submitted.
On server side, vulkan frames are mapped to vaapi surfaces, using
ffmpeg, then converted to a format suitable for encoding, encoded
through vaapi and sent with the usual mechanism.
In order to associate each frame with tracking information, timing
details are requested to the compositor, and tracking history is queried
to find the most suitable tracking index. This mechanism is still
inaccurate and will need significant upgrades.
Co-authored-by: Ron B <me@ronthecookie.me>
* include pose age in timing calculation
* linux: correctly set timestamps for bitrate
* fix uninitialized variable, layer metadata
* use stack inspection in layer to find pose
In order to get the correct pose associated to an image, search the
stack for the variable, then copy it and send to the server.
* Automatically wrap vrcompositor-launcher
This will allow the user to not have to modify `vrenv.sh` which is quite error-prone.
* update vulkan-layer shell.nix
Co-authored-by: Patrick Nicolas <patricknicolas@laposte.net>
Co-authored-by: Ron B <me@ronthecookie.me>
Co-authored-by: zarik5 <riccardo.zaglia5@gmail.com>
2021-04-22 06:00:45 -05:00
|
|
|
.debug(false) // This is because we cannot link to msvcrtd (see below)
|
2021-05-17 04:54:44 -05:00
|
|
|
.flag("/std:c++17")
|
|
|
|
.flag("/permissive-")
|
2020-11-04 07:18:45 -06:00
|
|
|
.define("NOMINMAX", None)
|
|
|
|
.define("_WINSOCKAPI_", None)
|
|
|
|
.define("_MBCS", None)
|
2021-01-28 17:26:00 -06:00
|
|
|
.define("_MT", None);
|
2020-11-04 07:18:45 -06:00
|
|
|
|
2021-11-13 06:52:45 -06:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
build.define("__APPLE__", None);
|
|
|
|
|
2021-01-06 13:38:34 -06:00
|
|
|
// #[cfg(debug_assertions)]
|
|
|
|
// build.define("ALVR_DEBUG_LOG", None);
|
2020-11-22 08:30:27 -06:00
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
#[cfg(feature = "local_ffmpeg")]
|
|
|
|
do_ffmpeg_config(&mut build);
|
2021-05-09 03:50:54 -05:00
|
|
|
|
2022-02-18 15:05:02 -06:00
|
|
|
#[cfg(all(windows, feature = "gpl"))]
|
2022-09-21 15:55:06 -05:00
|
|
|
build.define("ALVR_GPL", None);
|
2022-02-18 15:05:02 -06:00
|
|
|
|
2020-06-06 15:00:49 -05:00
|
|
|
build.compile("bindings");
|
|
|
|
|
2022-09-21 15:55:06 -05:00
|
|
|
do_ffmpeg_config_post();
|
2021-05-09 03:50:54 -05:00
|
|
|
|
2020-06-06 15:00:49 -05:00
|
|
|
bindgen::builder()
|
|
|
|
.clang_arg("-xc++")
|
|
|
|
.header("cpp/alvr_server/bindings.h")
|
2020-11-04 07:18:45 -06:00
|
|
|
.derive_default(true)
|
2020-06-06 15:00:49 -05:00
|
|
|
.generate()
|
|
|
|
.expect("bindings")
|
|
|
|
.write_to_file(out_dir.join("bindings.rs"))
|
|
|
|
.expect("bindings.rs");
|
|
|
|
|
2021-03-14 14:00:25 -05:00
|
|
|
println!(
|
2022-02-10 07:01:47 -06:00
|
|
|
"cargo:rustc-link-search=native={}",
|
|
|
|
cpp_dir.join("openvr/lib").to_string_lossy()
|
2021-03-14 14:00:25 -05:00
|
|
|
);
|
|
|
|
println!("cargo:rustc-link-lib=openvr_api");
|
2020-06-06 15:00:49 -05:00
|
|
|
|
2021-05-09 03:50:54 -05:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
{
|
|
|
|
pkg_config::Config::new().probe("vulkan").unwrap();
|
Vulkan based linux port (#604)
* Vulkan based linux port
This version replaces the "screen grab" version.
The mechanism is based on frame capture in vrcompositor process, which
are then shared with vrserver process, encoded there and transmitted to
the headset.
A vulkan layer is added to vrcompositor, this layer exposes the
VK_EXT_direct_mode_display, VK_EXT_acquire_xlib_display and some other
related vulkan functions. Functions implemented in the layer add one
display to the list naturally returned by the driver, this display
matches properties in ALVR settings (resolution and refresh rate), and
all functions required by SteamVR are implemented (xlib acquire,
properties enumeration, vsync event, swapchain creation).
The layer then connects to a socket owned by the server, submits the
VkImage creation parameters, and transfers file descriptors
corresponding to the images in the swapchain and associated semaphores.
The, on each frame, a packet is sent on the socket describing the image
that has been submitted.
On server side, vulkan frames are mapped to vaapi surfaces, using
ffmpeg, then converted to a format suitable for encoding, encoded
through vaapi and sent with the usual mechanism.
In order to associate each frame with tracking information, timing
details are requested to the compositor, and tracking history is queried
to find the most suitable tracking index. This mechanism is still
inaccurate and will need significant upgrades.
Co-authored-by: Ron B <me@ronthecookie.me>
* include pose age in timing calculation
* linux: correctly set timestamps for bitrate
* fix uninitialized variable, layer metadata
* use stack inspection in layer to find pose
In order to get the correct pose associated to an image, search the
stack for the variable, then copy it and send to the server.
* Automatically wrap vrcompositor-launcher
This will allow the user to not have to modify `vrenv.sh` which is quite error-prone.
* update vulkan-layer shell.nix
Co-authored-by: Patrick Nicolas <patricknicolas@laposte.net>
Co-authored-by: Ron B <me@ronthecookie.me>
Co-authored-by: zarik5 <riccardo.zaglia5@gmail.com>
2021-04-22 06:00:45 -05:00
|
|
|
|
|
|
|
// fail build if there are undefined symbols in final library
|
|
|
|
println!("cargo:rustc-cdylib-link-arg=-Wl,--no-undefined");
|
|
|
|
}
|
|
|
|
|
2020-06-06 15:00:49 -05:00
|
|
|
for path in cpp_paths {
|
|
|
|
println!("cargo:rerun-if-changed={}", path.to_string_lossy());
|
|
|
|
}
|
|
|
|
}
|