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}