Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ jobs:
run: cd xtask && cargo build
- name: xtask generate
run: cargo xtask generate ${{ matrix.integration }}
- name: check generated files are up-to-date
run: |
git add .
git diff --cached
# if this fails, the files committed don't match what should have been generated
git diff --quiet && git diff --cached --quiet
# no --locked, templates need to generate their lockfile
- name: cargo fetch
run: cargo xtask generate ${{ matrix.integration }} -x "cargo fetch --target $TARGET"
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
target
.idea
generated
generated/**/Cargo.lock
30 changes: 30 additions & 0 deletions generated/cargo-gpu/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[workspace]
members = [
"ash-graphics",
"ash-graphics-shaders"
]
resolver = "3"

[workspace.package]
version = "0.1.0"
authors = ["generated <generated>"]
edition = "2024"
license = "MIT"
repository = ""

[workspace.lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(target_arch, values("spirv"))'] }

[workspace.dependencies]
cargo-gpu = { git = "https://github.com/Rust-GPU/cargo-gpu", rev = "bf24eb6060e0c7b0013eceddd23b5d7cee68f4cc" }
spirv-std = { git = "https://github.com/Rust-GPU/rust-gpu", rev = "6fb875068d0d35b1a81ae89b73cf7a464f8c60f7" }

glam = { version = "0.30.9", default-features = false }
bytemuck = { version = "1.24.0", features = ["derive"] }
ash = "0.38"
ash-window = "0.13"
raw-window-handle = "0.6.2"
winit = "0.30.0"
cfg-if = "1.0.0"
anyhow = "1.0.98"

15 changes: 15 additions & 0 deletions generated/cargo-gpu/ash-graphics-shaders/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "ash-graphics-shaders"
version = "0.1.0"
edition = "2024"

[lints]
workspace = true

[lib]
crate-type = ["lib", "dylib"]

[dependencies]
spirv-std.workspace = true
glam.workspace = true
bytemuck.workspace = true
36 changes: 36 additions & 0 deletions generated/cargo-gpu/ash-graphics-shaders/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#![no_std]

use bytemuck::{Pod, Zeroable};
use core::f32::consts::PI;
use glam::{Vec3, Vec4, vec2, vec3};
#[cfg(target_arch = "spirv")]
use spirv_std::num_traits::Float;
use spirv_std::spirv;

#[derive(Copy, Clone, Pod, Zeroable)]
#[repr(C)]
pub struct ShaderConstants {
pub width: u32,
pub height: u32,
pub time: f32,
}

#[spirv(fragment)]
pub fn main_fs(vtx_color: Vec3, output: &mut Vec4) {
*output = Vec4::from((vtx_color, 1.));
}

#[spirv(vertex)]
pub fn main_vs(
#[spirv(vertex_index)] vert_id: i32,
#[spirv(push_constant)] constants: &ShaderConstants,
#[spirv(position)] vtx_pos: &mut Vec4,
vtx_color: &mut Vec3,
) {
let speed = 0.4;
let time = constants.time * speed + vert_id as f32 * (2. * PI * 120. / 360.);
let position = vec2(f32::sin(time), f32::cos(time));
*vtx_pos = Vec4::from((position, 0.0, 1.0));

*vtx_color = [vec3(1., 0., 0.), vec3(0., 1., 0.), vec3(0., 0., 1.)][vert_id as usize % 3];
}
25 changes: 25 additions & 0 deletions generated/cargo-gpu/ash-graphics/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "ash-graphics"
publish = false
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true

[lints]
workspace = true

[dependencies]
ash-graphics-shaders = { path = "../ash-graphics-shaders" }

ash.workspace = true
ash-window.workspace = true
raw-window-handle.workspace = true
winit.workspace = true
anyhow.workspace = true
bytemuck.workspace = true

[build-dependencies]
cargo-gpu.workspace = true
anyhow.workspace = true
24 changes: 24 additions & 0 deletions generated/cargo-gpu/ash-graphics/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use cargo_gpu::Install;
use cargo_gpu::spirv_builder::{MetadataPrintout, ShaderPanicStrategy};
use std::path::PathBuf;

pub fn main() -> anyhow::Result<()> {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let crate_path = [manifest_dir, "..", "ash-graphics-shaders"]
.iter()
.copied()
.collect::<PathBuf>();

let install = Install::from_shader_crate(crate_path.clone()).run()?;
let mut builder = install.to_spirv_builder(crate_path, "spirv-unknown-vulkan1.3");
builder.print_metadata = MetadataPrintout::DependencyOnly;
builder.shader_panic_strategy = ShaderPanicStrategy::DebugPrintfThenExit {
print_inputs: true,
print_backtrace: true,
};

let compile_result = builder.build()?;
let spv_path = compile_result.module.unwrap_single();
println!("cargo::rustc-env=SHADER_SPV_PATH={}", spv_path.display());
Ok(())
}
183 changes: 183 additions & 0 deletions generated/cargo-gpu/ash-graphics/src/device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
use anyhow::{Context, anyhow};
use ash::{ext, khr, vk};
use std::borrow::Cow;
use std::ffi::{CStr, c_char};
use std::ops::Deref;
use std::sync::Arc;

/// Central struct containing the Vulkan instance and device, among others
pub struct MyDevice {
pub entry: ash::Entry,
pub instance: ash::Instance,
pub physical_device: vk::PhysicalDevice,
pub device: ash::Device,
pub main_queue_family: u32,
pub main_queue: vk::Queue,
pub debug_ext_instance: ext::debug_utils::Instance,
pub debug_ext_device: ext::debug_utils::Device,
pub surface_ext: khr::surface::Instance,
pub swapchain_ext: khr::swapchain::Device,
debug_callback: vk::DebugUtilsMessengerEXT,
}

impl Deref for MyDevice {
type Target = ash::Device;

fn deref(&self) -> &Self::Target {
&self.device
}
}

impl MyDevice {
pub fn new(extension_names: &[*const c_char], debug_layer: bool) -> anyhow::Result<Arc<Self>> {
unsafe {
let entry = ash::Entry::load()?;

let instance = {
let layer_names: &'static [_] = if debug_layer {
const { &[c"VK_LAYER_KHRONOS_validation".as_ptr()] }
} else {
&[]
};

let mut extension_names_raw = extension_names.to_vec();
extension_names_raw.push(ext::debug_utils::NAME.as_ptr());

let app_name = c"VulkanTriangle";
entry
.create_instance(
&vk::InstanceCreateInfo::default()
.application_info(
&vk::ApplicationInfo::default()
.application_name(app_name)
.application_version(0)
.engine_name(app_name)
.engine_version(0)
.api_version(vk::make_api_version(0, 1, 3, 0)),
)
.enabled_layer_names(layer_names)
.enabled_extension_names(&extension_names_raw),
None,
)
.context("create_instance")?
};

let debug_instance = ext::debug_utils::Instance::new(&entry, &instance);
let debug_callback = {
debug_instance.create_debug_utils_messenger(
&vk::DebugUtilsMessengerCreateInfoEXT::default()
.message_severity(
vk::DebugUtilsMessageSeverityFlagsEXT::ERROR
| vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
| vk::DebugUtilsMessageSeverityFlagsEXT::INFO,
)
.message_type(
vk::DebugUtilsMessageTypeFlagsEXT::GENERAL
| vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION
| vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
)
.pfn_user_callback(Some(vulkan_debug_callback)),
None,
)?
};

let physical_device = {
instance
.enumerate_physical_devices()?
.into_iter()
.min_by_key(|phy| {
match instance.get_physical_device_properties(*phy).device_type {
vk::PhysicalDeviceType::DISCRETE_GPU => 1,
vk::PhysicalDeviceType::VIRTUAL_GPU => 2,
vk::PhysicalDeviceType::INTEGRATED_GPU => 3,
vk::PhysicalDeviceType::CPU => 4,
_ => 5,
}
})
.ok_or(anyhow!("No physical devices available"))?
};

let main_queue_family = {
instance
.get_physical_device_queue_family_properties(physical_device)
.into_iter()
.enumerate()
.find(|(_, prop)| prop.queue_flags.contains(vk::QueueFlags::GRAPHICS))
.ok_or(anyhow!(
"No graphics + compute queues on physical device available"
))?
.0 as u32
};

let device = instance
.create_device(
physical_device,
&vk::DeviceCreateInfo::default()
.push_next(
&mut vk::PhysicalDeviceVulkan12Features::default()
.vulkan_memory_model(true),
)
.push_next(
&mut vk::PhysicalDeviceVulkan13Features::default()
.synchronization2(true)
.dynamic_rendering(true),
)
.queue_create_infos(&[vk::DeviceQueueCreateInfo::default()
.queue_family_index(main_queue_family)
.queue_priorities(&[1.0])])
.enabled_extension_names(&[
khr::swapchain::NAME.as_ptr(),
khr::shader_non_semantic_info::NAME.as_ptr(),
]),
None,
)
.context("create_device")?;
let main_queue = device.get_device_queue(main_queue_family, 0);

Ok(Arc::new(Self {
debug_ext_device: ext::debug_utils::Device::new(&instance, &device),
surface_ext: khr::surface::Instance::new(&entry, &instance),
swapchain_ext: khr::swapchain::Device::new(&instance, &device),
entry,
instance,
physical_device,
device,
main_queue_family,
main_queue,
debug_ext_instance: debug_instance,
debug_callback,
}))
}
}
}

impl Drop for MyDevice {
fn drop(&mut self) {
unsafe {
self.debug_ext_instance
.destroy_debug_utils_messenger(self.debug_callback, None);
self.device.destroy_device(None);
self.instance.destroy_instance(None);
}
}
}

unsafe extern "system" fn vulkan_debug_callback(
message_severity: vk::DebugUtilsMessageSeverityFlagsEXT,
_message_type: vk::DebugUtilsMessageTypeFlagsEXT,
p_callback_data: *const vk::DebugUtilsMessengerCallbackDataEXT<'_>,
_user_data: *mut std::os::raw::c_void,
) -> vk::Bool32 {
unsafe {
let callback_data = *p_callback_data;
let message_id_name = callback_data
.message_id_name_as_c_str()
.map_or(Cow::Borrowed(""), CStr::to_string_lossy);
let message = callback_data
.message_as_c_str()
.map_or(Cow::Borrowed(""), CStr::to_string_lossy);

println!("{message_severity:?}: [{message_id_name}] : {message}");
vk::FALSE
}
}
Loading