feat(renderer): implement logical device creation

Created the logical device handle, enabled Vulkan 1.3 features (dynamic rendering, synchronization2), and retrieved the graphics queue. Added documentation for the new fields and helpers.
This commit is contained in:
Serkyo 2026-04-30 14:19:16 +02:00
parent 7034a24498
commit 92764f6f2d

View file

@ -1,7 +1,7 @@
pub mod error; pub mod error;
use std::ffi::{CStr, c_char}; use std::ffi::{CStr, c_char};
use ash::{Entry, Instance, ext, vk}; use ash::{Entry, Instance, ext, vk, Device};
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, warn};
pub use error::RendererError; pub use error::RendererError;
@ -18,10 +18,20 @@ pub struct Renderer {
debug_messenger: vk::DebugUtilsMessengerEXT, debug_messenger: vk::DebugUtilsMessengerEXT,
/// The selected physical device (GPU). /// The selected physical device (GPU).
physical_device: vk::PhysicalDevice, physical_device: vk::PhysicalDevice,
/// The logical device handle.
device: Device,
/// The handle to the graphics queue.
graphics_queue: vk::Queue,
/// The index of the graphics queue family.
graphics_queue_index: u32,
} }
impl Renderer { impl Renderer {
/// Initializes the Vulkan renderer. /// Initializes the Vulkan renderer.
///
/// This function loads the Vulkan library, creates an instance, selects a GPU,
/// and initializes a logical device with a graphics queue.
///
/// `required_extensions` are raw C-strings (pointers) provided by the windowing system. /// `required_extensions` are raw C-strings (pointers) provided by the windowing system.
pub fn new(required_extensions: &[*const c_char]) -> Result<Self, RendererError> { pub fn new(required_extensions: &[*const c_char]) -> Result<Self, RendererError> {
let entry = unsafe { Entry::load() }?; let entry = unsafe { Entry::load() }?;
@ -74,12 +84,19 @@ impl Renderer {
let physical_device = Self::pick_physical_device(&instance)?; let physical_device = Self::pick_physical_device(&instance)?;
// Find the graphics queue and create the logical device
let graphics_queue_index = Self::find_graphics_queue_family(&instance, physical_device)?;
let (device, graphics_queue) = Self::create_logical_device(&instance, physical_device, graphics_queue_index)?;
Ok(Self { Ok(Self {
_entry: entry, _entry: entry,
instance, instance,
debug_utils, debug_utils,
debug_messenger, debug_messenger,
physical_device, physical_device,
device,
graphics_queue,
graphics_queue_index,
}) })
} }
@ -112,6 +129,50 @@ impl Renderer {
Ok(selected) Ok(selected)
} }
/// Finds the index of the first queue family that supports graphics operations.
fn find_graphics_queue_family(
instance: &Instance,
physical_device: vk::PhysicalDevice,
) -> Result<u32, RendererError> {
let props = unsafe { instance.get_physical_device_queue_family_properties(physical_device) };
props.iter().enumerate()
.find(|(_, p)| p.queue_flags.contains(vk::QueueFlags::GRAPHICS))
.map(|(i, _)| i as u32)
.ok_or(RendererError::NoSuitableGpu)
}
/// Creates a logical device and retrieves the handle to its graphics queue.
fn create_logical_device(
instance: &Instance,
physical_device: vk::PhysicalDevice,
queue_index: u32,
) -> Result<(Device, vk::Queue), RendererError> {
// Request a single queue from the graphics family
let queue_priorities = [1.0];
let queue_info = vk::DeviceQueueCreateInfo::default()
.queue_family_index(queue_index)
.queue_priorities(&queue_priorities);
// Enable modern Vulkan 1.3 features
let mut features_13 = vk::PhysicalDeviceVulkan13Features::default()
.dynamic_rendering(true) // Removes the need for RenderPasses/Framebuffers
.synchronization2(true); // Cleaner memory barriers and synchronization
// We need the swapchain extension to present images to the window
let device_extensions = [ash::khr::swapchain::NAME.as_ptr()];
let create_info = vk::DeviceCreateInfo::default()
.queue_create_infos(std::slice::from_ref(&queue_info))
.enabled_extension_names(&device_extensions)
.push_next(&mut features_13);
let device = unsafe { instance.create_device(physical_device, &create_info, None)? };
let graphics_queue = unsafe { device.get_device_queue(queue_index, 0) };
Ok((device, graphics_queue))
}
} }
/// The callback function invoked by Vulkan's validation layers. /// The callback function invoked by Vulkan's validation layers.