mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 05:58:12 +08:00
Update Tauri to v2 and execute only the node graph in native (#2362)
* Migrate tauri app to v2 * Move flake files to sub directory * Remove unused plugins * Backport some of the tauri code * Implement async node graph execution Only move node runtime to native code * Always use gpu feature for tauri * Fix serialization * Add logging filters * Enable native window rendering with vello * Cleanup * Remove unused editor instance * Remove changes from vite config * Remove warnings * Remove unused files * Fix most tests * Cleanup * Apply frontend lint * Readd flake.nix * Fix tests using --all-features * Code review * Enable all backends * Fix monitor node downcast types * Change debug log to a warning * Disable shader passthrough * Cleanup unused imports * Remove warning * Update project setup instructions --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
29479f6e3e
commit
9b23c7e2db
Generated
+4
-9
@@ -7,7 +7,7 @@
|
||||
"name": "graphite-web-frontend",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.6.0",
|
||||
"@tauri-apps/api": "^2.2.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"reflect-metadata": "^0.2.2"
|
||||
@@ -1051,15 +1051,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/api": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.6.0.tgz",
|
||||
"integrity": "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.2.0.tgz",
|
||||
"integrity": "sha512-R8epOeZl1eJEl603aUMIGb4RXlhPjpgxbGVEaqY+0G5JG9vzV/clNlzTeqc+NLYXVqXcn8mb4c5b9pJIUDEyAg==",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"engines": {
|
||||
"node": ">= 14.6.0",
|
||||
"npm": ">= 6.6.0",
|
||||
"yarn": ">= 1.19.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/tauri"
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
"lint-fix": "eslint . --fix && tsc --noEmit",
|
||||
"---------- INTERNAL ----------": "",
|
||||
"setup": "node package-installer.js",
|
||||
"tauri:dev": "vite",
|
||||
"tauri:build": "wasm-pack build ./wasm --target=web --features=tauri",
|
||||
"wasm:build-dev": "wasm-pack build ./wasm --dev --target=web",
|
||||
"wasm:build-profiling": "wasm-pack build ./wasm --profiling --target=web",
|
||||
"wasm:build-production": "wasm-pack build ./wasm --release --target=web",
|
||||
@@ -27,7 +29,6 @@
|
||||
"wasm:watch-production": "cargo watch --postpone --watch-when-idle --workdir=wasm --shell \"wasm-pack build . --release --target=web -- --color=always\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.6.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"reflect-metadata": "^0.2.2"
|
||||
|
||||
@@ -10,37 +10,38 @@ edition = "2021"
|
||||
rust-version = "1.79"
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
default = ["custom-protocol"]
|
||||
# this feature is used for production builds where `devPath` points to the filesystem
|
||||
# By default Tauri runs in production mode when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
|
||||
default = ["custom-protocol", "gpu"]
|
||||
# This feature is used for production builds where `devPath` points to the filesystem
|
||||
# DO NOT remove this
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
gpu = ["graphite-editor/gpu"]
|
||||
|
||||
[dependencies]
|
||||
# Local dependencies
|
||||
graphite-editor = { path = "../../editor" }
|
||||
graphite-editor = { path = "../../editor", features = [
|
||||
"gpu",
|
||||
"ron",
|
||||
"vello",
|
||||
"decouple-execution",
|
||||
] }
|
||||
|
||||
# Workspace dependencies
|
||||
serde_json = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
axum = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
||||
tokio = { workspace = true, features = ["macros", "rt"] }
|
||||
ron = { workspace = true }
|
||||
log = { workspace = true }
|
||||
fern = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
|
||||
# Required dependencies
|
||||
tauri = { version = "1.5", features = [
|
||||
"api-all",
|
||||
"devtools",
|
||||
"linux-protocol-headers",
|
||||
"wry",
|
||||
] }
|
||||
tauri = { version = "2", features = ["devtools", "wry"] }
|
||||
tauri-plugin-shell = "2"
|
||||
tauri-plugin-http = "2"
|
||||
|
||||
[build-dependencies]
|
||||
# Required dependencies
|
||||
tauri-build = { version = "1.2", features = [] }
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"identifier": "desktop-capability",
|
||||
"platforms": ["macOS", "windows", "linux"],
|
||||
"windows": ["main"],
|
||||
"permissions": ["http:default"]
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"identifier": "migrated",
|
||||
"description": "permissions that were migrated from v1",
|
||||
"local": true,
|
||||
"windows": ["main"],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"core:window:allow-create",
|
||||
"core:window:allow-center",
|
||||
"core:window:allow-request-user-attention",
|
||||
"core:window:allow-set-resizable",
|
||||
"core:window:allow-set-maximizable",
|
||||
"core:window:allow-set-minimizable",
|
||||
"core:window:allow-set-closable",
|
||||
"core:window:allow-set-title",
|
||||
"core:window:allow-maximize",
|
||||
"core:window:allow-unmaximize",
|
||||
"core:window:allow-minimize",
|
||||
"core:window:allow-unminimize",
|
||||
"core:window:allow-show",
|
||||
"core:window:allow-hide",
|
||||
"core:window:allow-close",
|
||||
"core:window:allow-set-decorations",
|
||||
"core:window:allow-set-always-on-top",
|
||||
"core:window:allow-set-content-protected",
|
||||
"core:window:allow-set-size",
|
||||
"core:window:allow-set-min-size",
|
||||
"core:window:allow-set-max-size",
|
||||
"core:window:allow-set-position",
|
||||
"core:window:allow-set-fullscreen",
|
||||
"core:window:allow-set-focus",
|
||||
"core:window:allow-set-icon",
|
||||
"core:window:allow-set-skip-taskbar",
|
||||
"core:window:allow-set-cursor-grab",
|
||||
"core:window:allow-set-cursor-visible",
|
||||
"core:window:allow-set-cursor-icon",
|
||||
"core:window:allow-set-cursor-position",
|
||||
"core:window:allow-set-ignore-cursor-events",
|
||||
"core:window:allow-start-dragging",
|
||||
"core:webview:allow-print",
|
||||
"shell:allow-execute",
|
||||
"shell:allow-open",
|
||||
"http:default",
|
||||
"core:app:allow-app-show",
|
||||
"core:app:allow-app-hide",
|
||||
"shell:default",
|
||||
"http:default"
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"desktop-capability":{"identifier":"desktop-capability","description":"","local":true,"windows":["main"],"permissions":["http:default"],"platforms":["macOS","windows","linux"]},"migrated":{"identifier":"migrated","description":"permissions that were migrated from v1","local":true,"windows":["main"],"permissions":["core:default","core:window:allow-create","core:window:allow-center","core:window:allow-request-user-attention","core:window:allow-set-resizable","core:window:allow-set-maximizable","core:window:allow-set-minimizable","core:window:allow-set-closable","core:window:allow-set-title","core:window:allow-maximize","core:window:allow-unmaximize","core:window:allow-minimize","core:window:allow-unminimize","core:window:allow-show","core:window:allow-hide","core:window:allow-close","core:window:allow-set-decorations","core:window:allow-set-always-on-top","core:window:allow-set-content-protected","core:window:allow-set-size","core:window:allow-set-min-size","core:window:allow-set-max-size","core:window:allow-set-position","core:window:allow-set-fullscreen","core:window:allow-set-focus","core:window:allow-set-icon","core:window:allow-set-skip-taskbar","core:window:allow-set-cursor-grab","core:window:allow-set-cursor-visible","core:window:allow-set-cursor-icon","core:window:allow-set-cursor-position","core:window:allow-set-ignore-cursor-events","core:window:allow-start-dragging","core:webview:allow-print","shell:allow-execute","shell:allow-open","http:default","core:app:allow-app-show","core:app:allow-app-hide","shell:default","http:default"]}}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,37 +1,16 @@
|
||||
#![cfg_attr(all(not(debug_assertions), target_os = "windows"), windows_subsystem = "windows")]
|
||||
|
||||
use graphite_editor::application::Editor;
|
||||
use graphite_editor::messages::prelude::*;
|
||||
|
||||
// use axum::body::StreamBody;
|
||||
// use axum::extract::Path;
|
||||
// use axum::http;
|
||||
// use axum::response::IntoResponse;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use fern::colors::{Color, ColoredLevelConfig};
|
||||
// use http::{Response, StatusCode};
|
||||
use std::cell::RefCell;
|
||||
// use std::collections::HashMap;
|
||||
// use std::sync::Arc;
|
||||
// use std::sync::Mutex;
|
||||
use graphite_editor::application::Editor;
|
||||
use graphite_editor::messages::prelude::*;
|
||||
use graphite_editor::node_graph_executor::GraphRuntimeRequest;
|
||||
use graphite_editor::node_graph_executor::NODE_RUNTIME;
|
||||
use graphite_editor::node_graph_executor::*;
|
||||
use std::sync::Mutex;
|
||||
|
||||
thread_local! {
|
||||
static EDITOR: RefCell<Option<Editor>> = const { RefCell::new(None) };
|
||||
}
|
||||
|
||||
// async fn respond_to(id: Path<String>) -> impl IntoResponse {
|
||||
// let builder = Response::builder().header("Access-Control-Allow-Origin", "*").status(StatusCode::OK);
|
||||
|
||||
// let guard = IMAGES.lock().unwrap();
|
||||
// let images = guard;
|
||||
// let image = images.as_ref().unwrap().get(&id.0).unwrap();
|
||||
|
||||
// println!("image: {:#?}", image.path);
|
||||
// let result: Result<Vec<u8>, &str> = Ok((*image.image_data).clone());
|
||||
// let stream = futures::stream::once(async move { result });
|
||||
// builder.body(StreamBody::new(stream)).unwrap()
|
||||
// }
|
||||
static NODE_RUNTIME_IO: Mutex<Option<NodeRuntimeIO>> = const { Mutex::new(None) };
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -42,63 +21,68 @@ async fn main() {
|
||||
fern::Dispatch::new()
|
||||
.chain(std::io::stdout())
|
||||
.level(log::LevelFilter::Trace)
|
||||
.level_for("naga", log::LevelFilter::Error)
|
||||
.level_for("wgpu-hal", log::LevelFilter::Error)
|
||||
.level_for("wgpu_hal", log::LevelFilter::Error)
|
||||
.level_for("wgpu_core", log::LevelFilter::Error)
|
||||
.format(move |out, message, record| {
|
||||
out.finish(format_args!(
|
||||
"[{}]{} {}",
|
||||
"[{}]{} {} {}",
|
||||
// This will color the log level only, not the whole line. Just a touch.
|
||||
colors.color(record.level()),
|
||||
chrono::Utc::now().format("[%Y-%m-%d %H:%M:%S]"),
|
||||
message
|
||||
message,
|
||||
record.module_path().unwrap_or("")
|
||||
))
|
||||
})
|
||||
.apply()
|
||||
.unwrap();
|
||||
|
||||
// *(IMAGES.lock().unwrap()) = Some(HashMap::new());
|
||||
std::thread::spawn(|| loop {
|
||||
futures::executor::block_on(graphite_editor::node_graph_executor::run_node_graph());
|
||||
std::thread::sleep(std::time::Duration::from_millis(16))
|
||||
});
|
||||
graphite_editor::application::set_uuid_seed(0);
|
||||
EDITOR.with(|editor| editor.borrow_mut().replace(Editor::new()));
|
||||
let app = Router::new().route("/", get(|| async { "Hello, World!" }))/*.route("/image/:id", get(respond_to))*/;
|
||||
|
||||
// run it with hyper on localhost:3000
|
||||
let mut runtime_lock = NODE_RUNTIME_IO.lock().unwrap();
|
||||
*runtime_lock = Some(NodeRuntimeIO::new());
|
||||
drop(runtime_lock);
|
||||
|
||||
let app = Router::new().route("/", get(|| async { "Hello, World!" }));
|
||||
|
||||
// Run it with hyper on localhost:3000
|
||||
tauri::async_runtime::spawn(async {
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
});
|
||||
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![set_random_seed, handle_message])
|
||||
.plugin(tauri_plugin_http::init())
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.invoke_handler(tauri::generate_handler![poll_node_graph, runtime_message])
|
||||
.setup(|_app| {
|
||||
use tauri::Manager;
|
||||
_app.get_window("main").unwrap().open_devtools();
|
||||
_app.get_webview_window("main").unwrap().open_devtools();
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
#[tauri::command]
|
||||
fn set_random_seed(seed: f64) {
|
||||
graphite_editor::application::set_uuid_seed(seed as u64);
|
||||
fn poll_node_graph() -> String {
|
||||
let vec: Vec<_> = NODE_RUNTIME_IO.lock().as_mut().unwrap().as_mut().unwrap().receive().collect();
|
||||
ron::to_string(&vec).unwrap()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn handle_message(message: String) -> String {
|
||||
let Ok(message) = ron::from_str::<graphite_editor::messages::message::Message>(&message) else {
|
||||
panic!("Error parsing message: {message}")
|
||||
};
|
||||
let responses = EDITOR.with(|editor| {
|
||||
let mut editor = editor.borrow_mut();
|
||||
editor.as_mut().unwrap().handle_message(message)
|
||||
});
|
||||
|
||||
for response in &responses {
|
||||
let serialized = ron::to_string(&response.clone()).unwrap();
|
||||
if let Err(error) = ron::from_str::<FrontendMessage>(&serialized) {
|
||||
log::error!("Error deserializing message: {error}");
|
||||
fn runtime_message(message: String) -> Result<(), String> {
|
||||
let message = match ron::from_str(&message) {
|
||||
Ok(message) => message,
|
||||
Err(e) => {
|
||||
log::error!("Failed to deserialize message: {}\nwith error: {}", message, e);
|
||||
return Err("Failed to deserialize message".into());
|
||||
}
|
||||
}
|
||||
|
||||
// Process any `FrontendMessage` responses resulting from the backend processing the dispatched message
|
||||
let result: Vec<_> = responses.into_iter().collect();
|
||||
|
||||
ron::to_string(&result).expect("Failed to serialize FrontendMessage")
|
||||
};
|
||||
let response = NODE_RUNTIME_IO.lock().as_ref().unwrap().as_ref().unwrap().send(message);
|
||||
response
|
||||
}
|
||||
|
||||
@@ -1,60 +1,59 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"build": {
|
||||
"beforeBuildCommand": "npm run tauri:build-wasm",
|
||||
"beforeBuildCommand": "npm run tauri:build",
|
||||
"beforeDevCommand": "npm run tauri:dev",
|
||||
"distDir": "../dist",
|
||||
"devPath": "http://127.0.0.1:8080/"
|
||||
"frontendDist": "../dist",
|
||||
"devUrl": "http://127.0.0.1:8080/"
|
||||
},
|
||||
"package": {
|
||||
"productName": "Graphite",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": true
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"targets": "all",
|
||||
"externalBin": [],
|
||||
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"linux": {
|
||||
"deb": {
|
||||
"depends": ["librustc_codegen_spirv"]
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
|
||||
"identifier": "rs.graphite.editor",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all",
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
}
|
||||
},
|
||||
"productName": "Graphite",
|
||||
"mainBinaryName": "Graphite",
|
||||
"version": "0.1.0",
|
||||
"identifier": "rs.graphite.editor",
|
||||
"plugins": {},
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"windows": [
|
||||
{
|
||||
"decorations": false,
|
||||
"fullscreen": false,
|
||||
"height": 600,
|
||||
"height": 1080,
|
||||
"resizable": true,
|
||||
"title": "Graphite",
|
||||
"width": 800
|
||||
"width": 1920,
|
||||
"useHttpsScheme": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ license = "Apache-2.0"
|
||||
[features]
|
||||
default = ["gpu"]
|
||||
gpu = ["editor/gpu"]
|
||||
tauri = ["ron"]
|
||||
tauri = ["ron", "editor/tauri"]
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
@@ -37,6 +37,7 @@ js-sys = { workspace = true }
|
||||
wasm-bindgen-futures = { workspace = true }
|
||||
bezier-rs = { workspace = true }
|
||||
glam = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
math-parser = { workspace = true }
|
||||
wgpu = { workspace = true, features = [
|
||||
"fragile-send-sync-non-atomic-wasm",
|
||||
@@ -77,4 +78,6 @@ demangle-name-section = true
|
||||
dwarf-debug-info = true
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] }
|
||||
unexpected_cfgs = { level = "warn", check-cfg = [
|
||||
'cfg(wasm_bindgen_unstable_test_coverage)',
|
||||
] }
|
||||
|
||||
@@ -24,14 +24,6 @@ use std::sync::atomic::Ordering;
|
||||
use std::time::Duration;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
// /// We directly interface with the updateImage JS function for massively increased performance over serializing and deserializing.
|
||||
// /// This avoids creating a json with a list millions of numbers long.
|
||||
// #[wasm_bindgen(module = "/../src/editor.ts")]
|
||||
// extern "C" {
|
||||
// // fn dispatchTauri(message: String) -> String;
|
||||
// fn dispatchTauri(message: String);
|
||||
// }
|
||||
|
||||
/// Set the random seed used by the editor by calling this from JS upon initialization.
|
||||
/// This is necessary because WASM doesn't have a random number generator.
|
||||
#[wasm_bindgen(js_name = setRandomSeed)]
|
||||
@@ -184,21 +176,6 @@ impl EditorHandle {
|
||||
}
|
||||
}
|
||||
|
||||
// #[wasm_bindgen(js_name = tauriResponse)]
|
||||
// pub fn tauri_response(&self, _message: JsValue) {
|
||||
// #[cfg(feature = "tauri")]
|
||||
// match ron::from_str::<Vec<FrontendMessage>>(&_message.as_string().unwrap()) {
|
||||
// Ok(response) => {
|
||||
// for message in response {
|
||||
// self.send_frontend_message_to_js(message);
|
||||
// }
|
||||
// }
|
||||
// Err(error) => {
|
||||
// log::error!("tauri response: {error:?}\n{_message:?}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Displays a dialog with an error message
|
||||
#[wasm_bindgen(js_name = errorDialog)]
|
||||
pub fn error_dialog(&self, title: String, description: String) {
|
||||
|
||||
Reference in New Issue
Block a user