### Run Texture Example Source: https://github.com/ash-rs/ash/blob/master/README.md Compiles and runs the 'texture' example from the ash-examples crate, which displays a texture on a quad. ```sh cargo run -p ash-examples --bin texture ``` -------------------------------- ### Setup Vulkan Instance and Logical Device Source: https://context7.com/ash-rs/ash/llms.txt Enumerates physical devices, selects a discrete GPU if available, finds a graphics queue family, and creates a logical device with swapchain support. Requires an existing `ash::Instance`. ```rust use ash::{vk, Instance}; unsafe fn setup_device(instance: &Instance) -> Result<(vk::PhysicalDevice, ash::Device), vk::Result> { // Enumerate GPUs let physical_devices = instance.enumerate_physical_devices()?; // Pick a discrete GPU if available, otherwise the first device let physical_device = physical_devices.iter().copied() .find(|&pd| { let props = instance.get_physical_device_properties(pd); props.device_type == vk::PhysicalDeviceType::DISCRETE_GPU }) .unwrap_or(physical_devices[0]); let props = instance.get_physical_device_properties(physical_device); let name = std::ffi::CStr::from_ptr(props.device_name.as_ptr()); println!("Using GPU: {:?}", name); // Find a queue family supporting graphics let queue_families = instance.get_physical_device_queue_family_properties(physical_device); let graphics_family = queue_families.iter().enumerate() .find(|(_, qf)| qf.queue_flags.contains(vk::QueueFlags::GRAPHICS)) .map(|(i, _)| i as u32) .expect("No graphics queue family"); // Query memory properties (for later allocation) let _mem_props = instance.get_physical_device_memory_properties(physical_device); // Query Vulkan 1.1 extended features via pNext chain let mut vk11_features = vk::PhysicalDeviceVulkan11Features::default(); let mut features2 = vk::PhysicalDeviceFeatures2::default() .push(&mut vk11_features); instance.get_physical_device_features2(physical_device, &mut features2); println!("multiview: {}", vk11_features.multiview); // Create logical device let queue_priority = [1.0_f32]; let queue_info = vk::DeviceQueueCreateInfo::default() .queue_family_index(graphics_family) .queue_priorities(&queue_priority); let extension_names = [ash::khr::swapchain::NAME.as_ptr()]; let device_create_info = vk::DeviceCreateInfo::default() .queue_create_infos(std::slice::from_ref(&queue_info)) .enabled_extension_names(&extension_names); let device = instance.create_device(physical_device, &device_create_info, None)?; Ok((physical_device, device)) } ``` -------------------------------- ### Run Triangle Example Source: https://github.com/ash-rs/ash/blob/master/README.md Compiles and runs the 'triangle' example from the ash-examples crate, which displays a triangle with vertex colors. ```sh cargo run -p ash-examples --bin triangle ``` -------------------------------- ### Setup Vulkan Swapchain with khr::swapchain Source: https://context7.com/ash-rs/ash/llms.txt This function sets up a Vulkan swapchain using the `khr::swapchain` extension. It queries surface capabilities, selects an appropriate format and present mode, and creates the swapchain. Ensure that the `ash::Instance` and `ash::Device` are valid and that the `khr::surface::Instance` loader is correctly initialized. ```rust use ash::{khr, vk}; unsafe fn setup_swapchain( instance: &ash::Instance, device: &ash::Device, surface_loader: &khr::surface::Instance, surface: vk::SurfaceKHR, physical_device: vk::PhysicalDevice, width: u32, height: u32, ) -> Result<(vk::SwapchainKHR, Vec, vk::Format, vk::Extent2D), vk::Result> { let swapchain_loader = khr::swapchain::Device::new(instance, device); // Query surface capabilities and supported formats let capabilities = surface_loader .get_physical_device_surface_capabilities(physical_device, surface)?; let formats = surface_loader .get_physical_device_surface_formats(physical_device, surface)?; let present_modes = surface_loader .get_physical_device_surface_present_modes(physical_device, surface)?; // Pick format: prefer BGRA8_SRGB / SRGB_NONLINEAR let format = formats.iter().copied() .find(|f| { f.format == vk::Format::B8G8R8A8_SRGB && f.color_space == vk::ColorSpaceKHR::SRGB_NONLINEAR }) .unwrap_or(formats[0]); // Pick present mode: prefer MAILBOX (triple buffer) over FIFO (vsync) let present_mode = present_modes.iter().copied() .find(|&pm| pm == vk::PresentModeKHR::MAILBOX) .unwrap_or(vk::PresentModeKHR::FIFO); // Choose swap extent let extent = if capabilities.current_extent.width != u32::MAX { capabilities.current_extent } else { vk::Extent2D { width: width.clamp(capabilities.min_image_extent.width, capabilities.max_image_extent.width), height: height.clamp(capabilities.min_image_extent.height, capabilities.max_image_extent.height), } }; let image_count = (capabilities.min_image_count + 1) .min(if capabilities.max_image_count > 0 { capabilities.max_image_count } else { u32::MAX }); let create_info = vk::SwapchainCreateInfoKHR::default() .surface(surface) .min_image_count(image_count) .image_format(format.format) .image_color_space(format.color_space) .image_extent(extent) .image_array_layers(1) .image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT) .image_sharing_mode(vk::SharingMode::EXCLUSIVE) .pre_transform(capabilities.current_transform) .composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE) .present_mode(present_mode) .clipped(true); let swapchain = swapchain_loader.create_swapchain(&create_info, None)?; let images = swapchain_loader.get_swapchain_images(swapchain)?; Ok((swapchain, images, format.format, extent)) } ``` -------------------------------- ### Get Extension Names for Instance and Device Source: https://context7.com/ash-rs/ash/llms.txt Retrieves extension names for instance and device creation. Includes platform-specific extensions for Windows and Linux. ```rust use ash::{khr, ext, vk}; fn extension_names_for_instance() -> Vec<*const std::os::raw::c_char> { vec![ khr::surface::NAME.as_ptr(), #[cfg(target_os = "windows")] khr::win32_surface::NAME.as_ptr(), #[cfg(target_os = "linux")] khr::wayland_surface::NAME.as_ptr(), ext::debug_utils::NAME.as_ptr(), ] } fn extension_names_for_device() -> Vec<*const std::os::raw::c_char> { vec![ khr::swapchain::NAME.as_ptr(), khr::dynamic_rendering::NAME.as_ptr(), khr::timeline_semaphore::NAME.as_ptr(), ] } ``` -------------------------------- ### Setup Vulkan Debugging and Callback Source: https://context7.com/ash-rs/ash/llms.txt Configures a Vulkan debug messenger with a custom Rust callback to receive validation layer messages. It also demonstrates naming a Vulkan buffer object for GPU debuggers. ```rust use ash::{ext, vk}; use std::ffi::CStr; use std::os::raw::c_void; unsafe extern "system" fn vulkan_debug_callback( message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, message_type: vk::DebugUtilsMessageTypeFlagsEXT, p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT<'_>, _user_data: *mut c_void, ) -> vk::Bool32 { let message = CStr::from_ptr((*p_callback_data).p_message); let severity = match message_severity { vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => "ERROR", vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => "WARNING", vk::DebugUtilsMessageSeverityFlagsEXT::INFO => "INFO", _ => "VERBOSE", }; eprintln!("[Vulkan {severity} {message_type:?}] {{:?}}", message); vk::FALSE } unsafe fn setup_debug( entry: &ash::Entry, instance: &ash::Instance, device: &ash::Device, buffer: vk::Buffer, ) -> Result<(ext::debug_utils::Instance, vk::DebugUtilsMessengerEXT), vk::Result> { let debug_utils = ext::debug_utils::Instance::new(entry, instance); let messenger_info = vk::DebugUtilsMessengerCreateInfoEXT::default() .message_severity( vk::DebugUtilsMessageSeverityFlagsEXT::ERROR | vk::DebugUtilsMessageSeverityFlagsEXT::WARNING | vk::DebugUtilsMessageSeverityFlagsEXT::INFO, ) .message_type( vk::DebugUtilsMessageTypeFlagsEXT::GENERAL | vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION | vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE, ) .pfn_user_callback(Some(vulkan_debug_callback)); let messenger = debug_utils.create_debug_utils_messenger(&messenger_info, None)?; // Name a buffer for GPU debuggers (RenderDoc, Nsight, etc.) let debug_device = ext::debug_utils::Device::new(instance, device); let buffer_name = std::ffi::CString::new("VertexBuffer").unwrap(); let name_info = vk::DebugUtilsObjectNameInfoEXT::default() .object_handle(buffer) .object_name(&buffer_name); debug_device.set_debug_utils_object_name(&name_info)?; Ok((debug_utils, messenger)) } ``` -------------------------------- ### Timeline Semaphore Synchronization (Vulkan 1.2) Source: https://context7.com/ash-rs/ash/llms.txt Utilize timeline semaphores for advanced CPU/GPU synchronization by managing 64-bit counter values. This example demonstrates creating, signaling, waiting, and submitting work with timeline semaphores. ```rust use ash::vk; unsafe fn timeline_semaphore_example(device: &ash::Device) -> Result<(), vk::Result> { // Create a timeline semaphore starting at value 0 let mut type_info = vk::SemaphoreTypeCreateInfo::default() .semaphore_type(vk::SemaphoreType::TIMELINE) .initial_value(0); let semaphore_info = vk::SemaphoreCreateInfo::default().push(&mut type_info); let timeline_sem = device.create_semaphore(&semaphore_info, None)?; // Signal from CPU: advance counter to 1 let signal_info = vk::SemaphoreSignalInfo::default() .semaphore(timeline_sem) .value(1); device.signal_semaphore(&signal_info)?; // Submit GPU work: wait for value 1, signal value 2 let wait_values = [1_u64]; let signal_values = [2_u64]; let mut timeline_submit = vk::TimelineSemaphoreSubmitInfo::default() .wait_semaphore_values(&wait_values) .signal_semaphore_values(&signal_values); let wait_semaphores = [timeline_sem]; let signal_semaphores = [timeline_sem]; let wait_stages = [vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT]; let submit_info = vk::SubmitInfo::default() .wait_semaphores(&wait_semaphores) .wait_dst_stage_mask(&wait_stages) .signal_semaphores(&signal_semaphores) .push(&mut timeline_submit); let queue = device.get_device_queue(0, 0); device.queue_submit(queue, &[submit_info], vk::Fence::null())?; // CPU wait: block until counter reaches 2 let wait_info = vk::SemaphoreWaitInfo::default() .semaphores(std::slice::from_ref(&timeline_sem)) .values(&[2]); device.wait_semaphores(&wait_info, u64::MAX)?; println!("Timeline semaphore counter value: {}", device.get_semaphore_counter_value(timeline_sem)?); device.destroy_semaphore(timeline_sem, None); Ok(()) } ``` -------------------------------- ### Get Supported Extension Names Source: https://github.com/ash-rs/ash/blob/master/README.md Collects a list of supported Vulkan extension names, including surface, Xlib surface, and debug utils extensions. This is typically used on Unix-like systems. ```rust use ash::{ext, khr}; #[cfg(all(unix, not(target_os = "android")))] fn extension_names() -> Vec<*const i8> { vec![ khr::surface::NAME.as_ptr(), khr::xlib_surface::NAME.as_ptr(), ext::debug_utils::NAME.as_ptr(), ] } ``` -------------------------------- ### Get Swapchain Images with Vec Source: https://github.com/ash-rs/ash/blob/master/README.md Illustrates fetching swapchain images using `get_swapchain_images_khr`, which returns a `VkResult>`. This approach uses a `Vec` for convenience when the number of images is known or manageable. ```rust pub fn get_swapchain_images(&self, swapchain: vk::SwapchainKHR) -> VkResult>; let present_images = swapchain_loader.get_swapchain_images_khr(swapchain).unwrap(); ``` -------------------------------- ### Load Vulkan and Create Instance in Rust Source: https://context7.com/ash-rs/ash/llms.txt Demonstrates runtime Vulkan loading using `Entry::load()`, querying instance version, enumerating extensions and layers, and creating a Vulkan instance with application info and enabled layers/extensions. Explicit cleanup of the instance is required. ```rust use ash::{vk, Entry}; use std::ffi::CStr; fn main() -> Result<(), Box> { // Runtime loading (default "loaded" feature) let entry = unsafe { Entry::load()? }; // Query Vulkan instance version let version = entry.try_enumerate_instance_version()? .unwrap_or(vk::make_api_version(0, 1, 0, 0)); println!("Vulkan {}.{}.{}", vk::api_version_major(version), vk::api_version_minor(version), vk::api_version_patch(version), ); // Enumerate available instance extensions let ext_props = entry.enumerate_instance_extension_properties(None)?; for prop in &ext_props { let name = unsafe { CStr::from_ptr(prop.extension_name.as_ptr()) }; println!("Extension: {:?}", name); } // Enumerate validation layers let layer_props = entry.enumerate_instance_layer_properties()?; for layer in &layer_props { let name = unsafe { CStr::from_ptr(layer.layer_name.as_ptr()) }; println!("Layer: {:?}", name); } // Build ApplicationInfo and InstanceCreateInfo let app_name = c"MyApp"; let engine_name = c"NoEngine"; let app_info = vk::ApplicationInfo::default() .application_name(app_name) .application_version(vk::make_api_version(0, 1, 0, 0)) .engine_name(engine_name) .engine_version(vk::make_api_version(0, 1, 0, 0)) .api_version(vk::API_VERSION_1_3); let layer_names = [c"VK_LAYER_KHRONOS_validation".as_ptr()]; let extension_names = [ash::ext::debug_utils::NAME.as_ptr()]; let create_info = vk::InstanceCreateInfo::default() .application_info(&app_info) .enabled_layer_names(&layer_names) .enabled_extension_names(&extension_names); let instance = unsafe { entry.create_instance(&create_info, None)? }; // Cleanup (no Drop — must be explicit) unsafe { instance.destroy_instance(None) }; Ok(()) } ``` -------------------------------- ### Device Creation with Builder Pattern Source: https://github.com/ash-rs/ash/blob/master/README.md Demonstrates the builder pattern for creating a Vulkan `Device`. This pattern allows for a more readable and chained construction of complex structs like `DeviceCreateInfo`. ```rust let queue_info = [vk::DeviceQueueCreateInfo::default() .queue_family_index(queue_family_index) .queue_priorities(&priorities)]; let device_create_info = vk::DeviceCreateInfo::default() .queue_create_infos(&queue_info) .enabled_extension_names(&device_extension_names_raw) .enabled_features(&features); let device: Device = instance .create_device(pdevice, &device_create_info, None) .unwrap(); ``` -------------------------------- ### Create Vulkan Surface with Winit and ash-window Source: https://context7.com/ash-rs/ash/llms.txt Shows how to create a Vulkan surface (vk::SurfaceKHR) from a winit window using the ash-window crate. It first enumerates required instance extensions and then creates the surface, returning the surface handle. ```rust use ash::{khr, vk}; use raw_window_handle::{HasDisplayHandle, HasWindowHandle}; // With winit (or any HasDisplayHandle/HasWindowHandle implementor): fn create_surface_with_winit( entry: &ash::Entry, instance: &ash::Instance, event_loop: &winit::event_loop::EventLoop<()>, window: &winit::window::Window, ) -> Result> { // 1. Discover required instance extensions for this platform let required_extensions = ash_window::enumerate_required_extensions( event_loop.display_handle()?.as_raw() )?; // Pass these to InstanceCreateInfo::enabled_extension_names() // (see Entry section above for full Instance creation example) println!("Required extensions: {}", required_extensions.len()); // 2. Create the surface let surface = unsafe { ash_window::create_surface( entry, instance, event_loop.display_handle()?.as_raw(), window.window_handle()?.as_raw(), None, // allocation callbacks )? }; // 3. Verify physical device can present to this surface let surface_loader = khr::surface::Instance::new(entry, instance); // ... enumerate_physical_devices, then: // surface_loader.get_physical_device_surface_support(pd, queue_family, surface)? // Cleanup when done: // unsafe { surface_loader.destroy_surface(surface, None) }; Ok(surface) } ``` -------------------------------- ### Create Vulkan Instance with Result Source: https://github.com/ash-rs/ash/blob/master/README.md Demonstrates creating a Vulkan instance using the `create_instance` function, which returns a `Result` type. Use `.expect()` for simple error handling or proper `match` for robust error management. ```rust pub fn create_instance(&self, create_info: &vk::InstanceCreateInfo<'_>, allocation_callbacks: Option<&vk::AllocationCallbacks<'_>>) -> Result { .. } let instance = entry.create_instance(&create_info, None) .expect("Instance creation error"); ``` -------------------------------- ### Create Vulkan Surface Source: https://github.com/ash-rs/ash/blob/master/ash-window/README.md Use create_surface to generate a Vulkan surface from window handles. Ensure you have the necessary ash entry and instance objects. ```rust ash_window::create_surface(&entry, &instance, &window, None)?; ``` -------------------------------- ### Create Vulkan Device with Features using Builder Pattern Source: https://context7.com/ash-rs/ash/llms.txt Demonstrates composing a pNext feature chain for Vulkan device creation using the builder pattern. Ensure that referenced data outlives the struct by using borrow-checked lifetime parameters. ```rust use ash::vk; use ash::vk::TaggedStructure as _; unsafe fn create_device_with_features( instance: &ash::Instance, physical_device: vk::PhysicalDevice, ) -> Result { // Compose pNext feature chain let mut dynamic_rendering = vk::PhysicalDeviceDynamicRenderingFeatures::default() .dynamic_rendering(true); let mut timeline_semaphore = vk::PhysicalDeviceTimelineSemaphoreFeatures::default() .timeline_semaphore(true); let mut vk12_features = vk::PhysicalDeviceVulkan12Features::default() .buffer_device_address(true) .descriptor_indexing(true); // push() is safe: validates next.p_next is NULL, then prepends to chain let queue_priority = [1.0_f32]; let queue_info = vk::DeviceQueueCreateInfo::default() .queue_family_index(0) .queue_priorities(&queue_priority); let extension_names = [ ash::khr::swapchain::NAME.as_ptr(), ash::khr::dynamic_rendering::NAME.as_ptr(), ]; let device_create_info = vk::DeviceCreateInfo::default() .queue_create_infos(std::slice::from_ref(&queue_info)) .enabled_extension_names(&extension_names) // Chain: DeviceCreateInfo -> vk12_features -> timeline_semaphore -> dynamic_rendering .push(&mut dynamic_rendering) .push(&mut timeline_semaphore) .push(&mut vk12_features); instance.create_device(physical_device, &device_create_info, None) } ``` -------------------------------- ### Build Bottom-Level Acceleration Structure (BLAS) Source: https://context7.com/ash-rs/ash/llms.txt Demonstrates building a Bottom-Level Acceleration Structure (BLAS) for ray tracing. Requires vertex and index buffer addresses, counts, and Vulkan device access. It queries necessary buffer sizes and creates the acceleration structure buffer. ```rust use ash::{khr, vk}; unsafe fn build_blas( instance: &ash::Instance, device: &ash::Device, physical_device: vk::PhysicalDevice, vertex_buffer_address: vk::DeviceAddress, index_buffer_address: vk::DeviceAddress, vertex_count: u32, triangle_count: u32, ) -> Result { let accel_loader = khr::acceleration_structure::Device::new(instance, device); // Describe triangles geometry let triangles = vk::AccelerationStructureGeometryTrianglesDataKHR::default() .vertex_format(vk::Format::R32G32B32_SFLOAT) .vertex_data(vk::DeviceOrHostAddressConstKHR { device_address: vertex_buffer_address }) .vertex_stride(12) .max_vertex(vertex_count - 1) .index_type(vk::IndexType::UINT32) .index_data(vk::DeviceOrHostAddressConstKHR { device_address: index_buffer_address }); let geometry = vk::AccelerationStructureGeometryKHR::default() .geometry_type(vk::GeometryTypeKHR::TRIANGLES) .geometry(vk::AccelerationStructureGeometryDataKHR { triangles }) .flags(vk::GeometryFlagsKHR::OPAQUE); let build_info = vk::AccelerationStructureBuildGeometryInfoKHR::default() .ty(vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL) .flags(vk::BuildAccelerationStructureFlagsKHR::PREFER_FAST_TRACE) .geometries(std::slice::from_ref(&geometry)); // Query scratch and AS buffer sizes let sizes = accel_loader.get_acceleration_structure_build_sizes( vk::AccelerationBuildTypeKHR::DEVICE, &build_info, &[triangle_count], ); println!("AS size: {}, scratch: {}", sizes.acceleration_structure_size, sizes.build_scratch_size); // Create AS buffer (omitted: buffer + memory allocation for brevity) let as_buffer_info = vk::BufferCreateInfo::default() .size(sizes.acceleration_structure_size) .usage(vk::BufferUsageFlags::ACCELERATION_STRUCTURE_STORAGE_KHR | vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS); let as_buffer = device.create_buffer(&as_buffer_info, None)?; let create_info = vk::AccelerationStructureCreateInfoKHR::default() .ty(vk::AccelerationStructureTypeKHR::BOTTOM_LEVEL) .size(sizes.acceleration_structure_size) .buffer(as_buffer) .offset(0); let blas = accel_loader.create_acceleration_structure(&create_info, None)?; Ok(blas) } ``` -------------------------------- ### Query Physical Device Features with pNext Chain Source: https://context7.com/ash-rs/ash/llms.txt Demonstrates querying physical device features, including extensions, by building a pNext chain. The `push()` method is used to safely append structures to the chain. ```rust unsafe fn query_features(instance: &ash::Instance, pd: vk::PhysicalDevice) { let mut mesh_shader = vk::PhysicalDeviceMeshShaderFeaturesEXT::default(); let mut features2 = vk::PhysicalDeviceFeatures2::default() .push(&mut mesh_shader); instance.get_physical_device_features2(pd, &mut features2); println!("mesh shader supported: {}", mesh_shader.mesh_shader); } ``` -------------------------------- ### create_surface Source: https://github.com/ash-rs/ash/blob/master/ash-window/README.md Allows to create a Vulkan surface from a type implementing RawDisplayHandle and RawWindowHandle. ```APIDOC ## create_surface ### Description Allows to create a Vulkan surface from a type implementing `RawDisplayHandle` and `RawWindowHandle`. ### Function Signature `fn create_surface(entry: &Instance, instance: &Instance, window: W, allocator: Option<&vk::AllocationCallbacks>) -> Result, vk::FFIError> where W: HasWindowHandle, D: HasDisplayHandle, ### Parameters #### Path Parameters - **entry** (`&Instance`) - Required - The Vulkan entry point. - **instance** (`&Instance`) - Required - The Vulkan instance. - **window** (`W: HasWindowHandle`) - Required - The window handle. - **allocator** (`Option<&vk::AllocationCallbacks>`) - Optional - Custom allocator callbacks. ### Response #### Success Response - `Surface` - A Vulkan surface object. - `vk::FFIError` - Indicates failure during the FFI call. ``` -------------------------------- ### Render Frame with Device Operations Source: https://context7.com/ash-rs/ash/llms.txt Demonstrates memory allocation, buffer creation, command buffer recording, and queue submission using the ash::Device. Ensure proper memory type selection and synchronization mechanisms are used in practice. ```rust use ash::{vk, Device}; unsafe fn render_frame(device: &Device) -> Result<(), vk::Result> { // --- Memory & Buffers --- let buffer_info = vk::BufferCreateInfo::default() .size(1024) .usage(vk::BufferUsageFlags::VERTEX_BUFFER | vk::BufferUsageFlags::TRANSFER_DST) .sharing_mode(vk::SharingMode::EXCLUSIVE); let buffer = device.create_buffer(&buffer_info, None)?; let mem_req = device.get_buffer_memory_requirements(buffer); let alloc_info = vk::MemoryAllocateInfo::default() .allocation_size(mem_req.size) .memory_type_index(0); // select appropriate index in practice let memory = device.allocate_memory(&alloc_info, None)?; device.bind_buffer_memory(buffer, memory, 0)?; // Map, write, unmap host-visible memory let ptr = device.map_memory(memory, 0, mem_req.size, vk::MemoryMapFlags::empty())?; let vertices: &[f32] = &[0.0, -0.5, 0.5, 0.5, -0.5, 0.5]; std::ptr::copy_nonoverlapping(vertices.as_ptr() as *const u8, ptr as *mut u8, 24); device.unmap_memory(memory); // --- Command Buffers --- let pool_info = vk::CommandPoolCreateInfo::default() .queue_family_index(0) .flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER); let cmd_pool = device.create_command_pool(&pool_info, None)?; let alloc_info = vk::CommandBufferAllocateInfo::default() .command_pool(cmd_pool) .level(vk::CommandBufferLevel::PRIMARY) .command_buffer_count(1); let cmd_buffers = device.allocate_command_buffers(&alloc_info)?; let cmd = cmd_buffers[0]; let begin_info = vk::CommandBufferBeginInfo::default() .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT); device.begin_command_buffer(cmd, &begin_info)?; // Bind vertex buffer and draw device.cmd_bind_vertex_buffers(cmd, 0, &[buffer], &[0]); device.cmd_draw(cmd, 3, 1, 0, 0); device.end_command_buffer(cmd)?; // --- Synchronization & Submit --- let fence_info = vk::FenceCreateInfo::default(); let fence = device.create_fence(&fence_info, None)?; let submit_info = vk::SubmitInfo::default() .command_buffers(&cmd_buffers); let queue = device.get_device_queue(0, 0); device.queue_submit(queue, &[submit_info], fence)?; // Wait for GPU to finish device.wait_for_fences(&[fence], true, u64::MAX)?; // Cleanup device.destroy_fence(fence, None); device.free_command_buffers(cmd_pool, &cmd_buffers); device.destroy_command_pool(cmd_pool, None); device.destroy_buffer(buffer, None); device.free_memory(memory, None); Ok(()) } ``` -------------------------------- ### Dynamic Rendering without RenderPass (Vulkan 1.3) Source: https://context7.com/ash-rs/ash/llms.txt Use `cmd_begin_rendering` and `cmd_end_rendering` to perform rendering without explicit `VkRenderPass` and `VkFramebuffer` objects. Ensure image layouts are correctly transitioned before and after rendering. ```rust use ash::vk; unsafe fn render_without_render_pass( device: &ash::Device, cmd: vk::CommandBuffer, color_image_view: vk::ImageView, depth_image_view: vk::ImageView, extent: vk::Extent2D, ) -> Result<(), vk::Result> { // Transition color image to COLOR_ATTACHMENT_OPTIMAL (pipeline barrier omitted for brevity) let color_attachment = vk::RenderingAttachmentInfo::default() .image_view(color_image_view) .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL) .load_op(vk::AttachmentLoadOp::CLEAR) .store_op(vk::AttachmentStoreOp::STORE) .clear_value(vk::ClearValue { color: vk::ClearColorValue { float32: [0.0, 0.0, 0.0, 1.0] }, }); let depth_attachment = vk::RenderingAttachmentInfo::default() .image_view(depth_image_view) .image_layout(vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL) .load_op(vk::AttachmentLoadOp::CLEAR) .store_op(vk::AttachmentStoreOp::DONT_CARE) .clear_value(vk::ClearValue { depth_stencil: vk::ClearDepthStencilValue { depth: 1.0, stencil: 0 }, }); let rendering_info = vk::RenderingInfo::default() .render_area(vk::Rect2D { offset: vk::Offset2D::default(), extent, }) .layer_count(1) .color_attachments(std::slice::from_ref(&color_attachment)) .depth_attachment(&depth_attachment); device.cmd_begin_rendering(cmd, &rendering_info); // Bind pipeline, descriptor sets, vertex buffers, then draw device.cmd_draw(cmd, 3, 1, 0, 0); device.cmd_end_rendering(cmd); Ok(()) } ``` -------------------------------- ### Using vk::DeviceQueueCreateInfo with Lifetimes Source: https://github.com/ash-rs/ash/blob/master/Changelog.md Demonstrates the updated pattern for creating vk::DeviceQueueCreateInfo, where builder functions and lifetime generics are moved directly to the underlying Vulkan struct. This ensures that types carry lifetime information of contained references. ```rust let queue_info = [vk::DeviceQueueCreateInfo::default() .queue_family_index(queue_family_index) .queue_priorities(&priorities)]; ``` -------------------------------- ### Create Vulkan Command Pool Source: https://github.com/ash-rs/ash/blob/master/README.md Creates a Vulkan command pool using the device object. Handles implicit passing of instance and device handles. ```rust pub fn create_command_pool(&self, create_info: &vk::CommandPoolCreateInfo<'_>) -> VkResult; let pool = device.create_command_pool(&pool_create_info).unwrap(); ``` -------------------------------- ### Using Command Pool Create Flags Source: https://github.com/ash-rs/ash/blob/master/Changelog.md Demonstrates the transition from using `vk::COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT` to the more idiomatic `vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER_BIT` in Ash. ```Rust flags: vk::COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, //to flags: vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER_BIT, ``` -------------------------------- ### enumerate_required_extensions Source: https://github.com/ash-rs/ash/blob/master/ash-window/README.md Returns the required instance extensions needed for surface creation from a specific display handle. ```APIDOC ## enumerate_required_extensions ### Description Returns the required instance extensions needed for surface creation from a specific display handle. ### Function Signature `fn enumerate_required_extensions(display_handle: &RawDisplayHandle) -> Result, vk::Result>` ### Parameters #### Path Parameters - **display_handle** (`&RawDisplayHandle`) - Required - A reference to the raw display handle. ### Response #### Success Response - `Vec` - A vector of C-strings representing the required instance extensions. - `vk::Result` - Indicates success or failure of the operation. ``` -------------------------------- ### LoadKHR Swapchain Extension Source: https://github.com/ash-rs/ash/blob/master/README.md Loads the KHR swapchain extension for Vulkan using the Ash library. Ensure the instance and device are valid before creating the loader. ```rust use ash::khr; let swapchain_loader = khr::swapchain::Device::new(&instance, &device); let swapchain = swapchain_loader.create_swapchain(&swapchain_create_info).unwrap(); ``` -------------------------------- ### Add ash-window Dependency Source: https://github.com/ash-rs/ash/blob/master/ash-window/README.md Include the ash-window crate in your Cargo.toml file to manage dependencies. ```toml ash-window = "0.12.0" ``` -------------------------------- ### Using Constants for Pipeline Bind Point Source: https://github.com/ash-rs/ash/blob/master/README.md Demonstrates the usage of Vulkan constants, like `vk::PipelineBindPoint::GRAPHICS`, for specifying pipeline bind points. ```rust // Constant vk::PipelineBindPoint::GRAPHICS, ``` -------------------------------- ### Extending Pointer Chains with Push Source: https://github.com/ash-rs/ash/blob/master/README.md Illustrates how to extend Vulkan struct pointer chains using the `.push()` method, which safely inserts new structs into the chain. This is used for enabling features or extensions during device creation. ```rust let mut variable_pointers = vk::PhysicalDeviceVariablePointerFeatures::default(); let mut corner = vk::PhysicalDeviceCornerSampledImageFeaturesNV::default(); let mut device_create_info = vk::DeviceCreateInfo::default() .push(&mut corner) .push(&mut variable_pointers); ``` -------------------------------- ### Using Bitflags for Access Masks Source: https://github.com/ash-rs/ash/blob/master/README.md Shows how to combine Vulkan bitflags, such as `vk::AccessFlags`, using the bitwise OR operator (`|`) to specify multiple access types. ```rust // Bitflag vk::AccessFlags::COLOR_ATTACHMENT_READ | vk::AccessFlags::COLOR_ATTACHMENT_WRITE ``` -------------------------------- ### Ash Cargo Features Configuration Source: https://context7.com/ash-rs/ash/llms.txt Illustrates different Cargo.toml configurations for the Ash crate, including runtime loading, compile-time linking, no_std support, and provisional extensions. ```toml [dependencies] # Runtime loading (default) — finds libvulkan.so / vulkan-1.dll at runtime ash = "0.38" # Compile-time linking — requires Vulkan SDK in library path ash = { version = "0.38", default-features = false, features = ["linked", "debug", "std"] } # no_std (embedded / bare-metal) — requires `alloc` crate ash = { version = "0.38", default-features = false, features = ["linked"] } # All features including provisional extensions (semver exempt) ash = { version = "0.38", features = ["provisional"] } ``` -------------------------------- ### Debug and Display Vulkan Flags Source: https://github.com/ash-rs/ash/blob/master/README.md Demonstrates how to print Vulkan flags for debugging and display purposes using Rust's debug and display traits. ```rust let flag = vk::AccessFlags::COLOR_ATTACHMENT_READ | vk::AccessFlags::COLOR_ATTACHMENT_WRITE; println!("Debug: {:?}", flag); println!("Display: {}", flag); // Prints: // Debug: AccessFlags(110000000) // Display: COLOR_ATTACHMENT_READ | COLOR_ATTACHMENT_WRITE ``` -------------------------------- ### Vulkan Error Handling with VkResult and Propagation Source: https://context7.com/ash-rs/ash/llms.txt Illustrates how to handle Vulkan errors using `ash::prelude::VkResult` (a type alias for `Result`). Simple error propagation using the `?` operator and handling specific error codes like `VK_SUBOPTIMAL_KHR` are shown. ```rust use ash::vk; use ash::prelude::VkResult; unsafe fn error_handling_examples( device: &ash::Device, swapchain_loader: &ash::khr::swapchain::Device, swapchain: vk::SwapchainKHR, semaphore: vk::Semaphore, ) -> VkResult<()> { // Simple propagation with ? let fence_info = vk::FenceCreateInfo::default(); let fence = device.create_fence(&fence_info, None)?; // acquire_next_image returns (index, is_suboptimal) let result = swapchain_loader.acquire_next_image( swapchain, u64::MAX, // timeout (ns) semaphore, vk::Fence::null(), ); let (image_index, is_suboptimal) = match result { Ok(r) => r, Err(vk::Result::ERROR_OUT_OF_DATE_KHR) => { // Swapchain needs full recreation return Ok(()) } Err(e) => return Err(e), }; if is_suboptimal { eprintln!("Swapchain is suboptimal, consider recreation (index={})", image_index); } // wait_for_fences with timeout match device.wait_for_fences(&[fence], true, 1_000_000_000) { Ok(()) => {} // Do nothing on success Err(vk::Result::TIMEOUT) => eprintln!("Fence wait timed out!"), Err(e) => return Err(e), } device.destroy_fence(fence, None); Ok(()) } ``` -------------------------------- ### Add Ash Dependency Source: https://github.com/ash-rs/ash/blob/master/ash-window/README.md Specify the ash crate version in your Cargo.toml for Vulkan bindings. ```toml ash = "0.37" ``` -------------------------------- ### Access Raw Vulkan Function Pointers Source: https://context7.com/ash-rs/ash/llms.txt Demonstrates accessing raw Vulkan function pointers from an Ash device object for FFI interop. Requires an unsafe block. ```rust // Access raw function pointer tables for FFI interop unsafe fn raw_fp_access(device: &ash::Device) { // Directly call a raw Vulkan function pointer let fp = device.fp_v1_0(); let null_fence = vk::Fence::null(); // (fp.destroy_fence)(device.handle(), null_fence, std::ptr::null()); // Build from external handle + function pointers (for interop) // let device = ash::Device::load(&instance_fn, device_handle); let _ = fp; } ``` -------------------------------- ### macOS Environment Variables for Vulkan SDK Source: https://github.com/ash-rs/ash/blob/master/README.md Sets necessary environment variables for running Vulkan applications on macOS, including paths to the SDK, libraries, and ICD files. ```sh VULKAN_SDK=$HOME/VulkanSDK//macOS \ DYLD_FALLBACK_LIBRARY_PATH=$VULKAN_SDK/lib \ VK_ICD_FILENAMES=$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json \ VK_LAYER_PATH=$VULKAN_SDK/share/vulkan/explicit_layer.d \ cargo run ... ``` -------------------------------- ### Access Raw Vulkan Function Pointers Source: https://github.com/ash-rs/ash/blob/master/README.md Provides direct access to raw Vulkan function pointers for Vulkan 1.0 functions via the device object. Use with caution and ensure compatibility. ```rust device.fp_v1_0().destroy_device(...); ``` -------------------------------- ### Pipeline Barrier Command Signature Source: https://github.com/ash-rs/ash/blob/master/README.md Shows the function signature for `cmd_pipeline_barrier`, highlighting the use of slices (`&[T]`) for memory barriers, which is efficient for passing collections of barrier structures. ```rust pub fn cmd_pipeline_barrier(&self, command_buffer: vk::CommandBuffer, src_stage_mask: vk::PipelineStageFlags, dst_stage_mask: vk::PipelineStageFlags, dependency_flags: vk::DependencyFlags, memory_barriers: &[vk::MemoryBarrier<'_>], buffer_memory_barriers: &[vk::BufferMemoryBarrier<'_>], image_memory_barriers: &[vk::ImageMemoryBarrier<'_>]); ``` -------------------------------- ### Vulkan Enumeration Pattern in Ash Source: https://context7.com/ash-rs/ash/llms.txt Ash abstracts the common Vulkan pattern of enumerating resources by calling a function twice (once for count, once for data). Most Ash functions that enumerate return a `Vec` directly, simplifying the process. ```rust unsafe fn enumerate_example(instance: &ash::Instance, pd: vk::PhysicalDevice) -> VkResult<()> { let formats: Vec = vec![]; // returned directly as Vec let _ = formats; let _ = instance.enumerate_physical_devices()?; Ok(()) } ```