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:
@@ -719,4 +719,6 @@ fn main() {
|
|||||||
None => error!("skipping sim because no valid geometry: {:?}", params),
|
None => error!("skipping sim because no valid geometry: {:?}", params),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("done");
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,7 @@ impl<R: Real, M: Default> Driver<SimState<R, M>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M: spirv::IntoFfi> SpirvDriver<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 {
|
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))
|
Self::new_with_state(SpirvSim::new(size.to_index(feature_size), feature_size))
|
||||||
|
@@ -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.
|
/// hide the actual spirv backend structures inside a submodule to make their use/boundary clear.
|
||||||
mod ffi {
|
mod ffi {
|
||||||
|
pub use spirv_backend_lib::entry_points;
|
||||||
pub use spirv_backend_lib::sim::SerializedSimMeta;
|
pub use spirv_backend_lib::sim::SerializedSimMeta;
|
||||||
pub use spirv_backend_lib::support::{Optional, Vec3Std, UVec3Std};
|
pub use spirv_backend_lib::support::{Optional, Vec3Std, UVec3Std};
|
||||||
pub use spirv_backend_lib::mat::{Ferroxcube3R1MH, FullyGenericMaterial, IsoConductorOr, Material, MBPgram, MHPgram};
|
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;
|
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>
|
impl<L: IntoFfi> IntoFfi for Option<L>
|
||||||
where L::Ffi: Default
|
where L::Ffi: Default
|
||||||
{
|
{
|
||||||
@@ -338,3 +360,12 @@ impl<'de, F> Deserialize<'de> for Remote<F>
|
|||||||
Ok(Remote(local.into_ffi()))
|
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()
|
||||||
|
}
|
||||||
|
@@ -17,7 +17,7 @@ use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, SampleableSim}
|
|||||||
use crate::stim::AbstractStimulus;
|
use crate::stim::AbstractStimulus;
|
||||||
|
|
||||||
mod bindings;
|
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).
|
/// Wrapper around an inner state object which offloads stepping onto a spirv backend (e.g. GPU).
|
||||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||||
@@ -48,14 +48,17 @@ struct WgpuData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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;
|
use std::mem::size_of;
|
||||||
let max_elem_size = size_of::<M>().max(size_of::<Vec3<f32>>());
|
let max_elem_size = size_of::<M>().max(size_of::<Vec3<f32>>());
|
||||||
let max_buf_size = volume * max_elem_size as u64 + 0x1000;
|
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 (device, queue) = futures::executor::block_on(open_device(max_buf_size));
|
||||||
let shader_binary = get_shader();
|
let shader_binary = get_shader();
|
||||||
let shader_module = unsafe { device.create_shader_module_spirv(&shader_binary) };
|
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 {
|
Self {
|
||||||
step_bind_group_layout,
|
step_bind_group_layout,
|
||||||
step_h_pipeline,
|
step_h_pipeline,
|
||||||
@@ -68,7 +71,7 @@ impl WgpuData {
|
|||||||
|
|
||||||
impl Default for WgpuData {
|
impl Default for WgpuData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new::<()>(0)
|
Self::new::<FullyGenericMaterial>(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,10 +155,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M: IntoFfi> SpirvSim<M>
|
impl<M: IntoFfi> SpirvSim<M>
|
||||||
where M::Ffi: Default
|
where M::Ffi: Default + 'static
|
||||||
{
|
{
|
||||||
pub fn new(size: Index, feature_size: f32) -> Self {
|
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 {
|
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)
|
(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
|
wgpu::BindGroupLayout, wgpu::ComputePipeline, wgpu::ComputePipeline
|
||||||
) {
|
) {
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
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,
|
label: None,
|
||||||
layout: Some(&pipeline_layout),
|
layout: Some(&pipeline_layout),
|
||||||
module: shader_module,
|
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 {
|
let compute_step_e_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
layout: Some(&pipeline_layout),
|
layout: Some(&pipeline_layout),
|
||||||
module: shader_module,
|
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)
|
(bind_group_layout, compute_step_h_pipeline, compute_step_e_pipeline)
|
||||||
|
@@ -20,7 +20,9 @@ pub mod support;
|
|||||||
pub use sim::{SerializedSimMeta, SerializedStepE, SerializedStepH};
|
pub use sim::{SerializedSimMeta, SerializedStepE, SerializedStepH};
|
||||||
pub use support::{Optional, UnsizedArray, UVec3Std, Vec3Std};
|
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>(
|
fn step_h<M: Material>(
|
||||||
id: UVec3,
|
id: UVec3,
|
||||||
@@ -53,31 +55,58 @@ fn step_e<M: Material>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalSize/numthreads
|
/// Return the step_h/step_e entry point names for the provided material
|
||||||
#[spirv(compute(threads(4, 4, 4)))]
|
pub fn entry_points<M: 'static>() -> Optional<(&'static str, &'static str)> {
|
||||||
pub fn step_h_generic_material(
|
use core::any::TypeId;
|
||||||
#[spirv(global_invocation_id)] id: UVec3,
|
let mappings = [
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
|
(TypeId::of::<FullyGenericMaterial>(),
|
||||||
// XXX: delete this input?
|
("step_h_generic_material", "step_e_generic_material")
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] _unused_stimulus: &UnsizedArray<Vec3Std>,
|
),
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] material: &UnsizedArray<FullyGenericMaterial>,
|
(TypeId::of::<Iso3R1>(),
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] e: &UnsizedArray<Vec3Std>,
|
("step_h_iso_3r1", "step_e_iso_3r1")
|
||||||
#[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)
|
for (id, names) in mappings {
|
||||||
|
if id == TypeId::of::<M>() {
|
||||||
|
return Optional::some(names);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Optional::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[spirv(compute(threads(4, 4, 4)))]
|
macro_rules! steps {
|
||||||
pub fn step_e_generic_material(
|
($mat:ty, $step_h:ident, $step_e:ident) => {
|
||||||
#[spirv(global_invocation_id)] id: UVec3,
|
// LocalSize/numthreads
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
|
#[spirv(compute(threads(4, 4, 4)))]
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] stimulus: &UnsizedArray<Vec3Std>,
|
pub fn $step_h(
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] material: &UnsizedArray<FullyGenericMaterial>,
|
#[spirv(global_invocation_id)] id: UVec3,
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] e: &mut UnsizedArray<Vec3Std>,
|
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] h: &UnsizedArray<Vec3Std>,
|
// XXX: delete this input?
|
||||||
// XXX: can/should this m input be deleted?
|
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] _unused_stimulus: &UnsizedArray<Vec3Std>,
|
||||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] _unused_m: &UnsizedArray<Vec3Std>,
|
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] material: &UnsizedArray<$mat>,
|
||||||
) {
|
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] e: &UnsizedArray<Vec3Std>,
|
||||||
step_e(id, meta, stimulus, material, e, h)
|
#[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);
|
||||||
|
@@ -246,7 +246,8 @@ impl<M: Material + Copy> Material for IsoConductorOr<M> {
|
|||||||
}
|
}
|
||||||
fn move_b_vec(&self, m: Vec3Std, target_b: Vec3Std) -> Vec3Std {
|
fn move_b_vec(&self, m: Vec3Std, target_b: Vec3Std) -> Vec3Std {
|
||||||
if self.value < 0.0 {
|
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 {
|
} else {
|
||||||
m
|
m
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user