[package]
name = "vulkanrust"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1" # used for simple error handling
lazy_static = "1" # used to store static data like vertices
log = "0.4" # used for logging statements
nalgebra-glm = "0.18" # used as a Rust replacement for GLM (graphics math library)
png = "0.17" # used to load PNGs to use as textures
pretty_env_logger = "0.5.0" # used to print our logs to the console
thiserror = "1" # used to define custom errors types without boilerplate
tobj = { version = "4.0.0", features = ["log"] } # used to load 3D models in the Wavefront .obj format
vulkanalia = { version = "=0.21.0", features = ["libloading", "provisional", "window"] } # used to call the Vulkan API
winit = "0.28" # used to create a window to render to
Code
#![allow(
dead_code,
unused_variables,
clippy::too_many_arguments,
clippy::unnecessary_wraps
)]
use anyhow::{anyhow, Result, Ok};
use log::*;
use vulkanalia::loader::{LibloadingLoader, LIBRARY};
use vulkanalia::vk::{KhrSurfaceExtension, ExtDebugUtilsExtension};
use vulkanalia::window as vk_window;
use vulkanalia::prelude::v1_0::*;
use vulkanalia::Version;
use winit::dpi::LogicalSize;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use std::collections::HashSet;
use std::ffi::CStr;
use std::os::raw::c_void;
use thiserror::Error;
const PORTABILITY_MACOS_VERSION: Version = Version::new(1, 3, 216);
const VALIDATION_ENABLED: bool =
cfg!(debug_assertion);
const VALIDATION_LAYER: vk::ExtensionName =
vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation");
fn main() -> Result<()> {
pretty_env_logger::init();
// Window
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_title("Vulkan Tutorial (Rust)")
.with_inner_size(LogicalSize::new(1024, 768))
.build(&event_loop)?;
// App
let mut app = unsafe { App::create(&window)? };
let mut destroying = false;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;
match event {
// Render a frame if our Vulkan app is not being destroyed.
Event::MainEventsCleared if !destroying =>
unsafe { app.render(&window) }.unwrap(),
// Destroy our Vulkan app.
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
destroying = true;
*control_flow = ControlFlow::Exit;
unsafe { app.destroy(); }
}
_ => {}
}
});
}
/// Our Vulkan app.
#[derive(Clone, Debug)]
struct App {
entry: Entry,
instance: Instance,
data: AppData,
device: Device,
}
impl App {
/// Creates our Vulkan app.
unsafe fn create(window: &Window) -> Result<Self> {
let loader = LibloadingLoader::new(LIBRARY)?;
let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?;
let mut data = AppData::default();
let instance = create_instance(window, &entry, &mut data)?;
data.surface = vk_window::create_surface(&instance, &window, window)?;
pick_physical_device(&instance, &mut data)?;
let device = create_logical_device(&entry, &instance, &mut data)?;
Ok(Self { entry, instance, data, device})
}
/// Renders a frame for our Vulkan app.
unsafe fn render(&mut self, window: &Window) -> Result<()> {
Ok(())
}
/// Destroys our Vulkan app.
unsafe fn destroy(&mut self) {
self.device.destroy_device(None);
self.instance.destroy_surface_khr(self.data.surface, None);
self.instance.destroy_instance(None);
}
}
/// The Vulkan handles and associated properties used by our Vulkan app.
#[derive(Clone, Debug, Default)]
struct AppData {
surface: vk::SurfaceKHR,
messenger: vk::DebugUtilsMessengerEXT,
physical_device: vk::PhysicalDevice,
graphics_queue: vk::Queue,
present_queue: vk::Queue,
}
unsafe fn create_instance(window: &Window, entry: &Entry, data: &mut AppData) -> Result<Instance> {
let application_info = vk::ApplicationInfo::builder()
.application_name(b"Vulkan Tutorial\0")
.application_version(vk::make_version(1, 0, 0))
.engine_name(b"No Engine\0")
.engine_version(vk::make_version(1, 0, 0))
.api_version(vk::make_version(1, 0, 0));
let available_layers = entry
.enumerate_instance_layer_properties()?
.iter()
.map(|l| l.layer_name)
.collect::<HashSet<_>>();
if VALIDATION_ENABLED && !available_layers.contains(&VALIDATION_LAYER) {
return Err(anyhow!("Validation layer requested but your pc is shit"));
}
let layers = if VALIDATION_ENABLED {
vec![VALIDATION_LAYER.as_ptr()]
} else {
Vec::new()
};
let mut extensions = vk_window::get_required_instance_extensions(window)
.iter()
.map(|e| e.as_ptr())
.collect::<Vec<_>>();
let flags = if
cfg!(target_os = "macos") &&
entry.version()? >= PORTABILITY_MACOS_VERSION
{
info!("Enabiling extensions for macos");
extensions.push(vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION.name.as_ptr());
extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr());
vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
} else {
vk::InstanceCreateFlags::empty()
};
if VALIDATION_ENABLED {
extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION.name.as_ptr());
}
let mut info = vk::InstanceCreateInfo::builder()
.application_info(&application_info)
.enabled_layer_names(&layers)
.enabled_extension_names(&extensions)
.flags(flags);
let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
.message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all())
.message_type(vk::DebugUtilsMessageTypeFlagsEXT::all())
.user_callback(Some(debug_callback));
if VALIDATION_ENABLED {
info = info.push_next(&mut debug_info)
}
let instance = entry.create_instance(&info, None)?;
if VALIDATION_ENABLED {
let debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
.message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all())
.message_type(vk::DebugUtilsMessageTypeFlagsEXT::all())
.user_callback(Some(debug_callback));
data.messenger = instance.create_debug_utils_messenger_ext(&debug_info, None)?;
}
Ok(instance)
}
extern "system" fn debug_callback(
severity: vk::DebugUtilsMessageSeverityFlagsEXT,
type_: vk::DebugUtilsMessageTypeFlagsEXT,
data: *const vk::DebugUtilsMessengerCallbackDataEXT,
_: *mut c_void,
) -> vk::Bool32 {
let data = unsafe { *data };
let message = unsafe { CStr::from_ptr(data.message) }.to_string_lossy();
if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR {
error!("({:?}) {}", type_, message);
} else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING {
warn!("({:?}) {}", type_, message);
} else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO {
debug!("({:?}) {}", type_, message);
} else {
trace!("({:?}) {}", type_, message);
}
vk::FALSE
}
#[derive(Debug, Error)]
#[error("Missing {0}.")]
pub struct SuitabilityError(pub &'static str);
unsafe fn pick_physical_device(instance: &Instance, data: &mut AppData) -> Result<()> {
for physical_device in instance.enumerate_physical_devices()?{
let properties = instance.get_physical_device_properties(physical_device);
if let Err(error) = check_physical_device(instance, data, physical_device) {
warn!("Skipping physical device (`{}`): {}", properties.device_name, error);
} else {
info!("Selected physical device (`{}`).", properties.device_name);
return Ok(());
}
}
Err(anyhow!("Failed to find suitable physical device."))
}
unsafe fn check_physical_device(instance: &Instance, data: &AppData, physical_device: vk::PhysicalDevice) -> Result<()>{
QueueFamilyIndicies::get(instance, data, physical_device)?;
Ok(())
}
unsafe fn create_logical_device(entry: &Entry, instance: &Instance, data: &mut AppData) -> Result<Device> {
let indicies = QueueFamilyIndicies::get(instance, data, data.physical_device)?;
let mut unique_indices = HashSet::new();
unique_indices.insert(indicies.graphics);
unique_indices.insert(indicies.present);
let queue_priorities = &[1.0];
let queue_infos = unique_indices
.iter()
.map(|i| {
vk::DeviceQueueCreateInfo::builder()
.queue_family_index(*i)
.queue_priorities(queue_priorities)
})
.collect::<Vec<_>>();
let layers = if VALIDATION_ENABLED {
vec![VALIDATION_LAYER.as_ptr()]
} else {
vec![]
};
let mut extensions = vec![];
if cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION {
extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr());
}
let features = vk::PhysicalDeviceFeatures::builder();
let info = vk::DeviceCreateInfo::builder()
.queue_create_infos(&queue_infos)
.enabled_layer_names(&layers)
.enabled_extension_names(&extensions)
.enabled_features(&features);
let device = instance.create_device(data.physical_device, &info, None)?;
data.graphics_queue = device.get_device_queue(indicies.graphics, 0);
data.present_queue = device.get_device_queue(indicies.present, 0);
Ok(device)
}
#[derive(Copy, Clone, Debug)]
struct QueueFamilyIndicies {
graphics: u32,
present: u32,
}
impl QueueFamilyIndicies {
unsafe fn get(instance: &Instance, data: &AppData, physical_device: vk::PhysicalDevice) -> Result<Self> {
let properties = instance.get_physical_device_queue_family_properties(physical_device);
let graphics = properties
.iter()
.position(|p| p.queue_flags.contains(vk::QueueFlags::GRAPHICS))
.map(|i| i as u32);
let mut present = None;
for (index, properties) in properties.iter().enumerate() {
if instance.get_physical_device_surface_support_khr(physical_device, index as u32, data.surface)? {
present = Some(index as u32);
break;
}
}
if let (Some(graphics), Some(present)) = (graphics, present) {
Ok(Self { graphics, present })
} else {
Err(anyhow!(SuitabilityError("Missing required queue families.")))
}
}
}
Been having fun with this tutorial but whenever i run the program i get a sigsegv. Any help would be greatly appreciated
Error
Os and stuff
openSuse Tumbleweed intel & nvidia
Versions
rustc 1.67.0 (fc594f156 2023-01-24) Vulkan Instance Version: 1.3.250
Cargo toml
Code