Skip to content

Commit

Permalink
Fix child graphs (#32)
Browse files Browse the repository at this point in the history
* Remove midi store from traverser

* PolyphonicNode refactor pre-testing

* Overdue node api refactor

* WIP

* Fix unsafe behavior

* Uhh, WIP
  • Loading branch information
smj-edison authored Feb 5, 2024
1 parent 37fb8b8 commit 83dfc36
Show file tree
Hide file tree
Showing 62 changed files with 2,282 additions and 909 deletions.
205 changes: 111 additions & 94 deletions vpo-backend/Cargo.lock

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion vpo-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ snafu = "0.7"
sound-engine = { path = "./sound-engine" }
toml_edit = { version = "0.19.8", features = ["serde"] }
petgraph = { version = "0.6.0", features = ["serde-1"] }
clocked = "0.7.0"
clocked = "0.8.0"
rayon = "1.8.0"
flume = "0.11.0"
generational-arena = "0.2.9"
Expand All @@ -39,6 +39,11 @@ thread-priority = "0.15.1"
seahash = "4.1.0"
log = "0.4.20"
env_logger = "0.10.1"
ddgg = { git = "https://github.com/smj-edison/ddgg", features = [
"js_names",
"serde",
"serde_string_indexes",
] }

[lib]
crate-type = ["cdylib", "lib"]
Expand Down
18 changes: 9 additions & 9 deletions vpo-backend/common/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use buddy_system_allocator::Heap;

pub struct Alloc<'a, T> {
pub value: &'a mut T,
buddy_ref: &'a BuddyArena,
buddy_ref: &'a BuddyAlloc,
ptr: NonNull<u8>,
layout: Layout,
}
Expand All @@ -37,7 +37,7 @@ impl<'a, T> Drop for Alloc<'a, T> {

pub struct SliceAlloc<'a, T> {
pub value: &'a mut [T],
buddy_ref: &'a BuddyArena,
buddy_ref: &'a BuddyAlloc,
ptr: NonNull<u8>,
layout: Layout,
}
Expand All @@ -58,17 +58,17 @@ impl<'a, T> Drop for SliceAlloc<'a, T> {
}
}

unsafe { &mut *self.buddy_ref.heap.get() }.dealloc(self.ptr, self.layout)
unsafe { &mut *self.buddy_ref.heap.get() }.dealloc(self.ptr, self.layout);
}
}

