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