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                log::info!("[vkCreateInstance] Single-ICD mode: Loading instance functions for instance {:?}", *pInstance);
61                match super::icd_loader::update_instance_functions(*pInstance) {
62                    Ok(()) => log::info!("[vkCreateInstance] Successfully loaded instance functions"),
63                    Err(e) => log::error!("[vkCreateInstance] Failed to load instance functions: {:?}", e),
64                }
65            }
66            
67            return result;
68        }
69    }
70    
71    // No ICD available
72    VkResult::ErrorInitializationFailed
73}
74
75/// Destroy instance
76// SAFETY: This function is called from C code. Caller must ensure:
77// 1. instance is a valid VkInstance created by vkCreateInstance
78// 2. pAllocator matches the allocator used in vkCreateInstance (or both are null)
79// 3. All objects created from this instance have been destroyed
80#[no_mangle]
81pub unsafe extern "C" fn vkDestroyInstance(
82    instance: VkInstance,
83    pAllocator: *const VkAllocationCallbacks,
84) {
85    if instance.is_null() {
86        return;
87    }
88    // Aggregated mode: destroy all inner instances
89    if crate::implementation::icd_loader::aggregated_mode_enabled() {
90        if let Some(inners) = crate::implementation::icd_loader::take_meta_instance(instance.as_raw()) {
91            for (icd, inner) in inners {
92                if let Some(f) = icd.destroy_instance { f(inner, pAllocator); }
93            }
94            return;
95        }
96    }
97    
98    // Forward to real ICD if available
99    if let Some(icd) = super::forward::get_icd_if_enabled() {
100        if let Some(destroy_instance) = icd.destroy_instance {
101            destroy_instance(instance, pAllocator);
102        }
103    }
104}
105
106/// Enumerate physical devices (GPUs)
107// SAFETY: This function is called from C code. Caller must ensure:
108// 1. instance is a valid VkInstance
109// 2. pPhysicalDeviceCount points to valid memory
110// 3. If pPhysicalDevices is not null, it points to an array of at least *pPhysicalDeviceCount elements
111#[no_mangle]
112pub unsafe extern "C" fn vkEnumeratePhysicalDevices(
113    instance: VkInstance,
114    pPhysicalDeviceCount: *mut u32,
115    pPhysicalDevices: *mut VkPhysicalDevice,
116) -> VkResult {
117    if instance.is_null() || pPhysicalDeviceCount.is_null() {
118        return VkResult::ErrorInitializationFailed;
119    }
120    // Aggregated mode: sum counts across all inner instances for this meta instance
121    if crate::implementation::icd_loader::aggregated_mode_enabled() {
122        if let Some(inners) = crate::implementation::icd_loader::meta_instance_for(instance.as_raw()) {
123            let mut total = 0u32;
124            // First pass: count
125            for (icd, inner) in &inners {
126                if let Some(f) = icd.enumerate_physical_devices {
127                    let mut count = 0u32;
128                    let _ = f(*inner, &mut count, ptr::null_mut());
129                    total = total.saturating_add(count);
130                }
131            }
132            if pPhysicalDevices.is_null() {
133                *pPhysicalDeviceCount = total;
134                return VkResult::Success;
135            }
136            // Second pass: fill up to provided capacity
137            let cap = unsafe { *pPhysicalDeviceCount as usize };
138            let mut filled = 0usize;
139            for (icd, inner) in &inners {
140                if let Some(f) = icd.enumerate_physical_devices {
141                    if filled >= cap { break; }
142                    let mut count = (cap - filled) as u32;
143                    let buf_ptr = unsafe { pPhysicalDevices.add(filled) };
144                    let res = f(*inner, &mut count, buf_ptr);
145                    if res == VkResult::Success || res == VkResult::Incomplete {
146                        // Register ownership
147                        for i in 0..count as isize {
148                            let pd = unsafe { *buf_ptr.offset(i) };
149                            crate::implementation::icd_loader::register_physical_device_icd(pd, icd);
150                        }
151                        filled += count as usize;
152                    }
153                }
154            }
155            // Set actual filled count
156            unsafe { *pPhysicalDeviceCount = filled as u32; }
157            if filled < total as usize { return VkResult::Incomplete; }
158            return VkResult::Success;
159        }
160    }
161    
162    // Forward to real ICD (single)
163    log::debug!("[vkEnumeratePhysicalDevices] Single-ICD mode, forwarding to ICD");
164    if let Some(icd) = super::forward::get_icd_if_enabled() {
165        log::debug!("[vkEnumeratePhysicalDevices] Got ICD, checking enumerate function");
166        if let Some(enumerate_physical_devices) = icd.enumerate_physical_devices {
167            log::debug!("[vkEnumeratePhysicalDevices] Calling ICD's enumerate function");
168            let result = enumerate_physical_devices(instance, pPhysicalDeviceCount, pPhysicalDevices);
169            if pPhysicalDevices.is_null() {
170                log::info!("[vkEnumeratePhysicalDevices] Query returned {} devices", unsafe { *pPhysicalDeviceCount });
171            }
172            return result;
173        } else {
174            log::warn!("[vkEnumeratePhysicalDevices] ICD loaded but enumerate_physical_devices function pointer is null");
175        }
176    } else {
177        log::warn!("No ICD available for enumerate_physical_devices");
178    }
179    
180    // No ICD available
181    VkResult::ErrorInitializationFailed
182}
183
184/// Get physical device properties
185// SAFETY: This function is called from C code. Caller must ensure:
186// 1. physicalDevice is a valid VkPhysicalDevice obtained from vkEnumeratePhysicalDevices
187// 2. pProperties points to valid memory for a VkPhysicalDeviceProperties structure
188#[no_mangle]
189pub unsafe extern "C" fn vkGetPhysicalDeviceProperties(
190    physicalDevice: VkPhysicalDevice,
191    pProperties: *mut VkPhysicalDeviceProperties,
192) {
193    log::debug!("[vkGetPhysicalDeviceProperties] Called with device {:?}", physicalDevice);
194    if physicalDevice.is_null() || pProperties.is_null() {
195        log::error!("[vkGetPhysicalDeviceProperties] Null pointer provided");
196        return;
197    }
198    // Route by owning ICD if known
199    if let Some(icd) = crate::implementation::icd_loader::icd_for_physical_device(physicalDevice) {
200        log::debug!("[vkGetPhysicalDeviceProperties] Found ICD for device, routing call");
201        if let Some(f) = icd.get_physical_device_properties { 
202            f(physicalDevice, pProperties); 
203        } else {
204            log::error!("[vkGetPhysicalDeviceProperties] ICD has no get_physical_device_properties function!");
205        }
206        return;
207    }
208    log::debug!("[vkGetPhysicalDeviceProperties] No ICD found for device, using fallback");
209    // Fallback to single ICD
210    if let Some(icd) = super::forward::get_icd_if_enabled() {
211        if let Some(f) = icd.get_physical_device_properties { 
212            f(physicalDevice, pProperties); 
213        } else {
214            log::error!("[vkGetPhysicalDeviceProperties] Fallback ICD has no get_physical_device_properties function!");
215        }
216    } else {
217        log::error!("[vkGetPhysicalDeviceProperties] No fallback ICD available!");
218    }
219}
220
221/// Get physical device memory properties
222// SAFETY: This function is called from C code. Caller must ensure:
223// 1. physicalDevice is a valid VkPhysicalDevice obtained from vkEnumeratePhysicalDevices
224// 2. pMemoryProperties points to valid memory for a VkPhysicalDeviceMemoryProperties structure
225#[no_mangle]
226pub unsafe extern "C" fn vkGetPhysicalDeviceMemoryProperties(
227    physicalDevice: VkPhysicalDevice,
228    pMemoryProperties: *mut VkPhysicalDeviceMemoryProperties,
229) {
230    if physicalDevice.is_null() || pMemoryProperties.is_null() {
231        return;
232    }
233    if let Some(icd) = crate::implementation::icd_loader::icd_for_physical_device(physicalDevice) {
234        if let Some(f) = icd.get_physical_device_memory_properties { f(physicalDevice, pMemoryProperties); }
235        return;
236    }
237    if let Some(icd) = super::forward::get_icd_if_enabled() {
238        if let Some(f) = icd.get_physical_device_memory_properties { f(physicalDevice, pMemoryProperties); }
239    }
240}
241
242/// Get physical device queue family properties
243#[no_mangle]
244pub unsafe extern "C" fn vkGetPhysicalDeviceQueueFamilyProperties(
245    physicalDevice: VkPhysicalDevice,
246    pQueueFamilyPropertyCount: *mut u32,
247    pQueueFamilyProperties: *mut VkQueueFamilyProperties,
248) {
249    if physicalDevice.is_null() || pQueueFamilyPropertyCount.is_null() {
250        return;
251    }
252    // Try to route by physical device ownership first
253    if let Some(icd) = crate::implementation::icd_loader::icd_for_physical_device(physicalDevice) {
254        log::debug!("[vkGetPhysicalDeviceQueueFamilyProperties] Found ICD for physical device");
255        if let Some(f) = icd.get_physical_device_queue_family_properties { 
256            f(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); 
257        }
258        return;
259    }
260    // Fallback to single ICD
261    log::debug!("[vkGetPhysicalDeviceQueueFamilyProperties] Using fallback single ICD");
262    if let Some(icd) = super::forward::get_icd_if_enabled() {
263        if let Some(f) = icd.get_physical_device_queue_family_properties { 
264            log::debug!("[vkGetPhysicalDeviceQueueFamilyProperties] Calling ICD function");
265            f(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties); 
266        } else {
267            log::warn!("[vkGetPhysicalDeviceQueueFamilyProperties] Function pointer is null");
268        }
269    } else {
270        log::warn!("[vkGetPhysicalDeviceQueueFamilyProperties] No ICD available");
271    }
272}