pub struct BuddyArena {
pub struct BuddyAlloc {
_space: Vec<usize>,
heap: UnsafeCell<Heap<32>>,
}

impl BuddyArena {
pub fn new(bytes: usize) -> BuddyArena {
impl BuddyAlloc {
pub fn new(bytes: usize) -> BuddyAlloc {
let size = bytes / size_of::<usize>();

let mut heap = Heap::<32>::new();
Expand All @@ -78,13 +78,13 @@ impl BuddyArena {
heap.init(space.as_slice().as_ptr() as usize, size * size_of::<usize>());
}

BuddyArena {
BuddyAlloc {
_space: space,
heap: UnsafeCell::new(heap),
}
}

// most methods from here on out are taken from the fantastic `bumpalo` crate
// most methods from here on out are adapted from the fantastic `bumpalo` crate

pub fn alloc_with<'a, T, F>(&'a self, f: F) -> Result<Alloc<'a, T>, AllocError>
where
Expand Down Expand Up @@ -170,7 +170,7 @@ impl BuddyArena {

#[test]
fn test_alloc() {
let arena = BuddyArena::new(1_000_000);
let arena = BuddyAlloc::new(1_000_000);

let hello = arena.alloc_with(|| "hello").unwrap();
let world = arena.alloc_with(|| "world").unwrap();
Expand Down
2 changes: 1 addition & 1 deletion vpo-backend/node-engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ wasm-bindgen = "0.2.84"
self_cell = "1.0.1"
generational-arena = "0.2.9"
recycle_vec = "1.0.4"
clocked = "0.7.0"
clocked = "0.8.0"
seahash = "4.1.0"

[target.'cfg(target_arch="wasm32")'.dependencies]
Expand Down
21 changes: 17 additions & 4 deletions vpo-backend/node-engine/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub enum SocketType {
NodeRef,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[serde(tag = "variant", content = "data")]
pub enum SocketDirection {
Input,
Expand All @@ -78,6 +78,7 @@ pub enum Primitive {
Float(f32),
Int(i32),
Boolean(bool),
Bang,
None,
}

Expand Down Expand Up @@ -130,7 +131,8 @@ impl Primitive {
Primitive::Float(float) => Some(*float),
Primitive::Int(int) => Some(*int as f32),
Primitive::Boolean(boolean) => Some(if *boolean { 1.0 } else { 0.0 }),
_ => None,
Primitive::Bang => Some(1.0),
Primitive::None => None,
}
}

Expand All @@ -140,7 +142,8 @@ impl Primitive {
Primitive::Float(float) => Some(*float as i32),
Primitive::Int(int) => Some(*int),
Primitive::Boolean(boolean) => Some(i32::from(*boolean)),
_ => None,
Primitive::Bang => Some(1),
Primitive::None => None,
}
}

Expand All @@ -150,7 +153,16 @@ impl Primitive {
Primitive::Float(float) => Some(*float > 0.01),
Primitive::Int(int) => Some(*int > 0),
Primitive::Boolean(boolean) => Some(*boolean),
_ => None,
Primitive::Bang => Some(true),
Primitive::None => None,
}
}

#[inline]
pub fn as_bang(&self) -> Option<()> {
match self {
Primitive::None => None,
_ => Some(()),
}
}

Expand All @@ -160,6 +172,7 @@ impl Primitive {
Primitive::Float(float) => Dynamic::from(float),
Primitive::Int(int) => Dynamic::from(int),
Primitive::Boolean(boolean) => Dynamic::from(boolean),
Primitive::Bang => Dynamic::from("bang"),
Primitive::None => Dynamic::from(()),
}
}
Expand Down
173 changes: 156 additions & 17 deletions vpo-backend/node-engine/src/graph_manager.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use std::ops::{Index, IndexMut};

use common::SeaHashMap;
use ddgg::{EdgeIndex, Graph, GraphDiff, VertexIndex};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use snafu::OptionExt;
use snafu::{OptionExt, ResultExt};

use crate::connection::Socket;
use crate::errors::{GraphDoesNotExistSnafu, NodeError, NodeOk, NodeResult};
use crate::node::NodeGraphAndIo;
use crate::connection::{Socket, SocketDirection};
use crate::errors::{GraphDoesNotExistSnafu, NodeDoesNotExistSnafu, NodeError, NodeOk, NodeResult};
use crate::node::NodeGetIoContext;
use crate::node_graph::NodeGraphDiff;
use crate::node_instance::NodeInstance;
use crate::nodes::variant_io;
use crate::state::ActionInvalidation;
use crate::{node::NodeIndex, node_graph::NodeGraph};

Expand Down Expand Up @@ -194,6 +197,111 @@ impl GraphManager {

Ok(mapped)
}

pub fn update_node(&mut self, index: GlobalNodeIndex, new: NodeInstance) -> Result<GraphManagerDiff, NodeError> {
let mut diffs = vec![];

diffs.push(DiffElement::ChildGraphDiff(
index.graph_index,
self.get_graph_mut(index.graph_index)?
.update_node_no_row_updates(index.node_index, new)?,
));
diffs.extend(self.update_node_rows(index)?.0);

Ok(GraphManagerDiff(diffs))
}

pub fn update_node_rows(&mut self, index: GlobalNodeIndex) -> Result<GraphManagerDiff, NodeError> {
let graph = self.get_graph(index.graph_index)?;
let node = graph.get_node(index.node_index)?;

let ctx = self.create_get_io_context(index)?;
let new_rows = variant_io(&node.get_node_type(), ctx, node.get_properties().clone())?.node_rows;

let mut diffs = vec![];

let graph = self.get_graph_mut(index.graph_index)?;
let node = graph.get_node(index.node_index)?;

// it would be pretty silly to do anything if the rows are exactly the same
if *graph[index.node_index].get_node_rows() != new_rows {
// Figure out what rows were removed.
let removed: Vec<(Socket, SocketDirection)> = node
.get_node_rows()
.iter()
.filter(|&old_row| !new_rows.iter().any(|new_row| new_row == old_row))
.filter_map(|row| row.to_socket_and_direction().map(|x| (x.0.clone(), x.1)))
.collect();

// For any row that was removed, it needs to be disconnected (note we do all the disconnections
// _before_ we set the new node rows, that way disconnecting doesn't error out and our invariants
// stay all warm and fuzzy).
for input_connection in graph.get_input_side_connections(index.node_index)? {
if removed.iter().any(|(socket, direction)| {
socket == &input_connection.to_socket && direction == &SocketDirection::Input
}) {
let (_, diff) = graph.disconnect(
input_connection.from_node,
&input_connection.from_socket,
index.node_index,
&input_connection.to_socket,
)?;

diffs.push(diff);
}
}

for output_connection in graph.get_output_side_connections(index.node_index)? {
if removed.iter().any(|(socket, direction)| {
socket == &output_connection.to_socket && direction == &SocketDirection::Output
}) {
let (_, diff) = graph.disconnect(
index.node_index,
&output_connection.from_socket,
output_connection.to_node,
&output_connection.to_socket,
)?;

diffs.push(diff);
}
}

let mut modified_node = graph.get_node(index.node_index)?.clone();
modified_node.set_node_rows(new_rows);

diffs.push(graph.update_node_no_row_updates(index.node_index, modified_node)?);
}

Ok(GraphManagerDiff::from_graph_diffs(index.graph_index, diffs))
}

pub fn create_get_io_context(&self, index: GlobalNodeIndex) -> Result<NodeGetIoContext, NodeError> {
let graph = self.get_graph(index.graph_index)?.get_graph();
let vertex = graph.get_vertex(index.node_index.0).context(NodeDoesNotExistSnafu {
node_index: index.node_index,
})?;

let connected_inputs: Vec<Socket> = vertex
.get_connections_from()
.iter()
.map(|(_, connection)| graph[*connection].data().to_socket.clone())
.collect();
let connected_outputs: Vec<Socket> = vertex
.get_connections_to()
.iter()
.map(|(_, connection)| graph[*connection].data().from_socket.clone())
.collect();

Ok(NodeGetIoContext {
default_channel_count: self.default_channel_count,
connected_inputs,
connected_outputs,
child_graph: vertex
.data()
.get_child_graph()
.map(|index| self.get_graph(index).unwrap()),
})
}
}

impl GraphManager {
Expand Down Expand Up @@ -231,19 +339,12 @@ impl GraphManager {
diff.push(DiffElement::ChildGraphDiff(new_graph_index, inputs_diff));
diff.push(DiffElement::ChildGraphDiff(new_graph_index, outputs_diff));

NodeGraphAndIo {
graph_index: new_graph_index,
input_index: inputs_index,
output_index: outputs_index,
}
new_graph_index
};

// connect the two graphs together
let (_, connect_diff) = self.connect_graphs(
graph_index,
ConnectedThrough(new_node_index),
new_graph_index.graph_index,
)?;
let (_, connect_diff) =
self.connect_graphs(graph_index, ConnectedThrough(new_node_index), new_graph_index)?;
diff.extend(connect_diff.0);

Some(new_graph_index)
Expand Down Expand Up @@ -328,18 +429,28 @@ impl GraphManager {
let mut diff = vec![];

// first, see if the node has a child graph
let children = self
let children_of_graph = self
.node_graphs
.get_vertex(graph_index.0)
.with_context(|| GraphDoesNotExistSnafu {
graph_index: graph_index,
})?
.get_connections_to();

let child_graph = children_of_graph
.iter()
.find(|(_, connection)| {
self.node_graphs
.get_edge_data(*connection)
.map(|edge| edge.0 == node_index)
.unwrap_or(false)
})
.map(|(connected_to, _)| *connected_to);

// if it does have children, remove the connections
if !children.is_empty() {
if let Some(child_graph) = child_graph {
let (_, remove_diff) =
self.disconnect_graphs(graph_index, ConnectedThrough(node_index), GraphIndex(children[0].0))?;
self.disconnect_graphs(graph_index, ConnectedThrough(node_index), GraphIndex(child_graph))?;
diff.extend(remove_diff.0);
}

Expand Down Expand Up @@ -399,3 +510,31 @@ impl GraphManager {
Ok(invalidations)
}
}

impl Index<GraphIndex> for GraphManager {
type Output = NodeGraph;

fn index(&self, index: GraphIndex) -> &Self::Output {
self.get_graph(index).unwrap()
}
}

impl IndexMut<GraphIndex> for GraphManager {
fn index_mut(&mut self, index: GraphIndex) -> &mut Self::Output {
self.get_graph_mut(index).unwrap()
}
}

impl Index<GlobalNodeIndex> for GraphManager {
type Output = NodeInstance;

fn index(&self, index: GlobalNodeIndex) -> &Self::Output {
self.get_node(index).unwrap()
}
}

impl IndexMut<GlobalNodeIndex> for GraphManager {
fn index_mut(&mut self, index: GlobalNodeIndex) -> &mut Self::Output {
self.get_node_mut(index).unwrap()
}
}
1 change: 0 additions & 1 deletion vpo-backend/node-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ pub mod connection;
pub mod errors;
pub mod graph_manager;
pub mod io_routing;
pub mod midi_store;
pub mod node;
pub mod node_graph;
pub mod node_instance;
Expand Down
Loading

0 comments on commit 83dfc36

Please sign in to comment.