Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 63 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ glam = { version = "0.32.1", default-features = false, features = [
"bytemuck",
] }
base64 = "0.22"
blake3 = "1.5"
mmap-io = { version = "0.9", features = ["hugepages"] }
image = { version = "0.25", default-features = false, features = [
"png",
"jpeg",
Expand Down
6 changes: 4 additions & 2 deletions desktop/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ use winit::window::WindowId;

use crate::cef;
use crate::consts::CEF_MESSAGE_LOOP_MAX_ITERATIONS;
use crate::dirs;
use crate::event::{AppEvent, AppEventScheduler};
use crate::persist;
use crate::preferences;
use crate::render::{RenderError, RenderState};
use crate::window::Window;
use crate::wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, InputMessage, MouseKeys, MouseState, Preferences};
use crate::wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};
use crate::wrapper::{DesktopWrapper, MmapResourceStorage, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};

pub(crate) struct App {
render_state: Option<RenderState>,
Expand Down Expand Up @@ -91,7 +92,8 @@ impl App {
}
});

let desktop_wrapper = DesktopWrapper::new(rand::rng().random());
let resource_storage = MmapResourceStorage::new(dirs::app_resources_dir()).expect("Failed to initialize on-disk resource storage");
let desktop_wrapper = DesktopWrapper::new(rand::rng().random(), Box::new(resource_storage));

Self {
render_state: None,
Expand Down
1 change: 1 addition & 0 deletions desktop/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub(crate) const APP_SOCKET_FILE_NAME: &str = "instance.sock";
pub(crate) const APP_STATE_FILE_NAME: &str = "state.ron";
pub(crate) const APP_PREFERENCES_FILE_NAME: &str = "preferences.ron";
pub(crate) const APP_DOCUMENTS_DIRECTORY_NAME: &str = "documents";
pub(crate) const APP_RESOURCES_DIRECTORY_NAME: &str = "resources";

// CEF configuration constants
pub(crate) const CEF_WINDOWLESS_FRAME_RATE: i32 = 60;
Expand Down
8 changes: 7 additions & 1 deletion desktop/src/dirs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fs;
use std::io;
use std::path::{Path, PathBuf};

use crate::consts::{APP_DIRECTORY_NAME, APP_DOCUMENTS_DIRECTORY_NAME};
use crate::consts::{APP_DIRECTORY_NAME, APP_DOCUMENTS_DIRECTORY_NAME, APP_RESOURCES_DIRECTORY_NAME};

pub(crate) fn ensure_dir_exists(path: &PathBuf) {
if !path.exists() {
Expand Down Expand Up @@ -51,6 +51,12 @@ pub(crate) fn app_autosave_documents_dir() -> PathBuf {
path
}

pub(crate) fn app_resources_dir() -> PathBuf {
let path = app_data_dir().join(APP_RESOURCES_DIRECTORY_NAME);
ensure_dir_exists(&path);
path
}

/// Temporary directory that is automatically deleted when dropped.
pub struct TempDir {
path: PathBuf,
Expand Down
11 changes: 6 additions & 5 deletions desktop/wrapper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use graph_craft::application_io::PlatformApplicationIo;
use graph_craft::application_io::{PlatformApplicationIo, ResourceStorage};
use graphite_editor::application::{Editor, Environment, Host, Platform};
use graphite_editor::messages::prelude::{FrontendMessage, Message};
use message_dispatcher::DesktopWrapperMessageDispatcher;
use messages::{DesktopFrontendMessage, DesktopWrapperMessage};

pub use graph_craft::application_io::MmapResourceStorage;
pub use graphite_editor::consts::{DOUBLE_CLICK_MILLISECONDS, FILE_EXTENSION};
pub use wgpu_executor::WgpuContext;
pub use wgpu_executor::WgpuContextBuilder;
Expand All @@ -22,7 +23,7 @@ pub struct DesktopWrapper {
}

impl DesktopWrapper {
pub fn new(uuid_random_seed: u64) -> Self {
pub fn new(uuid_random_seed: u64, resource_storage: Box<dyn ResourceStorage>) -> Self {
#[cfg(target_os = "windows")]
let host = Host::Windows;
#[cfg(target_os = "macos")]
Expand All @@ -32,13 +33,13 @@ impl DesktopWrapper {
let env = Environment { platform: Platform::Desktop, host };

Self {
editor: Editor::new(env, uuid_random_seed),
editor: Editor::new(env, uuid_random_seed, resource_storage),
}
}

pub fn init(&self, wgpu_context: WgpuContext) {
pub fn init(&mut self, wgpu_context: WgpuContext) {
let application_io = PlatformApplicationIo::new_with_context(wgpu_context);
futures::executor::block_on(graphite_editor::node_graph_executor::replace_application_io(application_io));
futures::executor::block_on(self.editor.replace_application_io(application_io));
}

pub fn dispatch(&mut self, message: DesktopWrapperMessage) -> Vec<DesktopFrontendMessage> {
Expand Down
18 changes: 15 additions & 3 deletions editor/src/application.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::dispatcher::Dispatcher;
use crate::messages::prelude::*;
use graph_craft::application_io::{PlatformApplicationIo, ResourceStorage};
pub use graphene_std::uuid::*;
use std::sync::OnceLock;

Expand All @@ -8,23 +9,29 @@ pub struct Editor {
}

impl Editor {
pub fn new(environment: Environment, uuid_random_seed: u64) -> Self {
pub fn new(environment: Environment, uuid_random_seed: u64, resource_storage: Box<dyn ResourceStorage>) -> Self {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Editor::new() now returns a partially initialized editor and depends on a separate replace_application_io() call before graph execution is safe.

(Based on your team's feedback about placing integrity-enforcing initialization where the state is created.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At editor/src/application.rs, line 12:

<comment>`Editor::new()` now returns a partially initialized editor and depends on a separate `replace_application_io()` call before graph execution is safe.

(Based on your team's feedback about placing integrity-enforcing initialization where the state is created.) </comment>

<file context>
@@ -8,23 +9,29 @@ pub struct Editor {
 
 impl Editor {
-	pub fn new(environment: Environment, uuid_random_seed: u64) -> Self {
+	pub fn new(environment: Environment, uuid_random_seed: u64, resource_storage: Box<dyn ResourceStorage>) -> Self {
 		ENVIRONMENT.set(environment).expect("Editor shoud only be initialized once");
 		graphene_std::uuid::set_uuid_seed(uuid_random_seed);
</file context>

ENVIRONMENT.set(environment).expect("Editor shoud only be initialized once");
graphene_std::uuid::set_uuid_seed(uuid_random_seed);

Self { dispatcher: Dispatcher::new() }
Self {
dispatcher: Dispatcher::new(resource_storage),
}
}

#[cfg(test)]
pub(crate) fn new_local_executor() -> (Self, crate::node_graph_executor::NodeRuntime) {
let _ = ENVIRONMENT.set(*Editor::environment());
graphene_std::uuid::set_uuid_seed(0);

let (runtime, executor) = crate::node_graph_executor::NodeGraphExecutor::new_with_local_runtime();
let (mut runtime, executor) = crate::node_graph_executor::NodeGraphExecutor::new_with_local_runtime();
let editor = Self {
dispatcher: Dispatcher::with_executor(executor),
};

let mut application_io = PlatformApplicationIo::default();
application_io.inject_resources(editor.dispatcher.message_handlers.resource_message_handler.resources());
runtime.replace_application_io(application_io);

(editor, runtime)
}

Expand All @@ -37,6 +44,11 @@ impl Editor {
pub fn poll_node_graph_evaluation(&mut self, responses: &mut VecDeque<Message>) -> Result<(), String> {
self.dispatcher.poll_node_graph_evaluation(responses)
}

pub async fn replace_application_io(&mut self, mut application_io: PlatformApplicationIo) {
application_io.inject_resources(self.dispatcher.message_handlers.resource_message_handler.resources());
crate::node_graph_executor::replace_application_io(application_io).await;
}
}

static ENVIRONMENT: OnceLock<Environment> = OnceLock::new();
Expand Down
Loading
Loading