kronos_compute/implementation/
instance.rs

1//! Instance creation and management
2
3use crate::sys::*;
4use crate::core::*;
5use crate::ffi::*;
6use std::ptr;
7use std::sync::Arc;
8
9/// Create a Kronos instance
10// SAFETY: This function is called from C code. Caller must ensure:
11// 1. pCreateInfo points to a valid VkInstanceCreateInfo structure
12// 2. pAllocator is either null or points to valid allocation callbacks
13// 3. pInstance points to valid memory for writing the instance handle
14// 4. All pointers remain valid for the duration of this call
15#[no_mangle]
16pub unsafe extern "C" fn vkCreateInstance(
17    pCreateInfo: *const VkInstanceCreateInfo,
18    pAllocator: *const VkAllocationCallbacks,
19    pInstance: *mut VkInstance,
20) -> VkResult {
21    // Validate inputs
22    if pCreateInfo.is_null() || pInstance.is_null() {
23        return VkResult::ErrorInitializationFailed;
24    }
25    // Aggregated mode: create per-ICD instances and return a meta instance
26    if crate::implementation::icd_loader::aggregated_mode_enabled() {
27        let all = crate::implementation::icd_loader::discover_and_load_all_icds();
28        let mut inners = Vec::new();
29        for icd_arc in all {
30            if let Some(create_instance_fn) = icd_arc.create_instance {
31                let mut inner_inst = VkInstance::NULL;
32                let res = create_instance_fn(pCreateInfo, pAllocator, &mut inner_inst);
33                if res == VkResult::Success && !inner_inst.is_null() {
34                    // Clone the ICD and load instance functions
35                    let mut icd_copy = (*icd_arc).clone();
36                    if let Err(e) = crate::implementation::icd_loader::load_instance_functions_for_icd(&mut icd_copy, inner_inst) {
37                        log::warn!("Failed to load instance functions for ICD: {:?}", e);
38                        // Still include it, some functions might work
39                    }
40                    inners.push((Arc::new(icd_copy), inner_inst));
41                }
42            }
43        }
44        if inners.is_empty() {
45            return VkResult::ErrorInitializationFailed;
46        }
47        let meta_id = crate::implementation::icd_loader::new_meta_instance_id();
48        *pInstance = VkInstance::from_raw(meta_id);
49        crate::implementation::icd_loader::set_meta_instance(meta_id, inners);
50        return VkResult::Success;
51    }
52    
53    // Try to use real Vulkan driver (single ICD)
54    if let Some(icd) = super::icd_loader::get_icd() {
55        if let Some(create_instance_fn) = icd.create_instance {
56            let result = create_instance_fn(pCreateInfo, pAllocator, pInstance);
57            
58            // If successful, load instance functions
59            if result == VkResult::Success {
60                let _ = super::icd_loader::update_instance_functions(*pInstance);
61            }
62            
63            return result;
64        }
65    }
66    
67    // No ICD available
68    VkResult::ErrorInitializationFailed
69}
70
71/// Destroy instance
72// SAFETY: This function is called from C code. Caller must ensure:
73// 1. instance is a valid VkInstance created by vkCreateInstance
74// 2. pAllocator matches the allocator used in vkCreateInstance (or both are null)
75// 3. All objects created from this instance have been destroyed
76#[no_mangle]
77pub unsafe extern "C" fn vkDestroyInstance(
78    instance: VkInstance,
79    pAllocator: *const VkAllocationCallbacks,
80) {
81    if instance.is_null() {
82        return;
83    }
84    // Aggregated mode: destroy all inner instances
85    if crate::implementation::icd_loader::aggregated_mode_enabled() {
86        if let Some(inners) = crate::implementation::icd_loader::take_meta_instance(instance.as_raw()) {
87            for (icd, inner) in inners {
88                if let Some(f) = icd.destroy_instance { f(inner, pAllocator); }
89            }
90            return;
91        }
92    }
93    
94    // Forward to real ICD if available
95    if let Some(icd) = super::forward::get_icd_if_enabled() {
96        if let Some(destroy_instance) = icd.destroy_instance {
97            destroy_instance(instance, pAllocator);
98        }
99    }
100}
101
102/// Enumerate physical devices (GPUs)
103// SAFETY: This function is called from C code. Caller must ensure:
104// 1. instance is a valid VkInstance
105// 2. pPhysicalDeviceCount points to valid memory
106// 3. If pPhysicalDevices is not null, it points to an array of at least *pPhysicalDeviceCount elements
107#[no_mangle]
108pub unsafe extern "C" fn vkEnumeratePhysicalDevices(
109    instance: VkInstance,
110    pPhysicalDeviceCount: *mut u32,
111    pPhysicalDevices: *mut VkPhysicalDevice,
112) -> VkResult {
113    if instance.is_null() || pPhysicalDeviceCount.is_null() {
114        return VkResult::ErrorInitializationFailed;
115    }
116    // Aggregated mode: sum counts across all inner instances for this meta instance
117    if crate::implementation::icd_loader::aggregated_mode_enabled() {
118        if let Some(inners) = crate::implementation::icd_loader::meta_instance_for(instance.as_raw()) {
119            let mut total = 0u32;
120            // First pass: count
121            for (icd, inner) in &inners {
122                if let Some(f) = icd.enumerate_physical_devices {
123                    let mut count = 0u32;
124                    let _ = f(*inner, &mut count, ptr::null_mut());
125                    total = total.saturating_add(count);
126                }
127            }
128            if pPhysicalDevices.is_null() {
129                *pPhysicalDeviceCount = total;
130                return VkResult::Success;
131            }
132            // Second pass: fill up to provided capacity
133            let cap = unsafe { *pPhysicalDeviceCount as usize };
134            let mut filled = 0usize;
135            for (icd, inner) in &inners {
136                if let Some(f) = icd.enumerate_physical_devices {
137                    if filled >= cap { break; }
138                    let mut count = (cap - filled) as u32;
139                    let buf_ptr = unsafe { pPhysicalDevices.add(filled) };
140                    let res = f(*inner, &mut count, buf_ptr);
141                    if res == VkResult::Success || res == VkResult::Incomplete {
142                        // Register ownership
143                        for i in 0..count as isize {
144                            let pd = unsafe { *buf_ptr.offset(i) };
145                            crate::implementation::icd_loader::register_physical_device_icd(pd, icd);
146                        }
147                        filled += count as usize;
148                    }
149                }
150            }
151            // Set actual filled count
152            unsafe { *pPhysicalDeviceCount = filled as u32; }
153            if filled < total as usize { return VkResult::Incomplete; }
154            return VkResult::Success;
155        }
156    }
157    
158    // Forward to real ICD (single)
159    if let Some(icd) = super::forward::get_icd_if_enabled() {
160        if let Some(enumerate_physical_devices) = icd.enumerate_physical_devices {
161            return enumerate_physical_devices(instance, pPhysicalDeviceCount, pPhysicalDevices);
162        } else {
163            log::warn!("ICD loaded but enumerate_physical_devices function pointer is null");
164        }
165    } else {
166        log::warn!("No ICD available for enumerate_physical_devices");
167    }
168    
169    // No ICD available
170    VkResult::ErrorInitializationFailed
171}
172
173/// Get physical device properties
174// SAFETY: This function is called from C code. Caller must ensure:
175// 1. physicalDevice is a valid VkPhysicalDevice obtained from vkEnumeratePhysicalDevices
176// 2. pProperties points to valid memory for a VkPhysicalDeviceProperties structure
177#[no_mangle]
178pub unsafe extern "C" fn vkGetPhysicalDeviceProperties(
179    physicalDevice: VkPhysicalDevice,
180    pProperties: *mut VkPhysicalDeviceProperties,
181) {
182    if physicalDevice.is_null() || pProperties.is_null() {
183        return;
184    }
185    // Route by owning ICD if known
186    if let Some(icd) = crate::implementation::icd_loader::icd_for_physical_device(physicalDevice) {
187        if let Some(f) = icd.get_physical_device_properties { f(physicalDevice, pProperties); }
188        return;
189    }
190    // Fallback to single ICD
191    if let Some(icd) = super::forward::get_icd_if_enabled() {
192        if let Some(f) = icd.get_physical_device_properties { f(physicalDevice, pProperties); }
193    }
194}
195
196/// Get physical device memory properties
197// SAFETY: This function is called from C code. Caller must ensure:
198// 1. physicalDevice is a valid VkPhysicalDevice obtained from vkEnumeratePhysicalDevices
199// 2. pMemoryProperties points to valid memory for a VkPhysicalDeviceMemoryProperties structure
200#[no_mangle]
201pub unsafe extern "C" fn vkGetPhysicalDeviceMemoryProperties(
202    physicalDevice: VkPhysicalDevice,
203    pMemoryProperties: *mut VkPhysicalDeviceMemoryProperties,
204) {
205    if physicalDevice.is_null() || pMemoryProperties.is_null() {
206        return;
207    }
208    if let Some(icd) = crate::implementation::icd_loader::icd_for_physical_device(physicalDevice) {
209        if let Some(f) = icd.get_physical_device_memory_properties { f(physicalDevice, pMemoryProperties); }
210        return;
211    }
212    if let Some(icd) = super::forward::get_icd_if_enabled() {
213        if let Some(f) = icd.get_physical_device_memory_properties { f(physicalDevice, pMemoryProperties); }
214    }
215}
216
217/// Get physical device queue family properties
218#[no_mangle]
219pub unsafe extern "C" fn vkGetPhysicalDeviceQueueFamilyProperties(
220    physicalDevice: VkPhysicalDevice,
221    pQueueFamilyPropertyCount: *mut u32,
222    pQueueFamilyProperties: *mut VkQueueFamilyProperties,
223) {
224    if physicalDevice.is_null() || pQueueFamilyPropertyCount.is_null() {
225        return;
226    }
227    if let Some(icd) = crate::implementation::icd_loader::icd_for_physical_device(physicalDevice) {
228        if let Some(f) = icd.get_physical_device_queue_family_properties { f(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); }
229        return;
230    }
231    if let Some(icd) = super::forward::get_icd_if_enabled() {
232        if let Some(f) = icd.get_physical_device_queue_family_properties { f(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); }
233    }
234}