init commit
This commit is contained in:
commit
15a4041785
20 changed files with 37592 additions and 0 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
use flake
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
/target
|
||||
sponza/
|
||||
.direnv/
|
||||
3319
Cargo.lock
generated
Normal file
3319
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
48
Cargo.toml
Normal file
48
Cargo.toml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
|
||||
members = [
|
||||
"crates/rt-helper",
|
||||
"crates/shaders",
|
||||
"crates/shaders-shared",
|
||||
"crates/vk-rs",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
ash = { version = "0.37.3" }
|
||||
color-eyre = "0.6.3"
|
||||
winit = { version = "0.30.7", features = ["rwh_06"] }
|
||||
raw-window-handle = "0.6"
|
||||
gpu-allocator = { version = "0.25.0", features = ["vulkan"] }
|
||||
glam = { version = "0.22", default-features = false, features = ["libm"] }
|
||||
|
||||
spirv-builder = { git = "https://github.com/Rust-GPU/rust-gpu.git" }
|
||||
spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu.git" }
|
||||
|
||||
|
||||
# Enable incremental by default in release mode.
|
||||
[profile.release]
|
||||
incremental = true
|
||||
# HACK(eddyb) this is the default but without explicitly specifying it, Cargo
|
||||
# will treat the identical settings in `[profile.release.build-override]` below
|
||||
# as different sets of `rustc` flags and will not reuse artifacts between them.
|
||||
codegen-units = 256
|
||||
|
||||
# Compile build-dependencies in release mode with the same settings
|
||||
# as regular dependencies (including the incremental enabled above).
|
||||
[profile.release.build-override]
|
||||
opt-level = 3
|
||||
incremental = true
|
||||
codegen-units = 256
|
||||
|
||||
# HACK(eddyb) reduce the number of linker exports and/or imports, by avoiding
|
||||
# inter-CGU linkage, to stay under the 64Ki MSVC limit for `rustc_codegen_spirv`
|
||||
# when building it in "debug mode" (only relevant to CI for now, realistically),
|
||||
# i.e. working around this issue: https://github.com/rust-lang/rust/issues/53014.
|
||||
[profile.dev]
|
||||
# HACK(eddyb) fewer inter-crate exports/imports (not just inter-CGU), but sadly
|
||||
# not configurable w/o breaking `Cargo.toml` parsing from non-nightly Cargo
|
||||
# (moved to `.github/workflows/ci.yaml` as `RUSTFLAGS: -Zshare-generics=off`).
|
||||
#
|
||||
# rustflags = ["-Zshare-generics=off"]
|
||||
codegen-units = 1
|
||||
9
crates/rt-helper/Cargo.toml
Normal file
9
crates/rt-helper/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[package]
|
||||
name = "rt-helper"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ash.workspace = true
|
||||
gpu-allocator.workspace = true
|
||||
color-eyre.workspace = true
|
||||
101
crates/rt-helper/src/lib.rs
Normal file
101
crates/rt-helper/src/lib.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
use std::{
|
||||
sync::{Arc, Mutex, MutexGuard},
|
||||
thread::Result,
|
||||
};
|
||||
|
||||
use ash::{vk, Device};
|
||||
use gpu_allocator::{
|
||||
vulkan::{Allocation, AllocationCreateDesc, Allocator},
|
||||
MemoryLocation,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RtError {
|
||||
VulkanError(vk::Result),
|
||||
AllocationError(gpu_allocator::AllocationError),
|
||||
}
|
||||
|
||||
pub struct AccelerationStructure {
|
||||
accel: vk::AccelerationStructureKHR,
|
||||
buffer: vk::Buffer,
|
||||
allocation: Option<Allocation>,
|
||||
}
|
||||
|
||||
impl AccelerationStructure {
|
||||
fn destroy(&mut self, device: &Device, allocator: &mut Allocator) {
|
||||
unsafe { device.destroy_buffer(self.buffer, None) };
|
||||
if let Some(allocation) = self.allocation.take() {
|
||||
allocator.free(allocation).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Buffer {
|
||||
buffer: vk::Buffer,
|
||||
allocation: Option<Allocation>,
|
||||
size: vk::DeviceSize,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new(
|
||||
device: &Device,
|
||||
allocator: &mut Allocator,
|
||||
size: vk::DeviceSize,
|
||||
usage: vk::BufferUsageFlags,
|
||||
location: MemoryLocation,
|
||||
) -> color_eyre::Result<Self> {
|
||||
let buffer_info = vk::BufferCreateInfo::builder()
|
||||
.size(size)
|
||||
.usage(usage)
|
||||
.sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||
.build();
|
||||
|
||||
let buffer = unsafe { device.create_buffer(&buffer_info, None) }?;
|
||||
|
||||
let requirements = unsafe { device.get_buffer_memory_requirements(buffer) };
|
||||
|
||||
let allocation = allocator.allocate(&AllocationCreateDesc {
|
||||
name: "rt_buffer",
|
||||
requirements,
|
||||
location,
|
||||
linear: true,
|
||||
allocation_scheme: gpu_allocator::vulkan::AllocationScheme::GpuAllocatorManaged,
|
||||
})?;
|
||||
|
||||
unsafe { device.bind_buffer_memory(buffer, allocation.memory(), allocation.offset()) }?;
|
||||
|
||||
Ok(Self {
|
||||
buffer,
|
||||
allocation: Some(allocation),
|
||||
size,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn destroy(&mut self, device: &Device, allocator: &mut Allocator) {
|
||||
unsafe { device.destroy_buffer(self.buffer, None) };
|
||||
if let Some(allocation) = self.allocation.take() {
|
||||
allocator.free(allocation).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RaytracingBuilderKHR {
|
||||
device: Arc<Device>,
|
||||
queue_index: u32,
|
||||
allocator: Arc<Mutex<Allocator>>,
|
||||
blas: Vec<AccelerationStructure>,
|
||||
tlas: AccelerationStructure,
|
||||
command_pool: vk::CommandPool,
|
||||
}
|
||||
|
||||
impl RaytracingBuilderKHR {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
device: None,
|
||||
queue_index: 0,
|
||||
allocator: None,
|
||||
blas: Vec::new(),
|
||||
tlas: AccelerationStructure::de,
|
||||
}
|
||||
}
|
||||
}
|
||||
7
crates/shaders-shared/Cargo.toml
Normal file
7
crates/shaders-shared/Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "shaders-shared"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
glam.workspace = true
|
||||
11
crates/shaders-shared/src/lib.rs
Normal file
11
crates/shaders-shared/src/lib.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#![cfg_attr(target_arch = "spirv", no_std)]
|
||||
|
||||
use glam::Mat4;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct UniformBufferObject {
|
||||
pub model: Mat4,
|
||||
pub view: Mat4,
|
||||
pub proj: Mat4,
|
||||
}
|
||||
13
crates/shaders/Cargo.toml
Normal file
13
crates/shaders/Cargo.toml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "shaders"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
spirv-std.workspace = true
|
||||
glam.workspace = true
|
||||
|
||||
shaders-shared = { path = "../shaders-shared" }
|
||||
52
crates/shaders/src/lib.rs
Normal file
52
crates/shaders/src/lib.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#![cfg_attr(target_arch = "spirv", no_std)]
|
||||
|
||||
use shaders_shared::UniformBufferObject;
|
||||
use spirv_std::spirv;
|
||||
|
||||
use glam::{Mat3, Vec3, Vec4, Vec4Swizzles};
|
||||
|
||||
#[spirv(vertex)]
|
||||
pub fn main_vs(
|
||||
// Vertex inputs
|
||||
in_pos: Vec3,
|
||||
in_normal: Vec3,
|
||||
|
||||
// Uniform buffer
|
||||
#[spirv(uniform, descriptor_set = 0, binding = 0)] ubo: &UniformBufferObject,
|
||||
|
||||
// Vertex outputs
|
||||
out_world_position: &mut Vec3,
|
||||
out_world_normal: &mut Vec3,
|
||||
#[spirv(position)] gl_position: &mut Vec4,
|
||||
) {
|
||||
// Transform position to world space
|
||||
let pos = ubo.model * Vec4::from((in_pos, 1.0));
|
||||
*out_world_position = (pos / pos.w).xyz();
|
||||
|
||||
// Transform normal to world space
|
||||
let normal_matrix = Mat3::from_mat4(ubo.model).inverse().transpose();
|
||||
*out_world_normal = normal_matrix * in_normal;
|
||||
|
||||
// Calculate clip space position
|
||||
*gl_position = ubo.proj * ubo.view * pos;
|
||||
}
|
||||
|
||||
#[spirv(fragment)]
|
||||
pub fn main_fs(frag_world_position: Vec3, frag_world_normal: Vec3, out_color: &mut Vec4) {
|
||||
let base_color = Vec3::new(1.0, 0.5, 0.5);
|
||||
let light_pos = Vec3::new(2.0, 2.0, -2.0);
|
||||
|
||||
// Calculate light direction
|
||||
let l = (light_pos - frag_world_position).normalize();
|
||||
let n = frag_world_normal.normalize();
|
||||
|
||||
// Calculate lambertian lighting
|
||||
let lambertian = f32::max(n.dot(l), 0.0);
|
||||
|
||||
// Ambient lighting
|
||||
let ambient = Vec3::splat(0.1);
|
||||
|
||||
// Final color calculation with gamma correction
|
||||
let color = (base_color * lambertian + ambient).powf(2.2);
|
||||
*out_color = Vec4::from((color, 1.0));
|
||||
}
|
||||
23
crates/vk-rs/Cargo.toml
Normal file
23
crates/vk-rs/Cargo.toml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "vk-rs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ash.workspace = true
|
||||
color-eyre.workspace = true
|
||||
winit.workspace = true
|
||||
raw-window-handle.workspace = true
|
||||
cfg-if = "1.0.0"
|
||||
cgmath = "0.18.0"
|
||||
glam.workspace = true
|
||||
gpu-allocator.workspace = true
|
||||
egui-ash = { version = "0.4.0", features = ["gpu-allocator"] }
|
||||
tobj = "4.0.2"
|
||||
egui = "0.25.0"
|
||||
ash-window = "0.12.0"
|
||||
|
||||
shaders-shared = { path = "../shaders-shared" }
|
||||
|
||||
[build-dependencies]
|
||||
spirv-builder.workspace = true
|
||||
31664
crates/vk-rs/assets/suzanne.obj
Normal file
31664
crates/vk-rs/assets/suzanne.obj
Normal file
File diff suppressed because it is too large
Load diff
29
crates/vk-rs/build.rs
Normal file
29
crates/vk-rs/build.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use std::{
|
||||
fs::{self, File},
|
||||
io::{Read, Write},
|
||||
};
|
||||
|
||||
use spirv_builder::{MetadataPrintout, SpirvBuilder};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
SpirvBuilder::new("../shaders/", "spirv-unknown-vulkan1.2")
|
||||
.print_metadata(MetadataPrintout::None)
|
||||
.multimodule(true)
|
||||
.build()?
|
||||
.module
|
||||
.unwrap_multi()
|
||||
.iter()
|
||||
.for_each(|(name, path)| {
|
||||
let mut data = vec![];
|
||||
File::open(path).unwrap().read_to_end(&mut data).unwrap();
|
||||
|
||||
fs::create_dir_all("./shaders/").unwrap();
|
||||
|
||||
File::create(format!("./shaders/{name}.spv"))
|
||||
.unwrap()
|
||||
.write_all(&data)
|
||||
.unwrap();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
BIN
crates/vk-rs/shaders/main_fs.spv
Normal file
BIN
crates/vk-rs/shaders/main_fs.spv
Normal file
Binary file not shown.
BIN
crates/vk-rs/shaders/main_vs.spv
Normal file
BIN
crates/vk-rs/shaders/main_vs.spv
Normal file
Binary file not shown.
601
crates/vk-rs/src/main.rs
Normal file
601
crates/vk-rs/src/main.rs
Normal file
|
|
@ -0,0 +1,601 @@
|
|||
use std::{
|
||||
collections::HashSet,
|
||||
ffi::CString,
|
||||
mem::ManuallyDrop,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use ash::{
|
||||
extensions::{
|
||||
ext::DebugUtils,
|
||||
khr::{Surface, Swapchain},
|
||||
},
|
||||
vk::{self, KhrAccelerationStructureFn, KhrDeferredHostOperationsFn, KhrRayTracingPipelineFn},
|
||||
Device, Entry, Instance,
|
||||
};
|
||||
use egui_ash::{
|
||||
raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle},
|
||||
winit, App, AppCreator, AshRenderState, CreationContext, HandleRedraw, RunOption, Theme,
|
||||
};
|
||||
use glam::Vec3;
|
||||
use gpu_allocator::vulkan::{Allocator, AllocatorCreateDesc};
|
||||
use renderer::Renderer;
|
||||
|
||||
mod renderer;
|
||||
|
||||
struct Game {
|
||||
entry: Entry,
|
||||
instance: Instance,
|
||||
device: Device,
|
||||
debug_utils_loader: DebugUtils,
|
||||
debug_messenger: vk::DebugUtilsMessengerEXT,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
surface_loader: Surface,
|
||||
swapchain_loader: Swapchain,
|
||||
surface: vk::SurfaceKHR,
|
||||
queue: vk::Queue,
|
||||
command_pool: vk::CommandPool,
|
||||
allocator: ManuallyDrop<Arc<Mutex<Allocator>>>,
|
||||
|
||||
pub renderer: Renderer,
|
||||
|
||||
theme: Theme,
|
||||
rotate_y: f32,
|
||||
|
||||
camera_position: Vec3,
|
||||
camera_yaw: f32,
|
||||
camera_pitch: f32,
|
||||
right_mouse_pressed: bool,
|
||||
last_mouse_pos: Option<(f32, f32)>,
|
||||
|
||||
last_fps_update: std::time::Instant,
|
||||
frame_count_since_last_update: i32,
|
||||
current_fps: f32,
|
||||
}
|
||||
|
||||
impl App for Game {
|
||||
fn ui(&mut self, ctx: &egui::Context) {
|
||||
let now = std::time::Instant::now();
|
||||
self.frame_count_since_last_update += 1;
|
||||
|
||||
if now.duration_since(self.last_fps_update).as_secs_f32() >= 0.1 {
|
||||
self.current_fps = self.frame_count_since_last_update as f32
|
||||
/ now.duration_since(self.last_fps_update).as_secs_f32();
|
||||
self.frame_count_since_last_update = 0;
|
||||
self.last_fps_update = now;
|
||||
}
|
||||
|
||||
egui::SidePanel::left("my_side_panel").show(ctx, |ui| {
|
||||
ui.separator();
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Theme");
|
||||
let id = ui.make_persistent_id("theme_combo_box_side");
|
||||
egui::ComboBox::from_id_source(id)
|
||||
.selected_text(format!("{:?}", self.theme))
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut self.theme, Theme::Dark, "Dark");
|
||||
ui.selectable_value(&mut self.theme, Theme::Light, "Light");
|
||||
});
|
||||
});
|
||||
ui.separator();
|
||||
ui.label("Rotate");
|
||||
ui.add(egui::widgets::Slider::new(
|
||||
&mut self.rotate_y,
|
||||
-180.0..=180.0,
|
||||
));
|
||||
ui.separator();
|
||||
ui.label("Camera Position");
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("X:");
|
||||
ui.add(egui::DragValue::new(&mut self.camera_position.x).speed(0.1));
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Y:");
|
||||
ui.add(egui::DragValue::new(&mut self.camera_position.y).speed(0.1));
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Z:");
|
||||
ui.add(egui::DragValue::new(&mut self.camera_position.z).speed(0.1));
|
||||
});
|
||||
ui.label(format!("FPS: {:.1}", self.current_fps));
|
||||
});
|
||||
|
||||
if !ctx.wants_keyboard_input() {
|
||||
let movement_speed = 0.1;
|
||||
|
||||
let forward = Vec3::new(self.camera_yaw.sin(), 0.0, self.camera_yaw.cos()).normalize();
|
||||
|
||||
let right = Vec3::new(
|
||||
(self.camera_yaw + 90.0_f32.to_radians()).sin(),
|
||||
0.0,
|
||||
(self.camera_yaw + 90.0_f32.to_radians()).cos(),
|
||||
)
|
||||
.normalize();
|
||||
|
||||
ctx.input(|i| {
|
||||
if i.key_down(egui::Key::W) {
|
||||
self.camera_position += forward * movement_speed;
|
||||
}
|
||||
if i.key_down(egui::Key::S) {
|
||||
self.camera_position -= forward * movement_speed;
|
||||
}
|
||||
if i.key_down(egui::Key::A) {
|
||||
self.camera_position -= right * movement_speed;
|
||||
}
|
||||
if i.key_down(egui::Key::D) {
|
||||
self.camera_position += right * movement_speed;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle mouse input for camera rotation
|
||||
let is_right_mouse_down = ctx.input(|i| i.pointer.secondary_down());
|
||||
let hover_pos = ctx.input(|i| i.pointer.hover_pos());
|
||||
|
||||
// Set cursor visibility based on right mouse button
|
||||
if is_right_mouse_down != self.right_mouse_pressed {
|
||||
if is_right_mouse_down {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::CursorVisible(false));
|
||||
} else {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::CursorVisible(true));
|
||||
}
|
||||
}
|
||||
|
||||
self.right_mouse_pressed = is_right_mouse_down;
|
||||
|
||||
if self.right_mouse_pressed {
|
||||
if let Some(pos) = hover_pos {
|
||||
if let Some((last_x, last_y)) = self.last_mouse_pos {
|
||||
let delta_x = pos.x - last_x;
|
||||
let delta_y = pos.y - last_y;
|
||||
|
||||
// Update camera rotation
|
||||
let rotation_speed = 0.002;
|
||||
self.camera_yaw -= delta_x * rotation_speed;
|
||||
self.camera_pitch = (self.camera_pitch + delta_y * rotation_speed)
|
||||
.clamp(-89.0_f32.to_radians(), 89.0_f32.to_radians());
|
||||
}
|
||||
self.last_mouse_pos = Some((pos.x, pos.y));
|
||||
}
|
||||
} else {
|
||||
self.last_mouse_pos = None;
|
||||
}
|
||||
|
||||
match self.theme {
|
||||
Theme::Dark => ctx.set_visuals(egui::style::Visuals::dark()),
|
||||
Theme::Light => ctx.set_visuals(egui::style::Visuals::light()),
|
||||
}
|
||||
}
|
||||
|
||||
fn request_redraw(&mut self, _viewport_id: egui::ViewportId) -> HandleRedraw {
|
||||
HandleRedraw::Handle(Box::new({
|
||||
let renderer = self.renderer.clone();
|
||||
let rotate_y = self.rotate_y;
|
||||
let camera_position = self.camera_position;
|
||||
let camera_yaw = self.camera_yaw;
|
||||
let camera_pitch = self.camera_pitch;
|
||||
move |size, egui_cmd| {
|
||||
let mut renderer = renderer.inner.lock().unwrap();
|
||||
renderer.update_camera(camera_position, camera_yaw, camera_pitch);
|
||||
renderer.render(size.width, size.height, egui_cmd, rotate_y)
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Game {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.device.device_wait_idle().unwrap();
|
||||
self.renderer.destroy();
|
||||
self.device.destroy_command_pool(self.command_pool, None);
|
||||
self.surface_loader.destroy_surface(self.surface, None);
|
||||
ManuallyDrop::drop(&mut self.allocator);
|
||||
self.device.destroy_device(None);
|
||||
if self.debug_messenger != vk::DebugUtilsMessengerEXT::null() {
|
||||
self.debug_utils_loader
|
||||
.destroy_debug_utils_messenger(self.debug_messenger, None);
|
||||
}
|
||||
self.instance.destroy_instance(None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MyAppCreator;
|
||||
impl MyAppCreator {
|
||||
const ENABLE_VALIDATION_LAYERS: bool = true;
|
||||
const VALIDATION: [&'static str; 1] = ["VK_LAYER_KHRONOS_validation"];
|
||||
|
||||
unsafe extern "system" fn vulkan_debug_utils_callback(
|
||||
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||
message_types: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||
p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT,
|
||||
_p_user_data: *mut std::ffi::c_void,
|
||||
) -> vk::Bool32 {
|
||||
let severity = match message_severity {
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE => "[VERBOSE]",
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING => "[WARNING]",
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR => "[ERROR]",
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::INFO => "[INFO]",
|
||||
_ => panic!("[UNKNOWN]"),
|
||||
};
|
||||
let types = match message_types {
|
||||
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL => "[GENERAL]",
|
||||
vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE => "[PERFORMANCE]",
|
||||
vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION => "[VALIDATION]",
|
||||
_ => panic!("[UNKNOWN]"),
|
||||
};
|
||||
let message = std::ffi::CStr::from_ptr((*p_callback_data).p_message);
|
||||
println!("[DEBUG]{}{}{:?}", severity, types, message);
|
||||
|
||||
vk::FALSE
|
||||
}
|
||||
|
||||
fn create_entry() -> Entry {
|
||||
unsafe { Entry::load().unwrap() }
|
||||
}
|
||||
|
||||
fn create_instance(
|
||||
required_instance_extensions: &[CString],
|
||||
entry: &Entry,
|
||||
) -> (Instance, DebugUtils, vk::DebugUtilsMessengerEXT) {
|
||||
let mut debug_utils_messenger_create_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
|
||||
.flags(vk::DebugUtilsMessengerCreateFlagsEXT::empty())
|
||||
.message_severity(
|
||||
vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
|
||||
// | vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE
|
||||
// | vk::DebugUtilsMessageSeverityFlagsEXT::INFO
|
||||
| vk::DebugUtilsMessageSeverityFlagsEXT::ERROR,
|
||||
)
|
||||
.message_type(
|
||||
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
|
||||
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE
|
||||
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION,
|
||||
)
|
||||
.pfn_user_callback(Some(Self::vulkan_debug_utils_callback))
|
||||
.build();
|
||||
|
||||
let app_name = std::ffi::CString::new("egui-winit-ash example simple").unwrap();
|
||||
let app_info = vk::ApplicationInfo::builder()
|
||||
.application_name(&app_name)
|
||||
.application_version(vk::make_api_version(1, 0, 0, 0))
|
||||
.api_version(vk::API_VERSION_1_2);
|
||||
let mut extension_names = vec![DebugUtils::name().as_ptr()];
|
||||
for ext in required_instance_extensions {
|
||||
let name = ext.as_ptr();
|
||||
extension_names.push(name);
|
||||
}
|
||||
let raw_layer_names = Self::VALIDATION
|
||||
.iter()
|
||||
.map(|l| std::ffi::CString::new(*l).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
let layer_names = raw_layer_names
|
||||
.iter()
|
||||
.map(|l| l.as_ptr())
|
||||
.collect::<Vec<*const i8>>();
|
||||
let instance_create_info = vk::InstanceCreateInfo::builder()
|
||||
.push_next(&mut debug_utils_messenger_create_info)
|
||||
.application_info(&app_info)
|
||||
.enabled_extension_names(&extension_names);
|
||||
let instance_create_info = if Self::ENABLE_VALIDATION_LAYERS {
|
||||
instance_create_info.enabled_layer_names(&layer_names)
|
||||
} else {
|
||||
instance_create_info
|
||||
};
|
||||
let instance = unsafe {
|
||||
entry
|
||||
.create_instance(&instance_create_info, None)
|
||||
.expect("Failed to create instance")
|
||||
};
|
||||
|
||||
// setup debug utils
|
||||
let debug_utils_loader = DebugUtils::new(entry, &instance);
|
||||
let debug_messenger = if Self::ENABLE_VALIDATION_LAYERS {
|
||||
unsafe {
|
||||
debug_utils_loader
|
||||
.create_debug_utils_messenger(&debug_utils_messenger_create_info, None)
|
||||
.expect("Failed to create debug utils messenger")
|
||||
}
|
||||
} else {
|
||||
vk::DebugUtilsMessengerEXT::null()
|
||||
};
|
||||
|
||||
(instance, debug_utils_loader, debug_messenger)
|
||||
}
|
||||
|
||||
fn create_surface_loader(entry: &Entry, instance: &Instance) -> Surface {
|
||||
Surface::new(entry, instance)
|
||||
}
|
||||
|
||||
fn create_swapchain_loader(instance: &Instance, device: &Device) -> Swapchain {
|
||||
Swapchain::new(instance, device)
|
||||
}
|
||||
|
||||
fn create_surface(
|
||||
entry: &Entry,
|
||||
instance: &Instance,
|
||||
window: &winit::window::Window,
|
||||
) -> vk::SurfaceKHR {
|
||||
unsafe {
|
||||
ash_window::create_surface(
|
||||
entry,
|
||||
instance,
|
||||
window.raw_display_handle(),
|
||||
window.raw_window_handle(),
|
||||
None,
|
||||
)
|
||||
.expect("Failed to create surface")
|
||||
}
|
||||
}
|
||||
|
||||
fn create_physical_device(
|
||||
instance: &Instance,
|
||||
surface_loader: &Surface,
|
||||
surface: vk::SurfaceKHR,
|
||||
required_device_extensions: &[CString],
|
||||
) -> (vk::PhysicalDevice, vk::PhysicalDeviceMemoryProperties, u32) {
|
||||
let mut queue_family_index: Option<usize> = None;
|
||||
|
||||
let (physical_device, physical_device_memory_properties) = {
|
||||
let physical_devices = unsafe {
|
||||
instance
|
||||
.enumerate_physical_devices()
|
||||
.expect("Failed to enumerate physical devices")
|
||||
};
|
||||
let physical_device = physical_devices.into_iter().find(|physical_device| {
|
||||
let queue_families = unsafe {
|
||||
instance.get_physical_device_queue_family_properties(*physical_device)
|
||||
};
|
||||
for (i, queue_family) in queue_families.iter().enumerate() {
|
||||
let mut graphics_queue = false;
|
||||
let mut present_queue = false;
|
||||
if queue_family.queue_flags.contains(vk::QueueFlags::GRAPHICS) {
|
||||
graphics_queue = true;
|
||||
}
|
||||
let present_support = unsafe {
|
||||
surface_loader
|
||||
.get_physical_device_surface_support(
|
||||
*physical_device,
|
||||
i as u32,
|
||||
surface,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
if present_support {
|
||||
present_queue = true;
|
||||
}
|
||||
if graphics_queue && present_queue {
|
||||
queue_family_index = Some(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
let is_queue_family_supported = queue_family_index.is_some();
|
||||
|
||||
// check device extensions
|
||||
let device_extensions = unsafe {
|
||||
instance
|
||||
.enumerate_device_extension_properties(*physical_device)
|
||||
.unwrap()
|
||||
};
|
||||
let mut device_extensions_name = vec![];
|
||||
for device_extension in device_extensions {
|
||||
let name = unsafe {
|
||||
std::ffi::CStr::from_ptr(device_extension.extension_name.as_ptr())
|
||||
.to_owned()
|
||||
};
|
||||
device_extensions_name.push(name);
|
||||
}
|
||||
let mut required_extensions = HashSet::new();
|
||||
for extension in required_device_extensions.iter() {
|
||||
required_extensions.insert(extension.to_owned());
|
||||
}
|
||||
for extension_name in device_extensions_name {
|
||||
required_extensions.remove(&extension_name);
|
||||
}
|
||||
let is_device_extension_supported = required_extensions.is_empty();
|
||||
|
||||
// check swapchain support
|
||||
let surface_formats = unsafe {
|
||||
surface_loader
|
||||
.get_physical_device_surface_formats(*physical_device, surface)
|
||||
.unwrap()
|
||||
};
|
||||
let surface_present_modes = unsafe {
|
||||
surface_loader
|
||||
.get_physical_device_surface_present_modes(*physical_device, surface)
|
||||
.unwrap()
|
||||
};
|
||||
let is_swapchain_supported =
|
||||
!surface_formats.is_empty() && !surface_present_modes.is_empty();
|
||||
|
||||
is_queue_family_supported && is_swapchain_supported && is_device_extension_supported
|
||||
});
|
||||
let physical_device = physical_device.expect("Failed to get physical device");
|
||||
let physical_device_memory_properties =
|
||||
unsafe { instance.get_physical_device_memory_properties(physical_device) };
|
||||
|
||||
(physical_device, physical_device_memory_properties)
|
||||
};
|
||||
|
||||
(
|
||||
physical_device,
|
||||
physical_device_memory_properties,
|
||||
queue_family_index.unwrap() as u32,
|
||||
)
|
||||
}
|
||||
|
||||
fn create_device(
|
||||
instance: &Instance,
|
||||
physical_device: vk::PhysicalDevice,
|
||||
queue_family_index: u32,
|
||||
required_device_extensions: &[CString],
|
||||
) -> (Device, vk::Queue) {
|
||||
let queue_priorities = [1.0_f32];
|
||||
let mut queue_create_infos = vec![];
|
||||
let queue_create_info = vk::DeviceQueueCreateInfo::builder()
|
||||
.queue_family_index(queue_family_index)
|
||||
.queue_priorities(&queue_priorities)
|
||||
.build();
|
||||
queue_create_infos.push(queue_create_info);
|
||||
|
||||
let physical_device_features = vk::PhysicalDeviceFeatures::builder().build();
|
||||
|
||||
let enable_extension_names = required_device_extensions
|
||||
.iter()
|
||||
.map(|s| s.as_ptr())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// device create info
|
||||
let device_create_info = vk::DeviceCreateInfo::builder()
|
||||
.queue_create_infos(&queue_create_infos)
|
||||
.enabled_features(&physical_device_features)
|
||||
.enabled_extension_names(&enable_extension_names);
|
||||
|
||||
// create device
|
||||
let device = unsafe {
|
||||
instance
|
||||
.create_device(physical_device, &device_create_info, None)
|
||||
.expect("Failed to create device")
|
||||
};
|
||||
|
||||
// get device queue
|
||||
let queue = unsafe { device.get_device_queue(queue_family_index, 0) };
|
||||
|
||||
(device, queue)
|
||||
}
|
||||
|
||||
fn create_command_pool(device: &Device, queue_family_index: u32) -> vk::CommandPool {
|
||||
let command_pool_create_info = vk::CommandPoolCreateInfo::builder()
|
||||
.flags(vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER)
|
||||
.queue_family_index(queue_family_index);
|
||||
unsafe {
|
||||
device
|
||||
.create_command_pool(&command_pool_create_info, None)
|
||||
.expect("Failed to create command pool")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppCreator<Arc<Mutex<Allocator>>> for MyAppCreator {
|
||||
type App = Game;
|
||||
|
||||
fn create(&self, cc: CreationContext) -> (Self::App, AshRenderState<Arc<Mutex<Allocator>>>) {
|
||||
// create vk objects
|
||||
let entry = Self::create_entry();
|
||||
let (instance, debug_utils_loader, debug_messenger) =
|
||||
Self::create_instance(&cc.required_instance_extensions, &entry);
|
||||
let surface_loader = Self::create_surface_loader(&entry, &instance);
|
||||
let surface = Self::create_surface(&entry, &instance, cc.main_window);
|
||||
let mut req_ext = vec![
|
||||
KhrDeferredHostOperationsFn::name().to_owned(),
|
||||
KhrRayTracingPipelineFn::name().to_owned(),
|
||||
KhrAccelerationStructureFn::name().to_owned(),
|
||||
];
|
||||
for ext in &cc.required_device_extensions {
|
||||
req_ext.push(ext.to_owned());
|
||||
}
|
||||
let (physical_device, _physical_device_memory_properties, queue_family_index) =
|
||||
Self::create_physical_device(&instance, &surface_loader, surface, &req_ext);
|
||||
let (device, queue) = Self::create_device(
|
||||
&instance,
|
||||
physical_device,
|
||||
queue_family_index,
|
||||
&cc.required_device_extensions,
|
||||
);
|
||||
let swapchain_loader = Self::create_swapchain_loader(&instance, &device);
|
||||
let command_pool = Self::create_command_pool(&device, queue_family_index);
|
||||
|
||||
// create allocator
|
||||
let allocator = {
|
||||
Allocator::new(&AllocatorCreateDesc {
|
||||
instance: instance.clone(),
|
||||
device: device.clone(),
|
||||
physical_device,
|
||||
debug_settings: Default::default(),
|
||||
buffer_device_address: false,
|
||||
allocation_sizes: Default::default(),
|
||||
})
|
||||
.expect("Failed to create allocator")
|
||||
};
|
||||
let allocator = Arc::new(Mutex::new(allocator));
|
||||
|
||||
// setup context
|
||||
cc.context.set_visuals(egui::style::Visuals::dark());
|
||||
|
||||
let app = Game {
|
||||
entry,
|
||||
instance,
|
||||
device: device.clone(),
|
||||
debug_utils_loader,
|
||||
debug_messenger,
|
||||
physical_device,
|
||||
surface_loader: surface_loader.clone(),
|
||||
swapchain_loader: swapchain_loader.clone(),
|
||||
surface,
|
||||
queue,
|
||||
command_pool,
|
||||
allocator: ManuallyDrop::new(allocator.clone()),
|
||||
|
||||
renderer: Renderer::new(
|
||||
physical_device,
|
||||
device,
|
||||
surface_loader,
|
||||
swapchain_loader,
|
||||
allocator.clone(),
|
||||
surface,
|
||||
queue_family_index,
|
||||
queue,
|
||||
command_pool,
|
||||
1000,
|
||||
800,
|
||||
),
|
||||
|
||||
theme: if cc.context.style().visuals.dark_mode {
|
||||
Theme::Dark
|
||||
} else {
|
||||
Theme::Light
|
||||
},
|
||||
rotate_y: 0.0,
|
||||
|
||||
camera_position: Vec3::new(0.0, 0.0, -5.0),
|
||||
camera_pitch: 0.,
|
||||
camera_yaw: 0.,
|
||||
last_mouse_pos: None,
|
||||
right_mouse_pressed: false,
|
||||
last_fps_update: std::time::Instant::now(),
|
||||
frame_count_since_last_update: 0,
|
||||
current_fps: 0.0,
|
||||
};
|
||||
let ash_render_state = AshRenderState {
|
||||
entry: app.entry.clone(),
|
||||
instance: app.instance.clone(),
|
||||
physical_device: app.physical_device,
|
||||
device: app.device.clone(),
|
||||
surface_loader: app.surface_loader.clone(),
|
||||
swapchain_loader: app.swapchain_loader.clone(),
|
||||
queue: app.queue,
|
||||
queue_family_index,
|
||||
command_pool: app.command_pool,
|
||||
allocator: allocator.clone(),
|
||||
};
|
||||
|
||||
(app, ash_render_state)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::process::ExitCode {
|
||||
egui_ash::run(
|
||||
"vulkan",
|
||||
MyAppCreator,
|
||||
RunOption {
|
||||
viewport_builder: Some(
|
||||
egui::ViewportBuilder::default()
|
||||
.with_title("vulkan")
|
||||
.with_inner_size(egui::vec2(1000.0, 800.0)),
|
||||
),
|
||||
follow_system_theme: false,
|
||||
default_theme: Theme::Dark,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
1428
crates/vk-rs/src/renderer.rs
Normal file
1428
crates/vk-rs/src/renderer.rs
Normal file
File diff suppressed because it is too large
Load diff
160
flake.lock
generated
Normal file
160
flake.lock
generated
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1734808813,
|
||||
"narHash": "sha256-3aH/0Y6ajIlfy7j52FGZ+s4icVX0oHhqBzRdlOeztqg=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "72e2d02dbac80c8c86bf6bf3e785536acf8ee926",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733312601,
|
||||
"narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1734988233,
|
||||
"narHash": "sha256-Ucfnxq1rF/GjNP3kTL+uTfgdoE9a3fxDftSfeLIS8mA=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "de1864217bfa9b5845f465e771e0ecb48b30e02d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1733096140,
|
||||
"narHash": "sha256-1qRH7uAUsyQI7R1Uwl4T+XvdNv778H0Nb5njNrqvylY=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/5487e69da40cbd611ab2cadee0b4637225f7cfae.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/5487e69da40cbd611ab2cadee0b4637225f7cfae.tar.gz"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1728538411,
|
||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1733097829,
|
||||
"narHash": "sha256-9hbb1rqGelllb4kVUCZ307G2k3/UhmA8PPGBoyuWaSw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2c15aa59df0017ca140d9ba302412298ab4bf22a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"systems": "systems",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1735266518,
|
||||
"narHash": "sha256-2XkWYGgT+911gOLjgBj+8W8ZJk6P0qHJNz8RfKgT/5o=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "e0b3654b716098b47f3643c65fbb75ef49c033e1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1735135567,
|
||||
"narHash": "sha256-8T3K5amndEavxnludPyfj3Z1IkcFdRpR23q+T0BVeZE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "9e09d30a644c57257715902efbb3adc56c79cf28",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
116
flake.nix
Normal file
116
flake.nix
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
inputs = {
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
crane.url = "github:ipetkov/crane";
|
||||
};
|
||||
|
||||
# Add settings for your binary cache.
|
||||
nixConfig = {
|
||||
};
|
||||
|
||||
outputs = inputs @ {
|
||||
nixpkgs,
|
||||
flake-parts,
|
||||
...
|
||||
}: let
|
||||
# For details on these options, See
|
||||
# https://github.com/oxalica/rust-overlay?tab=readme-ov-file#cheat-sheet-common-usage-of-rust-bin
|
||||
#
|
||||
# Channel of the Rust toolchain (stable or beta).
|
||||
rustChannel = "nightly";
|
||||
# Version (latest or specific date/semantic version)
|
||||
rustVersion = "latest";
|
||||
# Profile (default or minimal)
|
||||
rustProfile = "default";
|
||||
in
|
||||
flake-parts.lib.mkFlake {inherit inputs;} {
|
||||
systems = import inputs.systems;
|
||||
|
||||
imports = [
|
||||
inputs.treefmt-nix.flakeModule
|
||||
];
|
||||
|
||||
perSystem = {
|
||||
config,
|
||||
system,
|
||||
pkgs,
|
||||
lib,
|
||||
craneLib,
|
||||
commonArgs,
|
||||
...
|
||||
}: {
|
||||
_module.args = {
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [inputs.rust-overlay.overlays.default];
|
||||
};
|
||||
craneLib = (inputs.crane.mkLib pkgs).overrideToolchain (
|
||||
pkgs: pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml
|
||||
);
|
||||
commonArgs = {
|
||||
# Depending on your code base, you may have to customize the
|
||||
# source filtering to include non-standard files during the build.
|
||||
# See
|
||||
# https://crane.dev/source-filtering.html?highlight=source#source-filtering
|
||||
pname = "vk-rs";
|
||||
version = "0.1.0";
|
||||
src = craneLib.cleanCargoSource (craneLib.path ./.);
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
pkg-config
|
||||
vulkan-tools
|
||||
vulkan-headers
|
||||
vulkan-loader
|
||||
vulkan-validation-layers
|
||||
];
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
libxkbcommon
|
||||
libGL
|
||||
# WINIT_UNIX_BACKEND=wayland
|
||||
wayland
|
||||
spirv-tools
|
||||
vulkan-loader
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Build the executable package.
|
||||
packages.default = craneLib.buildPackage (
|
||||
commonArgs
|
||||
// {
|
||||
cargoArtifacts = craneLib.buildDepsOnly commonArgs;
|
||||
}
|
||||
);
|
||||
|
||||
devShells.default = craneLib.devShell {
|
||||
packages =
|
||||
(commonArgs.nativeBuildInputs or [])
|
||||
++ (commonArgs.buildInputs or [])
|
||||
++ [pkgs.rust-analyzer-unwrapped pkgs.cargo-workspaces];
|
||||
|
||||
hardeningDisable = ["fortify"];
|
||||
|
||||
RUST_SRC_PATH = "${
|
||||
(pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml)
|
||||
}/lib/rustlib/src/rust/library";
|
||||
LD_LIBRARY_PATH = "${lib.makeLibraryPath commonArgs.buildInputs}:${pkgs.stdenv.cc.cc.lib}/lib";
|
||||
};
|
||||
|
||||
treefmt = {
|
||||
projectRootFile = "Cargo.toml";
|
||||
programs = {
|
||||
actionlint.enable = true;
|
||||
nixfmt.enable = true;
|
||||
rustfmt.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
7
rust-toolchain.toml
Normal file
7
rust-toolchain.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-11-22"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
# commit_hash = b19329a37cedf2027517ae22c87cf201f93d776e
|
||||
|
||||
# Whenever changing the nightly channel, update the commit hash above, and make
|
||||
# sure to change `REQUIRED_TOOLCHAIN` in `crates/rustc_codegen_spirv/build.rs` also.
|
||||
Loading…
Add table
Add a link
Reference in a new issue