Move to workspace
This commit is contained in:
Generated
+17
@@ -921,6 +921,12 @@ version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "2.1.1"
|
||||
@@ -2543,6 +2549,7 @@ dependencies = [
|
||||
"rand",
|
||||
"rspirv",
|
||||
"simplelog",
|
||||
"tape-load",
|
||||
"utf-8",
|
||||
"vulkano",
|
||||
"vulkano-shaders",
|
||||
@@ -2550,6 +2557,16 @@ dependencies = [
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tape-load"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"foldhash",
|
||||
"glam",
|
||||
"humantime",
|
||||
"rspirv",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
|
||||
+8
-47
@@ -1,45 +1,12 @@
|
||||
[package]
|
||||
name = "tape-drive"
|
||||
version = "0.3.0"
|
||||
edition = "2024"
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["tape-load", "tape-drive"]
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vulkano = "0.35.1"
|
||||
vulkano-shaders = { version = "0.35.0", features = ["shaderc-debug"] }
|
||||
winit = "0.30"
|
||||
vulkano-util = "0.35.0"
|
||||
|
||||
obj = "0.10"
|
||||
bytemuck = { version = "1.13", features = [
|
||||
"derive",
|
||||
"extern_crate_std",
|
||||
"min_const_generics",
|
||||
] }
|
||||
|
||||
glam = "0.30.3"
|
||||
|
||||
egui = "0.31.1"
|
||||
egui_winit_vulkano = "0.28.0"
|
||||
egui_plot = "0.32.1"
|
||||
|
||||
#serde = { version = "1", features = ["derive"] }
|
||||
#serde_json = "1"
|
||||
|
||||
utf-8 = "0.7"
|
||||
|
||||
rand = "0.9.1"
|
||||
foldhash = "0.1.5"
|
||||
|
||||
log = "0.4"
|
||||
simplelog = "0.12"
|
||||
|
||||
rspirv = "0.12"
|
||||
|
||||
num_cpus = "1"
|
||||
|
||||
notify = "8.2"
|
||||
[profile.final]
|
||||
inherits = "release"
|
||||
strip = true
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
|
||||
# using latest gits
|
||||
[patch.crates-io]
|
||||
@@ -49,9 +16,3 @@ notify = "8.2"
|
||||
#vulkano-taskgraph = { git = "https://github.com/vulkano-rs/vulkano" }
|
||||
#vulkano-util = { git = "https://github.com/vulkano-rs/vulkano" }
|
||||
#egui_winit_vulkano = { git = "https://github.com/Molive-0/egui_winit_vulkano" }
|
||||
|
||||
[profile.final]
|
||||
inherits = "release"
|
||||
strip = true
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
|
||||
-2829
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
[package]
|
||||
name = "tape-drive"
|
||||
version = "0.3.0"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vulkano = "0.35.1"
|
||||
vulkano-shaders = { version = "0.35.0", features = ["shaderc-debug"] }
|
||||
winit = "0.30"
|
||||
vulkano-util = "0.35.0"
|
||||
|
||||
obj = "0.10"
|
||||
bytemuck = { version = "1.13", features = [
|
||||
"derive",
|
||||
"extern_crate_std",
|
||||
"min_const_generics",
|
||||
] }
|
||||
|
||||
glam = "0.30.3"
|
||||
|
||||
egui = "0.31.1"
|
||||
egui_winit_vulkano = "0.28.0"
|
||||
egui_plot = "0.32.1"
|
||||
|
||||
#serde = { version = "1", features = ["derive"] }
|
||||
#serde_json = "1"
|
||||
|
||||
utf-8 = "0.7"
|
||||
|
||||
rand = "0.9.1"
|
||||
foldhash = "0.1.5"
|
||||
|
||||
log = "0.4"
|
||||
simplelog = "0.12"
|
||||
|
||||
rspirv = "0.12"
|
||||
|
||||
num_cpus = "1"
|
||||
|
||||
notify = "8.2"
|
||||
tape-load = { version = "*", path = "../tape-load" }
|
||||
@@ -6,12 +6,13 @@ import sys
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
SHADERS_DIR = "shaders_out"
|
||||
SHADERS_OUT = "shaders_out"
|
||||
SHADERS_IN = "src/shaders"
|
||||
TARGET_ENV = "vulkan1.3"
|
||||
|
||||
if os.path.isdir(SHADERS_DIR):
|
||||
shutil.rmtree(SHADERS_DIR)
|
||||
os.mkdir(SHADERS_DIR)
|
||||
if os.path.isdir(SHADERS_OUT):
|
||||
shutil.rmtree(SHADERS_OUT)
|
||||
os.mkdir(SHADERS_OUT)
|
||||
|
||||
normal_shaders = [
|
||||
("fullscreen.vert", "vert"),
|
||||
@@ -33,8 +34,8 @@ for shader, ty in normal_shaders:
|
||||
"--target-env",
|
||||
TARGET_ENV,
|
||||
"-o",
|
||||
f"{SHADERS_DIR}/{shader}.spv",
|
||||
f"src/shaders/{shader}.glsl",
|
||||
f"{SHADERS_OUT}/{shader}.spv",
|
||||
f"{SHADERS_IN}/{shader}.glsl",
|
||||
]
|
||||
)
|
||||
if result.returncode != 0:
|
||||
@@ -43,7 +44,7 @@ for shader, ty in normal_shaders:
|
||||
replacement_shaders = [("trace.frag", "frag"), ("normals.frag", "frag")]
|
||||
|
||||
for shader, ty in replacement_shaders:
|
||||
print(f"src/shaders/{shader}.glsl")
|
||||
print(f"{SHADERS_IN}/{shader}.glsl")
|
||||
result = subprocess.run(
|
||||
[
|
||||
"glslangValidator",
|
||||
@@ -55,7 +56,7 @@ for shader, ty in replacement_shaders:
|
||||
"--target-env",
|
||||
TARGET_ENV,
|
||||
"--quiet",
|
||||
"src/shaders/trace.frag.glsl",
|
||||
f"{SHADERS_IN}/{shader}.glsl",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
@@ -63,9 +64,11 @@ for shader, ty in replacement_shaders:
|
||||
if result.returncode != 0:
|
||||
sys.exit(result.returncode)
|
||||
asm = result.stdout
|
||||
asm = re.sub(r"(?ms)%11 =.*OpFunctionEnd", "", asm)
|
||||
with open(f"{SHADERS_OUT}/{shader}.old.spv-dis", "w") as f:
|
||||
f.write(asm)
|
||||
asm = re.sub(r"(?ms)%11 =.*?OpFunctionEnd", "", asm)
|
||||
asm = re.sub(r"%11 ", "%1000 ", asm)
|
||||
with open(f"{SHADERS_DIR}/{shader}.spv-dis", "w") as f:
|
||||
with open(f"{SHADERS_OUT}/{shader}.spv-dis", "w") as f:
|
||||
f.write(asm)
|
||||
result = subprocess.run(
|
||||
[
|
||||
@@ -74,7 +77,7 @@ for shader, ty in replacement_shaders:
|
||||
"--target-env",
|
||||
"vulkan1.3",
|
||||
"-o",
|
||||
f"{SHADERS_DIR}/{shader}.spv",
|
||||
f"{SHADERS_OUT}/{shader}.spv",
|
||||
],
|
||||
input=asm,
|
||||
encoding="ascii",
|
||||
@@ -38,7 +38,8 @@ pub(crate) struct GState {
|
||||
|
||||
pub(crate) new_csgs_needed: u8,
|
||||
|
||||
pub(crate) fps: [f64; 128],
|
||||
pub(crate) cpu_mpf: [f64; 1024],
|
||||
pub(crate) gpu_mpf: [f64; 1024],
|
||||
|
||||
pub(crate) debug: PreviousDebug,
|
||||
|
||||
@@ -65,7 +66,8 @@ impl Default for GState {
|
||||
|
||||
new_csgs_needed: 0,
|
||||
|
||||
fps: [0.0; 128],
|
||||
cpu_mpf: [0.0; 1024],
|
||||
gpu_mpf: [0.0; 1024],
|
||||
|
||||
debug: Default::default(),
|
||||
|
||||
@@ -271,17 +273,41 @@ pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState) {
|
||||
state.lights.push(Light::default());
|
||||
}
|
||||
|
||||
let fps: PlotPoints = state
|
||||
.fps
|
||||
let cpu_mpf: PlotPoints = state
|
||||
.cpu_mpf
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(x, y)| [x as f64, *y])
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
let average_fps = state.fps.iter().sum::<f64>() / state.fps.len() as f64;
|
||||
let line = Line::new("fps_line", fps);
|
||||
ui.heading(format!("FPS ({:.2})", average_fps));
|
||||
Plot::new("fps")
|
||||
let average_cpu_mpf =
|
||||
state.cpu_mpf.iter().sum::<f64>() / state.cpu_mpf.len() as f64;
|
||||
let line = Line::new("cpu_mpf_line", cpu_mpf);
|
||||
ui.heading(format!("CPU ms per frame ({:.2})", average_cpu_mpf));
|
||||
ui.heading(format!(
|
||||
"CPU frames per second ({:.2})",
|
||||
1000.0 / average_cpu_mpf
|
||||
));
|
||||
Plot::new("cpu_mpf")
|
||||
.view_aspect(2.0)
|
||||
.show(ui, |plot_ui| plot_ui.line(line));
|
||||
|
||||
let gpu_mpf: PlotPoints = state
|
||||
.gpu_mpf
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(x, y)| [x as f64, *y])
|
||||
.collect::<Vec<_>>()
|
||||
.into();
|
||||
let average_gpu_mpf =
|
||||
state.gpu_mpf.iter().sum::<f64>() / state.gpu_mpf.len() as f64;
|
||||
let line = Line::new("gpu_mpf_line", gpu_mpf);
|
||||
ui.heading(format!("GPU ms per frame ({:.2})", average_gpu_mpf));
|
||||
ui.heading(format!(
|
||||
"GPU frames per second ({:.2})",
|
||||
1000.0 / average_gpu_mpf
|
||||
));
|
||||
Plot::new("gpu_mpf")
|
||||
.view_aspect(2.0)
|
||||
.show(ui, |plot_ui| plot_ui.line(line));
|
||||
|
||||
@@ -5,14 +5,12 @@ const DUMP_SPV_TO_FILE: bool = true;
|
||||
const PIPELINE_CACHING: bool = false;
|
||||
const IGNORE_STENCIL: bool = true;
|
||||
|
||||
const BYTECODE_IMITATES_GLSL: bool = false;
|
||||
|
||||
const DEFAULT_SUBDIVISION: u32 = 16;
|
||||
const MAXIMUM_SUBDIVISION: u32 = 64;
|
||||
const MINUMUM_SUBDIVISION: u32 = 8;
|
||||
|
||||
const RUN_STANDARD_PIPELINE: bool = false;
|
||||
const RUN_RT_PIPELINE: bool = true;
|
||||
const RUN_STANDARD_PIPELINE: bool = true;
|
||||
const RUN_RT_PIPELINE: bool = false;
|
||||
|
||||
use std::{
|
||||
error::Error,
|
||||
@@ -77,6 +75,7 @@ use vulkano::{
|
||||
ShaderBindingTable,
|
||||
},
|
||||
},
|
||||
query::{QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::{ShaderModule, ShaderModuleCreateInfo, SpecializationConstant},
|
||||
swapchain::{
|
||||
@@ -84,7 +83,7 @@ use vulkano::{
|
||||
acquire_next_image,
|
||||
},
|
||||
sync::{
|
||||
self, GpuFuture,
|
||||
self, GpuFuture, PipelineStage,
|
||||
future::{FenceSignalFuture, NowFuture},
|
||||
},
|
||||
};
|
||||
@@ -106,17 +105,10 @@ use crate::{
|
||||
trace_vs::{Camera, Lights, PushConstantData},
|
||||
};
|
||||
mod objects;
|
||||
use tape_load::{instruction_set, interpreters, ssa, types, vm};
|
||||
|
||||
use crate::objects::*;
|
||||
|
||||
mod ssa;
|
||||
|
||||
mod instruction_set;
|
||||
|
||||
mod interpreter;
|
||||
|
||||
mod types;
|
||||
mod vm;
|
||||
|
||||
mod threads;
|
||||
|
||||
mod scene;
|
||||
@@ -155,18 +147,18 @@ struct Keys {
|
||||
|
||||
struct CState {
|
||||
position: Vec3,
|
||||
forward: Vec3,
|
||||
looking: bool,
|
||||
keys: Keys,
|
||||
forward: Vec3,
|
||||
looking: bool,
|
||||
keys: Keys,
|
||||
}
|
||||
|
||||
impl Default for CState {
|
||||
fn default() -> Self {
|
||||
CState {
|
||||
position: vec3(0., 0., 3.),
|
||||
forward: vec3(0., 0., 0.),
|
||||
looking: false,
|
||||
keys: Keys {
|
||||
forward: vec3(0., 0., 0.),
|
||||
looking: false,
|
||||
keys: Keys {
|
||||
w: false,
|
||||
s: false,
|
||||
a: false,
|
||||
@@ -229,16 +221,17 @@ struct App {
|
||||
rcx: Arc<Mutex<Option<RenderContext>>>,
|
||||
_watcher: Option<RecommendedWatcher>,
|
||||
glsl_changed: Arc<AtomicBool>,
|
||||
application_start: Instant,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct ShaderModules {
|
||||
trace_vs: Arc<ShaderModule>,
|
||||
trace_vs: Arc<ShaderModule>,
|
||||
fullscreen_vs: Arc<ShaderModule>,
|
||||
lighting_fs: Arc<ShaderModule>,
|
||||
raygen: Arc<ShaderModule>,
|
||||
closest_hit: Arc<ShaderModule>,
|
||||
miss: Arc<ShaderModule>,
|
||||
lighting_fs: Arc<ShaderModule>,
|
||||
raygen: Arc<ShaderModule>,
|
||||
closest_hit: Arc<ShaderModule>,
|
||||
miss: Arc<ShaderModule>,
|
||||
}
|
||||
|
||||
struct RenderContext {
|
||||
@@ -264,6 +257,7 @@ struct RenderContext {
|
||||
recreate_swapchain: bool,
|
||||
recreate_pipelines: bool,
|
||||
previous_frame_end: Vec<Option<FenceSignalFuture<Box<dyn GpuFuture>>>>,
|
||||
time_query_pool: Arc<QueryPool>,
|
||||
gui: Gui,
|
||||
render_start: Instant,
|
||||
}
|
||||
@@ -559,10 +553,10 @@ impl App {
|
||||
notify::EventKind::Modify(_) => {
|
||||
info!("event: {:?}", event);
|
||||
watcher_glsl_changed.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => error!("watch error: {:?}", e),
|
||||
},
|
||||
)
|
||||
@@ -614,6 +608,7 @@ impl App {
|
||||
rcx: Arc::new(Mutex::new(None)),
|
||||
_watcher: watcher,
|
||||
glsl_changed,
|
||||
application_start: Instant::now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -823,12 +818,12 @@ impl ApplicationHandler for App {
|
||||
.map(|load| load(self.device.clone()).unwrap());
|
||||
|
||||
let shader_modules = ShaderModules {
|
||||
trace_vs: pariter.next().unwrap(),
|
||||
trace_vs: pariter.next().unwrap(),
|
||||
fullscreen_vs: pariter.next().unwrap(),
|
||||
lighting_fs: pariter.next().unwrap(),
|
||||
raygen: pariter.next().unwrap(),
|
||||
closest_hit: pariter.next().unwrap(),
|
||||
miss: pariter.next().unwrap(),
|
||||
lighting_fs: pariter.next().unwrap(),
|
||||
raygen: pariter.next().unwrap(),
|
||||
closest_hit: pariter.next().unwrap(),
|
||||
miss: pariter.next().unwrap(),
|
||||
};
|
||||
|
||||
drop(pariter);
|
||||
@@ -892,8 +887,8 @@ impl ApplicationHandler for App {
|
||||
.unwrap();
|
||||
|
||||
let viewport = Viewport {
|
||||
offset: [0.0, window_size.height as f32],
|
||||
extent: [window_size.width as f32, window_size.height as f32 * -1.],
|
||||
offset: [0.0, window_size.height as f32],
|
||||
extent: [window_size.width as f32, window_size.height as f32 * -1.],
|
||||
depth_range: 0.0..=1.0,
|
||||
};
|
||||
|
||||
@@ -959,11 +954,15 @@ impl ApplicationHandler for App {
|
||||
images[0].format(),
|
||||
GuiConfig {
|
||||
allow_srgb_render_target: true,
|
||||
is_overlay: true,
|
||||
samples: SampleCount::Sample1,
|
||||
is_overlay: true,
|
||||
samples: SampleCount::Sample1,
|
||||
},
|
||||
);
|
||||
|
||||
let mut query_create_info = QueryPoolCreateInfo::query_type(QueryType::Timestamp);
|
||||
query_create_info.query_count = 2;
|
||||
let time_query_pool = QueryPool::new(self.device.clone(), query_create_info).unwrap();
|
||||
|
||||
*self.rcx.lock().unwrap() = Some(RenderContext {
|
||||
window,
|
||||
swapchain,
|
||||
@@ -987,6 +986,7 @@ impl ApplicationHandler for App {
|
||||
recreate_swapchain: false,
|
||||
recreate_pipelines: false,
|
||||
previous_frame_end,
|
||||
time_query_pool,
|
||||
gui,
|
||||
render_start: Instant::now(),
|
||||
});
|
||||
@@ -1025,16 +1025,16 @@ impl ApplicationHandler for App {
|
||||
match &event {
|
||||
WindowEvent::CloseRequested => {
|
||||
event_loop.exit();
|
||||
}
|
||||
},
|
||||
WindowEvent::Resized(_) => {
|
||||
rcx.recreate_swapchain = true;
|
||||
}
|
||||
},
|
||||
WindowEvent::ScaleFactorChanged { .. } => {
|
||||
rcx.recreate_swapchain = true;
|
||||
}
|
||||
},
|
||||
WindowEvent::DroppedFile(_file) => {
|
||||
todo!()
|
||||
}
|
||||
},
|
||||
WindowEvent::MouseInput {
|
||||
device_id: d,
|
||||
state: s,
|
||||
@@ -1045,7 +1045,7 @@ impl ApplicationHandler for App {
|
||||
if b == &MouseButton::Right {
|
||||
self.cstate.looking = s == &ElementState::Pressed;
|
||||
}
|
||||
}
|
||||
},
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: _,
|
||||
event: input,
|
||||
@@ -1053,19 +1053,19 @@ impl ApplicationHandler for App {
|
||||
} => match input.physical_key {
|
||||
PhysicalKey::Code(KeyCode::KeyW) => {
|
||||
self.cstate.keys.w = input.state == ElementState::Pressed;
|
||||
}
|
||||
},
|
||||
PhysicalKey::Code(KeyCode::KeyS) => {
|
||||
self.cstate.keys.s = input.state == ElementState::Pressed;
|
||||
}
|
||||
},
|
||||
PhysicalKey::Code(KeyCode::KeyA) => {
|
||||
self.cstate.keys.a = input.state == ElementState::Pressed;
|
||||
}
|
||||
},
|
||||
PhysicalKey::Code(KeyCode::KeyD) => {
|
||||
self.cstate.keys.d = input.state == ElementState::Pressed;
|
||||
}
|
||||
},
|
||||
PhysicalKey::Code(KeyCode::ShiftLeft) => {
|
||||
self.cstate.looking = input.state == ElementState::Pressed;
|
||||
}
|
||||
},
|
||||
PhysicalKey::Code(KeyCode::Space) => {
|
||||
if input.state == ElementState::Pressed {
|
||||
self.thread_work_creation
|
||||
@@ -1087,18 +1087,18 @@ impl ApplicationHandler for App {
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
PhysicalKey::Code(KeyCode::KeyG) => {
|
||||
if input.state == ElementState::Pressed {
|
||||
self.draw_gui = !self.draw_gui;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
WindowEvent::RedrawRequested => {
|
||||
self.redraw(rcx);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1169,23 +1169,23 @@ impl App {
|
||||
* Mat4::from_translation(Vec3::ZERO - self.cstate.position);
|
||||
|
||||
let uniform_data = trace_vs::Camera {
|
||||
proj_view: (proj * view).to_cols_array_2d(),
|
||||
inv_proj_view: (proj * view).inverse().to_cols_array_2d(),
|
||||
inv_proj: (proj).inverse().to_cols_array_2d(),
|
||||
inv_view: (view).inverse().to_cols_array_2d(),
|
||||
campos_and_time: [
|
||||
proj_view: (proj * view).to_cols_array_2d(),
|
||||
inv_proj_view: (proj * view).inverse().to_cols_array_2d(),
|
||||
inv_proj: (proj).inverse().to_cols_array_2d(),
|
||||
inv_view: (view).inverse().to_cols_array_2d(),
|
||||
campos_and_time: [
|
||||
self.cstate.position.x,
|
||||
self.cstate.position.y,
|
||||
self.cstate.position.z,
|
||||
self.time,
|
||||
],
|
||||
specular: self.gstate.specular.into(),
|
||||
specular_tint: self.gstate.specular_tint.into(),
|
||||
sheen_tint: self.gstate.sheen_tint.into(),
|
||||
sheen: self.gstate.sheen.into(),
|
||||
specular: self.gstate.specular.into(),
|
||||
specular_tint: self.gstate.specular_tint.into(),
|
||||
sheen_tint: self.gstate.sheen_tint.into(),
|
||||
sheen: self.gstate.sheen.into(),
|
||||
clear_coat_gloss: self.gstate.clear_coat_gloss.into(),
|
||||
subsurface: self.gstate.subsurface.into(),
|
||||
clear_coat: self.gstate.clear_coat.into(),
|
||||
subsurface: self.gstate.subsurface.into(),
|
||||
clear_coat: self.gstate.clear_coat.into(),
|
||||
};
|
||||
|
||||
if self.cstate.looking {
|
||||
@@ -1537,9 +1537,9 @@ impl App {
|
||||
} else {
|
||||
self.gstate.csg[index as usize] = csg;
|
||||
}
|
||||
}
|
||||
WorkComplete::GetPushConstants(..) => {}
|
||||
WorkComplete::RecompilePipelines(..) => {}
|
||||
},
|
||||
WorkComplete::GetPushConstants(..) => {},
|
||||
WorkComplete::RecompilePipelines(..) => {},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1706,7 +1706,7 @@ impl App {
|
||||
match work {
|
||||
WorkComplete::RecompilePipelines(_index) => {
|
||||
csg_left -= 1;
|
||||
}
|
||||
},
|
||||
other => work_for_later.push(other),
|
||||
}
|
||||
}
|
||||
@@ -1720,14 +1720,14 @@ impl App {
|
||||
return;
|
||||
}
|
||||
|
||||
for i in 1..self.gstate.fps.len() {
|
||||
self.gstate.fps[i - 1] = self.gstate.fps[i];
|
||||
for i in 1..self.gstate.cpu_mpf.len() {
|
||||
self.gstate.cpu_mpf[i - 1] = self.gstate.cpu_mpf[i];
|
||||
}
|
||||
|
||||
self.time = (Instant::now() - rcx.render_start).as_secs_f32();
|
||||
self.time = (Instant::now() - self.application_start).as_secs_f32();
|
||||
|
||||
self.gstate.fps[self.gstate.fps.len() - 1] =
|
||||
1.0 / (Instant::now() - rcx.render_start).as_secs_f64();
|
||||
self.gstate.cpu_mpf[self.gstate.cpu_mpf.len() - 1] =
|
||||
(Instant::now() - rcx.render_start).as_secs_f64() * 1000.0;
|
||||
|
||||
for future in rcx.previous_frame_end.iter_mut().flatten() {
|
||||
future.cleanup_finished();
|
||||
@@ -1780,7 +1780,7 @@ impl App {
|
||||
|
||||
let mut push_constants = vec![
|
||||
PushConstantData {
|
||||
world: Default::default(),
|
||||
world: Default::default(),
|
||||
inv_world: Default::default(),
|
||||
};
|
||||
self.gstate.csg.len()
|
||||
@@ -1857,7 +1857,7 @@ impl App {
|
||||
match work {
|
||||
WorkComplete::RecompilePipelines(_index) => {
|
||||
csg_left -= 1;
|
||||
}
|
||||
},
|
||||
other => work_for_later.push(other),
|
||||
}
|
||||
}
|
||||
@@ -1872,7 +1872,7 @@ impl App {
|
||||
Err(VulkanError::OutOfDate) => {
|
||||
rcx.recreate_swapchain = true;
|
||||
return;
|
||||
}
|
||||
},
|
||||
Err(e) => panic!("Failed to acquire next image: {e}"),
|
||||
};
|
||||
|
||||
@@ -1927,6 +1927,16 @@ impl App {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
unsafe {
|
||||
builder
|
||||
.reset_query_pool(rcx.time_query_pool.clone(), 0..2)
|
||||
.unwrap();
|
||||
|
||||
builder
|
||||
.write_timestamp(rcx.time_query_pool.clone(), 0, PipelineStage::TopOfPipe)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let mut futures = camera_and_lights.boxed();
|
||||
|
||||
if RUN_RT_PIPELINE {
|
||||
@@ -1975,7 +1985,7 @@ impl App {
|
||||
Some(future.boxed())
|
||||
};
|
||||
push_constants_left -= 1;
|
||||
}
|
||||
},
|
||||
other => work_for_later.push(other),
|
||||
}
|
||||
}
|
||||
@@ -2013,6 +2023,12 @@ impl App {
|
||||
builder.end_render_pass(Default::default()).unwrap();
|
||||
}
|
||||
|
||||
unsafe {
|
||||
builder
|
||||
.write_timestamp(rcx.time_query_pool.clone(), 1, PipelineStage::BottomOfPipe)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
||||
for future in rcx.previous_frame_end.iter_mut().flatten() {
|
||||
@@ -2020,6 +2036,22 @@ impl App {
|
||||
future.cleanup_finished();
|
||||
}
|
||||
|
||||
let mut time_stamps = [0u64; 2];
|
||||
|
||||
rcx.time_query_pool
|
||||
.get_results(0..2, &mut time_stamps, QueryResultFlags::WAIT)
|
||||
.unwrap();
|
||||
|
||||
let delta_in_ms = (time_stamps[1] - time_stamps[0]) as f32
|
||||
* self.device.physical_device().properties().timestamp_period
|
||||
/ 1000000.0;
|
||||
|
||||
for i in 1..self.gstate.gpu_mpf.len() {
|
||||
self.gstate.gpu_mpf[i - 1] = self.gstate.gpu_mpf[i];
|
||||
}
|
||||
|
||||
self.gstate.gpu_mpf[self.gstate.gpu_mpf.len() - 1] = delta_in_ms as f64;
|
||||
|
||||
let future = rcx.previous_frame_end[image_index]
|
||||
.take()
|
||||
.map(|f| f.boxed())
|
||||
@@ -2050,20 +2082,20 @@ impl App {
|
||||
match future.map_err(Validated::unwrap) {
|
||||
Ok(future) => {
|
||||
rcx.previous_frame_end[image_index] = Some(future);
|
||||
}
|
||||
},
|
||||
Err(VulkanError::OutOfDate) => {
|
||||
rcx.recreate_swapchain = true;
|
||||
rcx.previous_frame_end[image_index] = None;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to flush future: {e:?}");
|
||||
rcx.previous_frame_end[image_index] = None;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
for work in self.thread_work_completion.try_iter() {
|
||||
match work {
|
||||
WorkComplete::GetPushConstants(..) => {}
|
||||
WorkComplete::GetPushConstants(..) => {},
|
||||
other => work_for_later.push(other),
|
||||
}
|
||||
}
|
||||
@@ -2109,8 +2141,8 @@ fn framebuffer_generation(
|
||||
depth_buffer.clone(),
|
||||
ImageViewCreateInfo {
|
||||
subresource_range: ImageSubresourceRange {
|
||||
aspects: ImageAspects::DEPTH,
|
||||
mip_levels: 0..1,
|
||||
aspects: ImageAspects::DEPTH,
|
||||
mip_levels: 0..1,
|
||||
array_layers: 0..1,
|
||||
},
|
||||
..ImageViewCreateInfo::from_image(&depth_buffer.clone())
|
||||
@@ -2406,7 +2438,7 @@ fn pipeline_recompile(
|
||||
RayTracingShaderGroupCreateInfo::General { general_shader: 1 },
|
||||
RayTracingShaderGroupCreateInfo::TrianglesHit {
|
||||
closest_hit_shader: Some(2),
|
||||
any_hit_shader: None,
|
||||
any_hit_shader: None,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -11,6 +11,7 @@ use glam::{EulerRot, Mat4, Vec3};
|
||||
use log::info;
|
||||
use rand::{Rng, SeedableRng, rngs::SmallRng};
|
||||
use rspirv::{binary::Assemble, dr::Module};
|
||||
use tape_load::interpreters;
|
||||
use vulkano::{
|
||||
buffer::{Subbuffer, allocator::SubbufferAllocator},
|
||||
command_buffer::{CommandBufferExecFuture, allocator::StandardCommandBufferAllocator},
|
||||
@@ -42,7 +43,7 @@ use crate::{
|
||||
DUMP_SPV_TO_FILE, IVertex, MAXIMUM_SUBDIVISION, MINUMUM_SUBDIVISION, ShaderModules,
|
||||
get_spec_constants, gpu_upload,
|
||||
gui::PreviousDebug,
|
||||
interpreter::{self, IntervalInterpreter, PointInterpreter, VALUE_0},
|
||||
interpreters::{VALUE_0, interval::IntervalInterpreter, point::PointInterpreter},
|
||||
objects::CSG,
|
||||
ssa::{SSAInput, SSAOpcode, SSAOpcodeSized, SSATape},
|
||||
trace_vs::{Object, PushConstantData},
|
||||
@@ -520,25 +521,25 @@ fn interval_check(
|
||||
command_allocator: Arc<StandardCommandBufferAllocator>,
|
||||
transfer_queue: Arc<Queue>,
|
||||
) -> CommandBufferExecFuture<NowFuture> {
|
||||
const INTERPRET_INPUT_X: interpreter::Value =
|
||||
interpreter::Value::from_array([10000.0, 0.0, 0.0, -10000.0, 0.0, 0.0, 0.0, 0.0]);
|
||||
const INTERPRET_INPUT_Y: interpreter::Value =
|
||||
interpreter::Value::from_array([0.0, 10000.0, 0.0, 0.0, -10000.0, 0.0, 0.0, 0.0]);
|
||||
const INTERPRET_INPUT_Z: interpreter::Value =
|
||||
interpreter::Value::from_array([0.0, 0.0, 10000.0, 0.0, 0.0, -10000.0, 0.0, 0.0]);
|
||||
const INTERPRET_MUL: interpreter::Value =
|
||||
interpreter::Value::from_array([-1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.0, 0.0]);
|
||||
const INTERPRET_ADD: interpreter::Value = interpreter::Value::from_array([
|
||||
const INTERPRET_INPUT_X: interpreters::Value =
|
||||
interpreters::Value::from_array([10000.0, 0.0, 0.0, -10000.0, 0.0, 0.0, 0.0, 0.0]);
|
||||
const INTERPRET_INPUT_Y: interpreters::Value =
|
||||
interpreters::Value::from_array([0.0, 10000.0, 0.0, 0.0, -10000.0, 0.0, 0.0, 0.0]);
|
||||
const INTERPRET_INPUT_Z: interpreters::Value =
|
||||
interpreters::Value::from_array([0.0, 0.0, 10000.0, 0.0, 0.0, -10000.0, 0.0, 0.0]);
|
||||
const INTERPRET_MUL: interpreters::Value =
|
||||
interpreters::Value::from_array([-1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 0.0, 0.0]);
|
||||
const INTERPRET_ADD: interpreters::Value = interpreters::Value::from_array([
|
||||
10000.0, 10000.0, 10000.0, -10000.0, -10000.0, -10000.0, 0.0, 0.0,
|
||||
]);
|
||||
|
||||
let mut interpreter = PointInterpreter::new(csg);
|
||||
let mut interpreter = PointInterpreter::new(&csg.parts);
|
||||
let interpreter_out = interpreter
|
||||
.scene(
|
||||
INTERPRET_INPUT_X,
|
||||
INTERPRET_INPUT_Y,
|
||||
INTERPRET_INPUT_Z,
|
||||
interpreter::Value::splat(time),
|
||||
interpreters::Value::splat(time),
|
||||
)
|
||||
.mul_add(INTERPRET_MUL, INTERPRET_ADD)
|
||||
.to_array();
|
||||
@@ -576,7 +577,7 @@ fn interval_check(
|
||||
for y in 0..ydim {
|
||||
for z in 0..(zdim / 8) {
|
||||
let interval_input_z: Interval = Interval::new_unchecked(
|
||||
interpreter::Value::from_array([
|
||||
interpreters::Value::from_array([
|
||||
((((8.0 / (zdim as f32)) * z as f32) + (0.0 / (zdim as f32)))
|
||||
* obj.dimensions[2])
|
||||
+ obj.lowest_corner[2],
|
||||
@@ -602,7 +603,7 @@ fn interval_check(
|
||||
* obj.dimensions[2])
|
||||
+ obj.lowest_corner[2],
|
||||
]),
|
||||
interpreter::Value::from_array([
|
||||
interpreters::Value::from_array([
|
||||
((((8.0 / (zdim as f32)) * z as f32) + (1.0 / (zdim as f32)))
|
||||
* obj.dimensions[2])
|
||||
+ obj.lowest_corner[2],
|
||||
@@ -630,7 +631,7 @@ fn interval_check(
|
||||
]),
|
||||
);
|
||||
|
||||
let mut interpreter = IntervalInterpreter::new(csg);
|
||||
let mut interpreter = IntervalInterpreter::new(&csg.parts);
|
||||
let output = interpreter.scene(
|
||||
Interval::const_splat2(
|
||||
(x as f32 / (xdim as f32)) * obj.dimensions[0] + obj.lowest_corner[0],
|
||||
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "tape-load"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
glam = "0.30.3"
|
||||
rspirv = "0.12"
|
||||
foldhash = "0.1.5"
|
||||
humantime = "2.3"
|
||||
@@ -1,7 +1,7 @@
|
||||
#[repr(u8)]
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum InstructionSet {
|
||||
pub enum InstructionSet {
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(dead_code)]
|
||||
/// Returns the input. Useful for copying registers.
|
||||
@@ -1,411 +1,15 @@
|
||||
use std::simd::{
|
||||
StdFloat,
|
||||
cmp::{SimdPartialEq, SimdPartialOrd},
|
||||
num::SimdFloat,
|
||||
};
|
||||
use std::simd::{StdFloat, cmp::SimdPartialOrd, num::SimdFloat};
|
||||
|
||||
use crate::{
|
||||
BYTECODE_IMITATES_GLSL, CSG,
|
||||
ssa::{SSAInput, SSAInstruction, SSAOpcode},
|
||||
interpreters::VALUE_0,
|
||||
ssa::{SSAInput, SSAInstruction, SSAOpcode, SSATape},
|
||||
types::Interval,
|
||||
};
|
||||
|
||||
pub type Value = std::simd::f32x8;
|
||||
pub type Mask = std::simd::mask32x8;
|
||||
|
||||
pub const VALUE_NAN: Value = Value::splat(core::f32::NAN);
|
||||
pub const VALUE_1: Value = Value::splat(1.0);
|
||||
pub const VALUE_0: Value = Value::splat(0.0);
|
||||
pub const VALUE_05: Value = Value::splat(0.5);
|
||||
pub const VALUE_M1: Value = Value::splat(-1.0);
|
||||
pub const VALUE_2: Value = Value::splat(2.0);
|
||||
pub const VALUE_PI: Value = Value::splat(core::f32::consts::PI);
|
||||
pub const VALUE_PI_2: Value = Value::splat(core::f32::consts::FRAC_PI_2);
|
||||
pub const VALUE_TAU: Value = Value::splat(core::f32::consts::TAU);
|
||||
|
||||
pub fn glsign(f: Value) -> Value {
|
||||
if BYTECODE_IMITATES_GLSL {
|
||||
f.simd_eq(VALUE_0).select(f, f.signum())
|
||||
} else {
|
||||
f.signum()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn glfract(f: Value) -> Value {
|
||||
if BYTECODE_IMITATES_GLSL {
|
||||
f - f.floor()
|
||||
} else {
|
||||
f.fract()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct PointInterpreter<'csg> {
|
||||
value_map: Vec<Value>,
|
||||
csg: &'csg CSG,
|
||||
}
|
||||
|
||||
impl PointInterpreter<'_> {
|
||||
fn load(&self, consider: SSAInput) -> Value {
|
||||
match consider {
|
||||
SSAInput::Register(r) => self.value_map[r as usize],
|
||||
SSAInput::Constant(c) => Value::splat(c),
|
||||
}
|
||||
}
|
||||
|
||||
fn store(&mut self, location: u32, value: Value) {
|
||||
self.value_map[location as usize] = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'csg> PointInterpreter<'csg> {
|
||||
pub(crate) fn new(csg: &'csg CSG) -> Self {
|
||||
PointInterpreter {
|
||||
value_map: vec![VALUE_0; csg.parts.last_output as usize],
|
||||
csg,
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_stacks(&mut self) {
|
||||
self.value_map = vec![VALUE_0; self.csg.parts.last_output as usize];
|
||||
}
|
||||
|
||||
fn param_one(&mut self, instruction: &SSAInstruction, func: impl Fn(Value) -> Value) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
self.store(instruction.outputs[i], func(val_a));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_two(&mut self, instruction: &SSAInstruction, func: impl Fn(Value, Value) -> Value) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
let val_b = self.load(instruction.inputs[i + instruction.opcode.size as usize]);
|
||||
self.store(instruction.outputs[i], func(val_a, val_b));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_three(
|
||||
&mut self,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(Value, Value, Value) -> Value,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
let val_b = self.load(instruction.inputs[i + instruction.opcode.size as usize]);
|
||||
let val_c = self.load(instruction.inputs[i + (instruction.opcode.size * 2) as usize]);
|
||||
self.store(instruction.outputs[i], func(val_a, val_b, val_c));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_four(
|
||||
&mut self,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(Value, Value, Value, Value) -> Value,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
let val_b = self.load(instruction.inputs[i + instruction.opcode.size as usize]);
|
||||
let val_c = self.load(instruction.inputs[i + (instruction.opcode.size * 2) as usize]);
|
||||
let val_d = self.load(instruction.inputs[i + (instruction.opcode.size * 3) as usize]);
|
||||
self.store(instruction.outputs[i], func(val_a, val_b, val_c, val_d));
|
||||
}
|
||||
}
|
||||
|
||||
// cargo asm "tape-drive::interpreter::PointInterpreter::scene" --no-color
|
||||
// --rust > scene.asm
|
||||
|
||||
pub(crate) fn scene(&mut self, px: Value, py: Value, pz: Value, time: Value) -> Value {
|
||||
self.clear_stacks();
|
||||
|
||||
for instruction in &self.csg.parts.tape {
|
||||
use SSAOpcode::*;
|
||||
match instruction.opcode.opcode {
|
||||
SSAReturn => {
|
||||
return self.load(instruction.inputs[0]);
|
||||
},
|
||||
SSAPosition => {
|
||||
self.store(instruction.outputs[0], px);
|
||||
self.store(instruction.outputs[1], py);
|
||||
self.store(instruction.outputs[2], pz);
|
||||
self.store(instruction.outputs[3], time);
|
||||
},
|
||||
SSAAdd => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a + val_b);
|
||||
},
|
||||
SSASub => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a - val_b);
|
||||
},
|
||||
SSAMul => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a * val_b);
|
||||
},
|
||||
SSADiv => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a / val_b);
|
||||
},
|
||||
SSAMod => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a % val_b);
|
||||
},
|
||||
SSAAtan2 => self.param_two(instruction, |val_a, val_b| {
|
||||
let mut val_a = val_a.to_array();
|
||||
let val_b = val_b.to_array();
|
||||
for i in 0..Value::LEN {
|
||||
val_a[i] = val_a[i].atan2(val_b[i]);
|
||||
}
|
||||
Value::from_array(val_a)
|
||||
}),
|
||||
SSAMin => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a.simd_min(val_b));
|
||||
},
|
||||
SSAMinMaterial => todo!(),
|
||||
SSAMax => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a.simd_max(val_b));
|
||||
},
|
||||
SSAMaxMaterial => todo!(),
|
||||
SSADot => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
match instruction.opcode.size {
|
||||
1 => val_a[0] * val_b[0],
|
||||
2 => (val_a[0] * val_b[0]) + (val_a[1] * val_b[1]),
|
||||
3 => {
|
||||
(val_a[0] * val_b[0])
|
||||
+ (val_a[1] * val_b[1])
|
||||
+ (val_a[2] * val_b[2])
|
||||
},
|
||||
4 => {
|
||||
(val_a[0] * val_b[0])
|
||||
+ (val_a[1] * val_b[1])
|
||||
+ (val_a[2] * val_b[2])
|
||||
+ (val_a[3] * val_b[3])
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
},
|
||||
SSALength => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
match instruction.opcode.size {
|
||||
1 => val_a[0],
|
||||
2 => ((val_a[0] * val_a[0]) + (val_a[1] * val_a[1])).sqrt(),
|
||||
3 => ((val_a[0] * val_a[0])
|
||||
+ (val_a[1] * val_a[1])
|
||||
+ (val_a[2] * val_a[2]))
|
||||
.sqrt(),
|
||||
4 => ((val_a[0] * val_a[0])
|
||||
+ (val_a[1] * val_a[1])
|
||||
+ (val_a[2] * val_a[2])
|
||||
+ (val_a[3] * val_a[3]))
|
||||
.sqrt(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
},
|
||||
SSADistance => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
match instruction.opcode.size {
|
||||
1 => val_b[0] - val_a[0],
|
||||
2 => (((val_a[0] - val_b[0]) * (val_a[0] - val_b[0]))
|
||||
+ ((val_a[1] - val_b[1]) * (val_a[1] - val_b[1])))
|
||||
.sqrt(),
|
||||
3 => (((val_a[0] - val_b[0]) * (val_a[0] - val_b[0]))
|
||||
+ ((val_a[1] - val_b[1]) * (val_a[1] - val_b[1]))
|
||||
+ ((val_a[2] - val_b[2]) * (val_a[2] - val_b[2]))
|
||||
+ ((val_a[3] - val_b[3]) * (val_a[3] - val_b[3])))
|
||||
.sqrt(),
|
||||
4 => (((val_a[0] - val_b[0]) * (val_a[0] - val_b[0]))
|
||||
+ ((val_a[1] - val_b[1]) * (val_a[1] - val_b[1]))
|
||||
+ ((val_a[2] - val_b[2]) * (val_a[2] - val_b[2]))
|
||||
+ ((val_a[3] - val_b[3]) * (val_a[3] - val_b[3]))
|
||||
+ ((val_a[4] - val_b[4]) * (val_a[4] - val_b[4])))
|
||||
.sqrt(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
},
|
||||
SSANegate => {
|
||||
self.param_one(instruction, |val_a| -val_a);
|
||||
},
|
||||
SSARound => {
|
||||
self.param_one(instruction, |val_a| val_a.round());
|
||||
},
|
||||
SSAAbs => {
|
||||
self.param_one(instruction, |val_a| val_a.abs());
|
||||
},
|
||||
SSAFloor => {
|
||||
self.param_one(instruction, |val_a| val_a.floor());
|
||||
},
|
||||
SSACeil => {
|
||||
self.param_one(instruction, |val_a| val_a.ceil());
|
||||
},
|
||||
SSAFract => {
|
||||
self.param_one(instruction, |val_a| glfract(val_a));
|
||||
},
|
||||
SSASin => {
|
||||
self.param_one(instruction, |val_a| val_a.sin());
|
||||
},
|
||||
SSACos => {
|
||||
self.param_one(instruction, |val_a| val_a.cos());
|
||||
},
|
||||
SSATan => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.tan()))
|
||||
});
|
||||
},
|
||||
SSAAsin => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.asin()))
|
||||
});
|
||||
},
|
||||
SSAAcos => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.acos()))
|
||||
});
|
||||
},
|
||||
SSAAtan => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.atan()))
|
||||
});
|
||||
},
|
||||
SSAExp => {
|
||||
self.param_one(instruction, |val_a| val_a.exp());
|
||||
},
|
||||
SSALog => {
|
||||
self.param_one(instruction, |val_a| val_a.ln());
|
||||
},
|
||||
SSASqrt => {
|
||||
self.param_one(instruction, |val_a| val_a.sqrt());
|
||||
},
|
||||
SSASquare => {
|
||||
self.param_one(instruction, |val_a| val_a * val_a);
|
||||
},
|
||||
SSACube => {
|
||||
self.param_one(instruction, |val_a| val_a * val_a * val_a);
|
||||
},
|
||||
SSASmoothMin => {
|
||||
self.param_three(instruction, |d1, d2, k| {
|
||||
let h =
|
||||
(VALUE_05 + (VALUE_05 * (d2 - d1) / k)).simd_clamp(VALUE_0, VALUE_1);
|
||||
return ((d2 * (VALUE_1 - h)) + (d1 * h)) - k * h * (VALUE_1 - h);
|
||||
});
|
||||
},
|
||||
SSASmoothMax => {
|
||||
self.param_three(instruction, |d1, d2, k| {
|
||||
let h =
|
||||
(VALUE_05 - (VALUE_05 * (d2 + d1) / k)).simd_clamp(VALUE_0, VALUE_1);
|
||||
return ((d2 * (VALUE_1 - h)) + (-d1 * h)) + k * h * (VALUE_1 - h);
|
||||
});
|
||||
},
|
||||
SSASmoothMinMaterial => todo!(),
|
||||
SSASmoothMaxMaterial => todo!(),
|
||||
SSAClamp => {
|
||||
self.param_three(instruction, |val_a, val_b, val_c| {
|
||||
val_a.simd_clamp(val_b, val_c)
|
||||
});
|
||||
},
|
||||
SSAMix => {
|
||||
self.param_three(instruction, |val_a, val_b, val_c| {
|
||||
(val_a * (VALUE_1 - val_c)) + (val_b * val_c)
|
||||
});
|
||||
},
|
||||
SSAFMA => {
|
||||
self.param_three(instruction, |val_a, val_b, val_c| {
|
||||
val_a.mul_add(val_b, val_c)
|
||||
});
|
||||
},
|
||||
SSASDFSphere => {
|
||||
let pos_x = self.load(instruction.inputs[0]);
|
||||
let pos_y = self.load(instruction.inputs[1]);
|
||||
let pos_z = self.load(instruction.inputs[2]);
|
||||
let radius = self.load(instruction.inputs[3]);
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
((pos_x * pos_x) + (pos_y * pos_y) + (pos_z * pos_z)).sqrt() - radius,
|
||||
);
|
||||
},
|
||||
SSASDFBox => {
|
||||
let pos_x = self.load(instruction.inputs[0]);
|
||||
let pos_y = self.load(instruction.inputs[1]);
|
||||
let pos_z = self.load(instruction.inputs[2]);
|
||||
let rad_x = self.load(instruction.inputs[3]);
|
||||
let rad_y = self.load(instruction.inputs[4]);
|
||||
let rad_z = self.load(instruction.inputs[5]);
|
||||
let qx = pos_x.abs() - rad_x;
|
||||
let qy = pos_y.abs() - rad_y;
|
||||
let qz = pos_z.abs() - rad_z;
|
||||
let qxmax = qx.simd_max(VALUE_0);
|
||||
let qymax = qy.simd_max(VALUE_0);
|
||||
let qzmax = qz.simd_max(VALUE_0);
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
((qxmax * qxmax) + (qymax * qymax) + (qzmax * qzmax)).sqrt()
|
||||
+ qx.simd_max(qy.simd_max(qz)).simd_min(VALUE_0),
|
||||
);
|
||||
},
|
||||
SSASDFTorus => {
|
||||
let pos_x = self.load(instruction.inputs[0]);
|
||||
let pos_y = self.load(instruction.inputs[1]);
|
||||
let pos_z = self.load(instruction.inputs[2]);
|
||||
let radius1 = self.load(instruction.inputs[3]);
|
||||
let radius2 = self.load(instruction.inputs[4]);
|
||||
let q = ((pos_x * pos_x) + (pos_z * pos_z)).sqrt() - radius1;
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
((q * q) + (pos_y * pos_y)).sqrt() - radius2,
|
||||
);
|
||||
},
|
||||
SSACompare => {
|
||||
self.param_two(instruction, |val_a, val_b| {
|
||||
val_a
|
||||
.simd_gt(val_b)
|
||||
.select(VALUE_1, val_a.simd_lt(val_b).select(VALUE_M1, VALUE_0))
|
||||
});
|
||||
},
|
||||
SSAAnd => {
|
||||
self.param_two(instruction, |val_a, val_b| {
|
||||
val_a.simd_eq(VALUE_0).select(val_a, val_b)
|
||||
});
|
||||
},
|
||||
SSAOr => {
|
||||
self.param_two(instruction, |val_a, val_b| {
|
||||
val_a.simd_eq(VALUE_0).select(val_b, val_a)
|
||||
});
|
||||
},
|
||||
SSARecip => {
|
||||
self.param_one(instruction, |val_a| val_a.recip());
|
||||
},
|
||||
SSANot => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
val_a.simd_eq(VALUE_0).select(VALUE_1, VALUE_0)
|
||||
});
|
||||
},
|
||||
SSAStop => return VALUE_0,
|
||||
}
|
||||
}
|
||||
return VALUE_NAN;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct IntervalInterpreter<'csg> {
|
||||
pub struct IntervalInterpreter<'csg> {
|
||||
value_map: Vec<Interval>,
|
||||
csg: &'csg CSG,
|
||||
csg: &'csg SSATape,
|
||||
}
|
||||
|
||||
impl IntervalInterpreter<'_> {
|
||||
@@ -422,15 +26,15 @@ impl IntervalInterpreter<'_> {
|
||||
}
|
||||
|
||||
impl<'csg> IntervalInterpreter<'csg> {
|
||||
pub(crate) fn new(csg: &'csg CSG) -> Self {
|
||||
pub fn new(csg: &'csg SSATape) -> Self {
|
||||
IntervalInterpreter {
|
||||
value_map: vec![Interval::ZERO; csg.parts.last_output as usize],
|
||||
value_map: vec![Interval::ZERO; csg.last_output as usize],
|
||||
csg,
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_stacks(&mut self) {
|
||||
self.value_map = vec![Interval::ZERO; self.csg.parts.last_output as usize];
|
||||
self.value_map = vec![Interval::ZERO; self.csg.last_output as usize];
|
||||
}
|
||||
|
||||
fn param_one(&mut self, instruction: &SSAInstruction, func: impl Fn(Interval) -> Interval) {
|
||||
@@ -482,7 +86,7 @@ impl<'csg> IntervalInterpreter<'csg> {
|
||||
// cargo asm "tape-drive::interpreter::IntervalInterpreter::scene" --no-color
|
||||
// --rust > scene.asm
|
||||
|
||||
pub(crate) fn scene(
|
||||
pub fn scene(
|
||||
&mut self,
|
||||
px: Interval,
|
||||
py: Interval,
|
||||
@@ -491,7 +95,7 @@ impl<'csg> IntervalInterpreter<'csg> {
|
||||
) -> Interval {
|
||||
self.clear_stacks();
|
||||
|
||||
for instruction in &self.csg.parts.tape {
|
||||
for instruction in &self.csg.tape {
|
||||
use SSAOpcode::*;
|
||||
match instruction.opcode.opcode {
|
||||
SSAReturn => {
|
||||
@@ -0,0 +1,35 @@
|
||||
use std::simd::{StdFloat, cmp::SimdPartialEq, num::SimdFloat};
|
||||
|
||||
use crate::BYTECODE_IMITATES_GLSL;
|
||||
|
||||
pub mod interval;
|
||||
pub mod point;
|
||||
|
||||
pub type Value = std::simd::f32x8;
|
||||
pub type Mask = std::simd::mask32x8;
|
||||
|
||||
pub const VALUE_NAN: Value = Value::splat(core::f32::NAN);
|
||||
pub const VALUE_1: Value = Value::splat(1.0);
|
||||
pub const VALUE_0: Value = Value::splat(0.0);
|
||||
pub const VALUE_05: Value = Value::splat(0.5);
|
||||
pub const VALUE_M1: Value = Value::splat(-1.0);
|
||||
pub const VALUE_2: Value = Value::splat(2.0);
|
||||
pub const VALUE_PI: Value = Value::splat(core::f32::consts::PI);
|
||||
pub const VALUE_PI_2: Value = Value::splat(core::f32::consts::FRAC_PI_2);
|
||||
pub const VALUE_TAU: Value = Value::splat(core::f32::consts::TAU);
|
||||
|
||||
pub fn glsign(f: Value) -> Value {
|
||||
if BYTECODE_IMITATES_GLSL {
|
||||
f.simd_eq(VALUE_0).select(f, f.signum())
|
||||
} else {
|
||||
f.signum()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn glfract(f: Value) -> Value {
|
||||
if BYTECODE_IMITATES_GLSL {
|
||||
f - f.floor()
|
||||
} else {
|
||||
f.fract()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
use std::simd::{
|
||||
StdFloat,
|
||||
cmp::{SimdPartialEq, SimdPartialOrd},
|
||||
num::SimdFloat,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
interpreters::{VALUE_0, VALUE_1, VALUE_05, VALUE_M1, VALUE_NAN, Value, glfract},
|
||||
ssa::{SSAInput, SSAInstruction, SSAOpcode, SSATape},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PointInterpreter<'csg> {
|
||||
value_map: Vec<Value>,
|
||||
csg: &'csg SSATape,
|
||||
}
|
||||
|
||||
impl PointInterpreter<'_> {
|
||||
fn load(&self, consider: SSAInput) -> Value {
|
||||
match consider {
|
||||
SSAInput::Register(r) => self.value_map[r as usize],
|
||||
SSAInput::Constant(c) => Value::splat(c),
|
||||
}
|
||||
}
|
||||
|
||||
fn store(&mut self, location: u32, value: Value) {
|
||||
self.value_map[location as usize] = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'csg> PointInterpreter<'csg> {
|
||||
pub fn new(csg: &'csg SSATape) -> Self {
|
||||
PointInterpreter {
|
||||
value_map: vec![VALUE_0; csg.last_output as usize],
|
||||
csg,
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_stacks(&mut self) {
|
||||
self.value_map = vec![VALUE_0; self.csg.last_output as usize];
|
||||
}
|
||||
|
||||
fn param_one(&mut self, instruction: &SSAInstruction, func: impl Fn(Value) -> Value) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
self.store(instruction.outputs[i], func(val_a));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_two(&mut self, instruction: &SSAInstruction, func: impl Fn(Value, Value) -> Value) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
let val_b = self.load(instruction.inputs[i + instruction.opcode.size as usize]);
|
||||
self.store(instruction.outputs[i], func(val_a, val_b));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_three(
|
||||
&mut self,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(Value, Value, Value) -> Value,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
let val_b = self.load(instruction.inputs[i + instruction.opcode.size as usize]);
|
||||
let val_c = self.load(instruction.inputs[i + (instruction.opcode.size * 2) as usize]);
|
||||
self.store(instruction.outputs[i], func(val_a, val_b, val_c));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_four(
|
||||
&mut self,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(Value, Value, Value, Value) -> Value,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = self.load(instruction.inputs[i]);
|
||||
let val_b = self.load(instruction.inputs[i + instruction.opcode.size as usize]);
|
||||
let val_c = self.load(instruction.inputs[i + (instruction.opcode.size * 2) as usize]);
|
||||
let val_d = self.load(instruction.inputs[i + (instruction.opcode.size * 3) as usize]);
|
||||
self.store(instruction.outputs[i], func(val_a, val_b, val_c, val_d));
|
||||
}
|
||||
}
|
||||
|
||||
// cargo asm "tape-drive::interpreter::PointInterpreter::scene" --no-color
|
||||
// --rust > scene.asm
|
||||
|
||||
pub fn scene(&mut self, px: Value, py: Value, pz: Value, time: Value) -> Value {
|
||||
self.clear_stacks();
|
||||
|
||||
for instruction in &self.csg.tape {
|
||||
use SSAOpcode::*;
|
||||
match instruction.opcode.opcode {
|
||||
SSAReturn => {
|
||||
return self.load(instruction.inputs[0]);
|
||||
},
|
||||
SSAPosition => {
|
||||
self.store(instruction.outputs[0], px);
|
||||
self.store(instruction.outputs[1], py);
|
||||
self.store(instruction.outputs[2], pz);
|
||||
self.store(instruction.outputs[3], time);
|
||||
},
|
||||
SSAAdd => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a + val_b);
|
||||
},
|
||||
SSASub => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a - val_b);
|
||||
},
|
||||
SSAMul => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a * val_b);
|
||||
},
|
||||
SSADiv => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a / val_b);
|
||||
},
|
||||
SSAMod => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a % val_b);
|
||||
},
|
||||
SSAAtan2 => self.param_two(instruction, |val_a, val_b| {
|
||||
let mut val_a = val_a.to_array();
|
||||
let val_b = val_b.to_array();
|
||||
for i in 0..Value::LEN {
|
||||
val_a[i] = val_a[i].atan2(val_b[i]);
|
||||
}
|
||||
Value::from_array(val_a)
|
||||
}),
|
||||
SSAMin => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a.simd_min(val_b));
|
||||
},
|
||||
SSAMinMaterial => todo!(),
|
||||
SSAMax => {
|
||||
self.param_two(instruction, |val_a, val_b| val_a.simd_max(val_b));
|
||||
},
|
||||
SSAMaxMaterial => todo!(),
|
||||
SSADot => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
match instruction.opcode.size {
|
||||
1 => val_a[0] * val_b[0],
|
||||
2 => (val_a[0] * val_b[0]) + (val_a[1] * val_b[1]),
|
||||
3 => {
|
||||
(val_a[0] * val_b[0])
|
||||
+ (val_a[1] * val_b[1])
|
||||
+ (val_a[2] * val_b[2])
|
||||
},
|
||||
4 => {
|
||||
(val_a[0] * val_b[0])
|
||||
+ (val_a[1] * val_b[1])
|
||||
+ (val_a[2] * val_b[2])
|
||||
+ (val_a[3] * val_b[3])
|
||||
},
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
},
|
||||
SSALength => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
match instruction.opcode.size {
|
||||
1 => val_a[0],
|
||||
2 => ((val_a[0] * val_a[0]) + (val_a[1] * val_a[1])).sqrt(),
|
||||
3 => ((val_a[0] * val_a[0])
|
||||
+ (val_a[1] * val_a[1])
|
||||
+ (val_a[2] * val_a[2]))
|
||||
.sqrt(),
|
||||
4 => ((val_a[0] * val_a[0])
|
||||
+ (val_a[1] * val_a[1])
|
||||
+ (val_a[2] * val_a[2])
|
||||
+ (val_a[3] * val_a[3]))
|
||||
.sqrt(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
},
|
||||
SSADistance => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| self.load(instruction.inputs[i as usize]))
|
||||
.collect::<Vec<_>>();
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
match instruction.opcode.size {
|
||||
1 => val_b[0] - val_a[0],
|
||||
2 => (((val_a[0] - val_b[0]) * (val_a[0] - val_b[0]))
|
||||
+ ((val_a[1] - val_b[1]) * (val_a[1] - val_b[1])))
|
||||
.sqrt(),
|
||||
3 => (((val_a[0] - val_b[0]) * (val_a[0] - val_b[0]))
|
||||
+ ((val_a[1] - val_b[1]) * (val_a[1] - val_b[1]))
|
||||
+ ((val_a[2] - val_b[2]) * (val_a[2] - val_b[2]))
|
||||
+ ((val_a[3] - val_b[3]) * (val_a[3] - val_b[3])))
|
||||
.sqrt(),
|
||||
4 => (((val_a[0] - val_b[0]) * (val_a[0] - val_b[0]))
|
||||
+ ((val_a[1] - val_b[1]) * (val_a[1] - val_b[1]))
|
||||
+ ((val_a[2] - val_b[2]) * (val_a[2] - val_b[2]))
|
||||
+ ((val_a[3] - val_b[3]) * (val_a[3] - val_b[3]))
|
||||
+ ((val_a[4] - val_b[4]) * (val_a[4] - val_b[4])))
|
||||
.sqrt(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
);
|
||||
},
|
||||
SSANegate => {
|
||||
self.param_one(instruction, |val_a| -val_a);
|
||||
},
|
||||
SSARound => {
|
||||
self.param_one(instruction, |val_a| val_a.round());
|
||||
},
|
||||
SSAAbs => {
|
||||
self.param_one(instruction, |val_a| val_a.abs());
|
||||
},
|
||||
SSAFloor => {
|
||||
self.param_one(instruction, |val_a| val_a.floor());
|
||||
},
|
||||
SSACeil => {
|
||||
self.param_one(instruction, |val_a| val_a.ceil());
|
||||
},
|
||||
SSAFract => {
|
||||
self.param_one(instruction, |val_a| glfract(val_a));
|
||||
},
|
||||
SSASin => {
|
||||
self.param_one(instruction, |val_a| val_a.sin());
|
||||
},
|
||||
SSACos => {
|
||||
self.param_one(instruction, |val_a| val_a.cos());
|
||||
},
|
||||
SSATan => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.tan()))
|
||||
});
|
||||
},
|
||||
SSAAsin => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.asin()))
|
||||
});
|
||||
},
|
||||
SSAAcos => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.acos()))
|
||||
});
|
||||
},
|
||||
SSAAtan => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
Value::from_array(val_a.to_array().map(|f| f.atan()))
|
||||
});
|
||||
},
|
||||
SSAExp => {
|
||||
self.param_one(instruction, |val_a| val_a.exp());
|
||||
},
|
||||
SSALog => {
|
||||
self.param_one(instruction, |val_a| val_a.ln());
|
||||
},
|
||||
SSASqrt => {
|
||||
self.param_one(instruction, |val_a| val_a.sqrt());
|
||||
},
|
||||
SSASquare => {
|
||||
self.param_one(instruction, |val_a| val_a * val_a);
|
||||
},
|
||||
SSACube => {
|
||||
self.param_one(instruction, |val_a| val_a * val_a * val_a);
|
||||
},
|
||||
SSASmoothMin => {
|
||||
self.param_three(instruction, |d1, d2, k| {
|
||||
let h =
|
||||
(VALUE_05 + (VALUE_05 * (d2 - d1) / k)).simd_clamp(VALUE_0, VALUE_1);
|
||||
return ((d2 * (VALUE_1 - h)) + (d1 * h)) - k * h * (VALUE_1 - h);
|
||||
});
|
||||
},
|
||||
SSASmoothMax => {
|
||||
self.param_three(instruction, |d1, d2, k| {
|
||||
let h =
|
||||
(VALUE_05 - (VALUE_05 * (d2 + d1) / k)).simd_clamp(VALUE_0, VALUE_1);
|
||||
return ((d2 * (VALUE_1 - h)) + (-d1 * h)) + k * h * (VALUE_1 - h);
|
||||
});
|
||||
},
|
||||
SSASmoothMinMaterial => todo!(),
|
||||
SSASmoothMaxMaterial => todo!(),
|
||||
SSAClamp => {
|
||||
self.param_three(instruction, |val_a, val_b, val_c| {
|
||||
val_a.simd_clamp(val_b, val_c)
|
||||
});
|
||||
},
|
||||
SSAMix => {
|
||||
self.param_three(instruction, |val_a, val_b, val_c| {
|
||||
(val_a * (VALUE_1 - val_c)) + (val_b * val_c)
|
||||
});
|
||||
},
|
||||
SSAFMA => {
|
||||
self.param_three(instruction, |val_a, val_b, val_c| {
|
||||
val_a.mul_add(val_b, val_c)
|
||||
});
|
||||
},
|
||||
SSASDFSphere => {
|
||||
let pos_x = self.load(instruction.inputs[0]);
|
||||
let pos_y = self.load(instruction.inputs[1]);
|
||||
let pos_z = self.load(instruction.inputs[2]);
|
||||
let radius = self.load(instruction.inputs[3]);
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
((pos_x * pos_x) + (pos_y * pos_y) + (pos_z * pos_z)).sqrt() - radius,
|
||||
);
|
||||
},
|
||||
SSASDFBox => {
|
||||
let pos_x = self.load(instruction.inputs[0]);
|
||||
let pos_y = self.load(instruction.inputs[1]);
|
||||
let pos_z = self.load(instruction.inputs[2]);
|
||||
let rad_x = self.load(instruction.inputs[3]);
|
||||
let rad_y = self.load(instruction.inputs[4]);
|
||||
let rad_z = self.load(instruction.inputs[5]);
|
||||
let qx = pos_x.abs() - rad_x;
|
||||
let qy = pos_y.abs() - rad_y;
|
||||
let qz = pos_z.abs() - rad_z;
|
||||
let qxmax = qx.simd_max(VALUE_0);
|
||||
let qymax = qy.simd_max(VALUE_0);
|
||||
let qzmax = qz.simd_max(VALUE_0);
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
((qxmax * qxmax) + (qymax * qymax) + (qzmax * qzmax)).sqrt()
|
||||
+ qx.simd_max(qy.simd_max(qz)).simd_min(VALUE_0),
|
||||
);
|
||||
},
|
||||
SSASDFTorus => {
|
||||
let pos_x = self.load(instruction.inputs[0]);
|
||||
let pos_y = self.load(instruction.inputs[1]);
|
||||
let pos_z = self.load(instruction.inputs[2]);
|
||||
let radius1 = self.load(instruction.inputs[3]);
|
||||
let radius2 = self.load(instruction.inputs[4]);
|
||||
let q = ((pos_x * pos_x) + (pos_z * pos_z)).sqrt() - radius1;
|
||||
self.store(
|
||||
instruction.outputs[0],
|
||||
((q * q) + (pos_y * pos_y)).sqrt() - radius2,
|
||||
);
|
||||
},
|
||||
SSACompare => {
|
||||
self.param_two(instruction, |val_a, val_b| {
|
||||
val_a
|
||||
.simd_gt(val_b)
|
||||
.select(VALUE_1, val_a.simd_lt(val_b).select(VALUE_M1, VALUE_0))
|
||||
});
|
||||
},
|
||||
SSAAnd => {
|
||||
self.param_two(instruction, |val_a, val_b| {
|
||||
val_a.simd_eq(VALUE_0).select(val_a, val_b)
|
||||
});
|
||||
},
|
||||
SSAOr => {
|
||||
self.param_two(instruction, |val_a, val_b| {
|
||||
val_a.simd_eq(VALUE_0).select(val_b, val_a)
|
||||
});
|
||||
},
|
||||
SSARecip => {
|
||||
self.param_one(instruction, |val_a| val_a.recip());
|
||||
},
|
||||
SSANot => {
|
||||
self.param_one(instruction, |val_a| {
|
||||
val_a.simd_eq(VALUE_0).select(VALUE_1, VALUE_0)
|
||||
});
|
||||
},
|
||||
SSAStop => return VALUE_0,
|
||||
}
|
||||
}
|
||||
return VALUE_NAN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#![feature(portable_simd)]
|
||||
pub mod instruction_set;
|
||||
pub mod interpreters;
|
||||
mod spirv_compilers;
|
||||
pub mod ssa;
|
||||
pub mod types;
|
||||
pub mod vm;
|
||||
|
||||
const BYTECODE_IMITATES_GLSL: bool = false;
|
||||
@@ -0,0 +1,876 @@
|
||||
use foldhash::{HashMap, HashMapExt};
|
||||
use rspirv::{dr::Builder, spirv};
|
||||
|
||||
use crate::{
|
||||
spirv_compilers::SpirVTypes,
|
||||
ssa::{SSAInput, SSAInstruction, SSAOpcode, SSATape},
|
||||
};
|
||||
|
||||
pub(crate) fn compile_gradient_function(
|
||||
b: &mut Builder,
|
||||
tape: &SSATape,
|
||||
types: SpirVTypes,
|
||||
function_id: Option<spirv::Word>,
|
||||
) {
|
||||
let _scene = b
|
||||
.begin_function(
|
||||
types.float,
|
||||
function_id,
|
||||
//spirv::FunctionControl::DONT_INLINE
|
||||
spirv::FunctionControl::INLINE
|
||||
| spirv::FunctionControl::PURE
|
||||
| spirv::FunctionControl::CONST,
|
||||
types.point_fn_type,
|
||||
)
|
||||
.unwrap();
|
||||
let pos_p = b.function_parameter(types.vec4p).unwrap();
|
||||
|
||||
b.begin_block(None).unwrap();
|
||||
|
||||
let pos = b.load(types.vec4, None, pos_p, None, []).unwrap();
|
||||
|
||||
let mut mapping = HashMap::<u32, u32>::new();
|
||||
|
||||
for (line, instruction) in tape.tape.iter().enumerate() {
|
||||
use SSAOpcode::*;
|
||||
use rspirv::dr::Operand::IdRef;
|
||||
|
||||
b.line(types.jit_string, line as u32, 0);
|
||||
|
||||
fn input_resolve(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &HashMap<u32, u32>,
|
||||
value: SSAInput,
|
||||
) -> u32 {
|
||||
match value {
|
||||
SSAInput::Register(r) => mapping[&r],
|
||||
SSAInput::Constant(c) => b.constant_bit32(float, c.to_bits()),
|
||||
}
|
||||
}
|
||||
|
||||
fn param_one(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_two(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
let val_b = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + instruction.opcode.size as usize],
|
||||
);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a, val_b));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_three(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32, u32, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
let val_b = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + instruction.opcode.size as usize],
|
||||
);
|
||||
let val_c = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + (instruction.opcode.size as usize * 2)],
|
||||
);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a, val_b, val_c));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_four(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32, u32, u32, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
let val_b = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + instruction.opcode.size as usize],
|
||||
);
|
||||
let val_c = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + (instruction.opcode.size as usize * 2)],
|
||||
);
|
||||
let val_d = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + (instruction.opcode.size as usize * 3)],
|
||||
);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a, val_b, val_c, val_d));
|
||||
}
|
||||
}
|
||||
|
||||
match instruction.opcode.opcode {
|
||||
SSAStop => {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
b.ret_value(zero).unwrap();
|
||||
},
|
||||
SSAReturn => {
|
||||
let value = input_resolve(types.float, b, &mapping, instruction.inputs[0]);
|
||||
b.ret_value(value).unwrap();
|
||||
},
|
||||
SSAPosition => {
|
||||
mapping.insert(
|
||||
instruction.outputs[0],
|
||||
b.composite_extract(types.float, None, pos, [0]).unwrap(),
|
||||
);
|
||||
mapping.insert(
|
||||
instruction.outputs[1],
|
||||
b.composite_extract(types.float, None, pos, [1]).unwrap(),
|
||||
);
|
||||
mapping.insert(
|
||||
instruction.outputs[2],
|
||||
b.composite_extract(types.float, None, pos, [2]).unwrap(),
|
||||
);
|
||||
mapping.insert(
|
||||
instruction.outputs[3],
|
||||
b.composite_extract(types.float, None, pos, [3]).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAAdd => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_add(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSASub => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_sub(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAMul => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_mul(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSADiv => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_div(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAMod => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_mod(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAAtan2 => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Atan2 as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMin => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMin as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMinMaterial => todo!(),
|
||||
SSAMax => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMaxMaterial => todo!(),
|
||||
SSADot => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let dot = if instruction.opcode.size == 1 {
|
||||
b.f_mul(types.float, None, val_a[0], val_b[0]).unwrap()
|
||||
} else {
|
||||
let vector = [types.void, types.float, types.vec2, types.vec3, types.vec4]
|
||||
[instruction.opcode.size as usize];
|
||||
let val_a = b.composite_construct(vector, None, val_a).unwrap();
|
||||
let val_b = b.composite_construct(vector, None, val_b).unwrap();
|
||||
b.dot(types.float, None, val_a, val_b).unwrap()
|
||||
};
|
||||
mapping.insert(instruction.outputs[0], dot);
|
||||
},
|
||||
SSALength => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let length = if instruction.opcode.size == 1 {
|
||||
val_a[0]
|
||||
} else {
|
||||
let vector = [types.void, types.float, types.vec2, types.vec3, types.vec4]
|
||||
[instruction.opcode.size as usize];
|
||||
let val_a = b.composite_construct(vector, None, val_a).unwrap();
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
mapping.insert(instruction.outputs[0], length);
|
||||
},
|
||||
SSADistance => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let distance = if instruction.opcode.size == 1 {
|
||||
b.f_sub(types.float, None, val_b[0], val_a[0]).unwrap()
|
||||
} else {
|
||||
let vector = [types.void, types.float, types.vec2, types.vec3, types.vec4]
|
||||
[instruction.opcode.size as usize];
|
||||
let val_a = b.composite_construct(vector, None, val_a).unwrap();
|
||||
let val_b = b.composite_construct(vector, None, val_b).unwrap();
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Distance as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
mapping.insert(instruction.outputs[0], distance);
|
||||
},
|
||||
SSARecip => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
let one = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
b.f_div(types.float, None, one, val_a).unwrap()
|
||||
});
|
||||
},
|
||||
SSANegate => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.f_negate(types.float, None, val_a).unwrap()
|
||||
});
|
||||
},
|
||||
SSARound => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Round as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAbs => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FAbs as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAFloor => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Floor as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSACeil => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Ceil as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAFract => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Fract as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSASin => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Sin as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSACos => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Cos as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSATan => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Tan as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAsin => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Asin as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAcos => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Acos as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAtan => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Atan as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAExp => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Exp as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSALog => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Log as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSASqrt => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Sqrt as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSASquare => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.f_mul(types.float, None, val_a, val_a).unwrap()
|
||||
});
|
||||
},
|
||||
SSACube => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
let square = b.f_mul(types.float, None, val_a, val_a).unwrap();
|
||||
b.f_mul(types.float, None, val_a, square).unwrap()
|
||||
});
|
||||
},
|
||||
SSASmoothMin => {
|
||||
param_three(types.float, b, &mut mapping, instruction, |b, d1, d2, k| {
|
||||
let half_const = b.constant_bit32(types.float, (0.5f32).to_bits());
|
||||
let zero_const = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one_const = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let sub = b.f_sub(types.float, None, d2, d1).unwrap();
|
||||
let mul_half = b.f_mul(types.float, None, sub, half_const).unwrap();
|
||||
let div_k = b.f_div(types.float, None, mul_half, k).unwrap();
|
||||
let add_half = b.f_add(types.float, None, div_k, half_const).unwrap();
|
||||
let h = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FClamp as u32,
|
||||
[IdRef(add_half), IdRef(zero_const), IdRef(one_const)],
|
||||
)
|
||||
.unwrap();
|
||||
let negh = b.f_sub(types.float, None, one_const, h).unwrap();
|
||||
let h_negh = b.f_mul(types.float, None, h, negh).unwrap();
|
||||
let kh_negh = b.f_mul(types.float, None, k, h_negh).unwrap();
|
||||
let mix = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMix as u32,
|
||||
[IdRef(d2), IdRef(d1), IdRef(h)],
|
||||
)
|
||||
.unwrap();
|
||||
b.f_sub(types.float, None, mix, kh_negh).unwrap()
|
||||
});
|
||||
},
|
||||
SSASmoothMax => {
|
||||
param_three(types.float, b, &mut mapping, instruction, |b, d1, d2, k| {
|
||||
let half_const = b.constant_bit32(types.float, (0.5f32).to_bits());
|
||||
let zero_const = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one_const = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let sub = b.f_add(types.float, None, d2, d1).unwrap();
|
||||
let mul_half = b.f_mul(types.float, None, sub, half_const).unwrap();
|
||||
let div_k = b.f_div(types.float, None, mul_half, k).unwrap();
|
||||
let add_half = b.f_sub(types.float, None, half_const, div_k).unwrap();
|
||||
let h = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FClamp as u32,
|
||||
[IdRef(add_half), IdRef(zero_const), IdRef(one_const)],
|
||||
)
|
||||
.unwrap();
|
||||
let negh = b.f_sub(types.float, None, one_const, h).unwrap();
|
||||
let h_negh = b.f_mul(types.float, None, h, negh).unwrap();
|
||||
let kh_negh = b.f_mul(types.float, None, k, h_negh).unwrap();
|
||||
let negate = b.f_negate(types.float, None, d1).unwrap();
|
||||
let mix = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMix as u32,
|
||||
[IdRef(d2), IdRef(negate), IdRef(h)],
|
||||
)
|
||||
.unwrap();
|
||||
b.f_add(types.float, None, mix, kh_negh).unwrap()
|
||||
});
|
||||
},
|
||||
SSASmoothMinMaterial => todo!(),
|
||||
SSASmoothMaxMaterial => todo!(),
|
||||
SSAClamp => {
|
||||
param_three(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b, val_c| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FClamp as u32,
|
||||
[IdRef(val_a), IdRef(val_b), IdRef(val_c)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMix => {
|
||||
param_three(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b, val_c| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMix as u32,
|
||||
[IdRef(val_a), IdRef(val_b), IdRef(val_c)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAFMA => {
|
||||
param_three(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b, val_c| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Fma as u32,
|
||||
[IdRef(val_a), IdRef(val_b), IdRef(val_c)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSASDFSphere => {
|
||||
let pos_part = (0..3)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pos = b.composite_construct(types.vec3, None, pos_part).unwrap();
|
||||
let radius =
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[3 as usize]);
|
||||
|
||||
let length = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(pos)],
|
||||
)
|
||||
.unwrap();
|
||||
let sphere = b.f_sub(types.float, None, length, radius).unwrap();
|
||||
|
||||
mapping.insert(instruction.outputs[0], sphere);
|
||||
},
|
||||
SSASDFBox => {
|
||||
let pos_part = (0..3)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pos = b.composite_construct(types.vec3, None, pos_part).unwrap();
|
||||
|
||||
let dim_part = (3..6)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let dim = b.composite_construct(types.vec3, None, dim_part).unwrap();
|
||||
|
||||
let abs = b
|
||||
.ext_inst(
|
||||
types.vec3,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FAbs as u32,
|
||||
[IdRef(pos)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let q = b.f_sub(types.vec3, None, abs, dim).unwrap();
|
||||
|
||||
let zero = b.constant_bit32(types.float, 0);
|
||||
let zero_vec3 = b
|
||||
.composite_construct(types.vec3, None, [zero, zero, zero])
|
||||
.unwrap();
|
||||
let q_limit = b
|
||||
.ext_inst(
|
||||
types.vec3,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(q), IdRef(zero_vec3)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let length = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(q_limit)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let q_x = b.composite_extract(types.float, None, q, [0]).unwrap();
|
||||
let q_y = b.composite_extract(types.float, None, q, [1]).unwrap();
|
||||
let q_z = b.composite_extract(types.float, None, q, [2]).unwrap();
|
||||
let max1 = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(q_x), IdRef(q_y)],
|
||||
)
|
||||
.unwrap();
|
||||
let max2 = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(max1), IdRef(q_z)],
|
||||
)
|
||||
.unwrap();
|
||||
let min = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(max2), IdRef(zero)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mapping.insert(
|
||||
instruction.outputs[0],
|
||||
b.f_add(types.float, None, length, min).unwrap(),
|
||||
);
|
||||
},
|
||||
SSASDFTorus => {
|
||||
let pos_part = (0..3)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pos_vec2 = b
|
||||
.composite_construct(types.vec2, None, [pos_part[0], pos_part[2]])
|
||||
.unwrap();
|
||||
|
||||
let rad1 = input_resolve(types.float, b, &mapping, instruction.inputs[3 as usize]);
|
||||
let rad2 = input_resolve(types.float, b, &mapping, instruction.inputs[4 as usize]);
|
||||
|
||||
let dot = b.dot(types.float, None, pos_vec2, pos_vec2).unwrap();
|
||||
let sqrt = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Sqrt as u32,
|
||||
[IdRef(dot)],
|
||||
)
|
||||
.unwrap();
|
||||
let subtx = b.f_sub(types.float, None, sqrt, rad1).unwrap();
|
||||
|
||||
let q = b
|
||||
.composite_construct(types.vec2, None, [subtx, pos_part[1]])
|
||||
.unwrap();
|
||||
|
||||
let length = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(q)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mapping.insert(
|
||||
instruction.outputs[0],
|
||||
b.f_sub(types.float, None, length, rad2).unwrap(),
|
||||
);
|
||||
},
|
||||
SSACompare => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
let nan = b.constant_bit32(types.float, f32::NAN.to_bits());
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let onen = b.constant_bit32(types.float, (-1.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, val_b).unwrap();
|
||||
let less = b.f_ord_less_than(types.bool, None, val_a, val_b).unwrap();
|
||||
let more = b
|
||||
.f_ord_greater_than(types.bool, None, val_a, val_b)
|
||||
.unwrap();
|
||||
let select_less = b.select(types.float, None, less, onen, nan).unwrap();
|
||||
let select_more =
|
||||
b.select(types.float, None, more, one, select_less).unwrap();
|
||||
let select_eq = b
|
||||
.select(types.float, None, equal, zero, select_more)
|
||||
.unwrap();
|
||||
select_eq
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAAnd => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, zero).unwrap();
|
||||
b.select(types.float, None, equal, val_a, val_b).unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAOr => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, zero).unwrap();
|
||||
b.select(types.float, None, equal, val_b, val_a).unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSANot => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, zero).unwrap();
|
||||
b.select(types.float, None, equal, one, zero).unwrap()
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
b.end_function().unwrap();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
pub(crate) mod gradient;
|
||||
pub(crate) mod point;
|
||||
//pub(crate) mod interval;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct SpirVTypes {
|
||||
pub glsl: u32,
|
||||
pub void: u32,
|
||||
pub float: u32,
|
||||
pub bool: u32,
|
||||
pub vec2: u32,
|
||||
pub vec3: u32,
|
||||
pub vec4: u32,
|
||||
pub vec4p: u32,
|
||||
pub point_fn_type: u32,
|
||||
pub interval_fn_type: u32,
|
||||
pub jit_string: u32,
|
||||
}
|
||||
@@ -0,0 +1,876 @@
|
||||
use foldhash::{HashMap, HashMapExt};
|
||||
use rspirv::{dr::Builder, spirv};
|
||||
|
||||
use crate::{
|
||||
spirv_compilers::SpirVTypes,
|
||||
ssa::{SSAInput, SSAInstruction, SSAOpcode, SSATape},
|
||||
};
|
||||
|
||||
pub(crate) fn compile_point_function(
|
||||
b: &mut Builder,
|
||||
tape: &SSATape,
|
||||
types: SpirVTypes,
|
||||
function_id: Option<spirv::Word>,
|
||||
) {
|
||||
let _scene = b
|
||||
.begin_function(
|
||||
types.float,
|
||||
function_id,
|
||||
//spirv::FunctionControl::DONT_INLINE
|
||||
spirv::FunctionControl::INLINE
|
||||
| spirv::FunctionControl::PURE
|
||||
| spirv::FunctionControl::CONST,
|
||||
types.point_fn_type,
|
||||
)
|
||||
.unwrap();
|
||||
let pos_p = b.function_parameter(types.vec4p).unwrap();
|
||||
|
||||
b.begin_block(None).unwrap();
|
||||
|
||||
let pos = b.load(types.vec4, None, pos_p, None, []).unwrap();
|
||||
|
||||
let mut mapping = HashMap::<u32, u32>::new();
|
||||
|
||||
for (line, instruction) in tape.tape.iter().enumerate() {
|
||||
use SSAOpcode::*;
|
||||
use rspirv::dr::Operand::IdRef;
|
||||
|
||||
b.line(types.jit_string, line as u32, 0);
|
||||
|
||||
fn input_resolve(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &HashMap<u32, u32>,
|
||||
value: SSAInput,
|
||||
) -> u32 {
|
||||
match value {
|
||||
SSAInput::Register(r) => mapping[&r],
|
||||
SSAInput::Constant(c) => b.constant_bit32(float, c.to_bits()),
|
||||
}
|
||||
}
|
||||
|
||||
fn param_one(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_two(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
let val_b = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + instruction.opcode.size as usize],
|
||||
);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a, val_b));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_three(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32, u32, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
let val_b = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + instruction.opcode.size as usize],
|
||||
);
|
||||
let val_c = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + (instruction.opcode.size as usize * 2)],
|
||||
);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a, val_b, val_c));
|
||||
}
|
||||
}
|
||||
|
||||
fn param_four(
|
||||
float: u32,
|
||||
b: &mut rspirv::dr::Builder,
|
||||
mapping: &mut HashMap<u32, u32>,
|
||||
instruction: &SSAInstruction,
|
||||
func: impl Fn(&mut rspirv::dr::Builder, u32, u32, u32, u32) -> u32,
|
||||
) {
|
||||
for i in 0..instruction.opcode.size as usize {
|
||||
let val_a = input_resolve(float, b, &mapping, instruction.inputs[i]);
|
||||
let val_b = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + instruction.opcode.size as usize],
|
||||
);
|
||||
let val_c = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + (instruction.opcode.size as usize * 2)],
|
||||
);
|
||||
let val_d = input_resolve(
|
||||
float,
|
||||
b,
|
||||
&mapping,
|
||||
instruction.inputs[i + (instruction.opcode.size as usize * 3)],
|
||||
);
|
||||
mapping.insert(instruction.outputs[i], func(b, val_a, val_b, val_c, val_d));
|
||||
}
|
||||
}
|
||||
|
||||
match instruction.opcode.opcode {
|
||||
SSAStop => {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
b.ret_value(zero).unwrap();
|
||||
},
|
||||
SSAReturn => {
|
||||
let value = input_resolve(types.float, b, &mapping, instruction.inputs[0]);
|
||||
b.ret_value(value).unwrap();
|
||||
},
|
||||
SSAPosition => {
|
||||
mapping.insert(
|
||||
instruction.outputs[0],
|
||||
b.composite_extract(types.float, None, pos, [0]).unwrap(),
|
||||
);
|
||||
mapping.insert(
|
||||
instruction.outputs[1],
|
||||
b.composite_extract(types.float, None, pos, [1]).unwrap(),
|
||||
);
|
||||
mapping.insert(
|
||||
instruction.outputs[2],
|
||||
b.composite_extract(types.float, None, pos, [2]).unwrap(),
|
||||
);
|
||||
mapping.insert(
|
||||
instruction.outputs[3],
|
||||
b.composite_extract(types.float, None, pos, [3]).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAAdd => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_add(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSASub => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_sub(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAMul => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_mul(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSADiv => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_div(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAMod => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| b.f_mod(types.float, None, val_a, val_b).unwrap(),
|
||||
);
|
||||
},
|
||||
SSAAtan2 => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Atan2 as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMin => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMin as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMinMaterial => todo!(),
|
||||
SSAMax => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMaxMaterial => todo!(),
|
||||
SSADot => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let dot = if instruction.opcode.size == 1 {
|
||||
b.f_mul(types.float, None, val_a[0], val_b[0]).unwrap()
|
||||
} else {
|
||||
let vector = [types.void, types.float, types.vec2, types.vec3, types.vec4]
|
||||
[instruction.opcode.size as usize];
|
||||
let val_a = b.composite_construct(vector, None, val_a).unwrap();
|
||||
let val_b = b.composite_construct(vector, None, val_b).unwrap();
|
||||
b.dot(types.float, None, val_a, val_b).unwrap()
|
||||
};
|
||||
mapping.insert(instruction.outputs[0], dot);
|
||||
},
|
||||
SSALength => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let length = if instruction.opcode.size == 1 {
|
||||
val_a[0]
|
||||
} else {
|
||||
let vector = [types.void, types.float, types.vec2, types.vec3, types.vec4]
|
||||
[instruction.opcode.size as usize];
|
||||
let val_a = b.composite_construct(vector, None, val_a).unwrap();
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
mapping.insert(instruction.outputs[0], length);
|
||||
},
|
||||
SSADistance => {
|
||||
let val_a = (0..instruction.opcode.size)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let val_b = (instruction.opcode.size..(instruction.opcode.size * 2))
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let distance = if instruction.opcode.size == 1 {
|
||||
b.f_sub(types.float, None, val_b[0], val_a[0]).unwrap()
|
||||
} else {
|
||||
let vector = [types.void, types.float, types.vec2, types.vec3, types.vec4]
|
||||
[instruction.opcode.size as usize];
|
||||
let val_a = b.composite_construct(vector, None, val_a).unwrap();
|
||||
let val_b = b.composite_construct(vector, None, val_b).unwrap();
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Distance as u32,
|
||||
[IdRef(val_a), IdRef(val_b)],
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
mapping.insert(instruction.outputs[0], distance);
|
||||
},
|
||||
SSARecip => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
let one = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
b.f_div(types.float, None, one, val_a).unwrap()
|
||||
});
|
||||
},
|
||||
SSANegate => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.f_negate(types.float, None, val_a).unwrap()
|
||||
});
|
||||
},
|
||||
SSARound => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Round as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAbs => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FAbs as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAFloor => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Floor as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSACeil => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Ceil as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAFract => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Fract as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSASin => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Sin as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSACos => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Cos as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSATan => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Tan as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAsin => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Asin as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAcos => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Acos as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAAtan => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Atan as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSAExp => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Exp as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSALog => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Log as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSASqrt => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Sqrt as u32,
|
||||
[IdRef(val_a)],
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
},
|
||||
SSASquare => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
b.f_mul(types.float, None, val_a, val_a).unwrap()
|
||||
});
|
||||
},
|
||||
SSACube => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
let square = b.f_mul(types.float, None, val_a, val_a).unwrap();
|
||||
b.f_mul(types.float, None, val_a, square).unwrap()
|
||||
});
|
||||
},
|
||||
SSASmoothMin => {
|
||||
param_three(types.float, b, &mut mapping, instruction, |b, d1, d2, k| {
|
||||
let half_const = b.constant_bit32(types.float, (0.5f32).to_bits());
|
||||
let zero_const = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one_const = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let sub = b.f_sub(types.float, None, d2, d1).unwrap();
|
||||
let mul_half = b.f_mul(types.float, None, sub, half_const).unwrap();
|
||||
let div_k = b.f_div(types.float, None, mul_half, k).unwrap();
|
||||
let add_half = b.f_add(types.float, None, div_k, half_const).unwrap();
|
||||
let h = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FClamp as u32,
|
||||
[IdRef(add_half), IdRef(zero_const), IdRef(one_const)],
|
||||
)
|
||||
.unwrap();
|
||||
let negh = b.f_sub(types.float, None, one_const, h).unwrap();
|
||||
let h_negh = b.f_mul(types.float, None, h, negh).unwrap();
|
||||
let kh_negh = b.f_mul(types.float, None, k, h_negh).unwrap();
|
||||
let mix = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMix as u32,
|
||||
[IdRef(d2), IdRef(d1), IdRef(h)],
|
||||
)
|
||||
.unwrap();
|
||||
b.f_sub(types.float, None, mix, kh_negh).unwrap()
|
||||
});
|
||||
},
|
||||
SSASmoothMax => {
|
||||
param_three(types.float, b, &mut mapping, instruction, |b, d1, d2, k| {
|
||||
let half_const = b.constant_bit32(types.float, (0.5f32).to_bits());
|
||||
let zero_const = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one_const = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let sub = b.f_add(types.float, None, d2, d1).unwrap();
|
||||
let mul_half = b.f_mul(types.float, None, sub, half_const).unwrap();
|
||||
let div_k = b.f_div(types.float, None, mul_half, k).unwrap();
|
||||
let add_half = b.f_sub(types.float, None, half_const, div_k).unwrap();
|
||||
let h = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FClamp as u32,
|
||||
[IdRef(add_half), IdRef(zero_const), IdRef(one_const)],
|
||||
)
|
||||
.unwrap();
|
||||
let negh = b.f_sub(types.float, None, one_const, h).unwrap();
|
||||
let h_negh = b.f_mul(types.float, None, h, negh).unwrap();
|
||||
let kh_negh = b.f_mul(types.float, None, k, h_negh).unwrap();
|
||||
let negate = b.f_negate(types.float, None, d1).unwrap();
|
||||
let mix = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMix as u32,
|
||||
[IdRef(d2), IdRef(negate), IdRef(h)],
|
||||
)
|
||||
.unwrap();
|
||||
b.f_add(types.float, None, mix, kh_negh).unwrap()
|
||||
});
|
||||
},
|
||||
SSASmoothMinMaterial => todo!(),
|
||||
SSASmoothMaxMaterial => todo!(),
|
||||
SSAClamp => {
|
||||
param_three(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b, val_c| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FClamp as u32,
|
||||
[IdRef(val_a), IdRef(val_b), IdRef(val_c)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAMix => {
|
||||
param_three(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b, val_c| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMix as u32,
|
||||
[IdRef(val_a), IdRef(val_b), IdRef(val_c)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAFMA => {
|
||||
param_three(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b, val_c| {
|
||||
b.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Fma as u32,
|
||||
[IdRef(val_a), IdRef(val_b), IdRef(val_c)],
|
||||
)
|
||||
.unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSASDFSphere => {
|
||||
let pos_part = (0..3)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pos = b.composite_construct(types.vec3, None, pos_part).unwrap();
|
||||
let radius =
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[3 as usize]);
|
||||
|
||||
let length = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(pos)],
|
||||
)
|
||||
.unwrap();
|
||||
let sphere = b.f_sub(types.float, None, length, radius).unwrap();
|
||||
|
||||
mapping.insert(instruction.outputs[0], sphere);
|
||||
},
|
||||
SSASDFBox => {
|
||||
let pos_part = (0..3)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pos = b.composite_construct(types.vec3, None, pos_part).unwrap();
|
||||
|
||||
let dim_part = (3..6)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let dim = b.composite_construct(types.vec3, None, dim_part).unwrap();
|
||||
|
||||
let abs = b
|
||||
.ext_inst(
|
||||
types.vec3,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FAbs as u32,
|
||||
[IdRef(pos)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let q = b.f_sub(types.vec3, None, abs, dim).unwrap();
|
||||
|
||||
let zero = b.constant_bit32(types.float, 0);
|
||||
let zero_vec3 = b
|
||||
.composite_construct(types.vec3, None, [zero, zero, zero])
|
||||
.unwrap();
|
||||
let q_limit = b
|
||||
.ext_inst(
|
||||
types.vec3,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(q), IdRef(zero_vec3)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let length = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(q_limit)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let q_x = b.composite_extract(types.float, None, q, [0]).unwrap();
|
||||
let q_y = b.composite_extract(types.float, None, q, [1]).unwrap();
|
||||
let q_z = b.composite_extract(types.float, None, q, [2]).unwrap();
|
||||
let max1 = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(q_x), IdRef(q_y)],
|
||||
)
|
||||
.unwrap();
|
||||
let max2 = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(max1), IdRef(q_z)],
|
||||
)
|
||||
.unwrap();
|
||||
let min = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::FMax as u32,
|
||||
[IdRef(max2), IdRef(zero)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mapping.insert(
|
||||
instruction.outputs[0],
|
||||
b.f_add(types.float, None, length, min).unwrap(),
|
||||
);
|
||||
},
|
||||
SSASDFTorus => {
|
||||
let pos_part = (0..3)
|
||||
.map(|i| {
|
||||
input_resolve(types.float, b, &mapping, instruction.inputs[i as usize])
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pos_vec2 = b
|
||||
.composite_construct(types.vec2, None, [pos_part[0], pos_part[2]])
|
||||
.unwrap();
|
||||
|
||||
let rad1 = input_resolve(types.float, b, &mapping, instruction.inputs[3 as usize]);
|
||||
let rad2 = input_resolve(types.float, b, &mapping, instruction.inputs[4 as usize]);
|
||||
|
||||
let dot = b.dot(types.float, None, pos_vec2, pos_vec2).unwrap();
|
||||
let sqrt = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Sqrt as u32,
|
||||
[IdRef(dot)],
|
||||
)
|
||||
.unwrap();
|
||||
let subtx = b.f_sub(types.float, None, sqrt, rad1).unwrap();
|
||||
|
||||
let q = b
|
||||
.composite_construct(types.vec2, None, [subtx, pos_part[1]])
|
||||
.unwrap();
|
||||
|
||||
let length = b
|
||||
.ext_inst(
|
||||
types.float,
|
||||
None,
|
||||
types.glsl,
|
||||
spirv::GLOp::Length as u32,
|
||||
[IdRef(q)],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mapping.insert(
|
||||
instruction.outputs[0],
|
||||
b.f_sub(types.float, None, length, rad2).unwrap(),
|
||||
);
|
||||
},
|
||||
SSACompare => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
let nan = b.constant_bit32(types.float, f32::NAN.to_bits());
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let onen = b.constant_bit32(types.float, (-1.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, val_b).unwrap();
|
||||
let less = b.f_ord_less_than(types.bool, None, val_a, val_b).unwrap();
|
||||
let more = b
|
||||
.f_ord_greater_than(types.bool, None, val_a, val_b)
|
||||
.unwrap();
|
||||
let select_less = b.select(types.float, None, less, onen, nan).unwrap();
|
||||
let select_more =
|
||||
b.select(types.float, None, more, one, select_less).unwrap();
|
||||
let select_eq = b
|
||||
.select(types.float, None, equal, zero, select_more)
|
||||
.unwrap();
|
||||
select_eq
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAAnd => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, zero).unwrap();
|
||||
b.select(types.float, None, equal, val_a, val_b).unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSAOr => {
|
||||
param_two(
|
||||
types.float,
|
||||
b,
|
||||
&mut mapping,
|
||||
instruction,
|
||||
|b, val_a, val_b| {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, zero).unwrap();
|
||||
b.select(types.float, None, equal, val_b, val_a).unwrap()
|
||||
},
|
||||
);
|
||||
},
|
||||
SSANot => {
|
||||
param_one(types.float, b, &mut mapping, instruction, |b, val_a| {
|
||||
let zero = b.constant_bit32(types.float, (0.0f32).to_bits());
|
||||
let one = b.constant_bit32(types.float, (1.0f32).to_bits());
|
||||
let equal = b.f_ord_equal(types.bool, None, val_a, zero).unwrap();
|
||||
b.select(types.float, None, equal, one, zero).unwrap()
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
b.end_function().unwrap();
|
||||
}
|
||||
@@ -0,0 +1,536 @@
|
||||
use core::f32;
|
||||
|
||||
use rspirv::{binary::Disassemble, dr::Module, spirv};
|
||||
|
||||
use crate::{
|
||||
instruction_set::InstructionSet,
|
||||
spirv_compilers::{
|
||||
SpirVTypes,
|
||||
//gradient::compile_gradient_function,
|
||||
//interval::compile_interval_function,
|
||||
point::compile_point_function,
|
||||
},
|
||||
};
|
||||
|
||||
const JIT_VERSION: u32 = 1;
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum SSAOpcode {
|
||||
SSAAdd,
|
||||
SSASub,
|
||||
SSAMul,
|
||||
SSADiv,
|
||||
SSAAtan2,
|
||||
SSAMin,
|
||||
SSAMax,
|
||||
SSACompare,
|
||||
SSAMod,
|
||||
SSAAnd,
|
||||
SSAOr,
|
||||
|
||||
SSANegate,
|
||||
SSAAbs,
|
||||
SSARecip,
|
||||
SSASqrt,
|
||||
SSASquare,
|
||||
SSAFloor,
|
||||
SSACeil,
|
||||
SSARound,
|
||||
SSASin,
|
||||
SSACos,
|
||||
SSATan,
|
||||
SSAAsin,
|
||||
SSAAcos,
|
||||
SSAAtan,
|
||||
SSAExp,
|
||||
SSALog,
|
||||
SSANot,
|
||||
|
||||
SSAFract,
|
||||
SSACube,
|
||||
SSASmoothMin,
|
||||
SSASmoothMax,
|
||||
SSAClamp,
|
||||
SSAMix,
|
||||
SSAFMA,
|
||||
|
||||
SSADot,
|
||||
SSALength,
|
||||
SSADistance,
|
||||
|
||||
#[default]
|
||||
SSAStop,
|
||||
SSAReturn,
|
||||
SSAPosition,
|
||||
SSAMinMaterial,
|
||||
SSAMaxMaterial,
|
||||
SSASmoothMinMaterial,
|
||||
SSASmoothMaxMaterial,
|
||||
SSASDFSphere,
|
||||
SSASDFBox,
|
||||
SSASDFTorus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
|
||||
pub struct SSAOpcodeSized {
|
||||
pub opcode: SSAOpcode,
|
||||
pub size: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
pub enum SSAInput {
|
||||
Register(u32),
|
||||
Constant(f32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub struct SSAInstruction {
|
||||
pub opcode: SSAOpcodeSized,
|
||||
pub inputs: Vec<SSAInput>,
|
||||
pub outputs: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Clone)]
|
||||
pub struct SSATape {
|
||||
pub last_output: u32,
|
||||
pub tape: Vec<SSAInstruction>,
|
||||
constants: Vec<f32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
|
||||
struct GPUOpcode(u8);
|
||||
|
||||
pub struct GPUTape {
|
||||
pub instructions: Vec<u8>,
|
||||
pub io: Vec<u8>,
|
||||
pub constants: Vec<f32>,
|
||||
}
|
||||
|
||||
impl SSAOpcodeSized {
|
||||
const fn output(&self) -> u8 {
|
||||
use SSAOpcode::*;
|
||||
match self.opcode {
|
||||
SSAStop => 0,
|
||||
SSAReturn => 0,
|
||||
SSAPosition => 4,
|
||||
SSAMinMaterial => 1,
|
||||
SSAMaxMaterial => 1,
|
||||
SSASmoothMinMaterial => 1,
|
||||
SSASmoothMaxMaterial => 1,
|
||||
SSADistance => 1,
|
||||
SSALength => 1,
|
||||
SSADot => 1,
|
||||
SSASDFSphere => 1,
|
||||
SSASDFBox => 1,
|
||||
SSASDFTorus => 1,
|
||||
_ => self.size,
|
||||
}
|
||||
}
|
||||
|
||||
const fn input(&self) -> u8 {
|
||||
use SSAOpcode::*;
|
||||
match self.opcode {
|
||||
SSAStop => 0,
|
||||
SSAReturn => 1,
|
||||
SSAPosition => 0,
|
||||
SSAMinMaterial => 2,
|
||||
SSAMaxMaterial => 2,
|
||||
SSASmoothMinMaterial => 3,
|
||||
SSASmoothMaxMaterial => 3,
|
||||
SSASDFSphere => 3 + 1,
|
||||
SSASDFBox => 3 + 3,
|
||||
SSASDFTorus => 3 + 2,
|
||||
SSAAdd | SSASub | SSAMul | SSADiv | SSAAtan2 | SSAMin | SSAMax | SSACompare
|
||||
| SSAMod | SSAAnd | SSAOr | SSADot | SSADistance => self.size * 2,
|
||||
SSASmoothMin | SSASmoothMax | SSAClamp | SSAMix | SSAFMA => self.size * 3,
|
||||
_ => self.size,
|
||||
}
|
||||
}
|
||||
|
||||
const fn lifetime_elementwise(&self) -> (u8, u8) {
|
||||
use SSAOpcode::*;
|
||||
match self.opcode {
|
||||
SSAStop | SSAReturn | SSAPosition | SSAMinMaterial | SSAMaxMaterial
|
||||
| SSASmoothMinMaterial | SSASmoothMaxMaterial | SSASDFSphere | SSASDFBox
|
||||
| SSASDFTorus | SSADot | SSADistance | SSALength => (0, 0),
|
||||
SSAAdd | SSASub | SSAMul | SSADiv | SSAAtan2 | SSAMin | SSACompare | SSAMod
|
||||
| SSAAnd | SSAOr => (2, 1),
|
||||
SSASmoothMin | SSASmoothMax | SSAClamp | SSAMix | SSAFMA => (3, 1),
|
||||
_ => (1, 1),
|
||||
}
|
||||
}
|
||||
|
||||
const fn to_raw_opcode(&self) -> GPUOpcode {
|
||||
use InstructionSet::*;
|
||||
use SSAOpcode::*;
|
||||
const fn opcode_drop(inst: InstructionSet, width: u8) -> GPUOpcode {
|
||||
assert!(width <= 4);
|
||||
assert!(width > 0);
|
||||
GPUOpcode(inst as u8 + ((width - 1) << 6))
|
||||
}
|
||||
match self.opcode {
|
||||
SSAStop => opcode_drop(OPReturn, 1),
|
||||
SSAReturn => opcode_drop(OPReturn, 1),
|
||||
SSAPosition => opcode_drop(OPPosition, 1),
|
||||
SSAMinMaterial => opcode_drop(OPMinMaterial, 1),
|
||||
SSAMaxMaterial => opcode_drop(OPMaxMaterial, 1),
|
||||
SSASmoothMinMaterial => opcode_drop(OPSmoothMinMaterial, 1),
|
||||
SSASmoothMaxMaterial => opcode_drop(OPSmoothMaxMaterial, 1),
|
||||
SSASDFSphere => opcode_drop(OPSDFSphere, 1),
|
||||
SSASDFBox => opcode_drop(OPSDFBox, 1),
|
||||
SSASDFTorus => opcode_drop(OPSDFTorus, 1),
|
||||
SSAAdd => opcode_drop(OPAdd, self.size),
|
||||
SSASub => opcode_drop(OPSub, self.size),
|
||||
SSAMul => opcode_drop(OPMul, self.size),
|
||||
SSADiv => opcode_drop(OPDiv, self.size),
|
||||
SSAMod => opcode_drop(OPMod, self.size),
|
||||
SSAAtan2 => opcode_drop(OPAtan2, self.size),
|
||||
SSAMin => opcode_drop(OPMin, self.size),
|
||||
SSAMax => opcode_drop(OPMax, self.size),
|
||||
SSADot => opcode_drop(OPDot, self.size),
|
||||
SSALength => opcode_drop(OPLength, self.size),
|
||||
SSADistance => opcode_drop(OPDistance, self.size),
|
||||
SSANegate => opcode_drop(OPNegate, self.size),
|
||||
SSARound => opcode_drop(OPRound, self.size),
|
||||
SSAAbs => opcode_drop(OPAbs, self.size),
|
||||
SSAFloor => opcode_drop(OPFloor, self.size),
|
||||
SSACeil => opcode_drop(OPCeil, self.size),
|
||||
SSAFract => opcode_drop(OPFract, self.size),
|
||||
SSASin => opcode_drop(OPSin, self.size),
|
||||
SSACos => opcode_drop(OPCos, self.size),
|
||||
SSATan => opcode_drop(OPTan, self.size),
|
||||
SSAAsin => opcode_drop(OPAsin, self.size),
|
||||
SSAAcos => opcode_drop(OPAcos, self.size),
|
||||
SSAAtan => opcode_drop(OPAtan, self.size),
|
||||
SSAExp => opcode_drop(OPExp, self.size),
|
||||
SSALog => opcode_drop(OPLog, self.size),
|
||||
SSASqrt => opcode_drop(OPSqrt, self.size),
|
||||
SSASquare => opcode_drop(OPSquare, self.size),
|
||||
SSACube => opcode_drop(OPCube, self.size),
|
||||
SSASmoothMin => opcode_drop(OPSmoothMin, self.size),
|
||||
SSASmoothMax => opcode_drop(OPSmoothMax, self.size),
|
||||
SSAClamp => opcode_drop(OPClamp, self.size),
|
||||
SSAMix => opcode_drop(OPMix, self.size),
|
||||
SSAFMA => opcode_drop(OPFMA, self.size),
|
||||
SSACompare => opcode_drop(OPCompare, self.size),
|
||||
SSAAnd => opcode_drop(OPAnd, self.size),
|
||||
SSAOr => opcode_drop(OPOr, self.size),
|
||||
SSARecip => opcode_drop(OPRecip, self.size),
|
||||
SSANot => opcode_drop(OPNot, self.size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SSATape {
|
||||
pub fn push_instruction(
|
||||
&mut self,
|
||||
opcode: SSAOpcodeSized,
|
||||
inputs: Vec<SSAInput>,
|
||||
) -> Vec<SSAInput> {
|
||||
assert!(
|
||||
inputs
|
||||
.iter()
|
||||
.filter_map(|i| match i {
|
||||
SSAInput::Constant(_) => None,
|
||||
SSAInput::Register(r) => Some(r),
|
||||
})
|
||||
.all(|&i| i < self.last_output)
|
||||
);
|
||||
assert!(opcode.size <= 4);
|
||||
assert!(opcode.size >= 1);
|
||||
assert_eq!(inputs.len(), opcode.input() as usize);
|
||||
|
||||
let outputs = (self.last_output..)
|
||||
.take(opcode.output() as usize)
|
||||
.collect::<Vec<u32>>();
|
||||
let outputs_register = outputs
|
||||
.iter()
|
||||
.map(|r| SSAInput::Register(*r))
|
||||
.collect::<Vec<SSAInput>>();
|
||||
self.last_output += opcode.output() as u32;
|
||||
|
||||
self.constants.extend(inputs.iter().filter_map(|i| match i {
|
||||
SSAInput::Constant(0.0) => None,
|
||||
SSAInput::Constant(c) => Some(c),
|
||||
SSAInput::Register(_) => None,
|
||||
}));
|
||||
|
||||
self.tape.push(SSAInstruction {
|
||||
opcode,
|
||||
inputs,
|
||||
outputs,
|
||||
});
|
||||
return outputs_register;
|
||||
}
|
||||
|
||||
pub fn compile_to_gpu(&self) -> GPUTape {
|
||||
let mut lifetimes = Vec::<(u32, u32)>::with_capacity(self.last_output as usize);
|
||||
|
||||
let mut time_unit = 0;
|
||||
|
||||
for SSAInstruction {
|
||||
opcode,
|
||||
inputs,
|
||||
outputs,
|
||||
} in self.tape.iter()
|
||||
{
|
||||
let per_element = opcode.lifetime_elementwise();
|
||||
|
||||
if per_element == (0, 0) {
|
||||
for &value in inputs {
|
||||
if let SSAInput::Register(r) = value {
|
||||
assert!((r as usize) < lifetimes.len());
|
||||
lifetimes[r as usize].1 = time_unit;
|
||||
}
|
||||
}
|
||||
for &value in outputs {
|
||||
assert_eq!(value as usize, lifetimes.len());
|
||||
lifetimes.push((time_unit, time_unit));
|
||||
}
|
||||
time_unit += 1;
|
||||
} else {
|
||||
let mut input_iterators = (0..per_element.0)
|
||||
.map(|i| inputs.iter().skip(i.into()).step_by(per_element.0.into()))
|
||||
.collect::<Vec<_>>();
|
||||
let mut output_iterators = (0..per_element.1)
|
||||
.map(|i| outputs.iter().skip(i.into()).step_by(per_element.1.into()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
opcode.input() / per_element.0,
|
||||
opcode.output() / per_element.1
|
||||
);
|
||||
|
||||
for _ in 0..(opcode.input() / per_element.0) {
|
||||
for iterator in input_iterators.iter_mut() {
|
||||
let &value = iterator.next().unwrap();
|
||||
if let SSAInput::Register(r) = value {
|
||||
assert!((r as usize) < lifetimes.len());
|
||||
lifetimes[r as usize].1 = time_unit;
|
||||
}
|
||||
}
|
||||
for iterator in output_iterators.iter_mut() {
|
||||
let &value = iterator.next().unwrap();
|
||||
assert_eq!(value as usize, lifetimes.len());
|
||||
lifetimes.push((time_unit, time_unit));
|
||||
}
|
||||
time_unit += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Registers are held UNTIL, non inclusive.
|
||||
let mut register_hold = [0u32; 14];
|
||||
|
||||
let mut register_allocation = vec![0u8; lifetimes.len()];
|
||||
|
||||
for ((life_start, life_end), allocation) in
|
||||
lifetimes.iter().zip(register_allocation.iter_mut())
|
||||
{
|
||||
if life_start == life_end {
|
||||
*allocation = 0;
|
||||
} else if let Some(register) = register_hold.iter().position(|reg| reg <= life_start) {
|
||||
register_hold[register] = *life_end;
|
||||
*allocation = (register + 1) as u8;
|
||||
} else {
|
||||
panic!("Failed to allocate registers");
|
||||
}
|
||||
}
|
||||
|
||||
let mut gpu_tape = GPUTape {
|
||||
instructions: vec![],
|
||||
io: vec![],
|
||||
constants: self.constants.clone(),
|
||||
};
|
||||
|
||||
let mut low_nibble = true;
|
||||
let mut staging_byte = 0u8;
|
||||
|
||||
for SSAInstruction {
|
||||
opcode,
|
||||
inputs,
|
||||
outputs,
|
||||
} in self.tape.iter()
|
||||
{
|
||||
let code = opcode.to_raw_opcode();
|
||||
gpu_tape.instructions.push(code.0);
|
||||
|
||||
let per_element = opcode.lifetime_elementwise();
|
||||
|
||||
if per_element == (0, 0) {
|
||||
for input in inputs {
|
||||
let register = match input {
|
||||
SSAInput::Constant(0.0) => 0,
|
||||
SSAInput::Constant(_) => 15,
|
||||
SSAInput::Register(u) => register_allocation[*u as usize],
|
||||
};
|
||||
|
||||
if low_nibble {
|
||||
staging_byte |= register;
|
||||
} else {
|
||||
staging_byte |= register << 4;
|
||||
gpu_tape.io.push(staging_byte);
|
||||
}
|
||||
|
||||
low_nibble = !low_nibble;
|
||||
}
|
||||
|
||||
for output in outputs {
|
||||
let register = register_allocation[*output as usize];
|
||||
|
||||
if low_nibble {
|
||||
staging_byte |= register;
|
||||
} else {
|
||||
staging_byte |= register << 4;
|
||||
gpu_tape.io.push(staging_byte);
|
||||
}
|
||||
|
||||
low_nibble = !low_nibble;
|
||||
}
|
||||
|
||||
// Stop is implemented as SSAReturn(0);
|
||||
if opcode.opcode == SSAOpcode::SSAStop {
|
||||
let register = 0;
|
||||
|
||||
if low_nibble {
|
||||
staging_byte |= register;
|
||||
} else {
|
||||
staging_byte |= register << 4;
|
||||
gpu_tape.io.push(staging_byte);
|
||||
}
|
||||
|
||||
low_nibble = !low_nibble;
|
||||
}
|
||||
} else {
|
||||
let mut input_iterators = (0..per_element.0)
|
||||
.map(|i| inputs.iter().skip(i.into()).step_by(per_element.0.into()))
|
||||
.collect::<Vec<_>>();
|
||||
let mut output_iterators = (0..per_element.1)
|
||||
.map(|i| outputs.iter().skip(i.into()).step_by(per_element.1.into()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(
|
||||
opcode.input() / per_element.0,
|
||||
opcode.output() / per_element.1
|
||||
);
|
||||
|
||||
for _ in 0..(opcode.input() / per_element.0) {
|
||||
for iterator in input_iterators.iter_mut() {
|
||||
let &value = iterator.next().unwrap();
|
||||
let register = match value {
|
||||
SSAInput::Constant(0.0) => 0,
|
||||
SSAInput::Constant(_) => 15,
|
||||
SSAInput::Register(u) => register_allocation[u as usize],
|
||||
};
|
||||
|
||||
if low_nibble {
|
||||
staging_byte |= register;
|
||||
} else {
|
||||
staging_byte |= register << 4;
|
||||
gpu_tape.io.push(staging_byte);
|
||||
}
|
||||
|
||||
low_nibble = !low_nibble;
|
||||
}
|
||||
for iterator in output_iterators.iter_mut() {
|
||||
let &value = iterator.next().unwrap();
|
||||
let register = register_allocation[value as usize];
|
||||
|
||||
if low_nibble {
|
||||
staging_byte |= register;
|
||||
} else {
|
||||
staging_byte |= register << 4;
|
||||
gpu_tape.io.push(staging_byte);
|
||||
}
|
||||
|
||||
low_nibble = !low_nibble;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !low_nibble {
|
||||
gpu_tape.io.push(staging_byte);
|
||||
}
|
||||
|
||||
gpu_tape
|
||||
}
|
||||
|
||||
pub fn compile_to_spirv(&self, module: Option<Module>) -> rspirv::dr::Module {
|
||||
let with_module = module.is_some();
|
||||
let mut b = if let Some(module) = module {
|
||||
rspirv::dr::Builder::new_from_module(module)
|
||||
} else {
|
||||
let mut b = rspirv::dr::Builder::new();
|
||||
b.set_version(1, 6);
|
||||
b.module_processed(format!("Tape Drive JIT {JIT_VERSION}"));
|
||||
b.memory_model(spirv::AddressingModel::Logical, spirv::MemoryModel::GLSL450);
|
||||
b
|
||||
};
|
||||
let glsl = if with_module {
|
||||
1
|
||||
} else {
|
||||
b.ext_inst_import("GLSL.std.450")
|
||||
};
|
||||
|
||||
let void = b.type_void();
|
||||
let float = b.type_float(32);
|
||||
let bool = b.type_bool();
|
||||
let vec2 = b.type_vector(float, 2);
|
||||
let vec3 = b.type_vector(float, 3);
|
||||
let vec4 = b.type_vector(float, 4);
|
||||
let vec4p = b.type_pointer(None, spirv::StorageClass::Function, vec4);
|
||||
let point_fn_type = b.type_function(float, vec![vec4p]);
|
||||
let interval_fn_type = b.type_function(vec2, vec![vec4p, vec4p]);
|
||||
let jit_string = b.string("JIT");
|
||||
|
||||
let types = SpirVTypes {
|
||||
glsl,
|
||||
void,
|
||||
float,
|
||||
bool,
|
||||
vec2,
|
||||
vec3,
|
||||
vec4,
|
||||
vec4p,
|
||||
point_fn_type,
|
||||
interval_fn_type,
|
||||
jit_string,
|
||||
};
|
||||
|
||||
compile_point_function(
|
||||
&mut b,
|
||||
&self,
|
||||
types,
|
||||
if with_module { Some(1000) } else { None },
|
||||
);
|
||||
|
||||
//compile_interval_function(
|
||||
// &mut b,
|
||||
// &self,
|
||||
// types,
|
||||
// if with_module { Some(2000) } else { None },
|
||||
//);
|
||||
|
||||
//compile_gradient_function(
|
||||
// &mut b,
|
||||
// &self,
|
||||
// types,
|
||||
// if with_module { Some(3000) } else { None },
|
||||
//);
|
||||
|
||||
let module = b.module();
|
||||
|
||||
std::fs::write(
|
||||
format!(
|
||||
"{}.spv-dis",
|
||||
humantime::format_rfc3339(std::time::SystemTime::now())
|
||||
)
|
||||
.to_string(),
|
||||
module.disassemble(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
module
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,10 @@ use std::simd::{
|
||||
StdFloat,
|
||||
cmp::{SimdPartialEq, SimdPartialOrd},
|
||||
num::SimdFloat,
|
||||
u32x8,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
interpreter::{
|
||||
interpreters::{
|
||||
Mask, VALUE_0, VALUE_1, VALUE_2, VALUE_05, VALUE_M1, VALUE_NAN, VALUE_PI, VALUE_PI_2,
|
||||
VALUE_TAU, Value, glfract, glsign,
|
||||
},
|
||||
Reference in New Issue
Block a user