This commit is contained in:
2024-12-21 22:09:39 -05:00
parent d89721cc92
commit eb3bee1437
12 changed files with 1903 additions and 1 deletions

1586
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,28 @@
[workspace]
members = [
"crates/flare-kernel",
"crates/flare-lib",
"crates/flare-shader",
"crates/flare-xml"
]
resolver = "2"
[workspace.dependencies]
bytemuck = { version = "1.21.0", features = ["derive"] }
futures-executor = "0.3.31"
glam = { version = "0.29.2", features = ["cuda", "bytemuck"] }
serde = { version = "1.0.216", features = ["derive"] }
serde-xml-rs = "0.6.0"
spirv-std = { git = "https://github.com/rust-gpu/rust-gpu", rev = "1d76d59471eef54da481d63cfb9cbf3a5daded6c" }
spirv-builder = { git = "https://github.com/rust-gpu/rust-gpu", rev = "1d76d59471eef54da481d63cfb9cbf3a5daded6c" }
thiserror = "2.0.8"
xml-rs = "0.8.24"
wgpu = { version = "23.0.1", features = ["spirv"] }
xml-rs = "0.8.24"
# Compile build-dependencies in release mode with
# the same settings as regular dependencies.
[profile.release.build-override]
opt-level = 3
codegen-units = 16
[profile.dev.build-override]
opt-level = 3

View File

@ -0,0 +1,9 @@
[package]
name = "flare-kernel"
version = "0.1.0"
edition = "2021"
[dependencies]
bytemuck.workspace = true
glam.workspace = true
spirv-std.workspace = true

View File

@ -0,0 +1,17 @@
#![no_std]
macro_rules! import_glam {
() => {
#[cfg(target_arch = "spirv")]
use spirv_std::glam;
#[cfg(not(target_arch = "spirv"))]
use glam;
};
}
mod transforms;
mod variations;
pub use transforms::*;
pub use variations::*;

View File

@ -0,0 +1,15 @@
import_glam!();
#[derive(Copy, Clone, Default, Debug)]
#[repr(C)]
pub struct TransformSpec {
pub coefs: glam::Affine2,
pub post_coefs: glam::Affine2,
pub variation_offset: u32,
pub variation_count: u32,
}
// UNSAFE: Can't derive these types because Affine2 doesn't implement Pod
// Safe because all individual elements are the same size, so byte aligned
unsafe impl bytemuck::Zeroable for TransformSpec {}
unsafe impl bytemuck::Pod for TransformSpec {}

View File

@ -0,0 +1,36 @@
import_glam!();
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum VariationKind {
Linear,
}
// UNSAFE: I think this is fine for repr(C) enums?
unsafe impl bytemuck::Zeroable for VariationKind {}
unsafe impl bytemuck::Pod for VariationKind {}
#[derive(Copy, Clone, Debug, Default, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(transparent)]
pub struct VariationParams([f32; 8]);
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
#[repr(C)]
pub struct VariationSpec {
kind: VariationKind,
weight: f32,
params: VariationParams,
}
impl VariationSpec {
pub fn apply(&self, point: glam::Vec2) -> glam::Vec2 {
let point = match self.kind {
VariationKind::Linear => apply_linear(&self.params, point),
};
point * self.weight
}
}
fn apply_linear(_params: &VariationParams, point: glam::Vec2) -> glam::Vec2 {
point
}

View File

@ -0,0 +1,14 @@
[package]
name = "flare-lib"
version = "0.1.0"
edition = "2021"
[dependencies]
bytemuck.workspace = true
flare-kernel = { path = "../flare-kernel" }
futures-executor.workspace = true
glam.workspace = true
wgpu.workspace = true
[build-dependencies]
spirv-builder.workspace = true

22
crates/flare-lib/build.rs Normal file
View File

@ -0,0 +1,22 @@
use spirv_builder::{MetadataPrintout, SpirvBuilder};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let gpu_crate_path = Path::new("../flare-shader/");
// Compile the shader crate with SpirvBuilder.
let result = SpirvBuilder::new(gpu_crate_path, "spirv-unknown-vulkan1.2")
.print_metadata(MetadataPrintout::Full)
.build()?;
// Copy the SPIR-V to this crate's output directory
let shader_path = result.module.unwrap_single();
let output_path = PathBuf::from(env::var("OUT_DIR")?).join("shader_binary.spv");
fs::copy(shader_path, &output_path)?;
println!("Generated shader binary constant at {:?}", output_path);
Ok(())
}

