feat: get full evaluation back online
Very hacky, but this is enough to be finished with the graph IR for now.
This commit is contained in:
parent
3c529c3a1a
commit
3e208335c3
9 changed files with 105 additions and 26 deletions
|
@ -1,31 +1,39 @@
|
|||
use std::mem;
|
||||
|
||||
use ir::{
|
||||
id,
|
||||
instruction::{Filter, Kind},
|
||||
GraphIr, Instruction, InstructionRef,
|
||||
GraphIr, Instruction, Map,
|
||||
};
|
||||
|
||||
use crate::value::Dynamic;
|
||||
use crate::value::Variant;
|
||||
mod instr;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Evaluator {
|
||||
ir: GraphIr,
|
||||
|
||||
/// What the output of each individual streamer, and as result its output sockets, is.
|
||||
/// Grows larger as evaluation continues,
|
||||
/// as there's no mechanism for purging never-to-be-used-anymore instructions yet.
|
||||
evaluated: Map<id::Output, Variant>,
|
||||
}
|
||||
|
||||
impl crate::Evaluator for Evaluator {
|
||||
fn feed(&mut self, ir: GraphIr) {
|
||||
// TODO: should add instead of replace, see note in Evaluator trait above this method
|
||||
self.ir = ir;
|
||||
self.evaluated.clear();
|
||||
}
|
||||
|
||||
fn eval_full(&mut self) {
|
||||
// GraphIr::topological_sort returns InstructionRefs, which are mostly cool
|
||||
// but we'd like to have them owned, so we can call Self::step without lifetime hassle
|
||||
let queue: Vec<Instruction> = self
|
||||
.ir
|
||||
.topological_sort()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
|
||||
for instr in queue {
|
||||
self.step(instr);
|
||||
}
|
||||
|
@ -35,23 +43,64 @@ impl crate::Evaluator for Evaluator {
|
|||
impl Evaluator {
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
fn step(&mut self, instr: Instruction) {
|
||||
let _ = match instr.kind {
|
||||
Kind::Read(details) => Some(Dynamic::Image(instr::read::read(details))),
|
||||
// what inputs does this instr need? fetch them
|
||||
let inputs: Vec<_> = instr
|
||||
.input_sources()
|
||||
.iter()
|
||||
.map(|source| {
|
||||
let source_socket = source
|
||||
.as_ref()
|
||||
.expect("all inputs to be connected when an instruction is ran");
|
||||
self.evaluated
|
||||
.get(source_socket)
|
||||
.expect("toposort to yield later instrs only after previous ones")
|
||||
})
|
||||
.collect();
|
||||
|
||||
// then actually do whatever the instruction should do
|
||||
// NOTE: makes heavy use of index slicing,
|
||||
// on the basis that ir::instruction::Kind::socket_count is correct
|
||||
// TODO: make this a more flexible dispatch-ish arch
|
||||
let output = match instr.kind {
|
||||
Kind::Read(details) => Some(Variant::Image(instr::read::read(details))),
|
||||
Kind::Write(details) => {
|
||||
instr::write::write(details, todo!());
|
||||
#[allow(irrefutable_let_patterns)] // will necessarily change
|
||||
let Variant::Image(input) = inputs[0] else {
|
||||
panic!("cannot only write images, but received: `{:?}`", inputs[0]);
|
||||
};
|
||||
instr::write::write(details, input);
|
||||
None
|
||||
}
|
||||
Kind::Math(_) => todo!(),
|
||||
Kind::Blend(_) => todo!(),
|
||||
Kind::Noise(_) => todo!(),
|
||||
Kind::Filter(filter_instruction) => match filter_instruction {
|
||||
Filter::Invert => Some(Dynamic::Image(instr::filters::invert::invert(
|
||||
match todo!() {
|
||||
Some(Dynamic::Image(img)) => img,
|
||||
_ => panic!("invalid value type for invert"),
|
||||
},
|
||||
))),
|
||||
Filter::Invert => {
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
let Variant::Image(input) = inputs[0] else {
|
||||
panic!(
|
||||
"cannot only filter invert images, but received: `{:?}`",
|
||||
inputs[0]
|
||||
);
|
||||
};
|
||||
|
||||
Some(Variant::Image(instr::filters::invert::invert(
|
||||
input.clone(),
|
||||
)))
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if let Some(output) = output {
|
||||
// TODO: very inaccurate, actually respect individual instructions.
|
||||
// should be implied by a different arch
|
||||
// TODO: all of those should not be public, offer some methods to get this on
|
||||
// `Instruction` instead (can infer short-term based on Kind::socket_count)
|
||||
let socket = id::Output(id::Socket {
|
||||
belongs_to: instr.id,
|
||||
idx: id::SocketIdx(0),
|
||||
});
|
||||
self.evaluated.insert(socket, output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
use image::DynamicImage;
|
||||
|
||||
pub enum Dynamic {
|
||||
/// Any runtime value that an instruction can input or output.
|
||||
///
|
||||
/// The name is taken from [Godot's `Variant` type],
|
||||
/// which is very similar to this one.
|
||||
///
|
||||
/// [Godot's `Variant` type]: https://docs.godotengine.org/en/stable/classes/class_variant.html
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Variant {
|
||||
Image(DynamicImage),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue