kronos_compute/implementation/
instance.rs

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