151
crates/flare-lib/src/lib.rs Normal file
View File

@ -0,0 +1,151 @@
use glam;
#[cfg(test)]
pub mod tests {
use std::default::Default;
use wgpu::util::DeviceExt;
use flare_kernel::{TransformSpec, VariationSpec};
async fn create_instance() -> wgpu::Instance {
let backends = wgpu::util::backend_bits_from_env().unwrap_or_default();
wgpu::Instance::new(wgpu::InstanceDescriptor {
backends,
..Default::default()
})
}
async fn create_adapter(instance: &wgpu::Instance) -> wgpu::Adapter {
instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::HighPerformance,
force_fallback_adapter: false,
compatible_surface: None,
})
.await
.expect("Failed to create adapter")
}
async fn create_device_queue(adapter: &wgpu::Adapter) -> (wgpu::Device, wgpu::Queue) {
adapter
.request_device(
&wgpu::DeviceDescriptor {
label: Some("unit test"),
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::default(),
memory_hints: wgpu::MemoryHints::default(),
},
None,
)
.await
.expect("Failed to request device queue")
}
async fn create_shader(device: &wgpu::Device) -> wgpu::ShaderModule {
device.create_shader_module(wgpu::include_spirv!(concat!(env!("OUT_DIR"), "/shader_binary.spv")))
}
async fn create_pipeline_layout(device: &wgpu::Device, layout: &wgpu::BindGroupLayout) -> wgpu::PipelineLayout {
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("pipeline"),
bind_group_layouts: &[layout],
push_constant_ranges: &[],
})
}
async fn create_apply_transform_f32_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout{
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("apply_transform_f32"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage {
read_only: true,
},
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage {
read_only: true,
},
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage {
read_only: false,
},
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}
]
})
}
async fn create_apply_transform_f32_compute_pipeline(device: &wgpu::Device, pipeline_layout: &wgpu::PipelineLayout, shader: &wgpu::ShaderModule) -> wgpu::ComputePipeline {
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("apply_transform_f32_compute_pipeline"),
layout: Some(pipeline_layout),
module: shader,
entry_point: Some("apply_transform_f32"),
compilation_options: Default::default(),
cache: Default::default(),
})
}
async fn do_apply_transform_f32(
transform: &TransformSpec,
variations: &[VariationSpec],
point: &glam::Vec2,
) -> glam::Vec2 {
let instance = create_instance().await;
let adapter = create_adapter(&instance).await;
let (device, queue) = create_device_queue(&adapter).await;
let shader = create_shader(&device, ).await;
let bind_group_layout = create_apply_transform_f32_bind_group_layout(&device).await;
let pipeline_layout = create_pipeline_layout(&device, &bind_group_layout).await;
let compute_pipeline = create_apply_transform_f32_compute_pipeline(&device, &pipeline_layout, &shader).await;
let transform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
contents: bytemuck::cast_slice(&[transform]),
});
let variation_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
contents: bytemuck::cast_slice(variations),
});
glam::Vec2::new()
}
#[test]
pub fn apply_linear_transform() {}
}

View File

@ -0,0 +1,11 @@
[package]
name = "flare-shader"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["dylib", "lib"]
[dependencies]
flare-kernel = { path = "../flare-kernel" }
spirv-std.workspace = true

View File

@ -0,0 +1,21 @@
#![no_std]
use spirv_std::spirv;
use spirv_std::glam::{UVec3, Vec2};
use flare_kernel::{TransformSpec, VariationSpec};
#[spirv(compute(threads(1)))]
pub fn apply_transform_f32(
#[spirv(global_invocation_id)] _global_id: UVec3,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] transform: &TransformSpec,
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] variations: &[VariationSpec],
#[spirv(uniform, descriptor_set = 0, binding = 2)] point_in: &Vec2,
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] point_out: &mut Vec2,
) {
let mut point = transform.coefs.transform_point2(*point_in);
for i in transform.variation_offset as usize..transform.variation_count as usize {
point = variations[i].apply(point);
}
*point_out = transform.post_coefs.transform_point2(point);
}

3
rust-toolchain.toml Normal file
View File

@ -0,0 +1,3 @@
[toolchain]
channel = "nightly-2024-11-22"
components = ["rust-src", "rustc-dev", "llvm-tools"]