New instruction set
This commit is contained in:
Generated
+26
@@ -649,6 +649,7 @@ dependencies = [
|
|||||||
"obj",
|
"obj",
|
||||||
"rand",
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"rspirv",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"simplelog",
|
"simplelog",
|
||||||
@@ -1911,6 +1912,22 @@ dependencies = [
|
|||||||
"xmlparser",
|
"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]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.43"
|
version = "0.38.43"
|
||||||
@@ -2130,6 +2147,15 @@ dependencies = [
|
|||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ foldhash = "*"
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
simplelog = "0.12"
|
simplelog = "0.12"
|
||||||
|
|
||||||
|
rspirv = "0.12"
|
||||||
|
|
||||||
# using latest gits
|
# using latest gits
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
vulkano = { git = "https://github.com/vulkano-rs/vulkano" }
|
vulkano = { git = "https://github.com/vulkano-rs/vulkano" }
|
||||||
|
|||||||
@@ -12,29 +12,7 @@ fn main() -> io::Result<()> {
|
|||||||
let dest_path = Path::new(&out_dir).join("instructionset.rs");
|
let dest_path = Path::new(&out_dir).join("instructionset.rs");
|
||||||
let f = File::open("src/instructionset.glsl")?;
|
let f = File::open("src/instructionset.glsl")?;
|
||||||
let f = BufReader::new(f);
|
let f = BufReader::new(f);
|
||||||
let mut out = "#[allow(non_snake_case)]
|
let mut out = "
|
||||||
#[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,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
@@ -43,79 +21,23 @@ fn main() -> io::Result<()> {
|
|||||||
"
|
"
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
let mut outputimpl = "
|
for l in f.lines() {
|
||||||
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() {
|
|
||||||
let line = l?;
|
let line = l?;
|
||||||
let entries = line.split("//").map(str::trim).collect::<Vec<&str>>();
|
let entries = line.split("//").map(str::trim).collect::<Vec<&str>>();
|
||||||
if entries[0].is_empty() {
|
if entries[0].is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = &entries[0][11..entries[0].len() - 12];
|
let before_equals = entries[0].split("=").map(str::trim).collect::<Vec<&str>>();
|
||||||
let comment = entries[3];
|
let name = &before_equals[0][11..];
|
||||||
|
let value = &before_equals[1][..before_equals[1].len() - 1];
|
||||||
|
let comment = entries[1];
|
||||||
|
|
||||||
out += &format!(
|
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 += "}";
|
out += "}";
|
||||||
inputimpl += "}}";
|
|
||||||
outputimpl += "}}";
|
|
||||||
out += "#[allow(non_snake_case)]\nimpl InstructionSet {\n";
|
|
||||||
out += &inputimpl;
|
|
||||||
out += &outputimpl;
|
|
||||||
out += "}";
|
|
||||||
|
|
||||||
fs::write(dest_path, out).unwrap();
|
fs::write(dest_path, out).unwrap();
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
|||||||
+64
-149
@@ -1,149 +1,64 @@
|
|||||||
const uint OPNop=__LINE__-1; // // // No operation.
|
const uint OPCopy =0; // Returns the input. Useful for copying registers.
|
||||||
const uint OPStop=__LINE__-1; // // // Stops execution of the tape and returns 0.
|
const uint OPAdd =1; // Adds a vector to a vector component-wise.
|
||||||
const uint OPReturn=__LINE__-1; //V1 // // Stops execution of the tape and returns a single value.
|
const uint OPSub =2; // Subtracts a vector from a vector component-wise.
|
||||||
const uint OPPosition=__LINE__-1; // //V3 // Returns the current position being sampled.
|
const uint OPMul =3; // Multiplies a vector and a vector component-wise.
|
||||||
const uint OPPositionX=__LINE__-1; // //V1 // Returns the X component of the current position being sampled.
|
const uint OPDiv =4; // Divides a vector by a vector component-wise.
|
||||||
const uint OPPositionY=__LINE__-1; // //V1 // Returns the Y component of the current position being sampled.
|
const uint OPMod =5; // Calculates a vector modulo a vector component-wise.
|
||||||
const uint OPPositionZ=__LINE__-1; // //V1 // Returns the Z component of the current position being sampled.
|
const uint OPRem =6; // Calculates a vector remainder a vector component-wise.
|
||||||
const uint OPCopyVecX=__LINE__-1; //V1 //V1 // Returns the input. Useful for copying registers.
|
const uint OPPow =7; // Calculates a vector to the power of a vector component-wise.
|
||||||
const uint OPPromoteVec1Vec1Vec2=__LINE__-1; //V1 V1 //V2 // Copies two Vec1 registers into a single Vec2.
|
const uint OPAtan2 =8; // Calculates a vector Atan2 a vector component-wise.
|
||||||
const uint OPPromoteVec1Vec1Vec1Vec3=__LINE__-1; //V1 V1 V1 //V3 // Copies three Vec1 registers into a single Vec3.
|
const uint OPMin =9; // Calculates the minimum of a vector and a vector component-wise.
|
||||||
const uint OPPromoteVec1Vec1Vec1Vec1Vec4=__LINE__-1; //V1 V1 V1 V1 //V4 // Copies four Vec1 registers into a single Vec4.
|
const uint OPMax =10; // Calculates the maximum of a vector and a vector component-wise.
|
||||||
const uint OPPromoteVec2Vec1Vec3=__LINE__-1; //V2 V1 //V3 // Copies one Vec2 register and one Vec1 register into a single Vec3.
|
const uint OPNegate =11; // Returns the negation of all components of a vector.
|
||||||
const uint OPPromoteVec1Vec2Vec3=__LINE__-1; //V1 V2 //V3 // Copies one Vec1 register and one Vec2 register into a single Vec3.
|
const uint OPRound =12; // Returns all components of a vector rounded to the nearest integer.
|
||||||
const uint OPPromoteVec2Vec1Vec1Vec4=__LINE__-1; //V2 V1 V1 //V4 // Copies one Vec2 register and two Vec1 registers into a single Vec4.
|
const uint OPRoundEven =13; // Returns all components of a vector rounded to the nearest even integer.
|
||||||
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 OPTrunc =14; // Returns all components of a vector rounded towards zero.
|
||||||
const uint OPPromoteVec1Vec1Vec2Vec4=__LINE__-1; //V1 V1 V2 //V4 // Copies two Vec1 registers and one Vec2 register into a single Vec4.
|
const uint OPAbs =15; // Returns the absolute value of all components of a vector.
|
||||||
const uint OPPromoteVec2Vec2Vec4=__LINE__-1; //V2 V2 //V4 // Copies two Vec2 registers into a single Vec4.
|
const uint OPSign =16; // Returns the sign of all components of a vector.
|
||||||
const uint OPPromoteVec3Vec1Vec4=__LINE__-1; //V3 V1 //V4 // Copies one Vec3 register and one Vec1 register into a single Vec4.
|
const uint OPFloor =17; // Returns the floor of all components of a vector.
|
||||||
const uint OPPromoteVec1Vec3Vec4=__LINE__-1; //V1 V3 //V4 // Copies one Vec1 register and one Vec3 register into a single Vec4.
|
const uint OPCeil =18; // Returns the ceiling of all components of a vector.
|
||||||
const uint OPAddVecXVecX=__LINE__-1; //V1 V1 //V1 // Adds a VecX to a VecX component-wise.
|
const uint OPFract =19; // Returns the fractional part of all components of a vector.
|
||||||
const uint OPAddVec1VecX=__LINE__-1; //V1 VX //VX // Adds a Vec1 to a VecX component-wise.
|
const uint OPSin =20; // Returns the sine of all components of a vector.
|
||||||
const uint OPAddVecXVec1=__LINE__-1; //VX V1 //VX // Adds a VecX to a Vec1 component-wise.
|
const uint OPCos =21; // Returns the cosine of all components of a vector.
|
||||||
const uint OPSubVecXVecX=__LINE__-1; //V1 V1 //V1 // Subtracts a VecX from a VecX component-wise.
|
const uint OPTan =22; // Returns the tangent of all components of a vector.
|
||||||
const uint OPSubVec1VecX=__LINE__-1; //V1 VX //VX // Subtracts a VecX from a Vec1 component-wise.
|
const uint OPAsin =23; // Returns the arc sine of all components of a vector.
|
||||||
const uint OPSubVecXVec1=__LINE__-1; //VX V1 //VX // Subtracts a Vec1 from a VecX component-wise.
|
const uint OPAcos =24; // Returns the arc cosine of all components of a vector.
|
||||||
const uint OPMulVecXVecX=__LINE__-1; //V1 V1 //V1 // Multiplies a VecX and a VecX component-wise.
|
const uint OPAtan =25; // Returns the arc tangent of all components of a vector.
|
||||||
const uint OPMulVec1VecX=__LINE__-1; //V1 VX //VX // Multiplies a Vec1 and a VecX component-wise.
|
const uint OPSinh =26; // Returns the hyperbolic sine of all components of a vector.
|
||||||
const uint OPMulVecXVec1=__LINE__-1; //VX V1 //VX // Multiplies a VecX and a Vec1 component-wise.
|
const uint OPCosh =27; // Returns the hyperbolic cosine of all components of a vector.
|
||||||
const uint OPDivVecXVecX=__LINE__-1; //V1 V1 //V1 // Divides a VecX by a VecX component-wise.
|
const uint OPTanh =28; // Returns the hyperbolic tangent of all components of a vector.
|
||||||
const uint OPDivVec1VecX=__LINE__-1; //V1 VX //VX // Divides a Vec1 by a VecX component-wise.
|
const uint OPAsinh =29; // Returns the hyperbolic arc sine of all components of a vector.
|
||||||
const uint OPDivVecXVec1=__LINE__-1; //VX V1 //VX // Divides a VecX by a Vec1 component-wise.
|
const uint OPAcosh =30; // Returns the hyperbolic arc cosine of all components of a vector.
|
||||||
const uint OPModVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX modulo a VecX component-wise.
|
const uint OPAtanh =31; // Returns the hyperbolic arc tangent of all components of a vector.
|
||||||
const uint OPModVec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 modulo a VecX component-wise.
|
const uint OPExp =32; // Returns e raised to all components of a vector.
|
||||||
const uint OPModVecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX modulo a Vec1 component-wise.
|
const uint OPLog =33; // Returns the natural logarithm of all components of a vector.
|
||||||
const uint OPRemVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX remainder a VecX component-wise.
|
const uint OPExp2 =34; // Returns 2 raised to all components of a vector.
|
||||||
const uint OPRemVec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 remainder a VecX component-wise.
|
const uint OPLog2 =35; // Returns the base 2 logarithm of all components of a vector.
|
||||||
const uint OPRemVecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX remainder a Vec1 component-wise.
|
const uint OPSqrt =36; // Returns the square root of all components of a vector.
|
||||||
const uint OPPowVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX to the power of a VecX component-wise.
|
const uint OPInverseSqrt =37; // Returns one over the square root of all components of a vector.
|
||||||
const uint OPPowVec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 to the power of a VecX component-wise.
|
const uint OPSquare =38; // Returns the square of all components of a vector.
|
||||||
const uint OPPowVecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX to the power of a Vec1 component-wise.
|
const uint OPCube =39; // Returns the cube of all components of a vector.
|
||||||
const uint OPAtan2VecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates a VecX Atan2 a VecX component-wise.
|
const uint OPSmoothMin =40; // Returns the smooth minimum between a vector and a vector, varied by a vector.
|
||||||
const uint OPAtan2Vec1VecX=__LINE__-1; //V1 VX //VX // Calculates a Vec1 Atan2 a VecX component-wise.
|
const uint OPSmoothMax =41; // Returns the smooth maximum between a vector and a vector, varied by a vector.
|
||||||
const uint OPAtan2VecXVec1=__LINE__-1; //VX V1 //VX // Calculates a VecX Atan2 a Vec1 component-wise.
|
const uint OPClamp =42; // Clamps a vector between a vector and a vector.
|
||||||
const uint OPMinVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates the minimum of a VecX and a VecX component-wise.
|
const uint OPMix =43; // Mixes between a vector and a vector, varied by a vector.
|
||||||
const uint OPMinVec1VecX=__LINE__-1; //V1 VX //VX // Calculates the minimum of a Vec1 and a VecX component-wise.
|
const uint OPStep =44; // Steps between a vector and a vector, varied by a vector.
|
||||||
const uint OPMinVecXVec1=__LINE__-1; //VX V1 //VX // Calculates the minimum of a VecX and a Vec1 component-wise.
|
const uint OPSmoothStep =45; // Smooth Steps between a vector and a vector, varied by a vector.
|
||||||
const uint OPMinMaterialVec1Vec1=__LINE__-1; //V1 V1 //V1 // Calculates the minimum of two Vec1s, and also carries over the relevant material metadata.
|
const uint OPFMA =46; // Calculates a vector multiplied by a vector, then adds a vector.
|
||||||
const uint OPMaxVecXVecX=__LINE__-1; //V1 V1 //V1 // Calculates the maximum of a VecX and a VecX component-wise.
|
const uint OPDot =47; // Returns the dot product of two vectors.
|
||||||
const uint OPMaxVec1VecX=__LINE__-1; //V1 VX //VX // Calculates the maximum of a Vec1 and a VecX component-wise.
|
const uint OPLength =48; // Returns the length (magnitude) of a vector.
|
||||||
const uint OPMaxVecXVec1=__LINE__-1; //VX V1 //VX // Calculates the maximum of a VecX and a Vec1 component-wise.
|
const uint OPDistance =49; // Returns the length (magnitude) of the vector between two vectors.
|
||||||
const uint OPMaxMaterialVec1Vec1=__LINE__-1; //V1 V1 //V1 // Calculates the maximum of two Vec1s, and also carries over the relevant material metadata.
|
const uint OPNormalize =50; // Returns the normalised version of a vector.
|
||||||
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 OPNop =(0*64)+63; // No operation.
|
||||||
const uint OPLengthVecX=__LINE__-1; //VX //V1 // Returns the length (magnitude) of a VecX.
|
const uint OPStop =(1*64)+63; // Stops execution of the tape and returns 0.
|
||||||
const uint OPDistanceVecXVecX=__LINE__-1; //VX VX //V1 // Returns the length (magnitude) of the vector between two VecXs.
|
const uint OPReturn =(2*64)+63; // Stops execution of the tape and returns a single value.
|
||||||
const uint OPNormalizeVecX=__LINE__-1; //VX //VX // Returns the normalised version of a VecX.
|
const uint OPPosition =(3*64)+63; // Returns the current position being sampled.
|
||||||
const uint OPFaceForwardVecXVecX=__LINE__-1; //VX VX //VX // See GLSL's "FaceForward"
|
const uint OPMinMaterial =(0*64)+62; // Calculates the minimum of two Vec1s, and also carries over the relevant material metadata.
|
||||||
const uint OPReflectVecXVecX=__LINE__-1; //VX VX //VX // See GLSL's "Reflect"
|
const uint OPMaxMaterial =(1*64)+62; // Calculates the maximum of two Vec1s, and also carries over the relevant material metadata.
|
||||||
const uint OPRefractVecXVecXVec1=__LINE__-1; //VX VX V1 //VX // See GLSL's "Refract"
|
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 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 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 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 OPCross =(0*64)+61; // Returns the cross product of two Vec3s.
|
||||||
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 OPSDFSphere =(1*64)+61; // Returns the distance to a sphere.
|
||||||
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 OPSDFBox =(2*64)+61; // Returns the distance to a box.
|
||||||
const uint OPNegateVecX=__LINE__-1; //VX //VX // Returns the negation of all components of a VecX.
|
const uint OPSDFTorus =(3*64)+61; // Returns the distance to a torus.
|
||||||
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.
|
|
||||||
+7
-29
@@ -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.
|
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.
|
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:
|
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.
|
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.
|
||||||
1 bit encodes if the instruction works up or down.
|
Otherwise, all 8 bits encode an instruction.
|
||||||
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.
|
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
|
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.
|
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
|
- floor
|
||||||
- ceil
|
- ceil
|
||||||
- fract
|
- fract
|
||||||
- radians
|
|
||||||
- degrees
|
|
||||||
- sin
|
- sin
|
||||||
- cos
|
- cos
|
||||||
- tan
|
- tan
|
||||||
@@ -106,23 +102,9 @@ For a mesh that takes up 1024x1024 pixel on screen, each quad takes up 16x16 pix
|
|||||||
- LengthVecX (returns vec1)
|
- LengthVecX (returns vec1)
|
||||||
- DistanceVecX (returns vec1)
|
- DistanceVecX (returns vec1)
|
||||||
- NormaliseVecX (returns vec1)
|
- NormaliseVecX (returns vec1)
|
||||||
- FaceForwardVecX (returns vecx)
|
|
||||||
- ReflectVecX (returns vecx)
|
|
||||||
- RefractVecX (returns vecx)
|
|
||||||
## Data manipulation
|
## Data manipulation
|
||||||
### Instructions
|
### Instructions
|
||||||
- CopyVecX
|
- CopyVecX
|
||||||
- PromoteVec1Vec1Vec2
|
|
||||||
- PromoteVec1Vec1Vec1Vec3
|
|
||||||
- PromoteVec1Vec1Vec1Vec1Vec4
|
|
||||||
- PromoteVec2Vec1Vec3
|
|
||||||
- PromoteVec1Vec2Vec3
|
|
||||||
- PromoteVec2Vec1Vec1Vec4
|
|
||||||
- PromoteVec1Vec2Vec1Vec4
|
|
||||||
- PromoteVec1Vec1Vec2Vec4
|
|
||||||
- PromoteVec2Vec2Vec4
|
|
||||||
- PromoteVec3Vec1Vec4
|
|
||||||
- PromoteVec1Vec3Vec4
|
|
||||||
## SDF
|
## SDF
|
||||||
- SDFSphere
|
- SDFSphere
|
||||||
- SDFBox
|
- SDFBox
|
||||||
@@ -131,7 +113,3 @@ For a mesh that takes up 1024x1024 pixel on screen, each quad takes up 16x16 pix
|
|||||||
- Stop
|
- Stop
|
||||||
- Nop
|
- Nop
|
||||||
- Position
|
- Position
|
||||||
|
|
||||||
# Possible extra instructions
|
|
||||||
- Vector extract/insert dynamic?
|
|
||||||
- OpVectorShuffle
|
|
||||||
|
|||||||
+2
-253
@@ -87,6 +87,8 @@ mod objects;
|
|||||||
use crate::objects::*;
|
use crate::objects::*;
|
||||||
mod mcsg_deserialise;
|
mod mcsg_deserialise;
|
||||||
|
|
||||||
|
mod ssa;
|
||||||
|
|
||||||
mod instruction_set {
|
mod instruction_set {
|
||||||
include!(concat!(env!("OUT_DIR"), "/instructionset.rs"));
|
include!(concat!(env!("OUT_DIR"), "/instructionset.rs"));
|
||||||
}
|
}
|
||||||
@@ -1805,260 +1807,7 @@ fn object_size_dependent_setup(
|
|||||||
let mut desc: Vec<Description> = vec![Default::default()];
|
let mut desc: Vec<Description> = vec![Default::default()];
|
||||||
|
|
||||||
'nextcsg: for csg in state {
|
'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:?}");
|
trace!("floats: {floats:?}");
|
||||||
|
|||||||
@@ -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
@@ -1,14 +1,8 @@
|
|||||||
use std::{
|
use std::{collections::HashMap, io::Read, sync::Arc};
|
||||||
collections::HashMap,
|
|
||||||
io::{Cursor, Read},
|
|
||||||
mem,
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
use glam::{self, Mat2, Mat3, Mat4, Vec2, Vec3, Vec4};
|
use glam::{self, Mat2, Mat3, Mat4, Vec2, Vec3, Vec4};
|
||||||
use obj::{LoadConfig, ObjData, ObjError};
|
use obj::{LoadConfig, ObjData, ObjError};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
|
buffer::{Buffer, BufferCreateInfo, BufferUsage, Subbuffer},
|
||||||
memory::allocator::{
|
memory::allocator::{
|
||||||
@@ -17,16 +11,12 @@ use vulkano::{
|
|||||||
pipeline::graphics::vertex_input::Vertex,
|
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 PLATONIC_SOLIDS: [(&str, &[u8]); 1] = [("Buny", include_bytes!("bunny.obj"))];
|
||||||
pub(crate) const CSG_SOLIDS: [(&str, &[u8]); 1] =
|
pub(crate) const CSG_SOLIDS: [(&str, &[u8]); 1] =
|
||||||
[("Primitives", include_bytes!("primitive.mcsg"))];
|
[("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)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, Vertex)]
|
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, Vertex)]
|
||||||
pub(crate) struct OVertex {
|
pub(crate) struct OVertex {
|
||||||
@@ -73,10 +63,10 @@ pub(crate) enum Inputs {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct CSGPart {
|
pub(crate) struct CSGPart {
|
||||||
pub(crate) code: u16,
|
pub(crate) code: Vec<u8>,
|
||||||
pub(crate) opcode: InstructionSet,
|
pub(crate) opcode: InstructionSet,
|
||||||
pub(crate) constants: Vec<Inputs>,
|
pub(crate) inputs: Vec<u8>,
|
||||||
pub(crate) material: Option<Mat4>,
|
pub(crate) material: Option<Mat4>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CSGPart {
|
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)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Light {
|
pub(crate) struct Light {
|
||||||
pub(crate) pos: Vec3,
|
pub(crate) pos: Vec3,
|
||||||
|
|||||||
+517
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user