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:
parent
7034a24498
commit
92764f6f2d
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue