New instruction set

This commit is contained in:
2025-01-22 00:39:04 +00:00
parent 3d51484e0b
commit a2c7ee9987
9 changed files with 633 additions and 1233 deletions
Generated
+26
View File
@@ -649,6 +649,7 @@ dependencies = [
"obj",
"rand",
"rayon",
"rspirv",
"serde",
"serde_json",
"simplelog",
@@ -1911,6 +1912,22 @@ dependencies = [
"xmlparser",
]
[[package]]
name = "rspirv"
version = "0.12.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cf3a93856b6e5946537278df0d3075596371b1950ccff012f02b0f7eafec8d"
dependencies = [
"rustc-hash",
"spirv",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.43"
@@ -2130,6 +2147,15 @@ dependencies = [
"serde",
]
[[package]]
name = "spirv"
version = "0.3.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
dependencies = [
"bitflags 2.8.0",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
+2
View File
@@ -37,6 +37,8 @@ foldhash = "*"
log = "0.4"
simplelog = "0.12"
rspirv = "0.12"
# using latest gits
[patch.crates-io]
vulkano = { git = "https://github.com/vulkano-rs/vulkano" }
+7 -85
View File
@@ -12,29 +12,7 @@ fn main() -> io::Result<()> {
let dest_path = Path::new(&out_dir).join("instructionset.rs");
let f = File::open("src/instructionset.glsl")?;
let f = BufReader::new(f);
let mut out = "#[allow(non_snake_case)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum InputTypes{
#[allow(non_snake_case)]
Vec1,
#[allow(non_snake_case)]
Vec2,
#[allow(non_snake_case)]
Vec3,
#[allow(non_snake_case)]
Vec4,
#[allow(non_snake_case)]
VecX,
#[allow(non_snake_case)]
MatX1,
#[allow(non_snake_case)]
MatX2,
#[allow(non_snake_case)]
MatX3,
#[allow(non_snake_case)]
MatX4,
}
let mut out = "
#[repr(u8)]
#[allow(non_snake_case)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -43,79 +21,23 @@ fn main() -> io::Result<()> {
"
.to_owned();
let mut outputimpl = "
pub(crate) fn output(&self) -> Vec<InputTypes>
{
match self {
"
.to_owned();
let mut inputimpl = "
pub(crate) fn input(&self) -> Vec<InputTypes>
{
match self {
"
.to_owned();
for (index, l) in f.lines().enumerate() {
for l in f.lines() {
let line = l?;
let entries = line.split("//").map(str::trim).collect::<Vec<&str>>();
if entries[0].is_empty() {
continue;
}
let name = &entries[0][11..entries[0].len() - 12];
let comment = entries[3];
let before_equals = entries[0].split("=").map(str::trim).collect::<Vec<&str>>();
let name = &before_equals[0][11..];
let value = &before_equals[1][..before_equals[1].len() - 1];
let comment = entries[1];
out += &format!(
"#[allow(non_snake_case)]\n#[allow(dead_code)]\n/// {comment}\n{name}={index},\n"
"#[allow(non_snake_case)]\n#[allow(dead_code)]\n/// {comment}\n{name}={value},\n"
);
inputimpl += &format!("#[allow(non_snake_case)]\nInstructionSet::{name} => vec![");
for input in entries[1].split(' ').map(str::trim) {
if input.is_empty() {
continue;
}
match input {
"V1" => inputimpl += "InputTypes::Vec1,",
"V2" => inputimpl += "InputTypes::Vec2,",
"V3" => inputimpl += "InputTypes::Vec3,",
"V4" => inputimpl += "InputTypes::Vec4,",
"VX" => inputimpl += "InputTypes::VecX,",
"MX1" => inputimpl += "InputTypes::MatX1,",
"MX2" => inputimpl += "InputTypes::MatX2,",
"MX3" => inputimpl += "InputTypes::MatX3,",
"MX4" => inputimpl += "InputTypes::MatX4,",
_ => panic!("unknown input?? [{input}]"),
}
}
inputimpl += "],\n";
outputimpl += &format!("#[allow(non_snake_case)]\nInstructionSet::{name} => vec![");
for output in entries[2].split(' ').map(str::trim) {
if output.is_empty() {
continue;
}
match output {
"V1" => outputimpl += "InputTypes::Vec1,",
"V2" => outputimpl += "InputTypes::Vec2,",
"V3" => outputimpl += "InputTypes::Vec3,",
"V4" => outputimpl += "InputTypes::Vec4,",
"VX" => outputimpl += "InputTypes::VecX,",
_ => panic!("unknown output?? [{output}]"),
}
}
outputimpl += "],\n";
}
out += "}";
inputimpl += "}}";
outputimpl += "}}";
out += "#[allow(non_snake_case)]\nimpl InstructionSet {\n";
out += &inputimpl;
out += &outputimpl;
out += "}";
fs::write(dest_path, out).unwrap();
println!("cargo:rerun-if-changed=build.rs");
+64 -149
View File
@@ -1,149 +1,64 @@
const uint OPNop=__LINE__-1; // // // No operation.
const uint OPStop=__LINE__-1; // // // Stops execution of the tape and returns 0.
const uint OPReturn=__LINE__-1; //V1 // // Stops execution of the tape and returns a single value.
const uint OPPosition=__LINE__-1; // //V3 // Returns the current position being sampled.
const uint OPPositionX=__LINE__-1; // //V1 // Returns the X component of the current position being sampled.
const uint OPPositionY=__LINE__-1; // //V1 // Returns the Y component of the current position being sampled.
const uint OPPositionZ=__LINE__-1; // //V1 // Returns the Z component of the current position being sampled.
const uint OPCopyVecX=__LINE__-1; //V1 //V1 // Returns the input. Useful for copying registers.
const uint OPPromoteVec1Vec1Vec2=__LINE__-1; //V1 V1 //V2 // Copies two Vec1 registers into a single Vec2.
const uint OPPromoteVec1Vec1Vec1Vec3=__LINE__-1; //V1 V1 V1 //V3 // Copies three Vec1 registers into a single Vec3.
const uint OPPromoteVec1Vec1Vec1Vec1Vec4=__LINE__-1; //V1 V1 V1 V1 //V4 // Copies four Vec1 registers into a single Vec4.
const uint OPPromoteVec2Vec1Vec3=__LINE__-1; //V2 V1 //V3 // Copies one Vec2 register and one Vec1 register into a single Vec3.
const uint OPPromoteVec1Vec2Vec3=__LINE__-1; //V1 V2 //V3 // Copies one Vec1 register and one Vec2 register into a single Vec3.
const uint OPPromoteVec2Vec1Vec1Vec4=__LINE__-1; //V2 V1 V1 //V4 // Copies one Vec2 register and two Vec1 registers into a single Vec4.
const uint OPPromoteVec1Vec2Vec1Vec4=__LINE__-1; //V1 V2 V1 //V4 // Copies one Vec1 register, one Vec2 register, and one Vec1 register into a single Vec4.
const uint OPPromoteVec1Vec1Vec2Vec4=__LINE__-1; //V1 V1 V2 //V4 // Copies two Vec1 registers and one Vec2 register into a single Vec4.
const uint OPPromoteVec2Vec2Vec4=__LINE__-1; //V2 V2 //V4 // Copies two Vec2 registers into a single Vec4.
const uint OPPromoteVec3Vec1Vec4=__LINE__-1; //V3 V1 //V4 // Copies one Vec3 register and one Vec1 register into a single Vec4.
const uint OPPromoteVec1Vec3Vec4=__LINE__-1; //V1 V3 //V4 // Copies one Vec1 register and one Vec3 register into a single Vec4.
const uint OPAddVecXVecX=__LINE__-1; //V1 V1 //V1 // Adds a VecX to a VecX component-wise.
const uint OPAddVec1VecX=__LINE__-1; //V1 VX //VX // Adds a Vec1 to a VecX component-wise.
const uint OPAddVecXVec1=__LINE__-1; //VX V1 //VX // Adds a VecX to a Vec1 component-wise.
const uint OPSubVecXVecX=__LINE__-1; //V1 V1 //V1 // Subtracts a VecX from a VecX component-wise.
const uint OPSubVec1VecX=__LINE__-1; //V1 VX //VX // Subtracts a VecX from a Vec1 component-wise.
const uint OPSubVecXVec1=__LINE__-1; //VX V1 //VX // Subtracts a Vec1 from a VecX component-wise.
const uint OPMulVecXVecX=__LINE__-1; //V1 V1 //V1 // Multiplies a VecX and a VecX component-wise.
const uint OPMulVec1VecX=__LINE__-1; //V1 VX //VX // Multiplies a Vec1 and a VecX component-wise.
const uint OPMulVecXVec1=__LINE__-1; //VX V1 //VX // Multiplies a VecX and a Vec1 component-wise.
const uint OPDivVecXVecX=__LINE__-1; //V1 V1 //V1 // Divides a VecX by a VecX component-wise.
const uint OPDivVec1VecX=__LINE__-1; //V1 VX //VX // Divides a Vec1 by a VecX component-wise.
const uint OPDivVecXVec1=__LINE__-1; //VX V1 //VX // Divides a VecX by a Vec1 component-wise.
const uint OPModVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX modulo a VecX component-wise.
const uint OPModVec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 modulo a VecX component-wise.
const uint OPModVecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX modulo a Vec1 component-wise.
const uint OPRemVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX remainder a VecX component-wise.
const uint OPRemVec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 remainder a VecX component-wise.
const uint OPRemVecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX remainder a Vec1 component-wise.
const uint OPPowVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX to the power of a VecX component-wise.
const uint OPPowVec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 to the power of a VecX component-wise.
const uint OPPowVecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX to the power of a Vec1 component-wise.
const uint OPAtan2VecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX Atan2 a VecX component-wise.
const uint OPAtan2Vec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 Atan2 a VecX component-wise.
const uint OPAtan2VecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX Atan2 a Vec1 component-wise.
const uint OPMinVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates the minimum of a VecX and a VecX component-wise.
const uint OPMinVec1VecX=__LINE__-1; //V1 VX //VX // Calculates the minimum of a Vec1 and a VecX component-wise.
const uint OPMinVecXVec1=__LINE__-1; //VX V1 //VX // Calculates the minimum of a VecX and a Vec1 component-wise.
const uint OPMinMaterialVec1Vec1=__LINE__-1; //V1 V1 //V1 // Calculates the minimum of two Vec1s, and also carries over the relevant material metadata.
const uint OPMaxVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates the maximum of a VecX and a VecX component-wise.
const uint OPMaxVec1VecX=__LINE__-1; //V1 VX //VX // Calculates the maximum of a Vec1 and a VecX component-wise.
const uint OPMaxVecXVec1=__LINE__-1; //VX V1 //VX // Calculates the maximum of a VecX and a Vec1 component-wise.
const uint OPMaxMaterialVec1Vec1=__LINE__-1; //V1 V1 //V1 // Calculates the maximum of two Vec1s, and also carries over the relevant material metadata.
const uint OPCrossVec3Vec3=__LINE__-1; //V3 V3 //V3 // Returns the cross product of two Vec3s.
const uint OPDotVecXVecX=__LINE__-1; //VX VX //V1 // Returns the dot product of two VecXs.
const uint OPLengthVecX=__LINE__-1; //VX //V1 // Returns the length (magnitude) of a VecX.
const uint OPDistanceVecXVecX=__LINE__-1; //VX VX //V1 // Returns the length (magnitude) of the vector between two VecXs.
const uint OPNormalizeVecX=__LINE__-1; //VX //VX // Returns the normalised version of a VecX.
const uint OPFaceForwardVecXVecX=__LINE__-1; //VX VX //VX // See GLSL's "FaceForward"
const uint OPReflectVecXVecX=__LINE__-1; //VX VX //VX // See GLSL's "Reflect"
const uint OPRefractVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // See GLSL's "Refract"
const uint OPMulVecXMatX1=__LINE__-1; //VX MX1 //VX // Multiplies an X long vector by an X by 1 sized matrix, returning an X long vector.
const uint OPMulVecXMatX2=__LINE__-1; //VX MX2 //VX // Multiplies an X long vector by an X by 2 sized matrix, returning an X long vector.
const uint OPMulVecXMatX3=__LINE__-1; //VX MX3 //VX // Multiplies an X long vector by an X by 3 sized matrix, returning an X long vector.
const uint OPMulVecXMatX4=__LINE__-1; //VX MX4 //VX // Multiplies an X long vector by an X by 4 sized matrix, returning an X long vector.
const uint OPNegateVecX=__LINE__-1; //VX //VX // Returns the negation of all components of a VecX.
const uint OPRoundVecX=__LINE__-1; //VX //VX // Returns all components of a VecX rounded to the nearest integer.
const uint OPRoundEvenVecX=__LINE__-1; //VX //VX // Returns all components of a VecX rounded to the nearest even integer.
const uint OPTruncVecX=__LINE__-1; //VX //VX // Returns all components of a VecX rounded towards zero.
const uint OPAbsVecX=__LINE__-1; //VX //VX // Returns the absolute value of all components of a VecX.
const uint OPSignVecX=__LINE__-1; //VX //VX // Returns the sign of all components of a VecX.
const uint OPFloorVecX=__LINE__-1; //VX //VX // Returns the floor of all components of a VecX.
const uint OPCeilVecX=__LINE__-1; //VX //VX // Returns the ceiling of all components of a VecX.
const uint OPFractVecX=__LINE__-1; //VX //VX // Returns the fractional part of all components of a VecX.
const uint OPRadiansVecX=__LINE__-1; //VX //VX // Converts all components of a VecX from degrees to radians.
const uint OPDegreesVecX=__LINE__-1; //VX //VX // Converts all components of a VecX from radians to degrees.
const uint OPSinVecX=__LINE__-1; //VX //VX // Returns the sine of all components of a VecX.
const uint OPCosVecX=__LINE__-1; //VX //VX // Returns the cosine of all components of a VecX.
const uint OPTanVecX=__LINE__-1; //VX //VX // Returns the tangent of all components of a VecX.
const uint OPAsinVecX=__LINE__-1; //VX //VX // Returns the arc sine of all components of a VecX.
const uint OPAcosVecX=__LINE__-1; //VX //VX // Returns the arc cosine of all components of a VecX.
const uint OPAtanVecX=__LINE__-1; //VX //VX // Returns the arc tangent of all components of a VecX.
const uint OPSinhVecX=__LINE__-1; //VX //VX // Returns the hyperbolic sine of all components of a VecX.
const uint OPCoshVecX=__LINE__-1; //VX //VX // Returns the hyperbolic cosine of all components of a VecX.
const uint OPTanhVecX=__LINE__-1; //VX //VX // Returns the hyperbolic tangent of all components of a VecX.
const uint OPAsinhVecX=__LINE__-1; //VX //VX // Returns the hyperbolic arc sine of all components of a VecX.
const uint OPAcoshVecX=__LINE__-1; //VX //VX // Returns the hyperbolic arc cosine of all components of a VecX.
const uint OPAtanhVecX=__LINE__-1; //VX //VX // Returns the hyperbolic arc tangent of all components of a VecX.
const uint OPExpVecX=__LINE__-1; //VX //VX // Returns e raised to all components of a VecX.
const uint OPLogVecX=__LINE__-1; //VX //VX // Returns the natural logarithm of all components of a VecX.
const uint OPExp2VecX=__LINE__-1; //VX //VX // Returns 2 raised to all components of a VecX.
const uint OPLog2VecX=__LINE__-1; //VX //VX // Returns the base 2 logarithm of all components of a VecX.
const uint OPSqrtVecX=__LINE__-1; //VX //VX // Returns the square root of all components of a VecX.
const uint OPInverseSqrtVecX=__LINE__-1; //VX //VX // Returns one over the square root of all components of a VecX.
const uint OPSquareVecX=__LINE__-1; //VX //VX // Returns the square of all components of a VecX.
const uint OPCubeVecX=__LINE__-1; //VX //VX // Returns the cube of all components of a VecX.
const uint OPSmoothMinVecXVecXVecX=__LINE__-1; //VX VX VX //VX // Returns the smooth minimum between a VecX and a VecX, varied by a VecX.
const uint OPSmoothMinVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // Returns the smooth minimum between a VecX and a VecX, varied by a Vec1.
const uint OPSmoothMinVecXVec1VecX=__LINE__-1; //VX V1 VX //VX // Returns the smooth minimum between a VecX and a Vec1, varied by a VecX.
const uint OPSmoothMinVecXVec1Vec1=__LINE__-1; //VX V1 V1 //VX // Returns the smooth minimum between a VecX and a Vec1, varied by a Vec1.
const uint OPSmoothMinVec1VecXVecX=__LINE__-1; //V1 VX VX //VX // Returns the smooth minimum between a Vec1 and a VecX, varied by a VecX.
const uint OPSmoothMinVec1VecXVec1=__LINE__-1; //V1 VX V1 //VX // Returns the smooth minimum between a Vec1 and a VecX, varied by a Vec1.
const uint OPSmoothMinVec1Vec1VecX=__LINE__-1; //V1 V1 VX //VX // Returns the smooth minimum between a Vec1 and a Vec1, varied by a VecX.
const uint OPSmoothMaxVecXVecXVecX=__LINE__-1; //VX VX VX //VX // Returns the smooth maximum between a VecX and a VecX, varied by a VecX.
const uint OPSmoothMaxVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // Returns the smooth maximum between a VecX and a VecX, varied by a Vec1.
const uint OPSmoothMaxVecXVec1VecX=__LINE__-1; //VX V1 VX //VX // Returns the smooth maximum between a VecX and a Vec1, varied by a VecX.
const uint OPSmoothMaxVecXVec1Vec1=__LINE__-1; //VX V1 V1 //VX // Returns the smooth maximum between a VecX and a Vec1, varied by a Vec1.
const uint OPSmoothMaxVec1VecXVecX=__LINE__-1; //V1 VX VX //VX // Returns the smooth maximum between a Vec1 and a VecX, varied by a VecX.
const uint OPSmoothMaxVec1VecXVec1=__LINE__-1; //V1 VX V1 //VX // Returns the smooth maximum between a Vec1 and a VecX, varied by a Vec1.
const uint OPSmoothMaxVec1Vec1VecX=__LINE__-1; //V1 V1 VX //VX // Returns the smooth maximum between a Vec1 and a Vec1, varied by a VecX.
const uint OPSmoothMinMaterialVec1=__LINE__-1; //V1 V1 V1 //V1 // Returns the smooth minimum between a Vec1 and a Vec1, varied by a Vec1, and also carries over the relevant material metadata.
const uint OPSmoothMaxMaterialVec1=__LINE__-1; //V1 V1 V1 //V1 // Returns the smooth maximum between a Vec1 and a Vec1, varied by a Vec1, and also carries over the relevant material metadata.
const uint OPClampVecXVecXVecX=__LINE__-1; //VX VX VX //VX // Clamps a VecX between a VecX and a VecX.
const uint OPClampVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // Clamps a VecX between a VecX and a Vec1.
const uint OPClampVecXVec1VecX=__LINE__-1; //VX V1 VX //VX // Clamps a VecX between a Vec1 and a VecX.
const uint OPClampVecXVec1Vec1=__LINE__-1; //VX V1 V1 //VX // Clamps a VecX between a Vec1 and a Vec1.
const uint OPClampVec1VecXVecX=__LINE__-1; //V1 VX VX //VX // Clamps a Vec1 between a VecX and a VecX.
const uint OPClampVec1VecXVec1=__LINE__-1; //V1 VX V1 //VX // Clamps a Vec1 between a VecX and a Vec1.
const uint OPClampVec1Vec1VecX=__LINE__-1; //V1 V1 VX //VX // Clamps a Vec1 between a Vec1 and a VecX.
const uint OPMixVecXVecXVecX=__LINE__-1; //VX VX VX //VX // Mixes between a VecX and a VecX, varied by a VecX.
const uint OPMixVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // Mixes between a VecX and a VecX, varied by a Vec1.
const uint OPMixVecXVec1VecX=__LINE__-1; //VX V1 VX //VX // Mixes between a VecX and a Vec1, varied by a VecX.
const uint OPMixVecXVec1Vec1=__LINE__-1; //VX V1 V1 //VX // Mixes between a VecX and a Vec1, varied by a Vec1.
const uint OPMixVec1VecXVecX=__LINE__-1; //V1 VX VX //VX // Mixes between a Vec1 and a VecX, varied by a VecX.
const uint OPMixVec1VecXVec1=__LINE__-1; //V1 VX V1 //VX // Mixes between a Vec1 and a VecX, varied by a Vec1.
const uint OPMixVec1Vec1VecX=__LINE__-1; //V1 V1 VX //VX // Mixes between a Vec1 and a Vec1, varied by a VecX.
const uint OPStepVecXVecXVecX=__LINE__-1; //VX VX VX //VX // Steps between a VecX and a VecX, varied by a VecX.
const uint OPStepVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // Steps between a VecX and a VecX, varied by a Vec1.
const uint OPStepVecXVec1VecX=__LINE__-1; //VX V1 VX //VX // Steps between a VecX and a Vec1, varied by a VecX.
const uint OPStepVecXVec1Vec1=__LINE__-1; //VX V1 V1 //VX // Steps between a VecX and a Vec1, varied by a Vec1.
const uint OPStepVec1VecXVecX=__LINE__-1; //V1 VX VX //VX // Steps between a Vec1 and a VecX, varied by a VecX.
const uint OPStepVec1VecXVec1=__LINE__-1; //V1 VX V1 //VX // Steps between a Vec1 and a VecX, varied by a Vec1.
const uint OPStepVec1Vec1VecX=__LINE__-1; //V1 V1 VX //VX // Steps between a Vec1 and a Vec1, varied by a VecX.
const uint OPSmoothStepVecXVecXVecX=__LINE__-1; //VX VX VX //VX // Smooth Steps between a VecX and a VecX, varied by a VecX.
const uint OPSmoothStepVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // Smooth Steps between a VecX and a VecX, varied by a Vec1.
const uint OPSmoothStepVecXVec1VecX=__LINE__-1; //VX V1 VX //VX // Smooth Steps between a VecX and a Vec1, varied by a VecX.
const uint OPSmoothStepVecXVec1Vec1=__LINE__-1; //VX V1 V1 //VX // Smooth Steps between a VecX and a Vec1, varied by a Vec1.
const uint OPSmoothStepVec1VecXVecX=__LINE__-1; //V1 VX VX //VX // Smooth Steps between a Vec1 and a VecX, varied by a VecX.
const uint OPSmoothStepVec1VecXVec1=__LINE__-1; //V1 VX V1 //VX // Smooth Steps between a Vec1 and a VecX, varied by a Vec1.
const uint OPSmoothStepVec1Vec1VecX=__LINE__-1; //V1 V1 VX //VX // Smooth Steps between a Vec1 and a Vec1, varied by a VecX.
const uint OPFMAVecXVecXVecX=__LINE__-1; //VX VX VX //VX // Calculates a VecX multiplied by a VecX, then adds a VecX.
const uint OPFMAVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // Calculates a VecX multiplied by a VecX, then adds a Vec1.
const uint OPFMAVecXVec1VecX=__LINE__-1; //VX V1 VX //VX // Calculates a VecX multiplied by a Vec1, then adds a VecX.
const uint OPFMAVecXVec1Vec1=__LINE__-1; //VX V1 V1 //VX // Calculates a VecX multiplied by a Vec1, then adds a Vec1.
const uint OPFMAVec1VecXVecX=__LINE__-1; //V1 VX VX //VX // Calculates a Vec1 multiplied by a VecX, then adds a VecX.
const uint OPFMAVec1VecXVec1=__LINE__-1; //V1 VX V1 //VX // Calculates a Vec1 multiplied by a VecX, then adds a Vec1.
const uint OPFMAVec1Vec1VecX=__LINE__-1; //V1 V1 VX //VX // Calculates a Vec1 multiplied by a Vec1, then adds a VecX.
const uint OPSDFSphere=__LINE__-1; //V3 V1 //V1 // Returns the distance to a sphere.
const uint OPSDFBox=__LINE__-1; //V3 V3 //V1 // Returns the distance to a box.
const uint OPSDFTorus=__LINE__-1; //V3 V2 //V1 // Returns the distance to a torus.
const uint OPInvalid=__LINE__-1; // // // Invalid instruction.
const uint OPCopy =0; // Returns the input. Useful for copying registers.
const uint OPAdd =1; // Adds a vector to a vector component-wise.
const uint OPSub =2; // Subtracts a vector from a vector component-wise.
const uint OPMul =3; // Multiplies a vector and a vector component-wise.
const uint OPDiv =4; // Divides a vector by a vector component-wise.
const uint OPMod =5; // Calculates a vector modulo a vector component-wise.
const uint OPRem =6; // Calculates a vector remainder a vector component-wise.
const uint OPPow =7; // Calculates a vector to the power of a vector component-wise.
const uint OPAtan2 =8; // Calculates a vector Atan2 a vector component-wise.
const uint OPMin =9; // Calculates the minimum of a vector and a vector component-wise.
const uint OPMax =10; // Calculates the maximum of a vector and a vector component-wise.
const uint OPNegate =11; // Returns the negation of all components of a vector.
const uint OPRound =12; // Returns all components of a vector rounded to the nearest integer.
const uint OPRoundEven =13; // Returns all components of a vector rounded to the nearest even integer.
const uint OPTrunc =14; // Returns all components of a vector rounded towards zero.
const uint OPAbs =15; // Returns the absolute value of all components of a vector.
const uint OPSign =16; // Returns the sign of all components of a vector.
const uint OPFloor =17; // Returns the floor of all components of a vector.
const uint OPCeil =18; // Returns the ceiling of all components of a vector.
const uint OPFract =19; // Returns the fractional part of all components of a vector.
const uint OPSin =20; // Returns the sine of all components of a vector.
const uint OPCos =21; // Returns the cosine of all components of a vector.
const uint OPTan =22; // Returns the tangent of all components of a vector.
const uint OPAsin =23; // Returns the arc sine of all components of a vector.
const uint OPAcos =24; // Returns the arc cosine of all components of a vector.
const uint OPAtan =25; // Returns the arc tangent of all components of a vector.
const uint OPSinh =26; // Returns the hyperbolic sine of all components of a vector.
const uint OPCosh =27; // Returns the hyperbolic cosine of all components of a vector.
const uint OPTanh =28; // Returns the hyperbolic tangent of all components of a vector.
const uint OPAsinh =29; // Returns the hyperbolic arc sine of all components of a vector.
const uint OPAcosh =30; // Returns the hyperbolic arc cosine of all components of a vector.
const uint OPAtanh =31; // Returns the hyperbolic arc tangent of all components of a vector.
const uint OPExp =32; // Returns e raised to all components of a vector.
const uint OPLog =33; // Returns the natural logarithm of all components of a vector.
const uint OPExp2 =34; // Returns 2 raised to all components of a vector.
const uint OPLog2 =35; // Returns the base 2 logarithm of all components of a vector.
const uint OPSqrt =36; // Returns the square root of all components of a vector.
const uint OPInverseSqrt =37; // Returns one over the square root of all components of a vector.
const uint OPSquare =38; // Returns the square of all components of a vector.
const uint OPCube =39; // Returns the cube of all components of a vector.
const uint OPSmoothMin =40; // Returns the smooth minimum between a vector and a vector, varied by a vector.
const uint OPSmoothMax =41; // Returns the smooth maximum between a vector and a vector, varied by a vector.
const uint OPClamp =42; // Clamps a vector between a vector and a vector.
const uint OPMix =43; // Mixes between a vector and a vector, varied by a vector.
const uint OPStep =44; // Steps between a vector and a vector, varied by a vector.
const uint OPSmoothStep =45; // Smooth Steps between a vector and a vector, varied by a vector.
const uint OPFMA =46; // Calculates a vector multiplied by a vector, then adds a vector.
const uint OPDot =47; // Returns the dot product of two vectors.
const uint OPLength =48; // Returns the length (magnitude) of a vector.
const uint OPDistance =49; // Returns the length (magnitude) of the vector between two vectors.
const uint OPNormalize =50; // Returns the normalised version of a vector.
const uint OPNop =(0*64)+63; // No operation.
const uint OPStop =(1*64)+63; // Stops execution of the tape and returns 0.
const uint OPReturn =(2*64)+63; // Stops execution of the tape and returns a single value.
const uint OPPosition =(3*64)+63; // Returns the current position being sampled.
const uint OPMinMaterial =(0*64)+62; // Calculates the minimum of two Vec1s, and also carries over the relevant material metadata.
const uint OPMaxMaterial =(1*64)+62; // Calculates the maximum of two Vec1s, and also carries over the relevant material metadata.
const uint OPSmoothMinMaterial =(2*64)+62; // Returns the smooth minimum between a Vec1 and a Vec1, varied by a Vec1, and also carries over the relevant material metadata.
const uint OPSmoothMaxMaterial =(3*64)+62; // Returns the smooth maximum between a Vec1 and a Vec1, varied by a Vec1, and also carries over the relevant material metadata.
const uint OPCross =(0*64)+61; // Returns the cross product of two Vec3s.
const uint OPSDFSphere =(1*64)+61; // Returns the distance to a sphere.
const uint OPSDFBox =(2*64)+61; // Returns the distance to a box.
const uint OPSDFTorus =(3*64)+61; // Returns the distance to a torus.
+8 -30
View File
@@ -3,20 +3,18 @@ Ground up redesign of the interpreter
Maximum mesh shaders at once is 32*32*2, or 2048. For 65,536 vgprs, each mesh shader can only use 32.
Instead of a stack, use SSA and then limited registers (16?). This is a bit more compile friendly.
Instead of a stack, use SSA and then limited registers . This is a bit more compile friendly.
There are 16 available registers. Register 0 is always 0, and register 16 is the next item in the const tape.
There are 16 available registers. Register 0 is always 0, and register 15 is the next item in the const tape.
This leaves 14 usable 32 bit float registers.
Vectors are constructed starting at the input variable and counting up - e.g. a the vec3 at 5 is made from vec3(5, 6, 7);
Instruction format:
32 bits
8 bits
First 16 bits encode four 4 bit registers that are used as inputs. Next 4 bits are output register.
1 bit encodes if the instruction works up or down.
3 bits encode the length of the VecX type, where 0 means Vec1 and 7 means Vec8.
This leaves 8 bits to encode an opcode, for 256 possible opcodes.
If the lowest 6 bits are below 47, the top two bits are length of the VecX type, where 0 means Vec1 and 3 means Vec4.
Otherwise, all 8 bits encode an instruction.
Each following 8 bits encode two 4 bit registers that are registers. All inputs are listed, then all outputs. It is padded to 8 bits with zeros.
Each SDF can have up to 8 materials associated with it. The relative weight of each material is tracked through the interpreter as an
array of 8 floats, and at the end they are evaluated once.
@@ -74,8 +72,6 @@ For a mesh that takes up 1024x1024 pixel on screen, each quad takes up 16x16 pix
- floor
- ceil
- fract
- radians
- degrees
- sin
- cos
- tan
@@ -106,23 +102,9 @@ For a mesh that takes up 1024x1024 pixel on screen, each quad takes up 16x16 pix
- LengthVecX (returns vec1)
- DistanceVecX (returns vec1)
- NormaliseVecX (returns vec1)
- FaceForwardVecX (returns vecx)
- ReflectVecX (returns vecx)
- RefractVecX (returns vecx)
## Data manipulation
### Instructions
- CopyVecX
- PromoteVec1Vec1Vec2
- PromoteVec1Vec1Vec1Vec3
- PromoteVec1Vec1Vec1Vec1Vec4
- PromoteVec2Vec1Vec3
- PromoteVec1Vec2Vec3
- PromoteVec2Vec1Vec1Vec4
- PromoteVec1Vec2Vec1Vec4
- PromoteVec1Vec1Vec2Vec4
- PromoteVec2Vec2Vec4
- PromoteVec3Vec1Vec4
- PromoteVec1Vec3Vec4
## SDF
- SDFSphere
- SDFBox
@@ -130,8 +112,4 @@ For a mesh that takes up 1024x1024 pixel on screen, each quad takes up 16x16 pix
## Extra
- Stop
- Nop
- Position
# Possible extra instructions
- Vector extract/insert dynamic?
- OpVectorShuffle
- Position
+3 -254
View File
@@ -87,6 +87,8 @@ mod objects;
use crate::objects::*;
mod mcsg_deserialise;
mod ssa;
mod instruction_set {
include!(concat!(env!("OUT_DIR"), "/instructionset.rs"));
}
@@ -1805,260 +1807,7 @@ fn object_size_dependent_setup(
let mut desc: Vec<Description> = vec![Default::default()];
'nextcsg: for csg in state {
let mut data: Vec<[u32; 4]> = vec![];
let to_push = [
scene.len() as u32,
floats.len() as u32,
vec2s.len() as u32,
vec4s.len() as u32,
mat2s.len() as u32,
mat3s.len() as u32,
mat4s.len() as u32,
mats.len() as u32,
deps.len() as u32,
];
let example = vec![
CSGPart::opcode(
InstructionSet::OPMulVec3Float,
vec![Inputs::Variable, Inputs::Float(0.9)],
),
CSGPart::opcode(InstructionSet::OPDupVec3, vec![Inputs::Variable]),
CSGPart::opcode(
InstructionSet::OPAddVec3Vec3,
vec![Inputs::Variable, Inputs::Vec3([-0.7, -1.2, -0.7].into())],
),
CSGPart::opcode(
InstructionSet::OPSDFSphere,
vec![Inputs::Float(0.5), Inputs::Variable],
),
//CSGPart::opcode(InstructionSet::OPNop,vec![]),
//CSGPart::opcode(InstructionSet::OPDupVec3, vec![Inputs::Variable]),
//CSGPart::opcode(InstructionSet::OPAddVec3Vec3, vec![Inputs::Variable,
// Inputs::Vec3([-0.2, -0.2, -0.2].into())]),
// CSGPart::opcode(InstructionSet::OPAddVec3Vec3, vec![Inputs::Variable,
// Inputs::Vec3([-0.0, -0.0, -0.0].into())]),
// CSGPart::opcode(InstructionSet::OPSDFSphere,vec![Inputs::Float(1.2),
// Inputs::Variable]),
CSGPart::opcode(
InstructionSet::OPSDFTorus,
vec![Inputs::Vec2([0.7, 0.4].into()), Inputs::Variable],
),
//CSGPart::opcode(InstructionSet::OPSDFBox, vec![Inputs::Vec3([0.7, 0.4, 0.7].into()),
// Inputs::Variable]),
CSGPart::opcode(
InstructionSet::OPMinFloat,
vec![Inputs::Variable, Inputs::Variable],
),
CSGPart::opcode(
InstructionSet::OPDivFloatFloat,
vec![Inputs::Variable, Inputs::Float(0.9)],
),
CSGPart::opcode(InstructionSet::OPStop, vec![Inputs::Variable]),
];
let parts = if actual { &csg.parts } else { &example };
let mut dependencies: Vec<[u8; 2]> = vec![];
for _ in 0..parts.len() {
dependencies.push([u8::MAX, u8::MAX]);
}
let mut runtime_floats: Vec<usize> = vec![];
let mut runtime_vec2s: Vec<usize> = vec![];
let mut runtime_vec3s: Vec<usize> = vec![usize::MAX];
let mut runtime_vec4s: Vec<usize> = vec![];
let mut runtime_mat2s: Vec<usize> = vec![];
let mut runtime_mat3s: Vec<usize> = vec![];
let mut runtime_mat4s: Vec<usize> = vec![];
for (index, part) in parts.iter().enumerate() {
let inputs = part.opcode.input();
for (expected, actual) in inputs.iter().zip(part.constants.iter()) {
if actual != expected {
error!(
"csg {} is invalid ({:?} != {:?})",
csg.name, actual, expected
);
continue 'nextcsg;
}
if actual == &Inputs::Variable {
match *expected {
InputTypes::Float => match runtime_floats.pop() {
Some(u) => {
if dependencies[u][0] != u8::MAX {
dependencies[u][1] = index as u8
} else {
dependencies[u][0] = index as u8
}
},
None => {
error!("csg {} underflowed on floats", csg.name);
continue 'nextcsg;
},
},
InputTypes::Vec2 => match runtime_vec2s.pop() {
Some(u) => {
if dependencies[u][0] != u8::MAX {
dependencies[u][1] = index as u8
} else {
dependencies[u][0] = index as u8
}
},
None => {
error!("csg {} underflowed on vec2s", csg.name);
continue 'nextcsg;
},
},
InputTypes::Vec3 => match runtime_vec3s.pop() {
Some(u) => {
if u != usize::MAX {
if dependencies[u][0] != u8::MAX {
dependencies[u][1] = index as u8
} else {
dependencies[u][0] = index as u8
}
}
},
None => {
error!("csg {} underflowed on vec3s", csg.name);
continue 'nextcsg;
},
},
InputTypes::Vec4 => match runtime_vec4s.pop() {
Some(u) => {
if dependencies[u][0] != u8::MAX {
dependencies[u][1] = index as u8
} else {
dependencies[u][0] = index as u8
}
},
None => {
error!("csg {} underflowed on vec4s", csg.name);
continue 'nextcsg;
},
},
InputTypes::Mat2 => match runtime_mat2s.pop() {
Some(u) => {
if dependencies[u][0] != u8::MAX {
dependencies[u][1] = index as u8
} else {
dependencies[u][0] = index as u8
}
},
None => {
error!("csg {} underflowed on mat2s", csg.name);
continue 'nextcsg;
},
},
InputTypes::Mat3 => match runtime_mat3s.pop() {
Some(u) => {
if dependencies[u][0] != u8::MAX {
dependencies[u][1] = index as u8
} else {
dependencies[u][0] = index as u8
}
},
None => {
error!("csg {} underflowed on mat3s", csg.name);
continue 'nextcsg;
},
},
InputTypes::Mat4 => match runtime_mat4s.pop() {
Some(u) => {
if dependencies[u][0] != u8::MAX {
dependencies[u][1] = index as u8
} else {
dependencies[u][0] = index as u8
}
},
None => {
error!("csg {} underflowed on mat4s", csg.name);
continue 'nextcsg;
},
},
}
} else {
match *actual {
Inputs::Float(f) => floats.push(f),
Inputs::Vec2(f) => vec2s.push(f.map(|x| x).into()),
Inputs::Vec3(f) => vec4s.push(f.map(|x| x).extend(1.).into()),
Inputs::Vec4(f) => vec4s.push(f.map(|x| x).into()),
Inputs::Mat2(f) => mat2s.push(f.to_cols_array_2d()),
Inputs::Mat3(f) => mat3s.push(f.to_cols_array_2d()),
Inputs::Mat4(f) => mat4s.push(f.to_cols_array_2d()),
Inputs::Variable => unreachable!(),
}
}
}
let outputs = part.opcode.output();
for output in outputs {
match output {
InputTypes::Float => runtime_floats.push(index),
InputTypes::Vec2 => runtime_vec2s.push(index),
InputTypes::Vec3 => runtime_vec3s.push(index),
InputTypes::Vec4 => runtime_vec4s.push(index),
InputTypes::Mat2 => runtime_mat2s.push(index),
InputTypes::Mat3 => runtime_mat3s.push(index),
InputTypes::Mat4 => runtime_mat4s.push(index),
}
}
}
let mut lower = true;
let mut minor = 0;
let mut major = 0;
for part in parts.iter() {
if major == data.len() {
data.push([0; 4]);
}
data[major][minor] |= (part.code as u32) << (if lower { 0 } else { 16 });
lower = !lower;
if lower {
minor += 1;
if minor == 4 {
minor = 0;
major += 1;
if major == 29 {
panic!("CSGParts Too full!");
}
}
}
}
let temp_csg = &CSG {
name: "test".to_string(),
parts: parts.to_vec(),
pos: Vec3::ZERO,
rot: Vec3::ZERO,
scale: Vec3::ONE,
};
let mut interpreter = interpreter::Interpreter::new(temp_csg);
const CLIPCHECK: Float = 65536.;
let bounds = set_bound.unwrap_or([
((CLIPCHECK - interpreter.scene(vec3(CLIPCHECK, 0., 0.))) * 1.00001) as f32,
((CLIPCHECK - interpreter.scene(vec3(0., CLIPCHECK, 0.))) * 1.00001) as f32,
((CLIPCHECK - interpreter.scene(vec3(0., 0., CLIPCHECK))) * 1.00001) as f32,
((-CLIPCHECK + interpreter.scene(vec3(-CLIPCHECK, 0., 0.))) * 1.00001) as f32,
((-CLIPCHECK + interpreter.scene(vec3(0., -CLIPCHECK, 0.))) * 1.00001) as f32,
((-CLIPCHECK + interpreter.scene(vec3(0., 0., -CLIPCHECK))) * 1.00001) as f32,
]);
//trace!("bounds: {:?}",bounds);
desc.push(Description {
pointers: to_push,
bounds,
});
scene.append(&mut data);
deps.append(&mut dependencies);
}
trace!("floats: {floats:?}");
-520
View File
@@ -1,520 +0,0 @@
use std::{
fmt::Display,
io::{BufReader, Read},
str::Chars,
};
use serde::{
Deserialize,
de::{
self, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess, VariantAccess,
Visitor,
},
forward_to_deserialize_any,
};
use utf8::BufReadDecoder;
type Result<T> = core::result::Result<T, Error>;
#[derive(Debug)]
pub(crate) enum Error {
Message(String),
UTF8(String),
TrailingCharacters,
Eof,
ExpectedString,
Syntax,
ExpectedArrayEnd,
ExpectedArray,
ExpectedMapEnd,
ExpectedMap,
ExpectedMapColon,
ExpectedEnum,
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Message(msg) | Error::UTF8(msg) => f.write_str(msg),
_ => f.write_fmt(format_args!("Error: {self:?}")),
}
}
}
impl std::error::Error for Error {}
impl serde::de::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error::Message(msg.to_string())
}
}
impl serde::ser::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error::Message(msg.to_string())
}
}
pub(crate) struct Deserializer<'de> {
// This string starts with the input data and characters are truncated off
// the beginning as data is parsed.
input: BufReadDecoder<BufReader<&'de mut dyn Read>>,
read_buf: String,
peek: Option<(char, usize)>,
}
impl<'de> Deserializer<'de> {
// By convention, `Deserializer` constructors are named like `from_xyz`.
// That way basic use cases are satisfied by something like
// `serde_json::from_str(...)` while advanced use cases that require a
// deserializer can make one with `serde_json::Deserializer::from_str(...)`.
pub(crate) fn from_reader(input: &'de mut dyn Read) -> Self {
Deserializer {
input: BufReadDecoder::new(BufReader::new(input)),
read_buf: String::new(),
peek: None,
}
}
}
// By convention, the pub(crate)lic API of a Serde deserializer is one or more
// `from_xyz` methods such as `from_str`, `from_bytes`, or `from_reader`
// depending on what Rust types the deserializer is able to consume as input.
//
// This basic deserializer supports only `from_str`.
pub(crate) fn from_reader<'a, T>(s: &'a mut dyn Read) -> Result<T>
where
T: Deserialize<'a>,
{
let mut deserializer = Deserializer::from_reader(s);
let t = T::deserialize(&mut deserializer)?;
if deserializer.check_end() {
Ok(t)
} else {
Err(Error::TrailingCharacters)
}
}
fn get_char(mut s: Chars) -> Result<(char, usize)> {
let mut count = 0usize;
loop {
let next = s.next().ok_or(Error::Eof);
count += 1;
if next.as_ref().is_ok_and(|&c| c.is_whitespace()) {
continue;
}
if next.as_ref().is_ok_and(|this| this == &'/') {
if s.next() == Some('/') {
while s.next().is_some_and(|s| s != '\n' && s != '\r') {
count += 1;
}
count += 1;
}
count += 1;
} else {
return next.map(|c| (c, count));
}
}
}
// SERDE IS NOT A PARSING LIBRARY. This impl block defines a few basic parsing
// functions from scratch. More complicated formats may wish to use a dedicated
// parsing library to help implement their Serde deserializer.
impl Deserializer<'_> {
fn check_end(&mut self) -> bool {
self.input.next_strict().is_none()
}
// Look at the first character in the input without consuming it.
fn peek_char(&mut self) -> Result<(char, usize)> {
if let Some(p) = self.peek {
Ok(p)
} else {
loop {
match get_char(self.read_buf.chars()) {
Ok(c) => {
self.peek = Some(c);
return Ok(c);
},
Err(Error::Eof) => match self.input.next_strict() {
Some(e) => {
match e {
Ok(s) => {
s.clone_into(&mut self.read_buf);
},
Err(e) => return Err(Error::UTF8(format!("{e}"))),
};
},
None => return Err(Error::Eof),
},
Err(e) => return Err(e),
}
}
}
}
// Consume the first character in the input.
fn next_char(&mut self) -> Result<char> {
let ch = self.peek_char()?;
self.read_buf = self.read_buf[ch.1..].to_string();
self.peek = None;
Ok(ch.0)
}
// Parse a string until the next '"' character.
//
// Makes no attempt to handle escape sequences. What did you expect? This is
// example code!
fn parse_string(&mut self) -> Result<String> {
if self.next_char()? != '"' {
return Err(Error::ExpectedString);
}
loop {
match self.read_buf.find('"') {
Some(len) => {
let out = self.read_buf[..len].to_string();
self.read_buf = self.read_buf[len + 1..].to_string();
return Ok(out);
},
None => match self.input.next_strict() {
Some(e) => {
match e {
Ok(s) => {
s.clone_into(&mut self.read_buf);
},
Err(e) => return Err(Error::UTF8(format!("{e}"))),
};
},
None => return Err(Error::Eof),
},
}
}
}
}
impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
type Error = Error;
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char bytes byte_buf option unit unit_struct
}
// Look at the input data to decide what Serde data model type to
// deserialize as. Not all data formats are able to support this operation.
// Formats that support `deserialize_any` are known as self-describing.
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self.peek_char()?.0 {
'"' => self.deserialize_str(visitor),
'[' => self.deserialize_seq(visitor),
'{' => self.deserialize_map(visitor),
_ => Err(Error::Syntax),
}
}
// Refer to the "Understanding deserializer lifetimes" page for information
// about the three deserialization flavors of strings in Serde.
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_string(self.parse_string()?)
}
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_string(visitor)
}
// Deserialization of compound types like sequences and maps happens by
// passing the visitor an "Access" object that gives it the ability to
// iterate through the data contained in the sequence.
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
// Parse the opening bracket of the sequence.
if self.next_char()? == '[' {
// Give the visitor access to each element of the sequence.
let value = visitor.visit_seq(CommaSeparated::new(self))?;
// Parse the closing bracket of the sequence.
if self.next_char()? == ']' {
Ok(value)
} else {
Err(Error::ExpectedArrayEnd)
}
} else {
Err(Error::ExpectedArray)
}
}
// Much like `deserialize_seq` but calls the visitors `visit_map` method
// with a `MapAccess` implementation, rather than the visitor's `visit_seq`
// method with a `SeqAccess` implementation.
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
// Parse the opening brace of the map.
if self.next_char()? == '{' {
// Give the visitor access to each entry of the map.
let value = visitor.visit_map(CommaSeparated::new(self))?;
// Parse the closing brace of the map.
if self.next_char()? == '}' {
Ok(value)
} else {
Err(Error::ExpectedMapEnd)
}
} else {
Err(Error::ExpectedMap)
}
}
// Structs look just like maps in JSON.
//
// Notice the `fields` parameter - a "struct" in the Serde data model means
// that the `Deserialize` implementation is required to know what the fields
// are before even looking at the input data. Any key-value pairing in which
// the fields cannot be known ahead of time is probably a map.
fn deserialize_struct<V>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_map(visitor)
}
// An identifier in Serde is the type that identifies a field of a struct or
// the variant of an enum. In JSON, struct fields and enum variants are
// represented as strings. In other formats they may be represented as
// numeric indices.
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_str(visitor)
}
// Tuples look just like sequences in JSON. Some formats may be able to
// represent tuples more efficiently.
//
// As indicated by the length parameter, the `Deserialize` implementation
// for a tuple in the Serde data model is required to know the length of the
// tuple before even looking at the input data.
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
// Tuple structs look just like sequences in JSON.
fn deserialize_tuple_struct<V>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_seq(visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
if self.peek_char()?.0 == '"' {
// Visit a unit variant.
visitor.visit_enum(self.parse_string()?.into_deserializer())
} else if self.next_char()? == '{' {
// Visit a newtype variant, tuple variant, or struct variant.
let value = visitor.visit_enum(Enum::new(self))?;
// Parse the matching close brace.
if self.next_char()? == '}' {
Ok(value)
} else {
Err(Error::ExpectedMapEnd)
}
} else {
Err(Error::ExpectedEnum)
}
}
// As is done here, serializers are encouraged to treat newtype structs as
// insignificant wrappers around the data they contain. That means not
// parsing anything other than the contained value.
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_newtype_struct(self)
}
// Like `deserialize_any` but indicates to the `Deserializer` that it makes
// no difference which `Visitor` method is called because the data is
// ignored.
//
// Some deserializers are able to implement this more efficiently than
// `deserialize_any`, for example by rapidly skipping over matched
// delimiters without paying close attention to the data in between.
//
// Some formats are not able to implement this at all. Formats that can
// implement `deserialize_any` and `deserialize_ignored_any` are known as
// self-describing.
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
self.deserialize_any(visitor)
}
}
// In order to handle commas correctly when deserializing a JSON array or map,
// we need to track whether we are on the first element or past the first
// element.
struct CommaSeparated<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
}
impl<'a, 'de> CommaSeparated<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>) -> Self {
CommaSeparated { de }
}
}
// `SeqAccess` is provided to the `Visitor` to give it the ability to iterate
// through elements of the sequence.
impl<'de> SeqAccess<'de> for CommaSeparated<'_, 'de> {
type Error = Error;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
// Check if there are no more elements.
if self.de.peek_char()?.0 == ']' {
return Ok(None);
}
// Deserialize an array element.
seed.deserialize(&mut *self.de).map(Some)
}
}
// `MapAccess` is provided to the `Visitor` to give it the ability to iterate
// through entries of the map.
impl<'de> MapAccess<'de> for CommaSeparated<'_, 'de> {
type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
// Check if there are no more entries.
if self.de.peek_char()?.0 == '}' {
return Ok(None);
}
// Deserialize a map key.
seed.deserialize(&mut *self.de).map(Some)
}
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
// It doesn't make a difference whether the colon is parsed at the end
// of `next_key_seed` or at the beginning of `next_value_seed`. In this
// case the code is a bit simpler having it here.
if self.de.next_char()? != ':' {
return Err(Error::ExpectedMapColon);
}
// Deserialize a map value.
seed.deserialize(&mut *self.de)
}
}
struct Enum<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
}
impl<'a, 'de> Enum<'a, 'de> {
fn new(de: &'a mut Deserializer<'de>) -> Self {
Enum { de }
}
}
// `EnumAccess` is provided to the `Visitor` to give it the ability to determine
// which variant of the enum is supposed to be deserialized.
//
// Note that all enum deserialization methods in Serde refer exclusively to the
// "externally tagged" enum representation.
impl<'de> EnumAccess<'de> for Enum<'_, 'de> {
type Error = Error;
type Variant = Self;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
where
V: DeserializeSeed<'de>,
{
// The `deserialize_enum` method parsed a `{` character so we are
// currently inside of a map. The seed will be deserializing itself from
// the key of the map.
let val = seed.deserialize(&mut *self.de)?;
// Parse the colon separating map key from value.
if self.de.next_char()? == ':' {
Ok((val, self))
} else {
Err(Error::ExpectedMapColon)
}
}
}
// `VariantAccess` is provided to the `Visitor` to give it the ability to see
// the content of the single variant that it decided to deserialize.
impl<'de> VariantAccess<'de> for Enum<'_, 'de> {
type Error = Error;
// If the `Visitor` expected this variant to be a unit variant, the input
// should have been the plain string case handled in `deserialize_enum`.
fn unit_variant(self) -> Result<()> {
Err(Error::ExpectedString)
}
// Newtype variants are represented in JSON as `{ NAME: VALUE }` so
// deserialize the value here.
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
where
T: DeserializeSeed<'de>,
{
seed.deserialize(self.de)
}
// Tuple variants are represented in JSON as `{ NAME: [DATA...] }` so
// deserialize the sequence of data here.
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
de::Deserializer::deserialize_seq(self.de, visitor)
}
// Struct variants are represented in JSON as `{ NAME: { K: V, ... } }` so
// deserialize the inner map here.
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
de::Deserializer::deserialize_map(self.de, visitor)
}
}
+6 -195
View File
@@ -1,14 +1,8 @@
use std::{
collections::HashMap,
io::{Cursor, Read},
mem,
sync::Arc,
};
use std::{collections::HashMap, io::Read, sync::Arc};
use bytemuck::{Pod, Zeroable};
use glam::{self, Mat2, Mat3, Mat4, Vec2, Vec3, Vec4};
use obj::{LoadConfig, ObjData, ObjError};
use serde::{Deserialize, Serialize};
use vulkano::{
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
memory::allocator::{
@@ -17,16 +11,12 @@ use vulkano::{
pipeline::graphics::vertex_input::Vertex,
};
use crate::{instruction_set::InstructionSet, mcsg_deserialise::from_reader};
use crate::instruction_set::InstructionSet;
pub(crate) const PLATONIC_SOLIDS: [(&str, &[u8]); 1] = [("Buny", include_bytes!("bunny.obj"))];
pub(crate) const CSG_SOLIDS: [(&str, &[u8]); 1] =
[("Primitives", include_bytes!("primitive.mcsg"))];
// We now create a buffer that will store the shape of our triangle.
// We use #[repr(C)] here to force rustc to not do anything funky with our data,
// although for this particular example, it doesn't actually change the
// in-memory representation.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, Vertex)]
pub(crate) struct OVertex {
@@ -73,10 +63,10 @@ pub(crate) enum Inputs {
#[repr(C)]
#[derive(Clone, Debug)]
pub(crate) struct CSGPart {
pub(crate) code: u16,
pub(crate) opcode: InstructionSet,
pub(crate) constants: Vec<Inputs>,
pub(crate) material: Option<Mat4>,
pub(crate) code: Vec<u8>,
pub(crate) opcode: InstructionSet,
pub(crate) inputs: Vec<u8>,
pub(crate) material: Option<Mat4>,
}
impl CSGPart {
@@ -190,185 +180,6 @@ pub(crate) fn load_obj(
}])
}
#[derive(Serialize, Deserialize)]
struct MCSG {
object: Vec<MCSGObject>,
csg: Vec<MCSGCSG>,
}
type MCSGObject = HashMap<String, String>;
type MCSGCSG = Vec<MCSGCSGPart>;
type MCSGCSGPart = HashMap<String, String>;
fn mat3_from_string(input: &str) -> Result<Mat3, String> {
let vec = input
.split(' ')
.map(|s| s.parse::<f32>())
.collect::<Result<Vec<f32>, _>>()
.map_err(|_| "not floats")?;
let array: [f32; 9] = vec.try_into().map_err(|_| "wrong number of values")?;
let matrix = Mat3::from_cols_array(&array);
Ok(matrix)
}
fn vec3_from_string(input: &str) -> Result<Vec3, String> {
let vec = input
.split(' ')
.map(|s| s.parse::<f32>())
.collect::<Result<Vec<f32>, _>>()
.map_err(|_| "not floats")?;
let array: [f32; 3] = vec.try_into().map_err(|_| "wrong number of values")?;
let vector = Vec3::from_array(array);
Ok(vector)
}
struct TRS {
translation: Vec3,
rotation: Mat3,
scale: Vec3,
}
fn get_trs(o: &HashMap<String, String>) -> Result<TRS, String> {
Ok(TRS {
translation: o
.get("t")
.map(String::as_str)
.map(vec3_from_string)
.transpose()?
.unwrap_or(Vec3::ZERO),
rotation: o
.get("r")
.map(String::as_str)
.map(mat3_from_string)
.transpose()?
.unwrap_or(Mat3::IDENTITY),
scale: o
.get("s")
.map(String::as_str)
.map(vec3_from_string)
.transpose()?
.unwrap_or(Vec3::ONE),
})
}
fn get_color(o: &HashMap<String, String>) -> Result<Vec3, String> {
Ok(o.get("color")
.map(String::as_str)
.map(vec3_from_string)
.transpose()?
.unwrap_or(Vec3::splat(255.)))
}
fn get_rgb(o: &HashMap<String, String>) -> Result<Vec3, String> {
Ok(o.get("rgb")
.map(String::as_str)
.map(vec3_from_string)
.transpose()?
.unwrap_or(Vec3::splat(255.)))
}
fn get_f32(o: &HashMap<String, String>, tag: &str) -> Result<f32, String> {
get_f32_default(o, tag, 0.)
}
fn get_f32_default(o: &HashMap<String, String>, tag: &str, _default: f32) -> Result<f32, String> {
Ok(o.get(tag)
.map(|c| c.parse::<f32>())
.transpose()
.map_err(|e| e.to_string())?
.unwrap_or_default())
}
fn get_percentage(o: &HashMap<String, String>, tag: &str) -> Result<f32, String> {
get_f32(o, tag).map(|c| c / 100.0)
}
fn get_percentage_default(
o: &HashMap<String, String>,
tag: &str,
default: f32,
) -> Result<f32, String> {
get_f32_default(o, tag, default).map(|c| c / 100.0)
}
#[repr(u8)]
enum Half {
X,
Y,
Z,
XM,
YM,
ZM,
}
fn get_half(o: &HashMap<String, String>) -> Result<Half, String> {
Ok({
let half = o
.get("half")
.map(|c| c.parse::<u8>())
.transpose()
.map_err(|e| e.to_string())?
.unwrap_or(0);
if half as usize >= mem::variant_count::<Half>() {
return Err("invalid enum".to_owned());
}
unsafe { mem::transmute::<u8, Half>(half) }
})
}
pub(crate) fn load_csg(
_memory_allocator: &Arc<StandardMemoryAllocator>,
input: &mut dyn Read,
name: String,
) -> Result<Vec<CSG>, String> {
let mcsg: MCSG =
from_reader(&mut Cursor::new("{").chain(input).chain(Cursor::new("}"))).unwrap();
mcsg.object
.iter()
.map(|o| {
let name = name.clone() + "_" + o.get("name").unwrap_or(&"unknown".to_owned());
let _trs = get_trs(o)?;
let _color = get_color(o)?;
let cid = o
.get("cid")
.map(|c| c.parse::<usize>())
.transpose()
.map_err(|e| e.to_string())?
.unwrap_or(0);
if o.get("type").map(|ty| &ty[..] != "csg").unwrap_or(false) {
return Err("Type unknown".to_owned());
}
let parts = mcsg
.csg
.get(cid)
.ok_or("unknown cid")?
.iter()
.map(|inpart| {
let ty = inpart.get("type").ok_or("no type!")?.as_str();
let csgpart = CSGPart::opcode(InstructionSet::OPNop, vec![]);
if ty == "sphere" {
let _blend = get_f32(inpart, "blend")?;
let _shell = get_percentage(inpart, "shell%")?;
let _power = get_f32_default(inpart, "power", 2.)?;
let _rgb = get_rgb(inpart)?;
let _trs = get_trs(inpart)?;
let _half = get_half(inpart)?;
}
Ok(csgpart)
})
.collect::<Result<Vec<CSGPart>, String>>()?;
Ok(CSG {
parts,
pos: Vec3::ZERO,
rot: Vec3::ZERO,
scale: Vec3::ONE,
name,
})
})
.collect::<Result<Vec<CSG>, String>>()
}
#[derive(Debug)]
pub(crate) struct Light {
pub(crate) pos: Vec3,
+517
View File
@@ -0,0 +1,517 @@
use egui::ahash::HashMapExt;
use foldhash::HashMap;
use rspirv::spirv;
use crate::instruction_set::InstructionSet;
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
enum SSAOpcode {
#[default]
SSAStop,
SSAReturn,
SSAPosition,
SSAAdd,
SSASub,
SSAMul,
SSADiv,
SSAMod,
SSARem,
SSAPow,
SSAAtan2,
SSAMin,
SSAMinMaterial,
SSAMax,
SSAMaxMaterial,
SSACross,
SSADot,
SSALength,
SSADistance,
SSANormalize,
SSANegate,
SSARound,
SSARoundEven,
SSATrunc,
SSAAbs,
SSASign,
SSAFloor,
SSACeil,
SSAFract,
SSASin,
SSACos,
SSATan,
SSAAsin,
SSAAcos,
SSAAtan,
SSASinh,
SSACosh,
SSATanh,
SSAAsinh,
SSAAcosh,
SSAAtanh,
SSAExp,
SSALog,
SSAExp2,
SSALog2,
SSASqrt,
SSAInverseSqrt,
SSASquare,
SSACube,
SSASmoothMin,
SSASmoothMax,
SSASmoothMinMaterial,
SSASmoothMaxMaterial,
SSAClamp,
SSAMix,
SSAStep,
SSASmoothStep,
SSAFMA,
SSASDFSphere,
SSASDFBox,
SSASDFTorus,
}
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
struct SSAOpcodeSized {
opcode: SSAOpcode,
size: u8,
}
#[derive(Debug, PartialEq, Clone, Copy)]
enum SSAInput {
Register(u32),
Constant(f32),
}
#[derive(Debug, Default, PartialEq, Clone)]
struct SSAInstruction {
opcode: SSAOpcodeSized,
inputs: Vec<SSAInput>,
outputs: Vec<u32>,
}
#[derive(Debug, Default, PartialEq, Clone)]
struct SSATape {
last_output: u32,
tape: Vec<SSAInstruction>,
constants: Vec<f32>,
}
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
struct GPUOpcode(u8);
struct GPUTape {
instructions: Vec<u8>,
constants: Vec<f32>,
}
impl SSAOpcodeSized {
const fn output(&self) -> u8 {
use SSAOpcode::*;
match self.opcode {
SSAStop => 0,
SSAReturn => 0,
SSAPosition => 3,
SSAMinMaterial => 1,
SSAMaxMaterial => 1,
SSASmoothMinMaterial => 1,
SSASmoothMaxMaterial => 1,
SSACross => 3,
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,
SSACross => 3 + 3,
SSASDFSphere => 3 + 1,
SSASDFBox => 3 + 3,
SSASDFTorus => 3 + 2,
SSAAdd | SSASub | SSAMul | SSADiv | SSAMod | SSARem | SSAPow | SSAAtan2 | SSAMin
| SSAMax | SSADot | SSADistance => self.size * 2,
SSASmoothMin | SSASmoothMax | SSAClamp | SSAMix | SSAStep | SSASmoothStep | 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 | SSACross | SSASDFSphere | SSASDFBox
| SSASDFTorus => (0, 0),
SSAAdd | SSASub | SSAMul | SSADiv | SSAMod | SSARem | SSAPow | SSAAtan2 | SSAMin
| SSAMax | SSADot | SSADistance => (2, 1),
SSASmoothMin | SSASmoothMax | SSAClamp | SSAMix | SSAStep | SSASmoothStep | 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(OPStop, 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),
SSACross => opcode_drop(OPCross, 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),
SSARem => opcode_drop(OPRem, self.size),
SSAPow => opcode_drop(OPPow, 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),
SSANormalize => opcode_drop(OPNormalize, self.size),
SSANegate => opcode_drop(OPNegate, self.size),
SSARound => opcode_drop(OPRound, self.size),
SSARoundEven => opcode_drop(OPRoundEven, self.size),
SSATrunc => opcode_drop(OPTrunc, self.size),
SSAAbs => opcode_drop(OPAbs, self.size),
SSASign => opcode_drop(OPSign, 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),
SSASinh => opcode_drop(OPSinh, self.size),
SSACosh => opcode_drop(OPCosh, self.size),
SSATanh => opcode_drop(OPTanh, self.size),
SSAAsinh => opcode_drop(OPAsinh, self.size),
SSAAcosh => opcode_drop(OPAcosh, self.size),
SSAAtanh => opcode_drop(OPAtanh, self.size),
SSAExp => opcode_drop(OPExp, self.size),
SSALog => opcode_drop(OPLog, self.size),
SSAExp2 => opcode_drop(OPExp2, self.size),
SSALog2 => opcode_drop(OPLog2, self.size),
SSASqrt => opcode_drop(OPSqrt, self.size),
SSAInverseSqrt => opcode_drop(OPInverseSqrt, 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),
SSAStep => opcode_drop(OPStep, self.size),
SSASmoothStep => opcode_drop(OPSmoothStep, self.size),
SSAFMA => opcode_drop(OPFMA, self.size),
}
}
}
impl SSATape {
fn push_instruction(&mut self, opcode: SSAOpcodeSized, inputs: Vec<SSAInput>) -> Vec<u32> {
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>>();
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: outputs.clone(),
});
return outputs;
}
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 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![],
constants: self.constants.clone(),
};
for SSAInstruction {
opcode,
inputs,
outputs,
} in self.tape.iter()
{
let code = opcode.to_raw_opcode();
gpu_tape.instructions.push(code.0);
let mut low_nibble = true;
let mut staging_byte = 0u8;
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.instructions.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.instructions.push(staging_byte);
}
low_nibble = !low_nibble;
}
if !low_nibble {
gpu_tape.instructions.push(staging_byte);
}
}
gpu_tape
}
fn compile_to_spirv(&self) {
let mut b = rspirv::dr::Builder::new();
b.set_version(1, 5);
b.memory_model(spirv::AddressingModel::Logical, spirv::MemoryModel::GLSL450);
let void = b.type_void();
let float = b.type_float(32);
let vec1 = b.type_vector(float, 1);
let vec2 = b.type_vector(float, 2);
let vec3 = b.type_vector(float, 3);
let vec4 = b.type_vector(float, 4);
let scene_fn_type = b.type_function(float, vec![vec3]);
let scene = b
.begin_function(
float,
None,
spirv::FunctionControl::DONT_INLINE
| spirv::FunctionControl::PURE
| spirv::FunctionControl::CONST,
scene_fn_type,
)
.unwrap();
let pos = b.function_parameter(vec3).unwrap();
let mut mapping = HashMap::<u32,u32>::new();
for instruction in self.tape.iter() {
use SSAOpcode::*;
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() {
todo!();
}
match instruction.opcode.opcode {
SSAStop => {
b.ret().unwrap();
},
SSAReturn =>
{
let value = input_resolve(float, &mut b, &mapping, instruction.inputs[0]);
b.ret_value(value).unwrap();
},
SSAPosition => {
mapping.insert(instruction.outputs[0], b.composite_extract(float, None, pos, [0]).unwrap());
mapping.insert(instruction.outputs[1], b.composite_extract(float, None, pos, [1]).unwrap());
mapping.insert(instruction.outputs[2], b.composite_extract(float, None, pos, [2]).unwrap());
},
SSAAdd => {
for i in 0..instruction.opcode.size as usize {
let val_a = input_resolve(float, &mut b, &mapping, instruction.inputs[i]);
let val_b = input_resolve(float, &mut b, &mapping, instruction.inputs[i+instruction.opcode.size as usize]);
mapping.insert(instruction.outputs[i], b.f_add(float, None, val_a, val_b).unwrap());
}
},
SSASub => todo!(),
SSAMul => todo!(),
SSADiv => todo!(),
SSAMod => todo!(),
SSARem => todo!(),
SSAPow => todo!(),
SSAAtan2 => todo!(),
SSAMin => todo!(),
SSAMinMaterial => todo!(),
SSAMax => todo!(),
SSAMaxMaterial => todo!(),
SSACross => todo!(),
SSADot => todo!(),
SSALength => todo!(),
SSADistance => todo!(),
SSANormalize => todo!(),
SSANegate => todo!(),
SSARound => todo!(),
SSARoundEven => todo!(),
SSATrunc => todo!(),
SSAAbs => todo!(),
SSASign => todo!(),
SSAFloor => todo!(),
SSACeil => todo!(),
SSAFract => todo!(),
SSASin => todo!(),
SSACos => todo!(),
SSATan => todo!(),
SSAAsin => todo!(),
SSAAcos => todo!(),
SSAAtan => todo!(),
SSASinh => todo!(),
SSACosh => todo!(),
SSATanh => todo!(),
SSAAsinh => todo!(),
SSAAcosh => todo!(),
SSAAtanh => todo!(),
SSAExp => todo!(),
SSALog => todo!(),
SSAExp2 => todo!(),
SSALog2 => todo!(),
SSASqrt => todo!(),
SSAInverseSqrt => todo!(),
SSASquare => todo!(),
SSACube => todo!(),
SSASmoothMin => todo!(),
SSASmoothMax => todo!(),
SSASmoothMinMaterial => todo!(),
SSASmoothMaxMaterial => todo!(),
SSAClamp => todo!(),
SSAMix => todo!(),
SSAStep => todo!(),
SSASmoothStep => todo!(),
SSAFMA => todo!(),
SSASDFSphere => todo!(),
SSASDFBox => todo!(),
SSASDFTorus => todo!(),
}
}
b.end_function().unwrap();
}
}