Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
451 lines
12 KiB
Rust
451 lines
12 KiB
Rust
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum SemanticType {
|
|
MeshData,
|
|
Texture,
|
|
Bool,
|
|
F32,
|
|
U32,
|
|
Vec2,
|
|
Vec3,
|
|
Vec4,
|
|
Mat2,
|
|
Mat3,
|
|
Mat4,
|
|
U32x16,
|
|
LocalAabb,
|
|
}
|
|
|
|
impl SemanticType {
|
|
pub const fn is_virtual(self) -> bool {
|
|
!matches!(self, Self::MeshData | Self::Texture)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum ExecutionClass {
|
|
Source,
|
|
Expression,
|
|
Render,
|
|
Frame,
|
|
}
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum FullscreenPolicy {
|
|
Copy,
|
|
HdrSameExtent,
|
|
BloomExtract,
|
|
BloomComposite,
|
|
}
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub struct InputCardinality {
|
|
pub min: u8,
|
|
pub max: u8,
|
|
}
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum InputDefaultPolicy {
|
|
None,
|
|
ParameterLiteral,
|
|
CompilerTexture,
|
|
}
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
|
|
#[serde(tag = "kind", content = "types", rename_all = "snake_case")]
|
|
pub enum TypeConstraint {
|
|
Exact(SemanticType),
|
|
OneOf(&'static [SemanticType]),
|
|
}
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
|
|
#[serde(tag = "kind", rename_all = "snake_case")]
|
|
pub enum InputRole {
|
|
SemanticRead,
|
|
UniformRead,
|
|
StorageRead,
|
|
IndirectRead,
|
|
SampledTexture,
|
|
ColorTarget { location: u32 },
|
|
DepthTarget,
|
|
Expression,
|
|
}
|
|
#[derive(Clone, Copy, Debug, serde::Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct InputSocketContract {
|
|
pub name: &'static str,
|
|
pub accepted: TypeConstraint,
|
|
pub cardinality: InputCardinality,
|
|
pub default_policy: InputDefaultPolicy,
|
|
pub role: InputRole,
|
|
}
|
|
#[derive(Clone, Copy, Debug, serde::Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct OutputSocketContract {
|
|
pub name: &'static str,
|
|
pub semantic_type: SemanticType,
|
|
}
|
|
#[derive(Clone, Debug, serde::Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct Contract {
|
|
pub key: &'static str,
|
|
pub version: u32,
|
|
pub execution: ExecutionClass,
|
|
pub inputs: &'static [InputSocketContract],
|
|
pub outputs: &'static [OutputSocketContract],
|
|
pub inherently_observable: bool,
|
|
#[serde(skip)]
|
|
pub fullscreen_policy: Option<FullscreenPolicy>,
|
|
}
|
|
impl Contract {
|
|
pub const fn is_raster_draw(&self) -> bool {
|
|
matches!(self.execution, ExecutionClass::Render) && self.fullscreen_policy.is_none()
|
|
}
|
|
}
|
|
|
|
use SemanticType::*;
|
|
const R: InputCardinality = InputCardinality { min: 1, max: 1 };
|
|
const O: InputCardinality = InputCardinality { min: 0, max: 1 };
|
|
const V: InputCardinality = InputCardinality { min: 0, max: 8 };
|
|
const fn i(
|
|
name: &'static str,
|
|
ty: SemanticType,
|
|
cardinality: InputCardinality,
|
|
role: InputRole,
|
|
) -> InputSocketContract {
|
|
let default_policy = match (cardinality.min, cardinality.max) {
|
|
(_, 2..) => InputDefaultPolicy::None,
|
|
(1, _) => InputDefaultPolicy::None,
|
|
_ => match role {
|
|
InputRole::ColorTarget { .. } | InputRole::DepthTarget => {
|
|
InputDefaultPolicy::CompilerTexture
|
|
}
|
|
_ => InputDefaultPolicy::ParameterLiteral,
|
|
},
|
|
};
|
|
InputSocketContract {
|
|
name,
|
|
accepted: TypeConstraint::Exact(ty),
|
|
cardinality,
|
|
default_policy,
|
|
role,
|
|
}
|
|
}
|
|
const fn o(name: &'static str, semantic_type: SemanticType) -> OutputSocketContract {
|
|
OutputSocketContract {
|
|
name,
|
|
semantic_type,
|
|
}
|
|
}
|
|
const NONE_I: &[InputSocketContract] = &[];
|
|
const NONE_O: &[OutputSocketContract] = &[];
|
|
const MESH_O: &[OutputSocketContract] = &[
|
|
o("mesh", MeshData),
|
|
o("type", U32x16),
|
|
o("localAabb", LocalAabb),
|
|
];
|
|
const TEXTURE_O: &[OutputSocketContract] = &[o("texture", Texture)];
|
|
const RASTER_I: &[InputSocketContract] = &[
|
|
i("mesh", MeshData, R, InputRole::SemanticRead),
|
|
i("predicate", Bool, O, InputRole::Expression),
|
|
i(
|
|
"colorTarget",
|
|
Texture,
|
|
O,
|
|
InputRole::ColorTarget { location: 0 },
|
|
),
|
|
i("depthTarget", Texture, O, InputRole::DepthTarget),
|
|
];
|
|
const RASTER_O: &[OutputSocketContract] = &[o("color", Texture), o("depth", Texture)];
|
|
const CULL_I: &[InputSocketContract] = &[
|
|
i("mesh", MeshData, R, InputRole::Expression),
|
|
i("localAabb", LocalAabb, R, InputRole::Expression),
|
|
];
|
|
const CULL_O: &[OutputSocketContract] = &[o("isFrustumCulled", Bool)];
|
|
const COPY_I: &[InputSocketContract] = &[
|
|
i("source", Texture, R, InputRole::SampledTexture),
|
|
i(
|
|
"colorTarget",
|
|
Texture,
|
|
R,
|
|
InputRole::ColorTarget { location: 0 },
|
|
),
|
|
];
|
|
const BLOOM_I: &[InputSocketContract] = &[
|
|
i("source", Texture, R, InputRole::SampledTexture),
|
|
i("bloom", Texture, R, InputRole::SampledTexture),
|
|
i(
|
|
"colorTarget",
|
|
Texture,
|
|
R,
|
|
InputRole::ColorTarget { location: 0 },
|
|
),
|
|
];
|
|
const COLOR_O: &[OutputSocketContract] = &[o("color", Texture)];
|
|
const FRAME_I: &[InputSocketContract] = &[i("color", Texture, R, InputRole::SampledTexture)];
|
|
macro_rules! ins { ($($n:literal:$t:ident),*) => { &[$(i($n,$t,O,InputRole::Expression)),*] } }
|
|
macro_rules! outs { ($($n:literal:$t:ident),*) => { &[$(o($n,$t)),*] } }
|
|
macro_rules! c {
|
|
($k:literal,$v:expr,$e:ident,$ins:expr,$outs:expr,$obs:expr,$policy:expr) => {
|
|
Contract {
|
|
key: $k,
|
|
version: $v,
|
|
execution: ExecutionClass::$e,
|
|
inputs: $ins,
|
|
outputs: $outs,
|
|
inherently_observable: $obs,
|
|
fullscreen_policy: $policy,
|
|
}
|
|
};
|
|
}
|
|
macro_rules! ex {
|
|
($k:literal,$ins:expr,$outs:expr) => {
|
|
c!($k, 1, Expression, $ins, $outs, false, None)
|
|
};
|
|
}
|
|
const BOOL_VARIADIC_I: &[InputSocketContract] = &[i("inputs", Bool, V, InputRole::Expression)];
|
|
|
|
pub static CONTRACTS: &[Contract] = &[
|
|
c!("mesh", 2, Source, NONE_I, MESH_O, false, None),
|
|
c!("texture", 2, Source, NONE_I, TEXTURE_O, false, None),
|
|
c!("frustum_cull", 2, Expression, CULL_I, CULL_O, false, None),
|
|
c!("ground_plane", 1, Render, RASTER_I, RASTER_O, false, None),
|
|
c!("gltf_standard", 1, Render, RASTER_I, RASTER_O, false, None),
|
|
c!(
|
|
"gltf_standard_double_sided",
|
|
1,
|
|
Render,
|
|
RASTER_I,
|
|
RASTER_O,
|
|
false,
|
|
None
|
|
),
|
|
c!(
|
|
"and",
|
|
2,
|
|
Expression,
|
|
BOOL_VARIADIC_I,
|
|
outs!("value":Bool),
|
|
false,
|
|
None
|
|
),
|
|
c!(
|
|
"or",
|
|
2,
|
|
Expression,
|
|
BOOL_VARIADIC_I,
|
|
outs!("value":Bool),
|
|
false,
|
|
None
|
|
),
|
|
ex!("not", ins!("operand":Bool), outs!("value":Bool)),
|
|
c!(
|
|
"xor",
|
|
2,
|
|
Expression,
|
|
BOOL_VARIADIC_I,
|
|
outs!("value":Bool),
|
|
false,
|
|
None
|
|
),
|
|
c!(
|
|
"xnor",
|
|
2,
|
|
Expression,
|
|
BOOL_VARIADIC_I,
|
|
outs!("value":Bool),
|
|
false,
|
|
None
|
|
),
|
|
ex!(
|
|
"greater_than_f32",
|
|
ins!("left":F32,"right":F32),
|
|
outs!("value":Bool)
|
|
),
|
|
ex!(
|
|
"less_than_f32",
|
|
ins!("left":F32,"right":F32),
|
|
outs!("value":Bool)
|
|
),
|
|
ex!(
|
|
"equals_f32",
|
|
ins!("left":F32,"right":F32),
|
|
outs!("value":Bool)
|
|
),
|
|
ex!(
|
|
"greater_than_u32",
|
|
ins!("left":U32,"right":U32),
|
|
outs!("value":Bool)
|
|
),
|
|
ex!(
|
|
"less_than_u32",
|
|
ins!("left":U32,"right":U32),
|
|
outs!("value":Bool)
|
|
),
|
|
ex!(
|
|
"equals_u32",
|
|
ins!("left":U32,"right":U32),
|
|
outs!("value":Bool)
|
|
),
|
|
ex!("separate_vec2", ins!("vector":Vec2), outs!("x":F32,"y":F32)),
|
|
ex!("combine_vec2", ins!("x":F32,"y":F32), outs!("vector":Vec2)),
|
|
ex!(
|
|
"separate_vec3",
|
|
ins!("vector":Vec3),
|
|
outs!("x":F32,"y":F32,"z":F32)
|
|
),
|
|
ex!(
|
|
"combine_vec3",
|
|
ins!("x":F32,"y":F32,"z":F32),
|
|
outs!("vector":Vec3)
|
|
),
|
|
ex!(
|
|
"separate_vec4",
|
|
ins!("vector":Vec4),
|
|
outs!("x":F32,"y":F32,"z":F32,"w":F32)
|
|
),
|
|
ex!(
|
|
"combine_vec4",
|
|
ins!("x":F32,"y":F32,"z":F32,"w":F32),
|
|
outs!("vector":Vec4)
|
|
),
|
|
ex!(
|
|
"separate_mat2",
|
|
ins!("matrix":Mat2),
|
|
outs!("column0":Vec2,"column1":Vec2)
|
|
),
|
|
ex!(
|
|
"combine_mat2",
|
|
ins!("column0":Vec2,"column1":Vec2),
|
|
outs!("matrix":Mat2)
|
|
),
|
|
ex!(
|
|
"separate_mat3",
|
|
ins!("matrix":Mat3),
|
|
outs!("column0":Vec3,"column1":Vec3,"column2":Vec3)
|
|
),
|
|
ex!(
|
|
"combine_mat3",
|
|
ins!("column0":Vec3,"column1":Vec3,"column2":Vec3),
|
|
outs!("matrix":Mat3)
|
|
),
|
|
ex!(
|
|
"separate_mat4",
|
|
ins!("matrix":Mat4),
|
|
outs!("column0":Vec4,"column1":Vec4,"column2":Vec4,"column3":Vec4)
|
|
),
|
|
ex!(
|
|
"combine_mat4",
|
|
ins!("column0":Vec4,"column1":Vec4,"column2":Vec4,"column3":Vec4),
|
|
outs!("matrix":Mat4)
|
|
),
|
|
ex!(
|
|
"separate_u32x16",
|
|
ins!("value":U32x16),
|
|
outs!("word0":U32,"word1":U32,"word2":U32,"word3":U32,"word4":U32,"word5":U32,"word6":U32,"word7":U32,"word8":U32,"word9":U32,"word10":U32,"word11":U32,"word12":U32,"word13":U32,"word14":U32,"word15":U32)
|
|
),
|
|
ex!(
|
|
"combine_u32x16",
|
|
ins!("word0":U32,"word1":U32,"word2":U32,"word3":U32,"word4":U32,"word5":U32,"word6":U32,"word7":U32,"word8":U32,"word9":U32,"word10":U32,"word11":U32,"word12":U32,"word13":U32,"word14":U32,"word15":U32),
|
|
outs!("value":U32x16)
|
|
),
|
|
ex!(
|
|
"separate_u32_bits",
|
|
ins!("value":U32),
|
|
outs!("bit0":Bool,"bit1":Bool,"bit2":Bool,"bit3":Bool,"bit4":Bool,"bit5":Bool,"bit6":Bool,"bit7":Bool,"bit8":Bool,"bit9":Bool,"bit10":Bool,"bit11":Bool,"bit12":Bool,"bit13":Bool,"bit14":Bool,"bit15":Bool,"bit16":Bool,"bit17":Bool,"bit18":Bool,"bit19":Bool,"bit20":Bool,"bit21":Bool,"bit22":Bool,"bit23":Bool,"bit24":Bool,"bit25":Bool,"bit26":Bool,"bit27":Bool,"bit28":Bool,"bit29":Bool,"bit30":Bool,"bit31":Bool)
|
|
),
|
|
ex!(
|
|
"combine_u32_bits",
|
|
ins!("bit0":Bool,"bit1":Bool,"bit2":Bool,"bit3":Bool,"bit4":Bool,"bit5":Bool,"bit6":Bool,"bit7":Bool,"bit8":Bool,"bit9":Bool,"bit10":Bool,"bit11":Bool,"bit12":Bool,"bit13":Bool,"bit14":Bool,"bit15":Bool,"bit16":Bool,"bit17":Bool,"bit18":Bool,"bit19":Bool,"bit20":Bool,"bit21":Bool,"bit22":Bool,"bit23":Bool,"bit24":Bool,"bit25":Bool,"bit26":Bool,"bit27":Bool,"bit28":Bool,"bit29":Bool,"bit30":Bool,"bit31":Bool),
|
|
outs!("value":U32)
|
|
),
|
|
ex!(
|
|
"separate_local_aabb",
|
|
ins!("value":LocalAabb),
|
|
outs!("min":Vec3,"max":Vec3)
|
|
),
|
|
c!(
|
|
"fullscreen_copy",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::Copy)
|
|
),
|
|
c!(
|
|
"color_balance",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::HdrSameExtent)
|
|
),
|
|
c!(
|
|
"exposure_contrast",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::HdrSameExtent)
|
|
),
|
|
c!(
|
|
"saturation",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::HdrSameExtent)
|
|
),
|
|
c!(
|
|
"channel_mixer",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::HdrSameExtent)
|
|
),
|
|
c!(
|
|
"bloom_extract",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::BloomExtract)
|
|
),
|
|
c!(
|
|
"bloom_blur",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::HdrSameExtent)
|
|
),
|
|
c!(
|
|
"bloom_composite",
|
|
1,
|
|
Render,
|
|
BLOOM_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::BloomComposite)
|
|
),
|
|
c!(
|
|
"luminance_edge",
|
|
1,
|
|
Render,
|
|
COPY_I,
|
|
COLOR_O,
|
|
false,
|
|
Some(FullscreenPolicy::HdrSameExtent)
|
|
),
|
|
c!("frame_out", 3, Frame, FRAME_I, NONE_O, true, None),
|
|
];
|
|
pub fn contract(key: &str) -> Option<&'static Contract> {
|
|
CONTRACTS.iter().find(|c| c.key == key)
|
|
}
|