stereokit_rust/tools/xr_android_depth_texture.rs
1//! TODO: XR_ANDROID_depth_texture extension implementation (AndroidXR)
2//!
3//! This module provides access to the OpenXR XR_ANDROID_depth_texture extension,
4//! which allows Android applications to access depth and confidence texture data
5//! from the device's depth sensors.
6//!
7//! The extension provides both raw and smooth depth data, along with confidence
8//! values for each pixel, enabling advanced computer vision and depth-aware
9//! rendering applications.
10//!
11//! # Features
12//! - **Multiple Resolution Support**: Quarter, half, and full resolution depth textures
13//! - **Raw and Processed Data**: Access to both raw sensor data and smoothed depth information
14//! - **Confidence Values**: Per-pixel confidence metrics for depth accuracy assessment
15//! - **Swapchain Management**: Efficient depth texture rendering through OpenXR swapchains
16//! - **System Capability Detection**: Runtime checking for depth tracking support
17//!
18//!
19//! # OpenXR Specification
20//! This implementation follows the XR_ANDROID_depth_texture extension specification
21//! version 1, providing access to Android-specific depth sensor capabilities.
22//! <https://developer.android.com/develop/xr/openxr/extensions/XR_ANDROID_depth_texture>
23
24use crate::system::{Backend, BackendOpenXR, BackendXRType, Log};
25use openxr_sys::{
26 Bool32, Instance, MAX_SYSTEM_NAME_SIZE, Result, Session, StructureType, Swapchain, SystemGraphicsProperties,
27 SystemId, SystemProperties, SystemTrackingProperties, pfn::GetSystemProperties,
28};
29use std::os::raw::{c_uint, c_ulong, c_void};
30use std::ptr::null_mut;
31
32/// Extension name for XR_FB_render_model
33pub const XR_ANDROID_DEPTH_TEXTURE_EXTENSION_NAME: &str = "XR_ANDROID_depth_texture";
34
35/// Type definitions for XR_ANDROID_depth_texture (openxr_sys compatible)
36pub type SurfaceOriginAndroid = c_uint;
37pub type ViewConfigurationType = c_uint;
38pub type SessionState = c_uint;
39pub type SpaceLocationFlags = c_ulong;
40pub type ReferenceSpaceType = c_uint;
41pub type ActionType = c_uint;
42pub type DepthResolutionAndroid = c_uint;
43pub type DepthSwapchainCreateFlagsAndroid = c_ulong;
44
45/// Surface origin constants for Android depth textures
46pub const SURFACE_ORIGIN_TOP_LEFT_ANDROID: SurfaceOriginAndroid = 0;
47pub const SURFACE_ORIGIN_BOTTOM_LEFT_ANDROID: SurfaceOriginAndroid = 1;
48
49/// Depth swapchain creation flags for different types of depth data
50/// These flags control which depth and confidence images are generated
51pub const XR_DEPTH_SWAPCHAIN_CREATE_SMOOTH_DEPTH_IMAGE_BIT_ANDROID: DepthSwapchainCreateFlagsAndroid = 0x00000001;
52pub const XR_DEPTH_SWAPCHAIN_CREATE_SMOOTH_CONFIDENCE_IMAGE_BIT_ANDROID: DepthSwapchainCreateFlagsAndroid = 0x00000002;
53pub const XR_DEPTH_SWAPCHAIN_CREATE_RAW_DEPTH_IMAGE_BIT_ANDROID: DepthSwapchainCreateFlagsAndroid = 0x00000004;
54pub const XR_DEPTH_SWAPCHAIN_CREATE_RAW_CONFIDENCE_IMAGE_BIT_ANDROID: DepthSwapchainCreateFlagsAndroid = 0x00000008;
55
56/// Depth resolution enumeration values
57/// These define the available depth texture resolutions relative to the main display
58pub const XR_DEPTH_RESOLUTION_QUARTER_ANDROID: DepthResolutionAndroid = 1;
59pub const XR_DEPTH_RESOLUTION_HALF_ANDROID: DepthResolutionAndroid = 2;
60pub const XR_DEPTH_RESOLUTION_FULL_ANDROID: DepthResolutionAndroid = 3;
61
62/// Structures for the depth texture extension
63/// Information about depth resolution capabilities
64#[repr(C)]
65#[derive(Debug, Clone)]
66pub struct DepthResolutionInfoAndroid {
67 pub ty: StructureType,
68 pub next: *const c_void,
69 pub width: u32,
70 pub height: u32,
71}
72
73/// Surface information for depth texture rendering
74#[repr(C)]
75#[derive(Debug, Clone)]
76pub struct DepthSurfaceInfoAndroid {
77 pub ty: StructureType,
78 pub next: *const c_void,
79 pub depth_surface: *mut c_void,
80}
81
82/// Creation parameters for depth textures
83#[repr(C)]
84#[derive(Debug, Clone)]
85pub struct DepthTextureCreateInfoAndroid {
86 pub ty: StructureType,
87 pub next: *const c_void,
88 pub resolution: DepthResolutionInfoAndroid,
89 pub surface_origin: SurfaceOriginAndroid,
90}
91
92/// Handle to a depth texture resource
93#[repr(C)]
94#[derive(Debug)]
95pub struct DepthTextureAndroid {
96 pub ty: StructureType,
97 pub next: *const c_void,
98 pub texture: *mut c_void,
99}
100
101/// Creation parameters for depth swapchains
102#[repr(C)]
103#[derive(Debug, Clone)]
104pub struct DepthSwapchainCreateInfoAndroid {
105 pub ty: StructureType,
106 pub next: *const c_void,
107 pub resolution: DepthResolutionAndroid,
108 pub create_flags: DepthSwapchainCreateFlagsAndroid,
109}
110
111/// Individual depth swapchain image containing multiple texture types
112#[repr(C)]
113#[derive(Debug, Clone)]
114pub struct DepthSwapchainImageAndroid {
115 pub ty: StructureType,
116 pub next: *const c_void,
117 /// Raw depth image data directly from sensors
118 pub raw_depth_image: *mut c_void,
119 /// Confidence values for raw depth data
120 pub raw_depth_confidence_image: *mut c_void,
121 /// Processed smooth depth image
122 pub smooth_depth_image: *mut c_void,
123 /// Confidence values for smooth depth data
124 pub smooth_depth_confidence_image: *mut c_void,
125}
126
127/// System properties structure for depth tracking capabilities
128#[repr(C)]
129#[derive(Debug, Clone)]
130pub struct XrSystemDepthTrackingPropertiesANDROID {
131 pub ty: StructureType,
132 pub next: *mut c_void,
133 /// Boolean indicating if the system supports depth tracking
134 pub supports_depth_tracking: Bool32,
135}
136
137impl Default for XrSystemDepthTrackingPropertiesANDROID {
138 fn default() -> Self {
139 Self {
140 ty: xr_type_system_depth_tracking_properties_android(),
141 next: std::ptr::null_mut(),
142 supports_depth_tracking: Bool32::from_raw(0),
143 }
144 }
145}
146
147/// Function pointer types for extension functions
148type PfnEnumerateDepthResolutionsAndroid = unsafe extern "C" fn(
149 session: Session,
150 capacity_input: u32,
151 count_output: *mut u32,
152 resolutions: *mut DepthResolutionAndroid,
153) -> Result;
154
155type PfnCreateDepthSwapchainAndroid = unsafe extern "C" fn(
156 session: Session,
157 create_info: *const DepthSwapchainCreateInfoAndroid,
158 swapchain: *mut Swapchain,
159) -> Result;
160
161type PfnDestroyDepthSwapchainAndroid = unsafe extern "C" fn(session: Session, swapchain: Swapchain) -> Result;
162
163type PfnEnumerateDepthSwapchainImagesAndroid = unsafe extern "C" fn(
164 swapchain: Swapchain,
165 capacity_input: u32,
166 count_output: *mut u32,
167 images: *mut DepthSwapchainImageAndroid,
168) -> Result;
169
170type PfnAcquireDepthSwapchainImageAndroid =
171 unsafe extern "C" fn(session: Session, swapchain: Swapchain, index: *mut u32) -> Result;
172
173/// Structure type functions (using raw values from OpenXR specification)
174pub fn xr_type_depth_resolution_info_android() -> StructureType {
175 StructureType::from_raw(1000343000)
176}
177pub fn xr_type_depth_surface_info_android() -> StructureType {
178 StructureType::from_raw(1000343001)
179}
180pub fn xr_type_depth_texture_create_info_android() -> StructureType {
181 StructureType::from_raw(1000343002)
182}
183pub fn xr_type_depth_texture_android() -> StructureType {
184 StructureType::from_raw(1000343003)
185}
186pub fn xr_type_depth_swapchain_create_info_android() -> StructureType {
187 StructureType::from_raw(1000343004)
188}
189pub fn xr_type_depth_swapchain_image_android() -> StructureType {
190 StructureType::from_raw(1000343005)
191}
192pub fn xr_type_system_depth_tracking_properties_android() -> StructureType {
193 StructureType::from_raw(1000343006)
194}
195
196/// Raw structure type constants for direct OpenXR API usage
197pub const XR_TYPE_DEPTH_RESOLUTION_INFO_ANDROID_RAW: u32 = 1000343000;
198pub const XR_TYPE_DEPTH_SURFACE_INFO_ANDROID_RAW: u32 = 1000343001;
199pub const XR_TYPE_DEPTH_TEXTURE_CREATE_INFO_ANDROID_RAW: u32 = 1000343002;
200pub const XR_TYPE_DEPTH_TEXTURE_ANDROID_RAW: u32 = 1000343003;
201pub const XR_TYPE_DEPTH_SWAPCHAIN_CREATE_INFO_ANDROID_RAW: u32 = 1000343004;
202pub const XR_TYPE_DEPTH_SWAPCHAIN_IMAGE_ANDROID_RAW: u32 = 1000343005;
203pub const XR_TYPE_SYSTEM_DEPTH_TRACKING_PROPERTIES_ANDROID_RAW: u32 = 1000343006;
204
205/// Extension function names for dynamic loading
206const XR_ENUMERATE_DEPTH_RESOLUTIONS_ANDROID_NAME: &str = "xrEnumerateDepthResolutionsANDROID";
207const XR_CREATE_DEPTH_SWAPCHAIN_ANDROID_NAME: &str = "xrCreateDepthSwapchainANDROID";
208const XR_DESTROY_DEPTH_SWAPCHAIN_ANDROID_NAME: &str = "xrDestroyDepthSwapchainANDROID";
209const XR_ENUMERATE_DEPTH_SWAPCHAIN_IMAGES_ANDROID_NAME: &str = "xrEnumerateDepthSwapchainImagesANDROID";
210const XR_ACQUIRE_DEPTH_SWAPCHAIN_IMAGE_ANDROID_NAME: &str = "xrAcquireDepthSwapchainImagesANDROID";
211
212/// Main extension handler for Android depth texture functionality
213///
214/// This struct manages the XR_ANDROID_depth_texture extension, providing access to:
215/// - Depth and confidence texture data from device sensors
216/// - Multiple resolution options (quarter, half, full)
217/// - Both raw and processed depth information
218/// - Swapchain management for efficient rendering
219///
220///
221/// ###Examples
222/// ```
223/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
224/// use stereokit_rust::tools::xr_android_depth_texture::*;
225///
226/// number_of_steps = 50;
227/// test_steps!( // !!!! Get a proper main loop !!!!
228/// if iter == 10 {
229/// // Initialize extension and check system support
230/// if let Some(depth_ext) = XrAndroidDepthTexture::new() {
231/// // Check system support with logging
232/// match depth_ext.check_system_support(true) {
233/// Ok(_system_props) => {
234/// stereokit_rust::system::Log::info("✅ System supports depth tracking");
235///
236/// // Continue with depth texture operations...
237/// let session = openxr_sys::Session::from_raw(
238/// stereokit_rust::system::BackendOpenXR::session()
239/// );
240///
241/// // Create depth swapchain with smooth and raw depth images
242/// let swapchain_info = create_depth_swapchain_info(
243/// XR_DEPTH_RESOLUTION_HALF_ANDROID,
244/// XR_DEPTH_SWAPCHAIN_CREATE_SMOOTH_DEPTH_IMAGE_BIT_ANDROID
245/// | XR_DEPTH_SWAPCHAIN_CREATE_RAW_DEPTH_IMAGE_BIT_ANDROID
246/// );
247///
248/// match depth_ext.create_depth_swapchain(session, &swapchain_info) {
249/// Ok(swapchain) => {
250/// stereokit_rust::system::Log::info("✅ Depth swapchain created!");
251///
252/// // Enumerate swapchain images
253/// if let Ok(images) = depth_ext.enumerate_depth_swapchain_images(swapchain) {
254/// stereokit_rust::system::Log::info(
255/// format!("Found {} swapchain images", images.len())
256/// );
257/// }
258///
259/// // Test image acquisition
260/// if let Ok(index) = depth_ext.acquire_depth_swapchain_image(session, swapchain) {
261/// stereokit_rust::system::Log::info(
262/// format!("Acquired image at index: {}", index)
263/// );
264/// }
265///
266/// // Cleanup
267/// let _ = depth_ext.destroy_depth_swapchain(swapchain);
268/// stereokit_rust::system::Log::info("✅ Swapchain test completed!");
269/// }
270/// Err(e) => stereokit_rust::system::Log::err(format!("Swapchain creation failed: {}", e)),
271/// }
272/// }
273/// Err(e) => stereokit_rust::system::Log::err(format!("System support check failed: {:?}", e)),
274/// }
275/// }
276/// }
277/// );
278/// ```
279///
280///
281/// #### Depth Resolution Enumeration Example
282/// ```
283/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
284/// use stereokit_rust::tools::xr_android_depth_texture::*;
285///
286/// number_of_steps = 20;
287/// test_steps!( // !!!! Get a proper main loop !!!!
288/// if iter == 5 {
289/// // Test depth resolution enumeration and analysis
290/// if let Some(depth_ext) = XrAndroidDepthTexture::new() {
291/// let session = openxr_sys::Session::from_raw(
292/// stereokit_rust::system::BackendOpenXR::session()
293/// );
294///
295/// match depth_ext.enumerate_depth_resolutions(session) {
296/// Ok(resolutions) => {
297/// stereokit_rust::system::Log::info(
298/// format!("✅ Found {} supported depth resolutions", resolutions.len())
299/// );
300///
301/// for (i, resolution) in resolutions.iter().enumerate() {
302/// let (width, height) = get_resolution_dimensions(*resolution);
303/// let resolution_name = match *resolution {
304/// XR_DEPTH_RESOLUTION_QUARTER_ANDROID => "Quarter",
305/// XR_DEPTH_RESOLUTION_HALF_ANDROID => "Half",
306/// XR_DEPTH_RESOLUTION_FULL_ANDROID => "Full",
307/// _ => "Unknown",
308/// };
309///
310/// stereokit_rust::system::Log::info(format!(
311/// " Resolution {}: {} ({}x{}) - enum: {}",
312/// i, resolution_name, width, height, resolution
313/// ));
314/// }
315///
316/// stereokit_rust::system::Log::info("✅ Resolution enumeration completed!");
317/// }
318/// Err(e) => stereokit_rust::system::Log::err(
319/// format!("Resolution enumeration failed: {}", e)
320/// ),
321/// }
322/// }
323/// }
324/// );
325/// ```
326#[derive(Debug)]
327pub struct XrAndroidDepthTexture {
328 /// Loaded function pointers from the OpenXR runtime
329 xr_get_system_properties: Option<GetSystemProperties>,
330 enumerate_depth_resolutions: Option<PfnEnumerateDepthResolutionsAndroid>,
331 create_depth_swapchain: Option<PfnCreateDepthSwapchainAndroid>,
332 destroy_depth_swapchain: Option<PfnDestroyDepthSwapchainAndroid>,
333 enumerate_depth_swapchain_images: Option<PfnEnumerateDepthSwapchainImagesAndroid>,
334 acquire_depth_swapchain_image: Option<PfnAcquireDepthSwapchainImageAndroid>,
335 instance: Instance,
336}
337
338impl XrAndroidDepthTexture {
339 /// Create and initialize a new AndroidDepthTextureExtension instance
340 ///
341 /// This method combines creation and initialization, checking extension availability
342 /// and loading all necessary OpenXR functions for depth texture operations.
343 ///
344 /// # Returns
345 /// - `Some(Self)` if extension is available and initialization succeeds
346 /// - `None` if extension is not available or initialization fails
347 pub fn new() -> Option<Self> {
348 // Check if the extension is available first
349 if !is_android_depth_texture_extension_available() {
350 Log::warn("XR_ANDROID_depth_texture extension not available");
351 return None;
352 }
353
354 // Load functions using the generic system
355 let xr_get_system_properties = BackendOpenXR::get_function::<GetSystemProperties>("xrGetSystemProperties");
356 let enumerate_depth_resolutions = BackendOpenXR::get_function::<PfnEnumerateDepthResolutionsAndroid>(
357 XR_ENUMERATE_DEPTH_RESOLUTIONS_ANDROID_NAME,
358 );
359
360 let create_depth_swapchain =
361 BackendOpenXR::get_function::<PfnCreateDepthSwapchainAndroid>(XR_CREATE_DEPTH_SWAPCHAIN_ANDROID_NAME);
362
363 let destroy_depth_swapchain =
364 BackendOpenXR::get_function::<PfnDestroyDepthSwapchainAndroid>(XR_DESTROY_DEPTH_SWAPCHAIN_ANDROID_NAME);
365
366 let enumerate_depth_swapchain_images = BackendOpenXR::get_function::<PfnEnumerateDepthSwapchainImagesAndroid>(
367 XR_ENUMERATE_DEPTH_SWAPCHAIN_IMAGES_ANDROID_NAME,
368 );
369
370 let acquire_depth_swapchain_image = BackendOpenXR::get_function::<PfnAcquireDepthSwapchainImageAndroid>(
371 XR_ACQUIRE_DEPTH_SWAPCHAIN_IMAGE_ANDROID_NAME,
372 );
373
374 let instance = Instance::from_raw(BackendOpenXR::instance());
375
376 // Verify that all critical functions were loaded successfully
377 if xr_get_system_properties.is_none()
378 || enumerate_depth_resolutions.is_none()
379 || create_depth_swapchain.is_none()
380 || destroy_depth_swapchain.is_none()
381 || enumerate_depth_swapchain_images.is_none()
382 || acquire_depth_swapchain_image.is_none()
383 {
384 Log::warn("Failed to load all XR_ANDROID_depth_texture functions");
385 return None;
386 }
387
388 Log::info("XR_ANDROID_depth_texture extension initialized successfully");
389
390 Some(Self {
391 xr_get_system_properties,
392 enumerate_depth_resolutions,
393 create_depth_swapchain,
394 destroy_depth_swapchain,
395 enumerate_depth_swapchain_images,
396 acquire_depth_swapchain_image,
397 instance,
398 })
399 }
400
401 /// Check if the system supports depth tracking
402 ///
403 /// # Parameters
404 /// - `with_log`: If true, outputs system properties to diagnostic log
405 ///
406 /// # Returns
407 /// `Ok(SystemProperties)` with depth tracking properties if supported, or error on failure
408 pub fn check_system_support(&self, with_log: bool) -> std::result::Result<SystemProperties, openxr_sys::Result> {
409 let get_props_fn = self.xr_get_system_properties.ok_or(openxr_sys::Result::ERROR_FUNCTION_UNSUPPORTED)?;
410
411 let system_id = SystemId::from_raw(BackendOpenXR::system_id());
412
413 let mut depth_tracking_props = XrSystemDepthTrackingPropertiesANDROID {
414 ty: xr_type_system_depth_tracking_properties_android(),
415 next: null_mut(),
416 supports_depth_tracking: Bool32::from_raw(0),
417 };
418
419 let mut system_properties = SystemProperties {
420 ty: StructureType::SYSTEM_PROPERTIES,
421 next: &mut depth_tracking_props as *mut _ as *mut c_void,
422 system_id,
423 vendor_id: 0,
424 system_name: [0; MAX_SYSTEM_NAME_SIZE],
425 graphics_properties: SystemGraphicsProperties {
426 max_swapchain_image_height: 0,
427 max_swapchain_image_width: 0,
428 max_layer_count: 0,
429 },
430 tracking_properties: SystemTrackingProperties {
431 orientation_tracking: Bool32::from_raw(0),
432 position_tracking: Bool32::from_raw(0),
433 },
434 };
435
436 let result = unsafe { get_props_fn(self.instance, system_id, &mut system_properties) };
437
438 if result != openxr_sys::Result::SUCCESS {
439 return Err(result);
440 }
441
442 if with_log {
443 Log::diag("=== XR_ANDROID_depth_texture System Properties ===");
444 Log::diag(format!("System ID: {:?}", system_properties.system_id));
445 Log::diag(format!("Vendor ID: {}", system_properties.vendor_id));
446
447 // Convert system name from i8 array to string
448 let system_name = system_properties
449 .system_name
450 .iter()
451 .take_while(|&&c| c != 0)
452 .map(|&c| c as u8 as char)
453 .collect::<String>();
454 Log::diag(format!("System name: {}", system_name));
455
456 Log::diag("Graphics properties:");
457 Log::diag(format!(
458 " Max swapchain image height: {}",
459 system_properties.graphics_properties.max_swapchain_image_height
460 ));
461 Log::diag(format!(
462 " Max swapchain image width: {}",
463 system_properties.graphics_properties.max_swapchain_image_width
464 ));
465 Log::diag(format!(" Max layer count: {}", system_properties.graphics_properties.max_layer_count));
466
467 Log::diag("Tracking properties:");
468 Log::diag(format!(
469 " Orientation tracking: {}",
470 system_properties.tracking_properties.orientation_tracking.into_raw() != 0
471 ));
472 Log::diag(format!(
473 " Position tracking: {}",
474 system_properties.tracking_properties.position_tracking.into_raw() != 0
475 ));
476
477 Log::diag("Depth tracking properties:");
478 Log::diag(format!(
479 " Supports depth tracking: {}",
480 depth_tracking_props.supports_depth_tracking.into_raw() != 0
481 ));
482 Log::diag("================================================");
483 }
484
485 Ok(system_properties)
486 }
487
488 /// Wrapper methods used by lib.rs
489 /// Enumerate available depth resolutions supported by the device
490 ///
491 /// # Arguments
492 /// * `session` - The OpenXR session
493 ///
494 /// # Returns
495 /// Vector of supported depth resolution enum values
496 pub fn enumerate_depth_resolutions(
497 &self,
498 session: Session,
499 ) -> std::result::Result<Vec<DepthResolutionAndroid>, String> {
500 let enumerate_fn = self.enumerate_depth_resolutions.ok_or("enumerate_depth_resolutions function not loaded")?;
501
502 // First call to get the count
503 let mut count = 0u32;
504 let result = unsafe { enumerate_fn(session, 0, &mut count, std::ptr::null_mut()) };
505
506 if result != openxr_sys::Result::SUCCESS {
507 return Err(format!("Failed to get depth resolutions count: {:?}", result));
508 }
509
510 if count == 0 {
511 return Ok(vec![]);
512 }
513
514 // Second call to get the actual resolutions
515 let mut resolutions = vec![0u32; count as usize];
516 let result = unsafe { enumerate_fn(session, count, &mut count, resolutions.as_mut_ptr()) };
517
518 if result != openxr_sys::Result::SUCCESS {
519 return Err(format!("Failed to enumerate depth resolutions: {:?}", result));
520 }
521
522 // Resize to actual count returned
523 resolutions.resize(count as usize, 0);
524 Ok(resolutions)
525 }
526
527 /// Create a depth swapchain for rendering depth textures
528 ///
529 /// # Arguments
530 /// * `session` - The OpenXR session
531 /// * `create_info` - Configuration for the depth swapchain
532 ///
533 /// # Returns
534 /// Handle to the created swapchain or error description
535 pub fn create_depth_swapchain(
536 &self,
537 session: Session,
538 create_info: &DepthSwapchainCreateInfoAndroid,
539 ) -> std::result::Result<Swapchain, String> {
540 let create_fn = self.create_depth_swapchain.ok_or("create_depth_swapchain function not loaded")?;
541
542 let mut swapchain = Swapchain::from_raw(0);
543 let result = unsafe { create_fn(session, create_info, &mut swapchain as *mut Swapchain) };
544
545 if result != openxr_sys::Result::SUCCESS {
546 return Err(format!("Failed to create depth swapchain: {:?}", result));
547 }
548
549 Ok(swapchain)
550 }
551
552 /// Enumerate the images in a depth swapchain
553 ///
554 /// # Arguments
555 /// * `swapchain` - The depth swapchain to enumerate
556 ///
557 /// # Returns
558 /// Vector of depth swapchain images with texture handles
559 pub fn enumerate_depth_swapchain_images(
560 &self,
561 swapchain: Swapchain,
562 ) -> std::result::Result<Vec<DepthSwapchainImageAndroid>, String> {
563 let enumerate_fn = self
564 .enumerate_depth_swapchain_images
565 .ok_or("enumerate_depth_swapchain_images function not loaded")?;
566
567 // First call to get the count
568 let mut count = 0u32;
569 let result = unsafe { enumerate_fn(swapchain, 0, &mut count, std::ptr::null_mut()) };
570
571 if result != openxr_sys::Result::SUCCESS {
572 return Err(format!("Failed to get depth swapchain images count: {:?}", result));
573 }
574
575 if count == 0 {
576 return Ok(vec![]);
577 }
578
579 // Prepare vector with initialized structures
580 let mut images = vec![
581 DepthSwapchainImageAndroid {
582 ty: xr_type_depth_swapchain_image_android(),
583 next: std::ptr::null(),
584 raw_depth_image: std::ptr::null_mut(),
585 raw_depth_confidence_image: std::ptr::null_mut(),
586 smooth_depth_image: std::ptr::null_mut(),
587 smooth_depth_confidence_image: std::ptr::null_mut(),
588 };
589 count as usize
590 ];
591
592 // Second call to get the actual images
593 let result = unsafe { enumerate_fn(swapchain, count, &mut count, images.as_mut_ptr()) };
594
595 if result != openxr_sys::Result::SUCCESS {
596 return Err(format!("Failed to enumerate depth swapchain images: {:?}", result));
597 }
598
599 // Resize to actual count returned
600 images.resize(
601 count as usize,
602 DepthSwapchainImageAndroid {
603 ty: xr_type_depth_swapchain_image_android(),
604 next: std::ptr::null(),
605 raw_depth_image: std::ptr::null_mut(),
606 raw_depth_confidence_image: std::ptr::null_mut(),
607 smooth_depth_image: std::ptr::null_mut(),
608 smooth_depth_confidence_image: std::ptr::null_mut(),
609 },
610 );
611
612 Ok(images)
613 }
614
615 /// Destroy a previously created depth swapchain
616 ///
617 /// # Arguments
618 /// * `swapchain` - The depth swapchain to destroy
619 ///
620 /// # Returns
621 /// `Ok(())` on success or error description on failure
622 pub fn destroy_depth_swapchain(&self, swapchain: Swapchain) -> std::result::Result<(), String> {
623 let destroy_fn = self.destroy_depth_swapchain.ok_or("destroy_depth_swapchain function not loaded")?;
624
625 let session = Session::from_raw(BackendOpenXR::session());
626 let result = unsafe { destroy_fn(session, swapchain) };
627
628 if result != openxr_sys::Result::SUCCESS {
629 return Err(format!("Failed to destroy depth swapchain: {:?}", result));
630 }
631
632 Ok(())
633 }
634
635 /// Acquire an image from a depth swapchain
636 ///
637 /// # Arguments
638 /// * `session` - The OpenXR session
639 /// * `swapchain` - The depth swapchain to acquire from
640 ///
641 /// # Returns
642 /// Index of the acquired image or error description
643 pub fn acquire_depth_swapchain_image(
644 &self,
645 session: Session,
646 swapchain: Swapchain,
647 ) -> std::result::Result<u32, String> {
648 let acquire_fn =
649 self.acquire_depth_swapchain_image.ok_or("acquire_depth_swapchain_image function not loaded")?;
650
651 let mut image_index = 0u32;
652 let result = unsafe { acquire_fn(session, swapchain, &mut image_index) };
653
654 if result != openxr_sys::Result::SUCCESS {
655 return Err(format!("Failed to acquire depth swapchain image: {:?}", result));
656 }
657
658 Ok(image_index)
659 }
660}
661
662/// Helper function to create depth texture creation info
663///
664/// # Arguments
665/// * `width` - Texture width in pixels
666/// * `height` - Texture height in pixels
667/// * `surface_origin` - Surface origin (top-left or bottom-left)
668///
669/// # Returns
670/// Initialized `DepthTextureCreateInfoAndroid` structure
671pub fn create_depth_texture_info(
672 width: u32,
673 height: u32,
674 surface_origin: SurfaceOriginAndroid,
675) -> DepthTextureCreateInfoAndroid {
676 let resolution = DepthResolutionInfoAndroid {
677 ty: xr_type_depth_resolution_info_android(),
678 next: std::ptr::null(),
679 width,
680 height,
681 };
682
683 DepthTextureCreateInfoAndroid {
684 ty: xr_type_depth_texture_create_info_android(),
685 next: std::ptr::null(),
686 resolution,
687 surface_origin,
688 }
689}
690
691impl Default for XrAndroidDepthTexture {
692 fn default() -> Self {
693 // This will panic if extension is not available, which is the intended behavior
694 // for Default trait when the extension should always be available
695 Self::new().expect("XR_ANDROID_depth_texture extension should be available")
696 }
697}
698
699/// Convenience function to check if XR_FB_render_model extension is available
700pub fn is_android_depth_texture_extension_available() -> bool {
701 Backend::xr_type() == BackendXRType::OpenXR && BackendOpenXR::ext_enabled(XR_ANDROID_DEPTH_TEXTURE_EXTENSION_NAME)
702}
703
704/// Helper functions used by lib.rs
705/// Get the pixel dimensions for a given depth resolution enum
706///
707/// # Arguments
708/// * `resolution` - The depth resolution enum value
709///
710/// # Returns
711/// Tuple of (width, height) in pixels
712pub fn get_resolution_dimensions(resolution: DepthResolutionAndroid) -> (u32, u32) {
713 match resolution {
714 XR_DEPTH_RESOLUTION_QUARTER_ANDROID => (640, 480), // Quarter resolution
715 XR_DEPTH_RESOLUTION_HALF_ANDROID => (1280, 960), // Half resolution
716 XR_DEPTH_RESOLUTION_FULL_ANDROID => (2560, 1920), // Full resolution
717 _ => (0, 0), // Unknown resolution
718 }
719}
720
721/// Create a depth swapchain creation info structure
722///
723/// # Arguments
724/// * `resolution` - The desired depth resolution
725/// * `create_flags` - Flags controlling which depth/confidence images to create
726///
727/// # Returns
728/// Initialized `DepthSwapchainCreateInfoAndroid` structure
729pub fn create_depth_swapchain_info(
730 resolution: DepthResolutionAndroid,
731 create_flags: DepthSwapchainCreateFlagsAndroid,
732) -> DepthSwapchainCreateInfoAndroid {
733 DepthSwapchainCreateInfoAndroid {
734 ty: xr_type_depth_swapchain_create_info_android(),
735 next: std::ptr::null(),
736 resolution,
737 create_flags,
738 }
739}
740
741/// Comprehensive test function for XR_ANDROID_depth_texture extension
742///
743/// This function demonstrates the complete workflow for using Android depth textures:
744/// 1. Extension initialization and availability checking
745/// 2. System capability inspection for depth tracking support
746/// 3. Depth resolution enumeration and selection
747/// 4. Depth swapchain creation with multiple image types
748/// 5. Swapchain image enumeration and inspection
749/// 6. Proper cleanup and resource management
750///
751/// The test provides detailed logging of each step and handles errors gracefully,
752/// making it useful both for validation and as a reference implementation.
753///
754/// # Usage
755/// Call this function after StereoKit initialization in an OpenXR environment
756/// that supports the XR_ANDROID_depth_texture extension.
757///
758/// ### Example
759/// ```
760/// # stereokit_rust::test_init_sk!(); // !!!! Get a proper way to initialize sk !!!!
761/// use stereokit_rust::tools::xr_android_depth_texture::*;
762///
763/// number_of_steps = 60;
764/// test_steps!( // !!!! Get a proper main loop !!!!
765/// if iter == 30 {
766/// // Run comprehensive test of all extension functionality
767/// stereokit_rust::system::Log::info("🚀 Running comprehensive depth texture test...");
768/// test_depth_texture_extension();
769/// stereokit_rust::system::Log::info("🏁 Comprehensive test completed!");
770/// }
771/// );
772/// ```
773pub fn test_depth_texture_extension() {
774 Log::diag("🚀 === TESTING XR_ANDROID_DEPTH_TEXTURE EXTENSION ===");
775
776 // Initialize the depth texture extension
777 match XrAndroidDepthTexture::new() {
778 Some(depth_ext) => {
779 Log::diag("✅ XR_ANDROID_depth_texture extension initialized successfully");
780
781 Log::diag("✅ XR_ANDROID_depth_texture swapchain API is available");
782
783 // Get OpenXR handles from StereoKit for logging purposes
784 let instance_raw = BackendOpenXR::instance();
785 let system_id_raw = BackendOpenXR::system_id();
786 Log::diag(format!("✅ OpenXR instance obtained: {:?}", instance_raw));
787 Log::diag(format!("✅ OpenXR system ID obtained: {:?}", system_id_raw));
788
789 // === INSPECT SYSTEM CAPABILITY ===
790 Log::diag("=== Inspecting system depth tracking capabilities ===");
791
792 // Test system support check using the new method
793 match depth_ext.check_system_support(true) {
794 Ok(sys_prop) => {
795 Log::diag("✅ System support check completed successfully");
796
797 // Get the depth tracking properties from the next pointer
798 let depth_tracking_properties =
799 unsafe { &*(sys_prop.next as *const XrSystemDepthTrackingPropertiesANDROID) };
800
801 if depth_tracking_properties.supports_depth_tracking.into_raw() != 0 {
802 Log::diag("🎯 ✅ DEPTH TRACKING IS SUPPORTED BY THE SYSTEM!");
803
804 // Get session from StereoKit and convert to proper type
805 let session_raw = BackendOpenXR::session();
806 let session = openxr_sys::Session::from_raw(session_raw);
807 Log::diag(format!("✅ OpenXR session obtained: {:?}", session_raw));
808
809 // === QUERY SUPPORTED DEPTH RESOLUTIONS ===
810 Log::diag("=== Querying supported depth resolutions ===");
811
812 match depth_ext.enumerate_depth_resolutions(session) {
813 Ok(resolutions) => {
814 Log::diag(format!("✅ Found {} supported depth resolutions", resolutions.len()));
815 for (i, res) in resolutions.iter().enumerate() {
816 let (width, height) = get_resolution_dimensions(*res);
817 Log::diag(format!(
818 " Resolution {}: {}x{} (enum value: {})",
819 i, width, height, res
820 ));
821 }
822
823 if !resolutions.is_empty() {
824 let selected_resolution = resolutions[0];
825 let (width, height) = get_resolution_dimensions(selected_resolution);
826 Log::diag(format!(
827 "🎯 Selected resolution: {}x{} (enum: {})",
828 width, height, selected_resolution
829 ));
830
831 // === CREATE DEPTH SWAPCHAIN ===
832 Log::diag("=== Creating depth swapchain ===");
833
834 let swapchain_create_info = create_depth_swapchain_info(
835 selected_resolution,
836 XR_DEPTH_SWAPCHAIN_CREATE_SMOOTH_DEPTH_IMAGE_BIT_ANDROID
837 | XR_DEPTH_SWAPCHAIN_CREATE_SMOOTH_CONFIDENCE_IMAGE_BIT_ANDROID
838 | XR_DEPTH_SWAPCHAIN_CREATE_RAW_DEPTH_IMAGE_BIT_ANDROID
839 | XR_DEPTH_SWAPCHAIN_CREATE_RAW_CONFIDENCE_IMAGE_BIT_ANDROID,
840 );
841
842 Log::diag(format!(
843 "Swapchain create info - Resolution: {}, Flags: 0b{:08b}",
844 swapchain_create_info.resolution, swapchain_create_info.create_flags
845 ));
846
847 match depth_ext.create_depth_swapchain(session, &swapchain_create_info) {
848 Ok(depth_swapchain) => {
849 Log::diag(format!(
850 "✅ Depth swapchain created successfully: {:?}",
851 depth_swapchain
852 ));
853
854 // === ENUMERATE DEPTH SWAPCHAIN IMAGES ===
855 Log::diag("=== Enumerating depth swapchain images ===");
856
857 match depth_ext.enumerate_depth_swapchain_images(depth_swapchain) {
858 Ok(depth_images) => {
859 Log::diag(format!(
860 "✅ Enumerated {} depth swapchain images",
861 depth_images.len()
862 ));
863
864 for (i, image) in depth_images.iter().enumerate() {
865 Log::diag(format!(
866 " Image {}: raw_depth={:p}, raw_conf={:p}, smooth_depth={:p}, smooth_conf={:p}",
867 i,
868 image.raw_depth_image,
869 image.raw_depth_confidence_image,
870 image.smooth_depth_image,
871 image.smooth_depth_confidence_image
872 ));
873 }
874
875 Log::diag(
876 "🎯 ✅ DEPTH TEXTURE EXTENSION SETUP COMPLETE AND READY FOR USE!",
877 );
878
879 // Cleanup - destroy the swapchain
880 match depth_ext.destroy_depth_swapchain(depth_swapchain) {
881 Ok(()) => {
882 Log::diag("✅ Depth swapchain destroyed successfully")
883 }
884 Err(e) => Log::err(format!(
885 "❌ Failed to destroy depth swapchain: {:?}",
886 e
887 )),
888 }
889 }
890 Err(e) => {
891 Log::err(format!(
892 "❌ Failed to enumerate depth swapchain images: {:?}",
893 e
894 ));
895 }
896 }
897 }
898 Err(e) => {
899 Log::err(format!("❌ Failed to create depth swapchain: {:?}", e));
900 }
901 }
902 } else {
903 Log::warn("⚠️ No depth resolutions available");
904 }
905 }
906 Err(e) => {
907 Log::err(format!("❌ Failed to enumerate depth resolutions: {:?}", e));
908 }
909 }
910 } else {
911 Log::warn("⚠️ Depth tracking is NOT supported by this system");
912 }
913 }
914 Err(e) => {
915 Log::err(format!("❌ System support check failed: {:?}", e));
916 }
917 }
918 }
919 None => {
920 Log::err("❌ Failed to initialize XR_ANDROID_depth_texture extension");
921 }
922 }
923
924 Log::diag("🏁 === DEPTH TEXTURE EXTENSION TEST COMPLETE ===");
925}