renderer: remove Vulkan object, move debug mod to its own file
This commit is contained in:
parent
b06c76f1e1
commit
40ea757543
43
crates/renderer/src/debug.rs
Normal file
43
crates/renderer/src/debug.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use ash::vk;
|
||||
use tracing::{event, Level};
|
||||
|
||||
unsafe fn str_from_raw_parts<'a>(str: *const i8) -> std::borrow::Cow<'a, str> {
|
||||
use std::{borrow::Cow, ffi};
|
||||
if str.is_null() {
|
||||
Cow::from("")
|
||||
} else {
|
||||
ffi::CStr::from_ptr(str).to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe extern "system" fn debug_callback(
|
||||
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||
callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT<'_>,
|
||||
user_data: *mut core::ffi::c_void,
|
||||
) -> vk::Bool32 {
|
||||
_ = user_data;
|
||||
let callback_data = *callback_data;
|
||||
let message_id_number = callback_data.message_id_number;
|
||||
|
||||
let message_id_name = str_from_raw_parts(callback_data.p_message_id_name);
|
||||
let message = str_from_raw_parts(callback_data.p_message);
|
||||
|
||||
match message_severity {
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => {
|
||||
event!(target: "VK::DebugUtils", Level::ERROR, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => {
|
||||
event!(target: "VK::DebugUtils", Level::TRACE, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::INFO => {
|
||||
event!(target: "VK::DebugUtils", Level::INFO, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => {
|
||||
event!(target: "VK::DebugUtils", Level::WARN, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
vk::FALSE
|
||||
}
|
|
@ -9,7 +9,6 @@
|
|||
)]
|
||||
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
collections::{BTreeMap, BTreeSet, HashMap},
|
||||
ffi::{CStr, CString},
|
||||
fmt::Debug,
|
||||
|
@ -17,22 +16,23 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use parking_lot::{Mutex, MutexGuard, RwLock};
|
||||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
|
||||
use ash::{
|
||||
khr,
|
||||
prelude::VkResult,
|
||||
vk::{self, Handle},
|
||||
vk::{self},
|
||||
Entry,
|
||||
};
|
||||
use dyn_clone::DynClone;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use raw_window_handle::RawDisplayHandle;
|
||||
|
||||
pub use ash;
|
||||
|
||||
mod buffers;
|
||||
pub mod commands;
|
||||
mod debug;
|
||||
pub mod device;
|
||||
#[path = "egui.rs"]
|
||||
mod egui_pass;
|
||||
|
@ -41,6 +41,7 @@ mod memory;
|
|||
mod pipeline;
|
||||
pub mod render_graph;
|
||||
pub mod rendering;
|
||||
pub mod swapchain;
|
||||
pub mod sync;
|
||||
pub mod util;
|
||||
|
||||
|
@ -473,8 +474,6 @@ impl AsRef<ash::khr::surface::Instance> for Instance {
|
|||
}
|
||||
}
|
||||
|
||||
pub mod swapchain;
|
||||
|
||||
pub struct SamplerCache {
|
||||
device: Device,
|
||||
samplers: HashMap<pipeline::SamplerDesc, pipeline::Sampler>,
|
||||
|
@ -502,596 +501,9 @@ impl SamplerCache {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Vulkan {
|
||||
instance: Arc<Instance>,
|
||||
pub device: Device,
|
||||
samplers: SamplerCache,
|
||||
}
|
||||
|
||||
impl Drop for Vulkan {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
_ = self.device.dev().device_wait_idle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Vulkan {
|
||||
const VALIDATION_LAYER_NAME: &'static core::ffi::CStr = c"VK_LAYER_KHRONOS_validation";
|
||||
#[allow(unused)]
|
||||
const RENDERDOC_LAYER_NAME: &'static core::ffi::CStr = c"VK_LAYER_RENDERDOC_Capture";
|
||||
#[allow(unused)]
|
||||
const NSIGHT_TRACE_LAYER_NAME: &'static core::ffi::CStr =
|
||||
c"VK_LAYER_NV_GPU_Trace_release_public_2021_4_2";
|
||||
#[allow(unused)]
|
||||
const NSIGHT_INTERCEPTION_LAYER_NAME: &'static core::ffi::CStr =
|
||||
c"VK_LAYER_NV_nomad_release_public_2021_4_2";
|
||||
|
||||
pub fn samplers(&self) -> &SamplerCache {
|
||||
&self.samplers
|
||||
}
|
||||
|
||||
pub fn samplers_mut(&mut self) -> &mut SamplerCache {
|
||||
&mut self.samplers
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
app_name: &str,
|
||||
instance_layers: &[&CStr],
|
||||
instance_extensions: &[&CStr],
|
||||
display_handle: Option<RawDisplayHandle>,
|
||||
) -> Result<Self> {
|
||||
let entry = unsafe { ash::Entry::load()? };
|
||||
|
||||
let app_name = CString::new(app_name)?;
|
||||
let app_info = vk::ApplicationInfo::default()
|
||||
.api_version(vk::make_api_version(0, 1, 3, 0))
|
||||
.application_name(&app_name)
|
||||
.engine_name(c"PrimalGame")
|
||||
.application_version(0)
|
||||
.engine_version(0);
|
||||
|
||||
// TODO: make this a flag somewhere to enable or disable validation layers
|
||||
// DEBUG LAYERS/VALIDATION
|
||||
let validation_settings = [
|
||||
vk::LayerSettingEXT::default()
|
||||
.layer_name(Self::VALIDATION_LAYER_NAME)
|
||||
.setting_name(c"VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES")
|
||||
.ty(vk::LayerSettingTypeEXT::BOOL32)
|
||||
.values(&[1]),
|
||||
vk::LayerSettingEXT::default()
|
||||
.layer_name(Self::VALIDATION_LAYER_NAME)
|
||||
.setting_name(c"VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_AMD")
|
||||
.ty(vk::LayerSettingTypeEXT::BOOL32)
|
||||
.values(&[1]),
|
||||
vk::LayerSettingEXT::default()
|
||||
.layer_name(Self::VALIDATION_LAYER_NAME)
|
||||
.setting_name(c"VK_KHRONOS_VALIDATION_VALIDATE_SYNC")
|
||||
.ty(vk::LayerSettingTypeEXT::BOOL32)
|
||||
.values(&[1]),
|
||||
];
|
||||
let mut validation_info =
|
||||
vk::LayerSettingsCreateInfoEXT::default().settings(&validation_settings);
|
||||
|
||||
let layers = Self::get_layers(
|
||||
&entry,
|
||||
instance_layers
|
||||
.into_iter()
|
||||
.chain(&[
|
||||
#[cfg(debug_assertions)]
|
||||
Self::VALIDATION_LAYER_NAME,
|
||||
])
|
||||
.cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (extensions, unsupported_extensions) = Self::get_extensions(
|
||||
&entry,
|
||||
&layers,
|
||||
instance_extensions
|
||||
.into_iter()
|
||||
.chain([ash::ext::debug_utils::NAME, ash::ext::layer_settings::NAME].iter())
|
||||
.cloned(),
|
||||
display_handle,
|
||||
)?;
|
||||
|
||||
if !unsupported_extensions.is_empty() {
|
||||
tracing::error!(
|
||||
"extensions were requested but not supported by instance: {:?}",
|
||||
unsupported_extensions
|
||||
);
|
||||
}
|
||||
|
||||
let layers = VkNameList::from_strs(&layers);
|
||||
let extensions = VkNameList::from_strs(&extensions);
|
||||
|
||||
let create_info = vk::InstanceCreateInfo::default()
|
||||
.application_info(&app_info)
|
||||
.enabled_extension_names(&extensions.names)
|
||||
.enabled_layer_names(&layers.names)
|
||||
.push_next(&mut validation_info);
|
||||
let instance = unsafe { entry.create_instance(&create_info, None)? };
|
||||
|
||||
let debug_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(debug::debug_callback));
|
||||
|
||||
let debug_utils_instance = ash::ext::debug_utils::Instance::new(&entry, &instance);
|
||||
let debug_utils_messenger =
|
||||
unsafe { debug_utils_instance.create_debug_utils_messenger(&debug_info, None)? };
|
||||
let surface_instance = ash::khr::surface::Instance::new(&entry, &instance);
|
||||
|
||||
let instance = Arc::new(Instance {
|
||||
instance,
|
||||
debug_utils: debug_utils_instance,
|
||||
debug_utils_messenger,
|
||||
surface: surface_instance,
|
||||
entry,
|
||||
});
|
||||
|
||||
let features = PhysicalDeviceFeatures::all_default()
|
||||
.version(vk::make_api_version(0, 1, 3, 0))
|
||||
.features10(
|
||||
vk::PhysicalDeviceFeatures::default()
|
||||
.sampler_anisotropy(true)
|
||||
.fill_mode_non_solid(true)
|
||||
.multi_draw_indirect(true),
|
||||
)
|
||||
.features11(vk::PhysicalDeviceVulkan11Features::default().shader_draw_parameters(true))
|
||||
.features12(
|
||||
vk::PhysicalDeviceVulkan12Features::default()
|
||||
.shader_int8(true)
|
||||
.runtime_descriptor_array(true)
|
||||
.descriptor_binding_partially_bound(true)
|
||||
.shader_sampled_image_array_non_uniform_indexing(true)
|
||||
.descriptor_binding_sampled_image_update_after_bind(true)
|
||||
.storage_buffer8_bit_access(true),
|
||||
)
|
||||
.features13(
|
||||
vk::PhysicalDeviceVulkan13Features::default()
|
||||
.dynamic_rendering(true)
|
||||
.maintenance4(true)
|
||||
.synchronization2(true),
|
||||
)
|
||||
.with_extension(
|
||||
make_extention_properties(
|
||||
ash::ext::mesh_shader::NAME,
|
||||
ash::ext::mesh_shader::SPEC_VERSION,
|
||||
),
|
||||
vk::PhysicalDeviceMeshShaderFeaturesEXT::default()
|
||||
.mesh_shader(true)
|
||||
.task_shader(true),
|
||||
)
|
||||
.with_extension(
|
||||
make_extention_properties(
|
||||
ash::khr::present_id::NAME,
|
||||
ash::khr::present_id::SPEC_VERSION,
|
||||
),
|
||||
vk::PhysicalDevicePresentIdFeaturesKHR::default().present_id(true),
|
||||
)
|
||||
.with_extension(
|
||||
make_extention_properties(
|
||||
ash::khr::present_wait::NAME,
|
||||
ash::khr::present_wait::SPEC_VERSION,
|
||||
),
|
||||
vk::PhysicalDevicePresentWaitFeaturesKHR::default().present_wait(true),
|
||||
)
|
||||
.with_extension(
|
||||
make_extention_properties(
|
||||
ash::ext::index_type_uint8::NAME,
|
||||
ash::ext::index_type_uint8::SPEC_VERSION,
|
||||
),
|
||||
vk::PhysicalDeviceIndexTypeUint8FeaturesEXT::default().index_type_uint8(true),
|
||||
)
|
||||
.with_extensions2([
|
||||
make_extention_properties(khr::swapchain::NAME, khr::swapchain::SPEC_VERSION),
|
||||
make_extention_properties(khr::spirv_1_4::NAME, khr::spirv_1_4::SPEC_VERSION),
|
||||
]);
|
||||
|
||||
// Consider this: switching physical device in game?
|
||||
// anything above this point is device agnostic, everything below would have to be recreated
|
||||
// additionally, pdev would have to be derived from a device and not a scoring function.
|
||||
|
||||
let pdev = Self::choose_physical_device(
|
||||
&instance,
|
||||
display_handle,
|
||||
&features,
|
||||
vec![Box::new(
|
||||
vk::PhysicalDeviceMeshShaderPropertiesEXT::default(),
|
||||
)],
|
||||
)?;
|
||||
|
||||
tracing::trace!("pdev: {pdev:?}");
|
||||
let device = Device::new(instance.clone(), pdev, features)?;
|
||||
|
||||
Ok(Self {
|
||||
instance,
|
||||
samplers: SamplerCache::new(device.clone()),
|
||||
device,
|
||||
})
|
||||
}
|
||||
|
||||
fn queue_family_supports_presentation(
|
||||
instance: &Instance,
|
||||
pdev: vk::PhysicalDevice,
|
||||
queue_family: u32,
|
||||
display_handle: RawDisplayHandle,
|
||||
) -> bool {
|
||||
unsafe {
|
||||
match display_handle {
|
||||
RawDisplayHandle::Xlib(display) => {
|
||||
let surface =
|
||||
ash::khr::xlib_surface::Instance::new(&instance.entry, &instance.instance);
|
||||
surface.get_physical_device_xlib_presentation_support(
|
||||
pdev,
|
||||
queue_family,
|
||||
display.display.unwrap().as_ptr() as _,
|
||||
display.screen as _,
|
||||
)
|
||||
//todo!("xlib")
|
||||
}
|
||||
RawDisplayHandle::Xcb(_xcb_display_handle) => todo!("xcb"),
|
||||
RawDisplayHandle::Wayland(wayland_display_handle) => {
|
||||
let surface = ash::khr::wayland_surface::Instance::new(
|
||||
&instance.entry,
|
||||
&instance.instance,
|
||||
);
|
||||
surface.get_physical_device_wayland_presentation_support(
|
||||
pdev,
|
||||
queue_family,
|
||||
wayland_display_handle.display.cast().as_mut(),
|
||||
)
|
||||
}
|
||||
RawDisplayHandle::Drm(_) => {
|
||||
todo!()
|
||||
}
|
||||
RawDisplayHandle::Windows(_) => {
|
||||
ash::khr::win32_surface::Instance::new(&instance.entry, &instance.instance)
|
||||
.get_physical_device_win32_presentation_support(pdev, queue_family)
|
||||
}
|
||||
_ => panic!("unsupported platform"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn select_pdev_queue_families(
|
||||
instance: &Instance,
|
||||
display_handle: Option<RawDisplayHandle>,
|
||||
pdev: vk::PhysicalDevice,
|
||||
) -> DeviceQueueFamilies {
|
||||
let queue_families = unsafe {
|
||||
instance
|
||||
.instance
|
||||
.get_physical_device_queue_family_properties(pdev)
|
||||
};
|
||||
|
||||
struct QueueFamily {
|
||||
num_queues: u32,
|
||||
is_present: bool,
|
||||
is_compute: bool,
|
||||
is_graphics: bool,
|
||||
is_transfer: bool,
|
||||
}
|
||||
|
||||
impl QueueFamily {
|
||||
#[allow(dead_code)]
|
||||
fn is_graphics_and_compute(&self) -> bool {
|
||||
self.is_compute && self.is_graphics
|
||||
}
|
||||
}
|
||||
|
||||
struct QueueFamilies(Vec<QueueFamily>);
|
||||
impl QueueFamilies {
|
||||
fn find_first<F>(&mut self, mut pred: F) -> Option<u32>
|
||||
where
|
||||
F: FnMut(&QueueFamily) -> bool,
|
||||
{
|
||||
if let Some((q, family)) = self
|
||||
.0
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.filter(|(_, family)| family.num_queues > 0)
|
||||
.find(|(_, family)| pred(family))
|
||||
{
|
||||
family.num_queues -= 1;
|
||||
Some(q as u32)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn find_best<F>(&mut self, mut pred: F) -> Option<u32>
|
||||
where
|
||||
F: FnMut(&QueueFamily) -> Option<u32>,
|
||||
{
|
||||
let (_, q, family) = self
|
||||
.0
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.filter_map(|(i, family)| {
|
||||
if family.num_queues == 0 {
|
||||
return None;
|
||||
}
|
||||
pred(family).map(|score| (score, i, family))
|
||||
})
|
||||
.max_by_key(|(score, _, _)| *score)?;
|
||||
family.num_queues -= 1;
|
||||
Some(q as u32)
|
||||
}
|
||||
}
|
||||
|
||||
let mut queue_families = QueueFamilies(
|
||||
queue_families
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, family)| {
|
||||
let q = i as u32;
|
||||
let is_graphics = family.queue_flags.contains(vk::QueueFlags::GRAPHICS);
|
||||
let is_compute = family.queue_flags.contains(vk::QueueFlags::COMPUTE);
|
||||
let is_transfer = family.queue_flags.contains(vk::QueueFlags::TRANSFER)
|
||||
|| is_compute
|
||||
|| is_graphics;
|
||||
let is_present = display_handle
|
||||
.map(|display_handle| {
|
||||
Self::queue_family_supports_presentation(
|
||||
instance,
|
||||
pdev,
|
||||
q,
|
||||
display_handle,
|
||||
)
|
||||
})
|
||||
.unwrap_or(false);
|
||||
QueueFamily {
|
||||
num_queues: family.queue_count,
|
||||
is_compute,
|
||||
is_graphics,
|
||||
is_present,
|
||||
is_transfer,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
let graphics = queue_families
|
||||
.find_best(|family| {
|
||||
if !family.is_graphics {
|
||||
return None;
|
||||
}
|
||||
// a queue with Graphics+Compute is guaranteed to exist
|
||||
Some(family.is_compute as u32 * 2 + family.is_present as u32)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// find present queue first because it is rather more important than a secondary compute queue
|
||||
let present =
|
||||
if !queue_families.0.get(graphics as usize).unwrap().is_present {
|
||||
queue_families.find_first(|family| family.is_present)
|
||||
} else {
|
||||
None
|
||||
}.or({
|
||||
if display_handle.is_none() {
|
||||
// in this case the graphics queue will be used by default
|
||||
tracing::info!("no present queue available, using graphics queue as fallback for headless_surface");
|
||||
Some(graphics)
|
||||
} else {
|
||||
tracing::warn!("no present queue available, this is unexpected!");
|
||||
None}
|
||||
});
|
||||
|
||||
let async_compute = queue_families.find_first(|family| family.is_compute);
|
||||
let transfer = queue_families.find_first(|family| family.is_transfer);
|
||||
|
||||
let mut unique_families = BTreeMap::<u32, u32>::new();
|
||||
|
||||
let mut helper = |family: u32| {
|
||||
use std::collections::btree_map::Entry;
|
||||
let index = match unique_families.entry(family) {
|
||||
Entry::Vacant(vacant_entry) => {
|
||||
vacant_entry.insert(1);
|
||||
0
|
||||
}
|
||||
Entry::Occupied(mut occupied_entry) => {
|
||||
let idx = occupied_entry.get_mut();
|
||||
*idx += 1;
|
||||
*idx - 1
|
||||
}
|
||||
};
|
||||
|
||||
(family, index)
|
||||
};
|
||||
|
||||
let graphics = helper(graphics);
|
||||
let async_compute = async_compute.map(|f| helper(f)).unwrap_or(graphics);
|
||||
let transfer = transfer.map(|f| helper(f)).unwrap_or(async_compute);
|
||||
let present = present.map(|f| helper(f)).unwrap_or(graphics);
|
||||
|
||||
let families = unique_families
|
||||
.into_iter()
|
||||
.filter(|&(_family, count)| count > 0)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// family of each queue, of which one is allocated for each queue, with
|
||||
// graphics being the fallback queue for compute and transfer, and
|
||||
// present possibly being `None`, in which case it is Graphics
|
||||
let queues = DeviceQueueFamilies {
|
||||
families,
|
||||
graphics,
|
||||
async_compute,
|
||||
transfer,
|
||||
present,
|
||||
};
|
||||
|
||||
queues
|
||||
}
|
||||
|
||||
fn choose_physical_device(
|
||||
instance: &Instance,
|
||||
display_handle: Option<RawDisplayHandle>,
|
||||
requirements: &PhysicalDeviceFeatures,
|
||||
extra_properties: Vec<Box<dyn ExtendsDeviceProperties2Debug>>,
|
||||
) -> Result<PhysicalDevice> {
|
||||
let pdevs = unsafe { instance.instance.enumerate_physical_devices()? };
|
||||
|
||||
let (pdev, properties) = pdevs
|
||||
.into_iter()
|
||||
.map(|pdev| {
|
||||
let mut props = PhysicalDeviceProperties::default().extra_properties(
|
||||
extra_properties
|
||||
.iter()
|
||||
.map(|b| dyn_clone::clone_box(&**b))
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
props.query(&instance.instance, pdev);
|
||||
|
||||
(pdev, props)
|
||||
})
|
||||
// filter devices which dont support the version of Vulkan we are requesting
|
||||
.filter(|(_, props)| props.base.api_version >= requirements.version)
|
||||
// filter devices which don't support the device extensions we
|
||||
// are requesting
|
||||
// TODO: figure out a way to fall back to some
|
||||
// device which doesn't support all of the extensions.
|
||||
.filter(|(pdev, _)| {
|
||||
let query_features =
|
||||
PhysicalDeviceFeatures::query(&instance.instance, *pdev).unwrap();
|
||||
|
||||
requirements.compatible_with(&query_features)
|
||||
})
|
||||
.max_by_key(|(_, props)| {
|
||||
let score = match props.base.device_type {
|
||||
vk::PhysicalDeviceType::DISCRETE_GPU => 5,
|
||||
vk::PhysicalDeviceType::INTEGRATED_GPU => 4,
|
||||
vk::PhysicalDeviceType::VIRTUAL_GPU => 3,
|
||||
vk::PhysicalDeviceType::CPU => 2,
|
||||
vk::PhysicalDeviceType::OTHER => 1,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// score based on limits or other properties
|
||||
|
||||
score
|
||||
})
|
||||
.ok_or(Error::NoPhysicalDevice)?;
|
||||
|
||||
Ok(PhysicalDevice {
|
||||
queue_families: Self::select_pdev_queue_families(instance, display_handle, pdev),
|
||||
pdev,
|
||||
properties,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_available_extensions(
|
||||
entry: &ash::Entry,
|
||||
layers: &[&CStr],
|
||||
) -> Result<Vec<ash::vk::ExtensionProperties>> {
|
||||
unsafe {
|
||||
let extensions = core::iter::once(entry.enumerate_instance_extension_properties(None))
|
||||
.chain(
|
||||
layers
|
||||
.iter()
|
||||
.map(|&layer| entry.enumerate_instance_extension_properties(Some(layer))),
|
||||
)
|
||||
.filter_map(|result| result.ok())
|
||||
.flatten()
|
||||
.collect::<Vec<ash::vk::ExtensionProperties>>();
|
||||
|
||||
Ok(extensions)
|
||||
}
|
||||
}
|
||||
|
||||
/// returns a tuple of supported/enabled extensions and unsupported/requested extensions
|
||||
fn get_extensions<'a>(
|
||||
entry: &ash::Entry,
|
||||
layers: &[&'a CStr],
|
||||
extensions: impl Iterator<Item = &'a CStr> + 'a,
|
||||
display_handle: Option<RawDisplayHandle>,
|
||||
) -> Result<(Vec<&'a CStr>, Vec<&'a CStr>)> {
|
||||
unsafe {
|
||||
let available_extensions = Self::get_available_extensions(entry, layers)?;
|
||||
|
||||
let available_extension_names = available_extensions
|
||||
.iter()
|
||||
.filter_map(|layer| layer.extension_name_as_c_str().ok())
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
let mut out_extensions = Vec::new();
|
||||
let mut unsupported_extensions = Vec::new();
|
||||
|
||||
for extension in extensions {
|
||||
if available_extension_names.contains(extension) {
|
||||
out_extensions.push(extension);
|
||||
} else {
|
||||
unsupported_extensions.push(extension);
|
||||
}
|
||||
}
|
||||
|
||||
let required_extension_names = display_handle
|
||||
.map(|display_handle| ash_window::enumerate_required_extensions(display_handle))
|
||||
.unwrap_or(Ok(&[]))?;
|
||||
|
||||
for &extension in required_extension_names {
|
||||
let extension = core::ffi::CStr::from_ptr(extension);
|
||||
if available_extension_names.contains(&extension) {
|
||||
out_extensions.push(extension);
|
||||
} else {
|
||||
unsupported_extensions.push(extension);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((out_extensions, unsupported_extensions))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_layers<'a>(
|
||||
entry: &ash::Entry,
|
||||
wants_layers: impl Iterator<Item = &'a CStr> + 'a,
|
||||
) -> core::result::Result<Vec<&'a CStr>, (Vec<&'a CStr>, Vec<&'a CStr>)> {
|
||||
unsafe {
|
||||
let wants_layers = wants_layers.collect::<Vec<_>>();
|
||||
|
||||
let available_layers = entry
|
||||
.enumerate_instance_layer_properties()
|
||||
.map_err(|_| (Vec::<&'a CStr>::new(), wants_layers.clone()))?;
|
||||
let available_layer_names = available_layers
|
||||
.iter()
|
||||
.map(|layer| layer.layer_name_as_c_str())
|
||||
.collect::<core::result::Result<BTreeSet<_>, _>>()
|
||||
.map_err(|_| (Vec::<&'a CStr>::new(), wants_layers.clone()))?;
|
||||
|
||||
let mut out_layers = Vec::new();
|
||||
let mut unsupported_layers = Vec::new();
|
||||
|
||||
for layer in wants_layers {
|
||||
if available_layer_names.contains(&layer) {
|
||||
out_layers.push(layer);
|
||||
} else {
|
||||
unsupported_layers.push(layer);
|
||||
}
|
||||
}
|
||||
|
||||
if !unsupported_layers.is_empty() {
|
||||
Err((out_layers, unsupported_layers))
|
||||
} else {
|
||||
Ok(out_layers)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use raw_window_handle::RawWindowHandle;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EguiState {
|
||||
pub textures: HashMap<egui::TextureId, EguiTextureInfo>,
|
||||
textures: HashMap<egui::TextureId, EguiTextureInfo>,
|
||||
#[allow(unused)]
|
||||
descriptor_pool: pipeline::DescriptorPool,
|
||||
descriptor_set: vk::DescriptorSet,
|
||||
|
@ -1102,7 +514,7 @@ pub struct EguiState {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct EguiTextureInfo {
|
||||
pub struct EguiTextureInfo {
|
||||
id: texture::TextureId,
|
||||
options: egui::epaint::textures::TextureOptions,
|
||||
}
|
||||
|
@ -1412,52 +824,6 @@ impl Renderer2 {
|
|||
|
||||
pub use vk::Extent2D;
|
||||
|
||||
mod debug {
|
||||
use ash::vk;
|
||||
use tracing::{event, Level};
|
||||
|
||||
unsafe fn str_from_raw_parts<'a>(str: *const i8) -> std::borrow::Cow<'a, str> {
|
||||
use std::{borrow::Cow, ffi};
|
||||
if str.is_null() {
|
||||
Cow::from("")
|
||||
} else {
|
||||
ffi::CStr::from_ptr(str).to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe extern "system" fn debug_callback(
|
||||
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||
message_type: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||
callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT<'_>,
|
||||
user_data: *mut core::ffi::c_void,
|
||||
) -> vk::Bool32 {
|
||||
_ = user_data;
|
||||
let callback_data = *callback_data;
|
||||
let message_id_number = callback_data.message_id_number;
|
||||
|
||||
let message_id_name = str_from_raw_parts(callback_data.p_message_id_name);
|
||||
let message = str_from_raw_parts(callback_data.p_message);
|
||||
|
||||
match message_severity {
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => {
|
||||
event!(target: "VK::DebugUtils", Level::ERROR, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => {
|
||||
event!(target: "VK::DebugUtils", Level::TRACE, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::INFO => {
|
||||
event!(target: "VK::DebugUtils", Level::INFO, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => {
|
||||
event!(target: "VK::DebugUtils", Level::WARN, "{message_type:?} [{message_id_name}({message_id_number})]: {message}");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
vk::FALSE
|
||||
}
|
||||
}
|
||||
|
||||
pub mod utils {
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
|
@ -546,6 +546,7 @@ impl<T> Drop for RawMutexGuard<'_, T> {
|
|||
|
||||
pub struct CStringList {
|
||||
pub strings: Box<[*const i8]>,
|
||||
#[allow(unused)]
|
||||
bytes: Box<[u8]>,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue