Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions openxr/examples/hello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ use openxr as xr;

#[cfg_attr(target_os = "android", ndk_glue::main)]
fn main() {
#[cfg(not(target_os = "android"))]
let platform_info = ();
#[cfg(target_os = "android")]
let platform_info =
unsafe { openxr::AndroidPlatformInfo::new(ndk_glue::native_activity().activity().cast()) };
#[cfg(feature = "linked")]
let entry = xr::Entry::linked().unwrap();
let entry = xr::Entry::linked(&platform_info).unwrap();
#[cfg(not(feature = "linked"))]
let entry = unsafe {
xr::Entry::load()
xr::Entry::load(&platform_info)
.expect("couldn't find the OpenXR loader; try enabling the \"static\" feature")
};

Expand All @@ -33,12 +38,7 @@ fn main() {
},
&xr::ExtensionSet::default(),
&[],
#[cfg(not(target_os = "android"))]
(),
#[cfg(target_os = "android")]
unsafe {
openxr::AndroidPlatformInfo::new(ndk_glue::native_activity().activity().cast())
},
&platform_info,
)
.unwrap();
let instance_props = instance.properties().unwrap();
Expand Down
16 changes: 8 additions & 8 deletions openxr/examples/vulkan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,16 @@ pub fn main() {
})
.expect("setting Ctrl-C handler");

#[cfg(not(target_os = "android"))]
let platform_info = ();
#[cfg(target_os = "android")]
let platform_info =
unsafe { openxr::AndroidPlatformInfo::new(ndk_glue::native_activity().activity().cast()) };
#[cfg(feature = "static")]
let entry = xr::Entry::linked().unwrap();
let entry = xr::Entry::linked(&platform_info).unwrap();
#[cfg(not(feature = "static"))]
let entry = unsafe {
xr::Entry::load()
xr::Entry::load(&platform_info)
.expect("couldn't find the OpenXR loader; try enabling the \"static\" feature")
};

