feat: replace mesh queries with typed predicates

Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab

Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-07-28 20:37:44 +00:00
co-authored by heaust
parent c7ffb0543e
commit f6d6af7a17
36 changed files with 2793 additions and 6973 deletions
+278 -318
View File
@@ -1,27 +1,35 @@
use super::MeshFlag;
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SemanticType {
MeshData,
Texture,
LocalAabbBuffer,
BooleanFlagBuffer,
PipelineIndexStream,
PipelineActivation,
DrawStream,
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,
CpuPreparation,
Compute,
Expression,
Render,
Frame,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FullscreenPolicy {
Copy,
@@ -29,21 +37,18 @@ pub enum FullscreenPolicy {
BloomExtract,
BloomComposite,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum InputCardinality {
RequiredOne,
OptionalOne,
}
#[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 {
@@ -54,15 +59,8 @@ pub enum InputRole {
SampledTexture,
ColorTarget { location: u32 },
DepthTarget,
Expression,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum OutputMetadata {
None,
BooleanFlag { flag: MeshFlag },
}
#[derive(Clone, Copy, Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct InputSocketContract {
@@ -71,15 +69,12 @@ pub struct InputSocketContract {
pub cardinality: InputCardinality,
pub role: InputRole,
}
#[derive(Clone, Copy, Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct OutputSocketContract {
pub name: &'static str,
pub semantic_type: SemanticType,
pub metadata: OutputMetadata,
}
#[derive(Clone, Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Contract {
@@ -94,329 +89,294 @@ pub struct Contract {
}
use SemanticType::*;
const fn input(
const R: InputCardinality = InputCardinality::RequiredOne;
const O: InputCardinality = InputCardinality::OptionalOne;
const fn i(
name: &'static str,
accepted: TypeConstraint,
ty: SemanticType,
cardinality: InputCardinality,
role: InputRole,
) -> InputSocketContract {
InputSocketContract {
name,
accepted,
accepted: TypeConstraint::Exact(ty),
cardinality,
role,
}
}
const fn output(
name: &'static str,
semantic_type: SemanticType,
metadata: OutputMetadata,
) -> OutputSocketContract {
const fn o(name: &'static str, semantic_type: SemanticType) -> OutputSocketContract {
OutputSocketContract {
name,
semantic_type,
metadata,
}
}
const REQUIRED: InputCardinality = InputCardinality::RequiredOne;
const OPTIONAL: InputCardinality = InputCardinality::OptionalOne;
const NONE_IN: &[InputSocketContract] = &[];
const NONE_OUT: &[OutputSocketContract] = &[];
const TEXTURE_OUT: &[OutputSocketContract] = &[output("texture", Texture, OutputMetadata::None)];
const MESH_OUT: &[OutputSocketContract] = &[
output("mesh", MeshData, OutputMetadata::None),
output("localAabbs", LocalAabbBuffer, OutputMetadata::None),
output(
"isVisible",
BooleanFlagBuffer,
OutputMetadata::BooleanFlag {
flag: MeshFlag::IsVisible,
},
),
output("pipelineIndices", PipelineIndexStream, OutputMetadata::None),
const NONE_I: &[InputSocketContract] = &[];
const NONE_O: &[OutputSocketContract] = &[];
const MESH_O: &[OutputSocketContract] = &[
o("mesh", MeshData),
o("type", U32x16),
o("localAabb", LocalAabb),
];
const CULLED_OUT: &[OutputSocketContract] = &[output(
"isFrustumCulled",
BooleanFlagBuffer,
OutputMetadata::BooleanFlag {
flag: MeshFlag::IsFrustumCulled,
},
)];
const DRAW_OUT: &[OutputSocketContract] = &[output("draws", DrawStream, OutputMetadata::None)];
const ACTIVATION_OUT: &[OutputSocketContract] = &[output(
"activation",
PipelineActivation,
OutputMetadata::None,
)];
const PIPELINE_OUT: &[OutputSocketContract] = &[
output("color", Texture, OutputMetadata::None),
output("depth", Texture, OutputMetadata::None),
];
const FULLSCREEN_COPY_OUT: &[OutputSocketContract] =
&[output("color", Texture, OutputMetadata::None)];
const CULL_IN: &[InputSocketContract] = &[
input(
"mesh",
TypeConstraint::Exact(MeshData),
REQUIRED,
InputRole::StorageRead,
),
input(
"localAabbs",
TypeConstraint::Exact(LocalAabbBuffer),
REQUIRED,
InputRole::StorageRead,
),
];
const QUERY_IN: &[InputSocketContract] = &[
input(
"mesh",
TypeConstraint::Exact(MeshData),
REQUIRED,
InputRole::StorageRead,
),
input(
"isVisible",
TypeConstraint::Exact(BooleanFlagBuffer),
OPTIONAL,
InputRole::StorageRead,
),
input(
"isFrustumCulled",
TypeConstraint::Exact(BooleanFlagBuffer),
OPTIONAL,
InputRole::StorageRead,
),
];
const REGISTRY_IN: &[InputSocketContract] = &[input(
"pipelineIndices",
TypeConstraint::Exact(PipelineIndexStream),
REQUIRED,
InputRole::SemanticRead,
)];
const PIPELINE_IN: &[InputSocketContract] = &[
input(
"mesh",
TypeConstraint::Exact(MeshData),
REQUIRED,
InputRole::SemanticRead,
),
input(
"draws",
TypeConstraint::Exact(DrawStream),
REQUIRED,
InputRole::IndirectRead,
),
input(
"activation",
TypeConstraint::Exact(PipelineActivation),
REQUIRED,
InputRole::SemanticRead,
),
input(
const TEXTURE_O: &[OutputSocketContract] = &[o("texture", Texture)];
const PIPE_I: &[InputSocketContract] = &[
i("mesh", MeshData, R, InputRole::SemanticRead),
i("predicate", Bool, O, InputRole::Expression),
i(
"colorTarget",
TypeConstraint::Exact(Texture),
REQUIRED,
Texture,
R,
InputRole::ColorTarget { location: 0 },
),
input(
"depthTarget",
TypeConstraint::Exact(Texture),
REQUIRED,
InputRole::DepthTarget,
),
i("depthTarget", Texture, R, InputRole::DepthTarget),
];
const FULLSCREEN_COPY_IN: &[InputSocketContract] = &[
input(
"source",
TypeConstraint::Exact(Texture),
REQUIRED,
InputRole::SampledTexture,
),
input(
const PIPE_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",
TypeConstraint::Exact(Texture),
REQUIRED,
Texture,
R,
InputRole::ColorTarget { location: 0 },
),
];
const BLOOM_COMPOSITE_IN: &[InputSocketContract] = &[
input(
"source",
TypeConstraint::Exact(Texture),
REQUIRED,
InputRole::SampledTexture,
),
input(
"bloom",
TypeConstraint::Exact(Texture),
REQUIRED,
InputRole::SampledTexture,
),
input(
const BLOOM_I: &[InputSocketContract] = &[
i("source", Texture, R, InputRole::SampledTexture),
i("bloom", Texture, R, InputRole::SampledTexture),
i(
"colorTarget",
TypeConstraint::Exact(Texture),
REQUIRED,
Texture,
R,
InputRole::ColorTarget { location: 0 },
),
];
const FRAME_OUT_IN: &[InputSocketContract] = &[input(
"color",
TypeConstraint::Exact(Texture),
REQUIRED,
InputRole::SampledTexture,
)];
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)
};
}
pub static CONTRACTS: &[Contract] = &[
Contract {
key: "mesh",
version: 1,
execution: ExecutionClass::Source,
inputs: NONE_IN,
outputs: MESH_OUT,
inherently_observable: false,
fullscreen_policy: None,
},
Contract {
key: "texture",
version: 1,
execution: ExecutionClass::Source,
inputs: NONE_IN,
outputs: TEXTURE_OUT,
inherently_observable: false,
fullscreen_policy: None,
},
Contract {
key: "frustum_cull",
version: 1,
execution: ExecutionClass::Compute,
inputs: CULL_IN,
outputs: CULLED_OUT,
inherently_observable: false,
fullscreen_policy: None,
},
Contract {
key: "mesh_query",
version: 1,
execution: ExecutionClass::Compute,
inputs: QUERY_IN,
outputs: DRAW_OUT,
inherently_observable: false,
fullscreen_policy: None,
},
Contract {
key: "pipeline_registry",
version: 1,
execution: ExecutionClass::CpuPreparation,
inputs: REGISTRY_IN,
outputs: ACTIVATION_OUT,
inherently_observable: false,
fullscreen_policy: None,
},
Contract {
key: "pipeline",
version: 1,
execution: ExecutionClass::Render,
inputs: PIPELINE_IN,
outputs: PIPELINE_OUT,
inherently_observable: false,
fullscreen_policy: None,
},
Contract {
key: "fullscreen_copy",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::Copy),
},
Contract {
key: "color_balance",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::HdrSameExtent),
},
Contract {
key: "exposure_contrast",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::HdrSameExtent),
},
Contract {
key: "saturation",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::HdrSameExtent),
},
Contract {
key: "channel_mixer",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::HdrSameExtent),
},
Contract {
key: "bloom_extract",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::BloomExtract),
},
Contract {
key: "bloom_blur",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::HdrSameExtent),
},
Contract {
key: "bloom_composite",
version: 1,
execution: ExecutionClass::Render,
inputs: BLOOM_COMPOSITE_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::BloomComposite),
},
Contract {
key: "luminance_edge",
version: 1,
execution: ExecutionClass::Render,
inputs: FULLSCREEN_COPY_IN,
outputs: FULLSCREEN_COPY_OUT,
inherently_observable: false,
fullscreen_policy: Some(FullscreenPolicy::HdrSameExtent),
},
Contract {
key: "frame_out",
version: 3,
execution: ExecutionClass::Frame,
inputs: FRAME_OUT_IN,
outputs: NONE_OUT,
inherently_observable: true,
fullscreen_policy: None,
},
c!("mesh", 2, Source, NONE_I, MESH_O, false, None),
c!("texture", 1, Source, NONE_I, TEXTURE_O, false, None),
c!("frustum_cull", 2, Expression, CULL_I, CULL_O, false, None),
c!("pipeline", 2, Render, PIPE_I, PIPE_O, false, None),
ex!("and", ins!("left":Bool,"right":Bool), outs!("value":Bool)),
ex!("or", ins!("left":Bool,"right":Bool), outs!("value":Bool)),
ex!("not", ins!("operand":Bool), outs!("value":Bool)),
ex!("xor", ins!("left":Bool,"right":Bool), outs!("value":Bool)),
ex!("xnor", ins!("left":Bool,"right":Bool), outs!("value":Bool)),
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(|contract| contract.key == key)
CONTRACTS.iter().find(|c| c.key == key)
}