Add tri
This commit is contained in:
parent
9cfd9d8b17
commit
8a1c5237d5
19 changed files with 1952 additions and 175 deletions
|
|
@ -1,6 +1,8 @@
|
|||
use ash::vk;
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CStr;
|
||||
use std::sync::Weak;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::error::{GfxHalError, Result};
|
||||
|
|
@ -23,12 +25,13 @@ pub struct Device {
|
|||
|
||||
impl Device {
|
||||
/// Creates a new logical device. Typically called via `PhysicalDevice::create_logical_device`.
|
||||
/// Uses a two-stage initialization to avoid Arc::new_cyclic issues.
|
||||
///
|
||||
/// # Saftey
|
||||
/// # Safety
|
||||
/// - `instance` and `physical_device_handle` must be valid.
|
||||
/// - `queue_family_indicies` must be valid indicies obtained from the `physical_device_handle`.
|
||||
/// - `required_extensions` must be supported by the `physical_device_handle`.
|
||||
/// - `enabled_features` and `mesh_features` must be supported by the `physical_device_handle`.
|
||||
/// - All feature structs passed must be supported by the `physical_device_handle`.
|
||||
pub(crate) unsafe fn new(
|
||||
instance: Arc<Instance>,
|
||||
physical_device_handle: vk::PhysicalDevice,
|
||||
|
|
@ -36,22 +39,26 @@ impl Device {
|
|||
required_extensions: &[&CStr],
|
||||
enabled_features: &vk::PhysicalDeviceFeatures,
|
||||
mesh_features: Option<&vk::PhysicalDeviceMeshShaderFeaturesEXT>,
|
||||
dynamic_rendering_features: &vk::PhysicalDeviceDynamicRenderingFeatures,
|
||||
buffer_device_address_features: &vk::PhysicalDeviceBufferDeviceAddressFeatures,
|
||||
// Add other feature structs here as needed...
|
||||
) -> Result<Arc<Self>> {
|
||||
// --- 1. Prepare Queue Create Infos (Same as before) ---
|
||||
let mut queue_create_infos = Vec::new();
|
||||
let mut unique_queue_families = std::collections::HashSet::new();
|
||||
|
||||
let mut unique_queue_families = HashSet::new();
|
||||
let graphics_family = queue_family_indicies.graphics_family.ok_or_else(|| {
|
||||
GfxHalError::MissingQueueFamily("Graphics Queue Family Missing".to_string())
|
||||
})?;
|
||||
unique_queue_families.insert(graphics_family);
|
||||
|
||||
if let Some(compute_family) = queue_family_indicies.compute_family {
|
||||
unique_queue_families.insert(compute_family);
|
||||
}
|
||||
if let Some(transfer_family) = queue_family_indicies.transfer_family {
|
||||
unique_queue_families.insert(transfer_family);
|
||||
}
|
||||
|
||||
if let Some(present_family) = queue_family_indicies.present_family {
|
||||
unique_queue_families.insert(present_family);
|
||||
}
|
||||
let queue_priorities = [1.0f32];
|
||||
for &family_index in &unique_queue_families {
|
||||
let queue_create_info = vk::DeviceQueueCreateInfo::default()
|
||||
|
|
@ -60,74 +67,94 @@ impl Device {
|
|||
queue_create_infos.push(queue_create_info);
|
||||
}
|
||||
|
||||
// --- 2. Prepare Feature Chain (Same as before) ---
|
||||
let extension_names_raw: Vec<*const i8> =
|
||||
required_extensions.iter().map(|s| s.as_ptr()).collect();
|
||||
|
||||
let mut features2 = vk::PhysicalDeviceFeatures2::default().features(*enabled_features);
|
||||
let mut mesh_features_copy;
|
||||
|
||||
if let Some(mesh_feats) = mesh_features {
|
||||
mesh_features_copy = *mesh_feats;
|
||||
features2 = features2.push_next(&mut mesh_features_copy);
|
||||
}
|
||||
let mut dyn_rendering_feats_copy = *dynamic_rendering_features;
|
||||
if dyn_rendering_feats_copy.dynamic_rendering != vk::TRUE {
|
||||
return Err(GfxHalError::MissingFeature("Dynamic Rendering".to_string()));
|
||||
}
|
||||
features2 = features2.push_next(&mut dyn_rendering_feats_copy);
|
||||
let mut bda_features_copy = *buffer_device_address_features;
|
||||
if bda_features_copy.buffer_device_address != vk::TRUE {
|
||||
return Err(GfxHalError::MissingFeature(
|
||||
"Buffer Device Address".to_string(),
|
||||
));
|
||||
}
|
||||
features2 = features2.push_next(&mut bda_features_copy);
|
||||
// Chain other features here...
|
||||
|
||||
// --- 3. Create the SINGLE ash::Device (Same as before) ---
|
||||
let device_create_info = vk::DeviceCreateInfo::default()
|
||||
.queue_create_infos(&queue_create_infos)
|
||||
.enabled_extension_names(&extension_names_raw)
|
||||
.push_next(&mut features2);
|
||||
|
||||
tracing::info!(
|
||||
"Creating logical device with extensions: {:?}",
|
||||
required_extensions
|
||||
);
|
||||
let device = instance.ash_instance().create_device(
|
||||
let ash_device = instance.ash_instance().create_device(
|
||||
physical_device_handle,
|
||||
&device_create_info,
|
||||
None,
|
||||
)?;
|
||||
tracing::info!("logical device created successfully.");
|
||||
tracing::info!(
|
||||
"Logical device created successfully (ash::Device handle: {:?}).",
|
||||
ash_device.handle()
|
||||
);
|
||||
|
||||
let mut queues_map = HashMap::new();
|
||||
let arc_device_placeholder = Arc::new(Self {
|
||||
instance,
|
||||
// --- 4. Create the Device struct in an Arc (Stage 1) ---
|
||||
// Initialize the queues map as empty for now.
|
||||
let device_arc = Arc::new(Device {
|
||||
instance: instance.clone(),
|
||||
physical_device: physical_device_handle,
|
||||
device,
|
||||
queues: Mutex::new(HashMap::new()),
|
||||
device: ash_device, // Move the created ash::Device here
|
||||
queues: Mutex::new(HashMap::new()), // Start with empty map
|
||||
graphics_queue_family_index: graphics_family,
|
||||
compute_queue_family_index: queue_family_indicies.compute_family,
|
||||
transfer_queue_family_index: queue_family_indicies.transfer_family,
|
||||
});
|
||||
tracing::debug!(
|
||||
"Device Arc created (Stage 1) with ash::Device handle: {:?}",
|
||||
device_arc.raw().handle()
|
||||
);
|
||||
|
||||
// --- 5. Create Queues and Populate Map (Stage 2) ---
|
||||
// Now that we have the final Arc<Device>, we can create the Queues.
|
||||
let mut queues_to_insert = HashMap::new();
|
||||
for &family_index in &unique_queue_families {
|
||||
let queue_handler = arc_device_placeholder
|
||||
.device
|
||||
.get_device_queue(family_index, 0);
|
||||
// Get the Vulkan queue handle using the device stored in the Arc
|
||||
// Assuming queue index 0 for simplicity
|
||||
let vk_queue_handle = device_arc.device.get_device_queue(family_index, 0);
|
||||
|
||||
// Create the Queue wrapper, passing a clone of the device_arc
|
||||
let queue_wrapper = Arc::new(Queue::new(
|
||||
Arc::clone(&arc_device_placeholder),
|
||||
queue_handler,
|
||||
device_arc.clone(), // Pass the Arc<Device>
|
||||
vk_queue_handle,
|
||||
family_index,
|
||||
));
|
||||
queues_map.insert((family_index, 0), queue_wrapper);
|
||||
queues_to_insert.insert((family_index, 0), queue_wrapper);
|
||||
tracing::trace!("Created queue wrapper for family {}", family_index);
|
||||
}
|
||||
|
||||
let device_handle = unsafe {
|
||||
arc_device_placeholder
|
||||
.instance
|
||||
.ash_instance()
|
||||
.create_device(physical_device_handle, &device_create_info, None)?
|
||||
};
|
||||
// Lock the mutex and insert the created queues into the map within the Arc<Device>
|
||||
{
|
||||
// Scope for the mutex guard
|
||||
let mut queues_map_guard = device_arc.queues.lock();
|
||||
*queues_map_guard = queues_to_insert; // Replace the empty map with the populated one
|
||||
tracing::debug!(
|
||||
"Device Arc populated with {} queues (Stage 2).",
|
||||
queues_map_guard.len()
|
||||
);
|
||||
} // Mutex guard is dropped here
|
||||
|
||||
let final_device = Arc::new(Self {
|
||||
instance: Arc::clone(&arc_device_placeholder.instance), // Clone from placeholder
|
||||
physical_device: physical_device_handle,
|
||||
device: device_handle, // Use the newly created handle
|
||||
queues: Mutex::new(queues_map), // Use the populated map
|
||||
graphics_queue_family_index: graphics_family,
|
||||
compute_queue_family_index: queue_family_indicies.compute_family,
|
||||
transfer_queue_family_index: queue_family_indicies.transfer_family,
|
||||
});
|
||||
|
||||
Ok(final_device)
|
||||
Ok(device_arc) // Return the fully initialized Arc<Device>
|
||||
}
|
||||
|
||||
/// Provides raw access to the underlying `ash::Device`.
|
||||
|
|
@ -210,6 +237,8 @@ impl PhysicalDevice {
|
|||
queue_family_indices: &QueueFamilyIndices,
|
||||
enabled_features: &vk::PhysicalDeviceFeatures,
|
||||
mesh_features: Option<&vk::PhysicalDeviceMeshShaderFeaturesEXT>,
|
||||
dynamic_rendering_features: &vk::PhysicalDeviceDynamicRenderingFeatures,
|
||||
buffer_device_address_features: &vk::PhysicalDeviceBufferDeviceAddressFeatures,
|
||||
) -> Result<Arc<Device>> {
|
||||
Device::new(
|
||||
Arc::clone(self.instance()),
|
||||
|
|
@ -218,6 +247,8 @@ impl PhysicalDevice {
|
|||
required_extensions,
|
||||
enabled_features,
|
||||
mesh_features,
|
||||
dynamic_rendering_features,
|
||||
buffer_device_address_features,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ pub enum GfxHalError {
|
|||
MissingExtension(String),
|
||||
|
||||
/// A required Vulkan feature is not supported by the physical device.
|
||||
#[error("Missing required Vulkan feature.")]
|
||||
MissingFeature,
|
||||
#[error("Missing required Vulkan feature: {0}")]
|
||||
MissingFeature(String),
|
||||
|
||||
/// Failed to find a suitable queue family (e.g., graphics, present).
|
||||
#[error("Could not find required queue family: {0}")]
|
||||
|
|
|
|||
|
|
@ -5,9 +5,13 @@ use std::{
|
|||
};
|
||||
|
||||
use ash::{ext::debug_utils, vk};
|
||||
use winit::raw_window_handle::{DisplayHandle, HasDisplayHandle};
|
||||
use winit::raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};
|
||||
|
||||
use crate::error::{GfxHalError, Result};
|
||||
use crate::{
|
||||
error::{GfxHalError, Result},
|
||||
physical_device::PhysicalDevice,
|
||||
surface::Surface,
|
||||
};
|
||||
|
||||
unsafe extern "system" fn vulkan_debug_callback(
|
||||
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||
|
|
@ -303,39 +307,39 @@ impl Instance {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// /// Enumerates all physical devices available to this instance.
|
||||
// ///
|
||||
// /// # Safety
|
||||
// /// The `Instance` must be kept alive while the returned `PhysicalDevices`s are in use.
|
||||
// /// This is ensured by returning `PhysicalDevice`s holding an `Arc<Instance>`.
|
||||
// pub unsafe fn enumerate_phyiscal_devices(self: &Arc<Self>) -> Result<Vec<PhysicalDevice>> {
|
||||
// let physical_device_handles = self.instance.enumerate_physical_devices()?;
|
||||
//
|
||||
// if physical_device_handles.is_empty() {
|
||||
// return Err(GfxHalError::NoSuitableGpu(
|
||||
// "No Vulkan-compatibile GPUs found.".to_string(),
|
||||
// ));
|
||||
// }
|
||||
//
|
||||
// let devices = physical_device_handles
|
||||
// .into_iter()
|
||||
// .map(|handle| PhysicalDevice::new(Arc::clone(self), handle))
|
||||
// .collect()?;
|
||||
//
|
||||
// Ok(devices)
|
||||
// }
|
||||
/// Enumerates all physical devices available to this instance.
|
||||
///
|
||||
/// # Safety
|
||||
/// The `Instance` must be kept alive while the returned `PhysicalDevices`s are in use.
|
||||
/// This is ensured by returning `PhysicalDevice`s holding an `Arc<Instance>`.
|
||||
pub unsafe fn enumerate_physical_devices(self: &Arc<Self>) -> Result<Vec<PhysicalDevice>> {
|
||||
let physical_device_handles = self.instance.enumerate_physical_devices()?;
|
||||
|
||||
// /// Creates a vulkan surface for the given window
|
||||
// ///
|
||||
// /// # Safety
|
||||
// /// The `window_handle_trait_obj` must point to a valid window/display managed by caller.
|
||||
// /// The `Instance` must be kept alive longer than the returned `Surface`
|
||||
// pub unsafe fn create_surface(
|
||||
// self: &Arc<Self>,
|
||||
// window_handle_trait_obj: &(impl HasWindowHandle + HasDisplayHandle),
|
||||
// ) -> Result<Arc<Surface>> {
|
||||
// Surface::new(Arc::clone(self), window_handle_trait_obj)
|
||||
// }
|
||||
if physical_device_handles.is_empty() {
|
||||
return Err(GfxHalError::NoSuitableGpu(
|
||||
"No Vulkan-compatibile GPUs found.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let devices = physical_device_handles
|
||||
.into_iter()
|
||||
.map(|handle| PhysicalDevice::new(Arc::clone(self), handle))
|
||||
.collect();
|
||||
|
||||
Ok(devices)
|
||||
}
|
||||
|
||||
/// Creates a vulkan surface for the given window
|
||||
///
|
||||
/// # Safety
|
||||
/// The `window_handle_trait_obj` must point to a valid window/display managed by caller.
|
||||
/// The `Instance` must be kept alive longer than the returned `Surface`
|
||||
pub unsafe fn create_surface(
|
||||
self: &Arc<Self>,
|
||||
window_handle_trait_obj: &(impl HasWindowHandle + HasDisplayHandle),
|
||||
) -> Result<Arc<Surface>> {
|
||||
Surface::new(Arc::clone(self), window_handle_trait_obj)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Instance {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use ash::vk;
|
|||
|
||||
use crate::{error::GfxHalError, instance::Instance};
|
||||
|
||||
use std::{ffi::CStr, sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Represents a physical Vulkan device (GPU).
|
||||
///
|
||||
|
|
@ -21,7 +21,7 @@ pub struct PhysicalDevice {
|
|||
}
|
||||
|
||||
/// Holds information about queue families found on a `PhysicalDevice`.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct QueueFamilyIndices {
|
||||
/// Queue family index supporting graphics operations.
|
||||
pub graphics_family: Option<u32>,
|
||||
|
|
@ -100,16 +100,23 @@ impl PhysicalDevice {
|
|||
) -> (
|
||||
vk::PhysicalDeviceFeatures,
|
||||
vk::PhysicalDeviceMeshShaderFeaturesEXT,
|
||||
vk::PhysicalDeviceDynamicRenderingFeatures,
|
||||
) {
|
||||
let mut mesh_shader_features = vk::PhysicalDeviceMeshShaderFeaturesEXT::default();
|
||||
let mut features2 =
|
||||
vk::PhysicalDeviceFeatures2::default().push_next(&mut mesh_shader_features);
|
||||
let mut dynamic_rendering_features = vk::PhysicalDeviceDynamicRenderingFeatures::default();
|
||||
let mut features2 = vk::PhysicalDeviceFeatures2::default()
|
||||
.push_next(&mut mesh_shader_features)
|
||||
.push_next(&mut dynamic_rendering_features);
|
||||
|
||||
self.instance
|
||||
.ash_instance()
|
||||
.get_physical_device_features2(self.handle, &mut features2);
|
||||
|
||||
(features2.features, mesh_shader_features)
|
||||
(
|
||||
features2.features,
|
||||
mesh_shader_features,
|
||||
dynamic_rendering_features,
|
||||
)
|
||||
}
|
||||
|
||||
/// Queries the properties of all queue families available on the device.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use ash::vk;
|
||||
use ash::{vk, Device as AshDevice};
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::device::Device;
|
||||
|
|
@ -46,25 +46,41 @@ impl Queue {
|
|||
&self.device
|
||||
}
|
||||
|
||||
/// Submits command buffers to the queue.
|
||||
/// Submits command buffers to the queue using the provided device handle.
|
||||
///
|
||||
/// This method acquires an internal lock for the duration of the submission call
|
||||
/// to prevent concurrent `vkQueueSubmit` calls on the same queue from this wrapper.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `submit_device_raw` - The `ash::Device` handle corresponding to the device that owns the resources in `submits` and the `signal_fence`.
|
||||
/// * `submits` - A slice of `vk::SubmitInfo` describing the work to submit.
|
||||
/// * `signal_fence` - An optional `Fence` to signal when the submission completes.
|
||||
/// * `signal_fence` - An optional `Fence` to signal when the submission completes. The fence must have been created with the same logical device as `submit_device_raw`.
|
||||
///
|
||||
/// # Safety
|
||||
/// - The command buffers and synchronization primitieves within `submits` must be valid.
|
||||
/// - The `signal_fence`, if provided, must be valid and unsignaled.
|
||||
/// - `submit_device_raw` must be the correct, valid `ash::Device` handle associated with the resources being submitted.
|
||||
/// - The command buffers and synchronization primitives within `submits` must be valid and owned by the same logical device as `submit_device_raw`.
|
||||
/// - The `signal_fence`, if provided, must be valid, unsignaled, and owned by the same logical device as `submit_device_raw`.
|
||||
pub unsafe fn submit(
|
||||
&self,
|
||||
submit_device_raw: &AshDevice, // <<< Accept the ash::Device to use
|
||||
submits: &[vk::SubmitInfo],
|
||||
signal_fence: Option<&Fence>,
|
||||
) -> Result<()> {
|
||||
debug_assert!(
|
||||
self.device.raw().handle() == submit_device_raw.handle(),
|
||||
"Queue::submit called with an ash::Device from a different logical VkDevice than the queue belongs to!"
|
||||
);
|
||||
// Optional: Check fence device consistency
|
||||
if let Some(fence) = signal_fence {
|
||||
debug_assert!(
|
||||
fence.device().raw().handle() == submit_device_raw.handle(),
|
||||
"Fence passed to Queue::submit belongs to a different logical device than submit_device_raw!"
|
||||
);
|
||||
}
|
||||
|
||||
let fence_handle = signal_fence.map_or(vk::Fence::null(), |f| f.handle());
|
||||
|
||||
// Keep the lock for thread-safety on the VkQueue object itself
|
||||
let _lock = self.submit_lock.lock();
|
||||
|
||||
tracing::trace!(
|
||||
|
|
@ -72,9 +88,10 @@ impl Queue {
|
|||
submits.len(),
|
||||
self.family_index
|
||||
);
|
||||
self.device
|
||||
.raw()
|
||||
.queue_submit(self.queue, submits, fence_handle)?;
|
||||
|
||||
// Use the EXPLICITLY PASSED submit_device_raw for the Vulkan call
|
||||
submit_device_raw.queue_submit(self.queue, submits, fence_handle)?;
|
||||
|
||||
tracing::trace!("Submission successful.");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use std::sync::Arc;
|
|||
use ash::khr::swapchain::Device as SwapchainLoader;
|
||||
use ash::vk;
|
||||
|
||||
use crate::device::{self, Device};
|
||||
use crate::device::Device;
|
||||
use crate::error::{GfxHalError, Result};
|
||||
use crate::surface::{self, Surface};
|
||||
use crate::surface::Surface;
|
||||
use crate::sync::{Fence, Semaphore};
|
||||
|
||||
/// Configuration for creating or recreating a `Swapchain`.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ impl Fence {
|
|||
Ok(Self { device, fence })
|
||||
}
|
||||
|
||||
/// Returns the device used by the fence.
|
||||
pub fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
|
||||
/// Waits for the fence to become signaled.
|
||||
///
|
||||
/// # Arguments
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue