Allow printing proto graph in graphite-cli (#2388)
Allow disabling running of node network in graphite-cli It seems that graphite-cli currently crashes on some GPUs which do not support Vulkan. This commit improves the CLI, adding an option to disable running the node network, which prevents the crash (but also prevents any output from being shown). Change default log levels Restructure argument parsing
This commit is contained in:
parent
0a91dd2141
commit
85fac63bb2
|
|
@ -940,6 +940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
|
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -948,8 +949,22 @@ version = "4.5.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
|
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.5.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
||||||
|
dependencies = [
|
||||||
|
"heck 0.5.0",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2428,6 +2443,7 @@ dependencies = [
|
||||||
"bezier-rs",
|
"bezier-rs",
|
||||||
"bitflags 2.9.0",
|
"bitflags 2.9.0",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clap",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"fern",
|
"fern",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ image = { workspace = true, default-features = false, features = [
|
||||||
"png",
|
"png",
|
||||||
] }
|
] }
|
||||||
|
|
||||||
|
# Required dependencies
|
||||||
|
clap = { version = "4.5.31", features = ["cargo", "derive"] }
|
||||||
|
|
||||||
# Optional local dependencies
|
# Optional local dependencies
|
||||||
wgpu-executor = { path = "../wgpu-executor", optional = true }
|
wgpu-executor = { path = "../wgpu-executor", optional = true }
|
||||||
gpu-executor = { path = "../gpu-executor", optional = true }
|
gpu-executor = { path = "../gpu-executor", optional = true }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
use graph_craft::graphene_compiler::{Compiler, Executor};
|
use graph_craft::graphene_compiler::{Compiler, Executor};
|
||||||
|
use graph_craft::proto::ProtoNetwork;
|
||||||
use graph_craft::util::load_network;
|
use graph_craft::util::load_network;
|
||||||
use graph_craft::wasm_application_io::EditorPreferences;
|
use graph_craft::wasm_application_io::EditorPreferences;
|
||||||
use graphene_core::application_io::{ApplicationIo, NodeGraphUpdateSender};
|
use graphene_core::application_io::{ApplicationIo, NodeGraphUpdateSender};
|
||||||
|
|
@ -7,10 +8,11 @@ use graphene_core::text::FontCache;
|
||||||
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
||||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||||
|
|
||||||
|
use clap::{Args, Parser, Subcommand};
|
||||||
use fern::colors::{Color, ColoredLevelConfig};
|
use fern::colors::{Color, ColoredLevelConfig};
|
||||||
use futures::executor::block_on;
|
use futures::executor::block_on;
|
||||||
use interpreted_executor::util::wrap_network_in_scope;
|
use interpreted_executor::util::wrap_network_in_scope;
|
||||||
use std::{error::Error, sync::Arc};
|
use std::{error::Error, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
struct UpdateLogger {}
|
struct UpdateLogger {}
|
||||||
|
|
||||||
|
|
@ -20,57 +22,134 @@ impl NodeGraphUpdateSender for UpdateLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[clap(name = "graphene-cli", version)]
|
||||||
|
pub struct App {
|
||||||
|
#[clap(flatten)]
|
||||||
|
global_opts: GlobalOpts,
|
||||||
|
|
||||||
|
#[clap(subcommand)]
|
||||||
|
command: Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Subcommand)]
|
||||||
|
enum Command {
|
||||||
|
/// Help message for compile.
|
||||||
|
Compile {
|
||||||
|
/// Print proto network
|
||||||
|
#[clap(long, short = 'p')]
|
||||||
|
print_proto: bool,
|
||||||
|
|
||||||
|
/// Path to the .graphite document
|
||||||
|
document: PathBuf,
|
||||||
|
},
|
||||||
|
/// Help message for run.
|
||||||
|
Run {
|
||||||
|
/// Path to the .graphite document
|
||||||
|
document: PathBuf,
|
||||||
|
|
||||||
|
/// Path to the .graphite document
|
||||||
|
image: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Run the document in a loop. This is useful for spawning and maintaining a window
|
||||||
|
#[clap(long, short = 'l')]
|
||||||
|
run_loop: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Args)]
|
||||||
|
struct GlobalOpts {
|
||||||
|
/// Verbosity level (can be specified multiple times)
|
||||||
|
#[clap(long, short, global = true, action = clap::ArgAction::Count)]
|
||||||
|
verbose: u8,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn Error>> {
|
async fn main() -> Result<(), Box<dyn Error>> {
|
||||||
init_logging();
|
let app = App::parse();
|
||||||
|
|
||||||
let document_path = std::env::args().nth(1).expect("No document path provided");
|
let log_level = app.global_opts.verbose;
|
||||||
|
|
||||||
let image_path = std::env::args().nth(2);
|
init_logging(log_level);
|
||||||
|
|
||||||
let document_string = std::fs::read_to_string(&document_path).expect("Failed to read document");
|
let document_path = match app.command {
|
||||||
|
Command::Compile { ref document, .. } => document,
|
||||||
|
Command::Run { ref document, .. } => document,
|
||||||
|
};
|
||||||
|
|
||||||
println!("creating gpu context",);
|
let document_string = std::fs::read_to_string(document_path).expect("Failed to read document");
|
||||||
|
|
||||||
|
log::info!("creating gpu context",);
|
||||||
let mut application_io = block_on(WasmApplicationIo::new());
|
let mut application_io = block_on(WasmApplicationIo::new());
|
||||||
if let Some(image_path) = image_path {
|
|
||||||
|
if let Command::Run { image: Some(ref image_path), .. } = app.command {
|
||||||
application_io.resources.insert("null".to_string(), Arc::from(std::fs::read(image_path).expect("Failed to read image")));
|
application_io.resources.insert("null".to_string(), Arc::from(std::fs::read(image_path).expect("Failed to read image")));
|
||||||
}
|
}
|
||||||
|
|
||||||
let device = application_io.gpu_executor().unwrap().context.device.clone();
|
let device = application_io.gpu_executor().unwrap().context.device.clone();
|
||||||
std::thread::spawn(move || loop {
|
|
||||||
std::thread::sleep(std::time::Duration::from_nanos(10));
|
|
||||||
device.poll(wgpu::Maintain::Poll);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
let preferences = EditorPreferences {
|
||||||
|
use_vello: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
let editor_api = Arc::new(WasmEditorApi {
|
let editor_api = Arc::new(WasmEditorApi {
|
||||||
font_cache: FontCache::default(),
|
font_cache: FontCache::default(),
|
||||||
application_io: Some(application_io.into()),
|
application_io: Some(application_io.into()),
|
||||||
node_graph_message_sender: Box::new(UpdateLogger {}),
|
node_graph_message_sender: Box::new(UpdateLogger {}),
|
||||||
editor_preferences: Box::new(EditorPreferences::default()),
|
editor_preferences: Box::new(preferences),
|
||||||
});
|
});
|
||||||
|
|
||||||
let executor = create_executor(document_string, editor_api)?;
|
let proto_graph = compile_graph(document_string, editor_api)?;
|
||||||
|
|
||||||
|
match app.command {
|
||||||
|
Command::Compile { print_proto, .. } => {
|
||||||
|
if print_proto {
|
||||||
|
println!("{}", proto_graph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Command::Run { run_loop, .. } => {
|
||||||
|
std::thread::spawn(move || loop {
|
||||||
|
std::thread::sleep(std::time::Duration::from_nanos(10));
|
||||||
|
device.poll(wgpu::Maintain::Poll);
|
||||||
|
});
|
||||||
|
let executor = create_executor(proto_graph)?;
|
||||||
let render_config = graphene_core::application_io::RenderConfig::default();
|
let render_config = graphene_core::application_io::RenderConfig::default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let _result = (&executor).execute(render_config).await?;
|
let result = (&executor).execute(render_config).await?;
|
||||||
|
if !run_loop {
|
||||||
|
println!("{:?}", result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
std::thread::sleep(std::time::Duration::from_millis(16));
|
std::thread::sleep(std::time::Duration::from_millis(16));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_logging() {
|
fn init_logging(log_level: u8) {
|
||||||
|
let default_level = match log_level {
|
||||||
|
0 => log::LevelFilter::Error,
|
||||||
|
1 => log::LevelFilter::Info,
|
||||||
|
2 => log::LevelFilter::Debug,
|
||||||
|
_ => log::LevelFilter::Trace,
|
||||||
|
};
|
||||||
let colors = ColoredLevelConfig::new().debug(Color::Magenta).info(Color::Green).error(Color::Red);
|
let colors = ColoredLevelConfig::new().debug(Color::Magenta).info(Color::Green).error(Color::Red);
|
||||||
fern::Dispatch::new()
|
fern::Dispatch::new()
|
||||||
.chain(std::io::stdout())
|
.chain(std::io::stdout())
|
||||||
.level_for("iced", log::LevelFilter::Trace)
|
.level_for("wgpu", log::LevelFilter::Error)
|
||||||
.level_for("wgpu", log::LevelFilter::Debug)
|
.level_for("naga", log::LevelFilter::Error)
|
||||||
.level(log::LevelFilter::Trace)
|
.level_for("wgpu_hal", log::LevelFilter::Error)
|
||||||
|
.level_for("wgpu_core", log::LevelFilter::Error)
|
||||||
|
.level(default_level)
|
||||||
.format(move |out, message, record| {
|
.format(move |out, message, record| {
|
||||||
out.finish(format_args!(
|
out.finish(format_args!(
|
||||||
"[{}]{} {}",
|
"[{}]{}{} {}",
|
||||||
// This will color the log level only, not the whole line. Just a touch.
|
// This will color the log level only, not the whole line. Just a touch.
|
||||||
colors.color(record.level()),
|
colors.color(record.level()),
|
||||||
chrono::Utc::now().format("[%Y-%m-%d %H:%M:%S]"),
|
chrono::Utc::now().format("[%Y-%m-%d %H:%M:%S]"),
|
||||||
|
record.module_path().unwrap_or(""),
|
||||||
message
|
message
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
@ -98,53 +177,16 @@ fn fix_nodes(network: &mut NodeNetwork) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn compile_graph(document_string: String, editor_api: Arc<WasmEditorApi>) -> Result<ProtoNetwork, Box<dyn Error>> {
|
||||||
fn create_executor(document_string: String, editor_api: Arc<WasmEditorApi>) -> Result<DynamicExecutor, Box<dyn Error>> {
|
|
||||||
let mut network = load_network(&document_string);
|
let mut network = load_network(&document_string);
|
||||||
fix_nodes(&mut network);
|
fix_nodes(&mut network);
|
||||||
|
|
||||||
let wrapped_network = wrap_network_in_scope(network.clone(), editor_api);
|
let wrapped_network = wrap_network_in_scope(network.clone(), editor_api);
|
||||||
let compiler = Compiler {};
|
let compiler = Compiler {};
|
||||||
let protograph = compiler.compile_single(wrapped_network)?;
|
compiler.compile_single(wrapped_network).map_err(|x| x.into())
|
||||||
let executor = block_on(DynamicExecutor::new(protograph)).unwrap();
|
|
||||||
Ok(executor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(test)]
|
fn create_executor(proto_network: ProtoNetwork) -> Result<DynamicExecutor, Box<dyn Error>> {
|
||||||
// mod test {
|
let executor = block_on(DynamicExecutor::new(proto_network)).map_err(|errors| errors.iter().map(|e| format!("{e:?}")).reduce(|acc, e| format!("{acc}\n{e}")).unwrap_or_default())?;
|
||||||
// use super::*;
|
Ok(executor)
|
||||||
|
}
|
||||||
// #[tokio::test]
|
|
||||||
// #[cfg_attr(not(feature = "wayland"), ignore)]
|
|
||||||
// async fn grays_scale() {
|
|
||||||
// let document_string = include_str!("../test_files/gray.graphite");
|
|
||||||
// let executor = create_executor(document_string.to_string()).unwrap();
|
|
||||||
// let editor_api = WasmEditorApi {
|
|
||||||
// image_frame: None,
|
|
||||||
// font_cache: &FontCache::default(),
|
|
||||||
// application_io: &block_on(WasmApplicationIo::new()),
|
|
||||||
// node_graph_message_sender: &UpdateLogger {},
|
|
||||||
// editor_preferences: &EditorPreferences::default(),
|
|
||||||
// render_config: graphene_core::application_io::RenderConfig::default(),
|
|
||||||
// };
|
|
||||||
// let result = (&executor).execute(editor_api.clone()).await.unwrap();
|
|
||||||
// println!("result: {result:?}");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[tokio::test]
|
|
||||||
// #[cfg_attr(not(feature = "wayland"), ignore)]
|
|
||||||
// async fn hue() {
|
|
||||||
// let document_string = include_str!("../test_files/hue.graphite");
|
|
||||||
// let executor = create_executor(document_string.to_string()).unwrap();
|
|
||||||
// let editor_api = WasmEditorApi {
|
|
||||||
// image_frame: None,
|
|
||||||
// font_cache: &FontCache::default(),
|
|
||||||
// application_io: &block_on(WasmApplicationIo::new()),
|
|
||||||
// node_graph_message_sender: &UpdateLogger {},
|
|
||||||
// editor_preferences: &EditorPreferences::default(),
|
|
||||||
// render_config: graphene_core::application_io::RenderConfig::default(),
|
|
||||||
// };
|
|
||||||
// let result = (&executor).execute(editor_api.clone()).await.unwrap();
|
|
||||||
// println!("result: {result:?}");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue