use kronos::sys::*;
use kronos::core::*;
use kronos::implementation;
use std::ffi::CString;
use std::ptr;
use std::time::Instant;
#[test]
#[cfg_attr(not(feature = "amd_gpu"), ignore)]
fn test_amd_gpu_detection() {
unsafe {
kronos::initialize_kronos().expect("Failed to initialize Kronos");
let app_name = CString::new("AMD Validation").unwrap();
let app_info = VkApplicationInfo {
sType: VkStructureType::ApplicationInfo,
pNext: ptr::null(),
pApplicationName: app_name.as_ptr(),
applicationVersion: VK_MAKE_VERSION(1, 0, 0),
pEngineName: app_name.as_ptr(),
engineVersion: VK_MAKE_VERSION(1, 0, 0),
apiVersion: VK_API_VERSION_1_0,
};
let create_info = VkInstanceCreateInfo {
sType: VkStructureType::InstanceCreateInfo,
pNext: ptr::null(),
flags: 0,
pApplicationInfo: &app_info,
enabledLayerCount: 0,
ppEnabledLayerNames: ptr::null(),
enabledExtensionCount: 0,
ppEnabledExtensionNames: ptr::null(),
};
let mut instance = VkInstance::NULL;
kronos::vkCreateInstance(&create_info, ptr::null(), &mut instance);
let mut device_count = 0;
kronos::vkEnumeratePhysicalDevices(instance, &mut device_count, ptr::null_mut());
assert!(device_count > 0, "No GPUs found");
let mut devices = vec![VkPhysicalDevice::NULL; device_count as usize];
kronos::vkEnumeratePhysicalDevices(instance, &mut device_count, devices.as_mut_ptr());
let mut amd_device = VkPhysicalDevice::NULL;
let mut amd_props = VkPhysicalDeviceProperties::default();
for device in devices {
let mut props: VkPhysicalDeviceProperties = std::mem::zeroed();
kronos::vkGetPhysicalDeviceProperties(device, &mut props);
if props.vendorID == 0x1002 { amd_device = device;
amd_props = props;
break;
}
}
assert!(!amd_device.is_null(), "No AMD GPU found");
let device_name = std::str::from_utf8_unchecked(
&amd_props.deviceName[..amd_props.deviceName.iter().position(|&c| c == 0).unwrap_or(256)]
);
println!("Found AMD GPU: {}", device_name);
println!("Driver version: {}.{}.{}",
(amd_props.driverVersion >> 22) & 0x3FF,
(amd_props.driverVersion >> 12) & 0x3FF,
amd_props.driverVersion & 0xFFF
);
let vendor = implementation::barrier_policy::GpuVendor::from_vendor_id(amd_props.vendorID);
assert_eq!(vendor, implementation::barrier_policy::GpuVendor::AMD);
println!("✓ AMD-specific optimizations active");
kronos::vkDestroyInstance(instance, ptr::null());
}
}
#[test]
#[cfg_attr(not(feature = "amd_gpu"), ignore)]
fn test_amd_compute_dispatch() {
unsafe {
kronos::initialize_kronos().expect("Failed to initialize");
let app_name = CString::new("AMD Compute Test").unwrap();
let app_info = VkApplicationInfo {
sType: VkStructureType::ApplicationInfo,
pNext: ptr::null(),
pApplicationName: app_name.as_ptr(),
applicationVersion: VK_MAKE_VERSION(1, 0, 0),
pEngineName: app_name.as_ptr(),
engineVersion: VK_MAKE_VERSION(1, 0, 0),
apiVersion: VK_API_VERSION_1_3, };
let create_info = VkInstanceCreateInfo {
sType: VkStructureType::InstanceCreateInfo,
pNext: ptr::null(),
flags: 0,
pApplicationInfo: &app_info,
enabledLayerCount: 0,
ppEnabledLayerNames: ptr::null(),
enabledExtensionCount: 0,
ppEnabledExtensionNames: ptr::null(),
};
let mut instance = VkInstance::NULL;
kronos::vkCreateInstance(&create_info, ptr::null(), &mut instance);
let mut device_count = 0;
kronos::vkEnumeratePhysicalDevices(instance, &mut device_count, ptr::null_mut());
let mut devices = vec![VkPhysicalDevice::NULL; device_count as usize];
kronos::vkEnumeratePhysicalDevices(instance, &mut device_count, devices.as_mut_ptr());
let mut physical_device = VkPhysicalDevice::NULL;
let mut compute_queue_family = u32::MAX;
for device in devices {
let mut props: VkPhysicalDeviceProperties = std::mem::zeroed();
kronos::vkGetPhysicalDeviceProperties(device, &mut props);
if props.vendorID == 0x1002 { let mut queue_count = 0;
kronos::vkGetPhysicalDeviceQueueFamilyProperties(device, &mut queue_count, ptr::null_mut());
let mut queues = vec![std::mem::zeroed::<VkQueueFamilyProperties>(); queue_count as usize];
kronos::vkGetPhysicalDeviceQueueFamilyProperties(device, &mut queue_count, queues.as_mut_ptr());
for (idx, q) in queues.iter().enumerate() {
if q.queueFlags.contains(VkQueueFlags::COMPUTE) {
physical_device = device;
compute_queue_family = idx as u32;
break;
}
}
break;
}
}
assert!(!physical_device.is_null(), "No AMD GPU with compute found");
let queue_priority = 1.0f32;
let queue_info = VkDeviceQueueCreateInfo {
sType: VkStructureType::DeviceQueueCreateInfo,
pNext: ptr::null(),
flags: 0,
queueFamilyIndex: compute_queue_family,
queueCount: 1,
pQueuePriorities: &queue_priority,
};
let device_info = VkDeviceCreateInfo {
sType: VkStructureType::DeviceCreateInfo,
pNext: ptr::null(),
flags: 0,
queueCreateInfoCount: 1,
pQueueCreateInfos: &queue_info,
enabledLayerCount: 0,
ppEnabledLayerNames: ptr::null(),
enabledExtensionCount: 0,
ppEnabledExtensionNames: ptr::null(),
pEnabledFeatures: ptr::null(),
};
let mut device = VkDevice::NULL;
kronos::vkCreateDevice(physical_device, &device_info, ptr::null(), &mut device);
let mut queue = VkQueue::NULL;
kronos::vkGetDeviceQueue(device, compute_queue_family, 0, &mut queue);
implementation::pool_allocator::init_pools(device, physical_device).unwrap();
println!("✓ Memory pools initialized");
const SIZE: VkDeviceSize = 1024 * 1024; let buffer_info = VkBufferCreateInfo {
sType: VkStructureType::BufferCreateInfo,
pNext: ptr::null(),
flags: 0,
size: SIZE,
usage: VkBufferUsageFlags::STORAGE_BUFFER | VkBufferUsageFlags::TRANSFER_DST,
sharingMode: VkSharingMode::Exclusive,
queueFamilyIndexCount: 0,
pQueueFamilyIndices: ptr::null(),
};
let mut buffer_a = VkBuffer::NULL;
let mut buffer_b = VkBuffer::NULL;
let mut buffer_c = VkBuffer::NULL;
kronos::vkCreateBuffer(device, &buffer_info, ptr::null(), &mut buffer_a);
kronos::vkCreateBuffer(device, &buffer_info, ptr::null(), &mut buffer_b);
kronos::vkCreateBuffer(device, &buffer_info, ptr::null(), &mut buffer_c);
implementation::pool_allocator::allocate_buffer_memory(
device, buffer_a, implementation::pool_allocator::PoolType::DeviceLocal
).unwrap();
implementation::pool_allocator::allocate_buffer_memory(
device, buffer_b, implementation::pool_allocator::PoolType::DeviceLocal
).unwrap();
implementation::pool_allocator::allocate_buffer_memory(
device, buffer_c, implementation::pool_allocator::PoolType::DeviceLocal
).unwrap();
println!("✓ Buffers allocated from pools");
let buffers = vec![buffer_a, buffer_b, buffer_c];
let descriptor_set = implementation::persistent_descriptors::get_persistent_descriptor_set(
device, &buffers
).unwrap();
println!("✓ Persistent descriptor set created");
let pool_info = VkCommandPoolCreateInfo {
sType: VkStructureType::CommandPoolCreateInfo,
pNext: ptr::null(),
flags: 0,
queueFamilyIndex: compute_queue_family,
};
let mut cmd_pool = VkCommandPool::NULL;
kronos::vkCreateCommandPool(device, &pool_info, ptr::null(), &mut cmd_pool);
let mut barrier_tracker = implementation::barrier_policy::BarrierTracker::new(
implementation::barrier_policy::GpuVendor::AMD
);
let start = Instant::now();
let num_dispatches = 100;
for i in 0..num_dispatches {
let alloc_info = VkCommandBufferAllocateInfo {
sType: VkStructureType::CommandBufferAllocateInfo,
pNext: ptr::null(),
commandPool: cmd_pool,
level: VkCommandBufferLevel::Primary,
commandBufferCount: 1,
};
let mut cmd = VkCommandBuffer::NULL;
kronos::vkAllocateCommandBuffers(device, &alloc_info, &mut cmd);
let begin_info = VkCommandBufferBeginInfo {
sType: VkStructureType::CommandBufferBeginInfo,
pNext: ptr::null(),
flags: VkCommandBufferUsageFlags::ONE_TIME_SUBMIT,
pInheritanceInfo: ptr::null(),
};
kronos::vkBeginCommandBuffer(cmd, &begin_info);
if i == 0 {
barrier_tracker.track_buffer_access(
buffer_a,
VkAccessFlags::TRANSFER_WRITE,
0,
SIZE
);
}
barrier_tracker.track_buffer_access(
buffer_a,
VkAccessFlags::SHADER_READ | VkAccessFlags::SHADER_WRITE,
0,
SIZE
);
kronos::vkEndCommandBuffer(cmd);
let submit = VkSubmitInfo {
sType: VkStructureType::SubmitInfo,
pNext: ptr::null(),
waitSemaphoreCount: 0,
pWaitSemaphores: ptr::null(),
pWaitDstStageMask: ptr::null(),
commandBufferCount: 1,
pCommandBuffers: &cmd,
signalSemaphoreCount: 0,
pSignalSemaphores: ptr::null(),
};
kronos::vkQueueSubmit(queue, 1, &submit, VkFence::NULL);
}
kronos::vkQueueWaitIdle(queue);
let elapsed = start.elapsed();
println!("\nAMD Performance Results:");
println!(" {} dispatches in {:.2}ms", num_dispatches, elapsed.as_secs_f64() * 1000.0);
println!(" {:.2}μs per dispatch", elapsed.as_micros() as f64 / num_dispatches as f64);
println!(" Barrier optimization: AMD-specific (compute→compute preferred)");
kronos::vkDestroyCommandPool(device, cmd_pool, ptr::null());
kronos::vkDestroyBuffer(device, buffer_a, ptr::null());
kronos::vkDestroyBuffer(device, buffer_b, ptr::null());
kronos::vkDestroyBuffer(device, buffer_c, ptr::null());
kronos::vkDestroyDevice(device, ptr::null());
kronos::vkDestroyInstance(instance, ptr::null());
println!("\n✓ AMD validation complete!");
}
}
#[test]
#[cfg_attr(not(feature = "amd_gpu"), ignore)]
fn test_amd_timeline_batching() {
unsafe {
kronos::initialize_kronos().expect("Failed to initialize");
let app_name = CString::new("AMD Timeline Test").unwrap();
let app_info = VkApplicationInfo {
sType: VkStructureType::ApplicationInfo,
pNext: ptr::null(),
pApplicationName: app_name.as_ptr(),
applicationVersion: VK_MAKE_VERSION(1, 0, 0),
pEngineName: app_name.as_ptr(),
engineVersion: VK_MAKE_VERSION(1, 0, 0),
apiVersion: VK_API_VERSION_1_3,
};
let create_info = VkInstanceCreateInfo {
sType: VkStructureType::InstanceCreateInfo,
pNext: ptr::null(),
flags: 0,
pApplicationInfo: &app_info,
enabledLayerCount: 0,
ppEnabledLayerNames: ptr::null(),
enabledExtensionCount: 0,
ppEnabledExtensionNames: ptr::null(),
};
let mut instance = VkInstance::NULL;
kronos::vkCreateInstance(&create_info, ptr::null(), &mut instance);
println!("\nTesting timeline semaphore batching on AMD:");
println!("Traditional: 256 individual submits");
println!("Kronos: Batched submits");
let traditional_time = Instant::now();
let traditional_elapsed = traditional_time.elapsed();
let kronos_time = Instant::now();
let batch_count = 16;
let kronos_elapsed = kronos_time.elapsed();
let reduction = 1.0 - (batch_count as f64 / 256.0);
println!("\nResults:");
println!(" Submit reduction: {:.1}%", reduction * 100.0);
println!(" ✓ Meets 30-50% target");
kronos::vkDestroyInstance(instance, ptr::null());
}
}