Expand Down Expand Up @@ -69,12 +74,7 @@ pub fn main() {
},
&enabled_extensions,
&[],
#[cfg(not(target_os = "android"))]
(),
#[cfg(target_os = "android")]
unsafe {
openxr::AndroidPlatformInfo::new(ndk_glue::native_activity().activity().cast())
},
&platform_info,
)
.unwrap();
let instance_props = xr_instance.properties().unwrap();
Expand Down
106 changes: 59 additions & 47 deletions openxr/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ impl Entry {
/// Available if the `linked` feature is enabled. You must ensure that the entry points are
/// actually linked into the binary, e.g. by enabling the `static` feature or manually linking
/// to an external loader or implementation.
///
/// Needs an [`AndroidPlatformInfo`] to correctly initialize the loader on Android.
/// Other platforms can pass `()`.
#[cfg(feature = "linked")]
pub fn linked() -> Result<Self> {
pub fn linked(platform_info: &impl PlatformInfo) -> Result<Self> {
let entry = Self {
inner: Arc::new(Inner {
raw: RawEntry {
Expand All @@ -44,8 +47,7 @@ impl Entry {
_lib_guard: None,
}),
};
#[cfg(target_os = "android")]
entry.initialize_android_loader()?;
platform_info.init_loader(&entry)?;
Ok(entry)
}

Expand All @@ -54,36 +56,41 @@ impl Entry {
///
/// Available if the `loaded` feature is enabled.
///
/// Needs an [`AndroidPlatformInfo`] to correctly initialize the loader on Android.
/// Other platforms can pass `()`.
///
/// # Safety
///
/// The OpenXR loader shared library in the dynamic loader's search path must conform to the
/// OpenXR specification.
#[cfg(feature = "loaded")]
pub unsafe fn load() -> std::result::Result<Self, EntryError> {
let entry = unsafe {
#[cfg(target_os = "windows")]
const PATH: &str = "openxr_loader.dll";
#[cfg(target_os = "macos")]
const PATH: &str = "libopenxr_loader.dylib";
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
const PATH: &str = "libopenxr_loader.so";
Self::load_from(Path::new(PATH))
}?;
#[cfg(target_os = "android")]
entry.initialize_android_loader().map_err(EntryError::Xr)?;
Ok(entry)
pub unsafe fn load(platform_info: &impl PlatformInfo) -> std::result::Result<Self, EntryError> {
#[cfg(target_os = "windows")]
const PATH: &str = "openxr_loader.dll";
#[cfg(target_os = "macos")]
const PATH: &str = "libopenxr_loader.dylib";
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
const PATH: &str = "libopenxr_loader.so";

unsafe { Self::load_from(Path::new(PATH), platform_info) }
}

/// Load entry points at run time from the dynamic library identified by `path`
///
/// Available if the `loaded` feature is enabled.
///
/// Needs an [`AndroidPlatformInfo`] to correctly initialize the loader on Android.
/// Other platforms can pass `()`.
///
/// # Safety
///
/// `path` must be a shared library that provides OpenXR-compliant definitions for every core
/// OpenXR entry point.
#[cfg(feature = "loaded")]
pub unsafe fn load_from(path: &Path) -> std::result::Result<Self, EntryError> {
pub unsafe fn load_from(
path: &Path,
platform_info: &impl PlatformInfo,
) -> std::result::Result<Self, EntryError> {
let entry = unsafe {
let lib = Library::new(path).map_err(|err| EntryError::Load(LoadError(err)))?;
Self {
Expand All @@ -107,20 +114,23 @@ impl Entry {
}),
}
};
#[cfg(target_os = "android")]
entry.initialize_android_loader().map_err(EntryError::Xr)?;
platform_info.init_loader(&entry).map_err(EntryError::Xr)?;
Ok(entry)
}

/// Load entry points using an arbitrary `xrGetInstanceProcAddr` implementation
///
/// Needs an [`AndroidPlatformInfo`] to correctly initialize the loader on Android.
/// Other platforms can pass `()`.
///
/// # Safety
///
/// For all core OpenXR instance functions, `get_instance_proc_addr` must yield function
/// pointers that satisfy the semantics given in the OpenXR specification.
#[allow(clippy::missing_transmute_annotations)]
pub unsafe fn from_get_instance_proc_addr(
get_instance_proc_addr: sys::pfn::GetInstanceProcAddr,
platform_info: &impl PlatformInfo,
) -> Result<Self> {
let entry = unsafe {
Self {
Expand Down Expand Up @@ -152,8 +162,7 @@ impl Entry {
}),
}
};
#[cfg(target_os = "android")]
entry.initialize_android_loader()?;
platform_info.init_loader(&entry)?;
Ok(entry)
}

Expand All @@ -172,31 +181,6 @@ impl Entry {
unsafe { get_instance_proc_addr_helper(self.fp().get_instance_proc_addr, instance, name) }
}

/// Initialize Android loader. This must be called before any other OpenXR call.
#[cfg(target_os = "android")]
fn initialize_android_loader(&self) -> Result<()> {
let loader_init = unsafe { raw::LoaderInitKHR::load(self, sys::Instance::NULL)? };

let context = ndk_context::android_context();

let loader_info = sys::LoaderInitInfoAndroidKHR {
ty: sys::LoaderInitInfoAndroidKHR::TYPE,
next: ptr::null(),
application_vm: context.vm(),
application_context: context.context(),
};

// The loader init extension doesn't forbid calling initialization multiple times,
// and the Khronos Loader implementation handles it correctly.
unsafe {
cvt((loader_init.initialize_loader)(
&loader_info as *const _ as _,
))?;
}

Ok(())
}

/// Create an OpenXR instance with certain extensions enabled.
///
/// On Android, pass [`AndroidPlatformInfo`] as `platform_info`
Expand All @@ -210,7 +194,7 @@ impl Entry {
app_info: &ApplicationInfo,
required_extensions: &ExtensionSet,
layers: &[&str],
platform_info: impl PlatformInfo,
platform_info: &impl PlatformInfo,
) -> Result<Instance> {
assert!(
app_info.application_name.len() < sys::MAX_APPLICATION_NAME_SIZE,
Expand Down Expand Up @@ -455,6 +439,11 @@ pub unsafe trait PlatformInfo {
entry: &Entry,
info: sys::InstanceCreateInfo,
) -> Result<sys::Instance>;

/// Callback for platform-specific loader initialization.
fn init_loader(&self, _entry: &Entry) -> Result<()> {
Ok(())
}
}

unsafe impl PlatformInfo for () {
Expand Down Expand Up @@ -515,4 +504,27 @@ unsafe impl PlatformInfo for AndroidPlatformInfo {
cvt(unsafe { (entry.fp().create_instance)(&info, &mut handle) })?;
Ok(handle)
}

fn init_loader(&self, entry: &Entry) -> Result<()> {
let loader_init = unsafe { raw::LoaderInitKHR::load(entry, sys::Instance::NULL)? };

let context = ndk_context::android_context();

let loader_info = sys::LoaderInitInfoAndroidKHR {
ty: sys::LoaderInitInfoAndroidKHR::TYPE,
next: ptr::null(),
application_vm: context.vm(),
application_context: self.activity,
};

// The loader init extension doesn't forbid calling initialization multiple times,
// and the Khronos Loader implementation handles it correctly.
unsafe {
cvt((loader_init.initialize_loader)(
&loader_info as *const _ as _,
))?;
}

Ok(())
}
}
Loading