spirv: get the optimized IsoConductorOr<Ferroxcube3R1> plumbed all the way through

buffer_proto5 example shows it in action (results weren't verified)
This commit is contained in:
2022-01-29 16:30:29 -08:00
parent bef39789a7
commit e574bf71ca
6 changed files with 103 additions and 37 deletions

View File

@@ -719,4 +719,6 @@ fn main() {
None => error!("skipping sim because no valid geometry: {:?}", params),
}
}
info!("done");
}

View File

@@ -44,7 +44,7 @@ impl<R: Real, M: Default> Driver<SimState<R, M>> {
}
impl<M: spirv::IntoFfi> SpirvDriver<M>
where M::Ffi: Default
where M::Ffi: Default + 'static
{
pub fn new_spirv<C: Coord>(size: C, feature_size: f32) -> Self {
Self::new_with_state(SpirvSim::new(size.to_index(feature_size), feature_size))

View File

@@ -7,6 +7,7 @@ use crate::geom::{Index, Vec3, Vec3u};
/// hide the actual spirv backend structures inside a submodule to make their use/boundary clear.
mod ffi {
pub use spirv_backend_lib::entry_points;
pub use spirv_backend_lib::sim::SerializedSimMeta;
pub use spirv_backend_lib::support::{Optional, Vec3Std, UVec3Std};
pub use spirv_backend_lib::mat::{Ferroxcube3R1MH, FullyGenericMaterial, IsoConductorOr, Material, MBPgram, MHPgram};
@@ -34,6 +35,27 @@ pub trait IntoLib {
fn into_lib(self) -> Self::Lib;
}
macro_rules! identity {
($($param:ident,)* => $t:ty) => {
impl<$($param: IntoFfi),*> IntoFfi for $t {
type Ffi = $t;
fn into_ffi(self) -> Self::Ffi {
self
}
}
impl<$($param: IntoLib),*> IntoLib for $t {
type Lib = $t;
fn into_lib(self) -> Self::Lib {
self
}
}
};
}
// XXX: should work for any other lifetime, not just 'static
identity!(=> &'static str);
identity!(T0, T1, => (T0, T1));
impl<L: IntoFfi> IntoFfi for Option<L>
where L::Ffi: Default
{
@@ -338,3 +360,12 @@ impl<'de, F> Deserialize<'de> for Remote<F>
Ok(Remote(local.into_ffi()))
}
}
// FUNCTION BINDINGS
pub fn entry_points<L>() -> Option<(&'static str, &'static str)>
where
L: IntoFfi,
L::Ffi: 'static
{
ffi::entry_points::<L::Ffi>().into_lib()
}

View File

@@ -17,7 +17,7 @@ use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, SampleableSim}
use crate::stim::AbstractStimulus;
mod bindings;
pub use bindings::{IntoFfi, IntoLib, IsoConductorOr, FullyGenericMaterial, Remote, SimMeta, Material};
pub use bindings::{entry_points, IntoFfi, IntoLib, IsoConductorOr, FullyGenericMaterial, Remote, SimMeta, Material};
/// Wrapper around an inner state object which offloads stepping onto a spirv backend (e.g. GPU).
#[derive(Clone, Default, Serialize, Deserialize)]
@@ -48,14 +48,17 @@ struct WgpuData {
}
impl WgpuData {
pub fn new<M>(volume: u64) -> Self {
pub fn new<M: IntoFfi>(volume: u64) -> Self
where M::Ffi: 'static
{
use std::mem::size_of;
let max_elem_size = size_of::<M>().max(size_of::<Vec3<f32>>());
let max_buf_size = volume * max_elem_size as u64 + 0x1000;
let entry_names = entry_points::<M>().unwrap_or(("invalid_mat", "invalid_mat"));
let (device, queue) = futures::executor::block_on(open_device(max_buf_size));
let shader_binary = get_shader();
let shader_module = unsafe { device.create_shader_module_spirv(&shader_binary) };
let (step_bind_group_layout, step_h_pipeline, step_e_pipeline) = make_pipelines(&device, &shader_module);
let (step_bind_group_layout, step_h_pipeline, step_e_pipeline) = make_pipelines(&device, &shader_module, entry_names);
Self {
step_bind_group_layout,
step_h_pipeline,
@@ -68,7 +71,7 @@ impl WgpuData {
impl Default for WgpuData {
fn default() -> Self {
Self::new::<()>(0)
Self::new::<FullyGenericMaterial>(0)
}
}
@@ -152,10 +155,10 @@ where
}
impl<M: IntoFfi> SpirvSim<M>
where M::Ffi: Default
where M::Ffi: Default + 'static
{
pub fn new(size: Index, feature_size: f32) -> Self {
Self::new_with_wgpu_handle(size, feature_size, Some(Arc::new(WgpuData::new::<M::Ffi>(size.volume()))))
Self::new_with_wgpu_handle(size, feature_size, Some(Arc::new(WgpuData::new::<M>(size.volume()))))
}
pub fn new_no_wgpu(size: Index, feature_size: f32) -> Self {
@@ -534,7 +537,7 @@ async fn open_device(max_buf_size: u64) -> (wgpu::Device, wgpu::Queue) {
(device, queue)
}
fn make_pipelines(device: &wgpu::Device, shader_module: &wgpu::ShaderModule) -> (
fn make_pipelines(device: &wgpu::Device, shader_module: &wgpu::ShaderModule, entry_names: (&'static str, &'static str)) -> (
wgpu::BindGroupLayout, wgpu::ComputePipeline, wgpu::ComputePipeline
) {
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
@@ -619,14 +622,14 @@ fn make_pipelines(device: &wgpu::Device, shader_module: &wgpu::ShaderModule) ->
label: None,
layout: Some(&pipeline_layout),
module: shader_module,
entry_point: "step_h_generic_material",
entry_point: entry_names.0,
});
let compute_step_e_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
module: shader_module,
entry_point: "step_e_generic_material",
entry_point: entry_names.1,
});
(bind_group_layout, compute_step_h_pipeline, compute_step_e_pipeline)

View File

@@ -20,7 +20,9 @@ pub mod support;
pub use sim::{SerializedSimMeta, SerializedStepE, SerializedStepH};
pub use support::{Optional, UnsizedArray, UVec3Std, Vec3Std};
use mat::{FullyGenericMaterial, Material};
use mat::{IsoConductorOr, Ferroxcube3R1MH, FullyGenericMaterial, Material};
type Iso3R1 = IsoConductorOr<Ferroxcube3R1MH>;
fn step_h<M: Material>(
id: UVec3,
@@ -53,31 +55,58 @@ fn step_e<M: Material>(
}
}
// LocalSize/numthreads
#[spirv(compute(threads(4, 4, 4)))]
pub fn step_h_generic_material(
#[spirv(global_invocation_id)] id: UVec3,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
// XXX: delete this input?
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] _unused_stimulus: &UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] material: &UnsizedArray<FullyGenericMaterial>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] e: &UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] h: &mut UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] m: &mut UnsizedArray<Vec3Std>,
) {
step_h(id, meta, material, e, h, m)
/// Return the step_h/step_e entry point names for the provided material
pub fn entry_points<M: 'static>() -> Optional<(&'static str, &'static str)> {
use core::any::TypeId;
let mappings = [
(TypeId::of::<FullyGenericMaterial>(),
("step_h_generic_material", "step_e_generic_material")
),
(TypeId::of::<Iso3R1>(),
("step_h_iso_3r1", "step_e_iso_3r1")
),
];
for (id, names) in mappings {
if id == TypeId::of::<M>() {
return Optional::some(names);
}
}
Optional::none()
}
#[spirv(compute(threads(4, 4, 4)))]
pub fn step_e_generic_material(
#[spirv(global_invocation_id)] id: UVec3,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] stimulus: &UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] material: &UnsizedArray<FullyGenericMaterial>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] e: &mut UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] h: &UnsizedArray<Vec3Std>,
// XXX: can/should this m input be deleted?
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] _unused_m: &UnsizedArray<Vec3Std>,
) {
step_e(id, meta, stimulus, material, e, h)
macro_rules! steps {
($mat:ty, $step_h:ident, $step_e:ident) => {
// LocalSize/numthreads
#[spirv(compute(threads(4, 4, 4)))]
pub fn $step_h(
#[spirv(global_invocation_id)] id: UVec3,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
// XXX: delete this input?
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] _unused_stimulus: &UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] material: &UnsizedArray<$mat>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] e: &UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] h: &mut UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] m: &mut UnsizedArray<Vec3Std>,
) {
step_h(id, meta, material, e, h, m)
}
#[spirv(compute(threads(4, 4, 4)))]
pub fn $step_e(
#[spirv(global_invocation_id)] id: UVec3,
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] stimulus: &UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] material: &UnsizedArray<$mat>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] e: &mut UnsizedArray<Vec3Std>,
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] h: &UnsizedArray<Vec3Std>,
// XXX: can/should this m input be deleted?
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] _unused_m: &UnsizedArray<Vec3Std>,
) {
step_e(id, meta, stimulus, material, e, h)
}
};
}
steps!(FullyGenericMaterial, step_h_generic_material, step_e_generic_material);
steps!(Iso3R1, step_h_iso_3r1, step_e_iso_3r1);

View File

@@ -246,7 +246,8 @@ impl<M: Material + Copy> Material for IsoConductorOr<M> {
}
fn move_b_vec(&self, m: Vec3Std, target_b: Vec3Std) -> Vec3Std {
if self.value < 0.0 {
self.mat.move_b_vec(m, target_b)
let mat = self.mat; //< XXX hack for ZST
mat.move_b_vec(m, target_b)
} else {
m
}