Upgrade several Rust dependencies (#1613)

`specta` from Hypercube's fork commit to latest upstream commit
`wasm-bindgen` 0.2.87 -> 0.2.91
`spirv-std` from 0.9 to not-yet-merged commit in https://github.com/EmbarkStudios/rust-gpu/pull/1115
`wgpu` 0.17 -> 0.19
`winit` 0.28.6 -> 0.29
`vello` and `vello_svg` from latest upstream commit to not-yet-merged commit in https://github.com/linebender/vello/pull/427
`resvg` 0.36.0 -> 0.39
`glam` 0.24 -> 0.25
`rustybuzz` 0.8.0 -> 0.10.0
`js-sys` and `web-sys` 0.3.55 -> 0.3.67
`usvg` 0.36.0 -> 0.39
`spirv` 0.2.0 -> 0.3

* Update a couple of dependencies

* More test fixing…

* Use upstream Specta instead of fork

* Update comments in Cargo.toml

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube 2024-02-17 23:02:41 +00:00 committed by GitHub
parent 80bffd39bf
commit 6f6fb3bcd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 879 additions and 893 deletions

1527
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -20,26 +20,22 @@ members = [
"libraries/bezier-rs", "libraries/bezier-rs",
"website/other/bezier-rs-demos/wasm", "website/other/bezier-rs-demos/wasm",
] ]
resolver = "2" resolver = "2"
exclude = ["node-graph/gpu-compiler"] exclude = ["node-graph/gpu-compiler"]
[workspace.dependencies] [workspace.dependencies]
# We are using this fork because: specta = { git = "https://github.com/oscartbeaumont/specta.git", features = [
# - They specify glam=0.22 whereas we use glam=0.24 so the encoding doesn't work.
# - Their current release doesn't allow doc comments and produces a compile error.
# See: https://github.com/GraphiteEditor/Graphite/pull/1346/files/a2206401b5b4cf669e71df57f6c95c67336802c8#r1280201659
specta = { git = "https://github.com/0HyperCube/specta.git", rev = "c47a22b4c0863d27bc47529f300de3969480c66d", features = [
"glam", "glam",
"typescript",
] } ] }
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
# wasm-bindgen upgrades may break various things so we pin the version # wasm-bindgen upgrades may break various things so we pin the version
wasm-bindgen = "=0.2.87" wasm-bindgen = "=0.2.91"
dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam"] } dyn-any = { path = "libraries/dyn-any", features = ["derive", "glam"] }
graphene-core = { path = "node-graph/gcore" } graphene-core = { path = "node-graph/gcore" }
graph-craft = { path = "node-graph/graph-craft", features = ["serde"] } graph-craft = { path = "node-graph/graph-craft", features = ["serde"] }
spirv-std = { version = "0.9" } # Remove the `rev` commit hash field once this merges: https://github.com/EmbarkStudios/rust-gpu/pull/1115 (and consider switching to a release version upon the next release)
spirv-std = { git = "https://github.com/EmbarkStudios/rust-gpu.git", rev = "08e7559012ab6645cf36f6cce84426f9e34b88d9" }
bytemuck = { version = "1.13", features = ["derive"] } bytemuck = { version = "1.13", features = ["derive"] }
async-trait = { version = "0.1" } async-trait = { version = "0.1" }
serde = { version = "1.0", features = ["derive", "rc"] } serde = { version = "1.0", features = ["derive", "rc"] }
@ -61,33 +57,34 @@ chrono = "^0.4.23"
ron = "0.8" ron = "0.8"
fastnoise-lite = "1.1.0" fastnoise-lite = "1.1.0"
wgpu-types = "0.17" wgpu-types = "0.17"
wgpu = "0.17" wgpu = "0.19"
wasm-bindgen-futures = { version = "0.4.36" } wasm-bindgen-futures = { version = "0.4.36" }
winit = "0.28.6" winit = "0.29"
url = "2.4.0" url = "2.4.0"
tokio = { version = "1.29", features = ["fs", "io-std"] } tokio = { version = "1.29", features = ["fs", "io-std"] }
vello = { git = "https://github.com/linebender/vello", version = "0.0.1" } # Remove the `rev` commit hash field once this merges: https://github.com/linebender/vello/pull/427
vello_svg = { git = "https://github.com/linebender/vello", version = "0.0.1" } vello = { git = "https://github.com/linebender/vello.git", rev = "f075f58fc50c569daf5ca720fe81b5fee946ce7f", version = "0.0.1" }
resvg = { version = "0.36.0" } vello_svg = { git = "https://github.com/linebender/vello.git", rev = "f075f58fc50c569daf5ca720fe81b5fee946ce7f", version = "0.0.1" }
resvg = { version = "0.39" }
rand = { version = "0.8.5", default-features = false } rand = { version = "0.8.5", default-features = false }
rand_chacha = { version = "0.3.1" } rand_chacha = { version = "0.3.1" }
bezier-rs = { path = "libraries/bezier-rs", features = ["dyn-any"] } bezier-rs = { path = "libraries/bezier-rs", features = ["dyn-any"] }
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [ kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
"serde", "serde",
] } ] }
glam = { version = "0.24", default-features = false, features = ["serde"] } glam = { version = "0.25", default-features = false, features = ["serde"] }
node-macro = { path = "node-graph/node-macro" } node-macro = { path = "node-graph/node-macro" }
base64 = { version = "0.21" } base64 = { version = "0.21" }
image = { version = "0.24", default-features = false, features = ["png"] } image = { version = "0.24", default-features = false, features = ["png"] }
rustybuzz = { version = "0.8.0" } rustybuzz = { version = "0.10.0" }
num-derive = { version = "0.4" } num-derive = { version = "0.4" }
num-traits = { version = "0.2.15", default-features = false, features = [ num-traits = { version = "0.2.15", default-features = false, features = [
"i128", "i128",
] } ] }
js-sys = { version = "0.3.55" } js-sys = { version = "=0.3.67" }
web-sys = { version = "0.3.55" } web-sys = { version = "=0.3.67" }
usvg = "0.36.0" usvg = "0.39"
spirv = "0.2.0" spirv = "0.3"
fern = { version = "0.6", features = ["colored"] } fern = { version = "0.6", features = ["colored"] }
[profile.dev.package.graphite-editor] [profile.dev.package.graphite-editor]

View file

@ -5,31 +5,26 @@
#[test] #[test]
fn generate_ts_types() { fn generate_ts_types() {
use crate::messages::prelude::FrontendMessage; use crate::messages::prelude::FrontendMessage;
use specta::{ use specta::ts::{export_named_datatype, BigIntExportBehavior, ExportConfig};
ts::{export_datatype, BigIntExportBehavior, ExportConfiguration}, use specta::{NamedType, TypeMap};
DefOpts, NamedType, Type, TypeDefs,
};
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
let config = ExportConfiguration::new().bigint(BigIntExportBehavior::Number); let config = ExportConfig::new().bigint(BigIntExportBehavior::Number);
let mut type_map = TypeDefs::new(); let mut type_map = TypeMap::default();
let datatype = FrontendMessage::named_data_type( let datatype = FrontendMessage::definition_named_data_type(&mut type_map);
DefOpts {
parent_inline: false,
type_map: &mut type_map,
},
&FrontendMessage::definition_generics().into_iter().map(Into::into).collect::<Vec<_>>(),
)
.unwrap();
let mut export = String::new(); let mut export = String::new();
export += &export_datatype(&config, &datatype).unwrap(); export += &export_named_datatype(&config, &datatype, &type_map).unwrap();
type_map.values().flatten().flat_map(|v| export_datatype(&config, v)).for_each(|e| export += &format!("\n\n{e}")); type_map
.iter()
.map(|(_, v)| v)
.flat_map(|v| export_named_datatype(&config, v, &type_map))
.for_each(|e| export += &format!("\n\n{e}"));
let mut file = File::create("../types.ts").unwrap(); let mut file = File::create("../types.ts").unwrap();

View file

@ -457,8 +457,9 @@ impl WidgetHolder {
} }
} }
#[derive(Clone)] #[derive(Clone, specta::Type)]
pub struct WidgetCallback<T> { pub struct WidgetCallback<T> {
#[specta(skip)]
pub callback: Arc<dyn Fn(&T) -> Message + 'static + Send + Sync>, pub callback: Arc<dyn Fn(&T) -> Message + 'static + Send + Sync>,
} }

View file

@ -41,6 +41,8 @@ pub enum Message {
/// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`. /// Provides an impl of `specta::Type` for `MessageDiscriminant`, the struct created by `impl_message`.
/// Specta isn't integrated with `impl_message`, so a remote impl must be provided using this struct. /// Specta isn't integrated with `impl_message`, so a remote impl must be provided using this struct.
#[derive(specta::Type)] impl specta::Type for MessageDiscriminant {
#[specta(inline, remote = "MessageDiscriminant")] fn inline(_type_map: &mut specta::TypeMap, _generics: specta::Generics) -> specta::DataType {
pub struct MessageDiscriminantDef(pub u8); specta::DataType::Any
}
}

View file

@ -16,7 +16,6 @@ use graphene_core::{Artboard, Color};
use transform_utils::LayerBounds; use transform_utils::LayerBounds;
use glam::{DAffine2, DVec2, IVec2}; use glam::{DAffine2, DVec2, IVec2};
use usvg::NodeExt;
pub mod transform_utils; pub mod transform_utils;
@ -761,7 +760,6 @@ impl MessageHandler<GraphOperationMessage, GraphOperationHandlerData<'_>> for Gr
parent, parent,
insert_index, insert_index,
} => { } => {
use usvg::TreeParsing;
let tree = match usvg::Tree::from_str(&svg, &usvg::Options::default()) { let tree = match usvg::Tree::from_str(&svg, &usvg::Options::default()) {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
@ -774,7 +772,7 @@ impl MessageHandler<GraphOperationMessage, GraphOperationHandlerData<'_>> for Gr
}; };
let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses); let mut modify_inputs = ModifyInputsContext::new(document_network, document_metadata, node_graph, responses);
import_usvg_node(&mut modify_inputs, &tree.root, transform, id, parent, insert_index); import_usvg_node(&mut modify_inputs, &usvg::Node::Group(Box::new(tree.root)), transform, id, parent, insert_index);
load_network_structure(document_network, document_metadata, selected_nodes, collapsed); load_network_structure(document_network, document_metadata, selected_nodes, collapsed);
} }
} }
@ -803,14 +801,14 @@ fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node,
return; return;
}; };
modify_inputs.layer_node = Some(layer); modify_inputs.layer_node = Some(layer);
match &*node.borrow() { match node {
usvg::NodeKind::Group(_group) => { usvg::Node::Group(group) => {
for child in node.children() { for child in &group.children {
import_usvg_node(modify_inputs, &child, transform, NodeId(generate_uuid()), LayerNodeIdentifier::new_unchecked(layer), -1); import_usvg_node(modify_inputs, &child, transform, NodeId(generate_uuid()), LayerNodeIdentifier::new_unchecked(layer), -1);
} }
modify_inputs.layer_node = Some(layer); modify_inputs.layer_node = Some(layer);
} }
usvg::NodeKind::Path(path) => { usvg::Node::Path(path) => {
let subpaths = convert_usvg_path(path); let subpaths = convert_usvg_path(path);
let bounds = subpaths.iter().filter_map(|subpath| subpath.bounding_box()).reduce(Quad::combine_bounds).unwrap_or_default(); let bounds = subpaths.iter().filter_map(|subpath| subpath.bounding_box()).reduce(Quad::combine_bounds).unwrap_or_default();
let transformed_bounds = subpaths let transformed_bounds = subpaths
@ -836,10 +834,10 @@ fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node,
); );
apply_usvg_stroke(&path.stroke, modify_inputs); apply_usvg_stroke(&path.stroke, modify_inputs);
} }
usvg::NodeKind::Image(_image) => { usvg::Node::Image(_image) => {
warn!("Skip image") warn!("Skip image")
} }
usvg::NodeKind::Text(text) => { usvg::Node::Text(text) => {
let font = Font::new(crate::consts::DEFAULT_FONT_FAMILY.to_string(), crate::consts::DEFAULT_FONT_STYLE.to_string()); let font = Font::new(crate::consts::DEFAULT_FONT_FAMILY.to_string(), crate::consts::DEFAULT_FONT_STYLE.to_string());
modify_inputs.insert_text(text.chunks.iter().map(|chunk| chunk.text.clone()).collect(), font, 24., layer); modify_inputs.insert_text(text.chunks.iter().map(|chunk| chunk.text.clone()).collect(), font, 24., layer);
modify_inputs.fill_set(Fill::Solid(Color::BLACK)); modify_inputs.fill_set(Fill::Solid(Color::BLACK));

View file

@ -1490,7 +1490,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
name: "Render Texture".to_string(), name: "Render Texture".to_string(),
inputs: vec![ inputs: vec![
NodeInput::Network(concrete!(ShaderInputFrame<WgpuExecutor>)), NodeInput::Network(concrete!(ShaderInputFrame<WgpuExecutor>)),
NodeInput::Network(concrete!(Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface>>)), NodeInput::Network(concrete!(Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface<'_>>>)),
NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(0), 0),
], ],
implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("gpu_executor::RenderTextureNode<_, _>")), implementation: DocumentNodeImplementation::Unresolved(ProtoNodeIdentifier::new("gpu_executor::RenderTextureNode<_, _>")),

View file

@ -19,6 +19,7 @@ pub fn empty_provider() -> OverlayProvider {
pub struct OverlayContext { pub struct OverlayContext {
// Serde functionality isn't used but is required by the message system macros // Serde functionality isn't used but is required by the message system macros
#[serde(skip, default = "overlay_canvas_context")] #[serde(skip, default = "overlay_canvas_context")]
#[specta(skip)]
pub render_context: web_sys::CanvasRenderingContext2d, pub render_context: web_sys::CanvasRenderingContext2d,
pub size: DVec2, pub size: DVec2,
} }

View file

@ -28,10 +28,10 @@ wasm-bindgen = { workspace = true }
serde-wasm-bindgen = "0.6" serde-wasm-bindgen = "0.6"
js-sys = { workspace = true } js-sys = { workspace = true }
wasm-bindgen-futures = { workspace = true } wasm-bindgen-futures = { workspace = true }
ron = { version = "0.8", optional = true } ron = { workspace = true, optional = true }
bezier-rs = { workspace = true } bezier-rs = { workspace = true }
# We don't have wgpu on multiple threads (yet) https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#wgpu-types-now-send-sync-on-wasm # We don't have wgpu on multiple threads (yet) https://github.com/gfx-rs/wgpu/blob/trunk/CHANGELOG.md#wgpu-types-now-send-sync-on-wasm
wgpu = { version = "0.17", features = ["fragile-send-sync-non-atomic-wasm"] } wgpu = { workspace = true, features = ["fragile-send-sync-non-atomic-wasm"] }
meval = "0.2.0" meval = "0.2.0"
[dependencies.web-sys] [dependencies.web-sys]

View file

@ -14,8 +14,8 @@ repository = "https://github.com/GraphiteEditor/Graphite/tree/master/libraries/b
documentation = "https://graphite.rs/libraries/bezier-rs/" documentation = "https://graphite.rs/libraries/bezier-rs/"
[dependencies] [dependencies]
glam = { version = "0.24", features = ["serde"] } glam = { version = "0.25", features = ["serde"] }
dyn-any = { version = "0.3.0", path = "../dyn-any", optional = true } dyn-any = { version = "0.3.0", path = "../dyn-any", optional = true }
serde = { version = "1.0", workspace = true, optional = true } serde = { workspace = true, optional = true }
log = { workspace = true, optional = true } log = { workspace = true, optional = true }

View file

@ -14,7 +14,7 @@ documentation = "https://docs.rs/dyn-any"
[dependencies] [dependencies]
dyn-any-derive = { path = "derive", version = "0.3.0", optional = true } dyn-any-derive = { path = "derive", version = "0.3.0", optional = true }
log = { version = "0.4", optional = true } log = { version = "0.4", optional = true }
glam = { version = "0.24", optional = true, default-features = false } glam = { version = "0.25", optional = true, default-features = false }
[features] [features]
derive = ["dyn-any-derive"] derive = ["dyn-any-derive"]

View file

@ -233,7 +233,7 @@ impl GraphicGroup {
}; };
pub fn to_usvg_tree(&self, resolution: UVec2, viewbox: [DVec2; 2]) -> usvg::Tree { pub fn to_usvg_tree(&self, resolution: UVec2, viewbox: [DVec2; 2]) -> usvg::Tree {
let root_node = usvg::Node::new(usvg::NodeKind::Group(usvg::Group::default())); let mut root_node = usvg::Group::default();
let tree = usvg::Tree { let tree = usvg::Tree {
size: usvg::Size::from_wh(resolution.x as f32, resolution.y as f32).unwrap(), size: usvg::Size::from_wh(resolution.x as f32, resolution.y as f32).unwrap(),
view_box: usvg::ViewBox { view_box: usvg::ViewBox {
@ -244,7 +244,7 @@ impl GraphicGroup {
}; };
for element in self.iter() { for element in self.iter() {
root_node.append(element.to_usvg_node()); root_node.children.push(element.to_usvg_node());
} }
tree tree
} }
@ -283,20 +283,20 @@ impl GraphicElement {
} }
let path = builder.finish().unwrap(); let path = builder.finish().unwrap();
let mut path = usvg::Path::new(path.into()); let mut path = usvg::Path::new(path.into());
path.transform = transform; path.abs_transform = transform;
// TODO: use proper style // TODO: use proper style
path.fill = None; path.fill = None;
path.stroke = Some(usvg::Stroke::default()); path.stroke = Some(usvg::Stroke::default());
usvg::Node::new(usvg::NodeKind::Path(path)) usvg::Node::Path(Box::new(path))
} }
GraphicElement::ImageFrame(image_frame) => { GraphicElement::ImageFrame(image_frame) => {
if image_frame.image.width * image_frame.image.height == 0 { if image_frame.image.width * image_frame.image.height == 0 {
return usvg::Node::new(usvg::NodeKind::Group(usvg::Group::default())); return usvg::Node::Group(Box::new(usvg::Group::default()));
} }
let png = image_frame.image.to_png(); let png = image_frame.image.to_png();
usvg::Node::new(usvg::NodeKind::Image(usvg::Image { usvg::Node::Image(Box::new(usvg::Image {
id: String::new(), id: String::new(),
transform: to_transform(image_frame.transform), abs_transform: to_transform(image_frame.transform),
visibility: usvg::Visibility::Visible, visibility: usvg::Visibility::Visible,
view_box: usvg::ViewBox { view_box: usvg::ViewBox {
rect: usvg::NonZeroRect::from_xywh(0., 0., 1., 1.).unwrap(), rect: usvg::NonZeroRect::from_xywh(0., 0., 1., 1.).unwrap(),
@ -304,14 +304,13 @@ impl GraphicElement {
}, },
rendering_mode: usvg::ImageRendering::OptimizeSpeed, rendering_mode: usvg::ImageRendering::OptimizeSpeed,
kind: usvg::ImageKind::PNG(png.into()), kind: usvg::ImageKind::PNG(png.into()),
bounding_box: None,
})) }))
} }
GraphicElement::Text(text) => usvg::Node::new(usvg::NodeKind::Text(usvg::Text { GraphicElement::Text(text) => usvg::Node::Text(Box::new(usvg::Text {
id: String::new(), id: String::new(),
transform: usvg::Transform::identity(), abs_transform: usvg::Transform::identity(),
rendering_mode: usvg::TextRendering::OptimizeSpeed, rendering_mode: usvg::TextRendering::OptimizeSpeed,
positions: Vec::new(),
rotate: Vec::new(),
writing_mode: usvg::WritingMode::LeftToRight, writing_mode: usvg::WritingMode::LeftToRight,
chunks: vec![usvg::TextChunk { chunks: vec![usvg::TextChunk {
text: text.clone(), text: text.clone(),
@ -321,17 +320,25 @@ impl GraphicElement {
spans: vec![], spans: vec![],
text_flow: usvg::TextFlow::Linear, text_flow: usvg::TextFlow::Linear,
}], }],
dx: Vec::new(),
dy: Vec::new(),
rotate: Vec::new(),
bounding_box: None,
abs_bounding_box: None,
stroke_bounding_box: None,
abs_stroke_bounding_box: None,
flattened: None,
})), })),
GraphicElement::GraphicGroup(group) => { GraphicElement::GraphicGroup(group) => {
let group_element = usvg::Node::new(usvg::NodeKind::Group(usvg::Group::default())); let mut group_element = usvg::Group::default();
for element in group.iter() { for element in group.iter() {
group_element.append(element.to_usvg_node()); group_element.children.push(element.to_usvg_node());
} }
group_element usvg::Node::Group(Box::new(group_element))
} }
// TODO // TODO
GraphicElement::Artboard(_board) => usvg::Node::new(usvg::NodeKind::Group(usvg::Group::default())), GraphicElement::Artboard(_board) => usvg::Node::Group(Box::new(usvg::Group::default())),
} }
} }
} }

View file

@ -10,7 +10,6 @@ use bezier_rs::Subpath;
use base64::Engine; use base64::Engine;
use glam::{DAffine2, DVec2}; use glam::{DAffine2, DVec2};
use usvg::TreeParsing;
/// Represents a clickable target for the layer /// Represents a clickable target for the layer
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -216,18 +215,21 @@ pub trait GraphicElementRendered {
let opt = usvg::Options::default(); let opt = usvg::Options::default();
let tree = usvg::Tree::from_str(&svg, &opt).expect("Failed to parse SVG"); let tree = usvg::Tree::from_str(&svg, &opt).expect("Failed to parse SVG");
tree.root.clone() usvg::Node::Group(Box::new(tree.root.clone()))
} }
fn to_usvg_tree(&self, resolution: glam::UVec2, viewbox: [DVec2; 2]) -> usvg::Tree { fn to_usvg_tree(&self, resolution: glam::UVec2, viewbox: [DVec2; 2]) -> usvg::Tree {
let root_node = self.to_usvg_node(); let root = match self.to_usvg_node() {
usvg::Node::Group(root_node) => *root_node,
_ => usvg::Group::default(),
};
usvg::Tree { usvg::Tree {
size: usvg::Size::from_wh(resolution.x as f32, resolution.y as f32).unwrap(), size: usvg::Size::from_wh(resolution.x as f32, resolution.y as f32).unwrap(),
view_box: usvg::ViewBox { view_box: usvg::ViewBox {
rect: usvg::NonZeroRect::from_ltrb(viewbox[0].x as f32, viewbox[0].y as f32, viewbox[1].x as f32, viewbox[1].y as f32).unwrap(), rect: usvg::NonZeroRect::from_ltrb(viewbox[0].x as f32, viewbox[0].y as f32, viewbox[1].x as f32, viewbox[1].y as f32).unwrap(),
aspect: usvg::AspectRatio::default(), aspect: usvg::AspectRatio::default(),
}, },
root: root_node.clone(), root,
} }
} }
@ -275,11 +277,11 @@ impl GraphicElementRendered for GraphicGroup {
} }
fn to_usvg_node(&self) -> usvg::Node { fn to_usvg_node(&self) -> usvg::Node {
let root_node = usvg::Node::new(usvg::NodeKind::Group(usvg::Group::default())); let mut root_node = usvg::Group::default();
for element in self.iter() { for element in self.iter() {
root_node.append(element.to_usvg_node()); root_node.children.push(element.to_usvg_node());
} }
root_node usvg::Node::Group(Box::new(root_node))
} }
fn contains_artboard(&self) -> bool { fn contains_artboard(&self) -> bool {
@ -358,11 +360,11 @@ impl GraphicElementRendered for VectorData {
} }
let path = builder.finish().unwrap(); let path = builder.finish().unwrap();
let mut path = usvg::Path::new(path.into()); let mut path = usvg::Path::new(path.into());
path.transform = transform; path.abs_transform = transform;
// TODO: use proper style // TODO: use proper style
path.fill = None; path.fill = None;
path.stroke = Some(usvg::Stroke::default()); path.stroke = Some(usvg::Stroke::default());
usvg::Node::new(usvg::NodeKind::Path(path)) usvg::Node::Path(Box::new(path))
} }
} }
@ -499,12 +501,12 @@ impl GraphicElementRendered for ImageFrame<Color> {
fn to_usvg_node(&self) -> usvg::Node { fn to_usvg_node(&self) -> usvg::Node {
let image_frame = self; let image_frame = self;
if image_frame.image.width * image_frame.image.height == 0 { if image_frame.image.width * image_frame.image.height == 0 {
return usvg::Node::new(usvg::NodeKind::Group(usvg::Group::default())); return usvg::Node::Group(Box::new(usvg::Group::default()));
} }
let png = image_frame.image.to_png(); let png = image_frame.image.to_png();
usvg::Node::new(usvg::NodeKind::Image(usvg::Image { usvg::Node::Image(Box::new(usvg::Image {
id: String::new(), id: String::new(),
transform: to_transform(image_frame.transform), abs_transform: to_transform(image_frame.transform),
visibility: usvg::Visibility::Visible, visibility: usvg::Visibility::Visible,
view_box: usvg::ViewBox { view_box: usvg::ViewBox {
rect: usvg::NonZeroRect::from_xywh(0., 0., 1., 1.).unwrap(), rect: usvg::NonZeroRect::from_xywh(0., 0., 1., 1.).unwrap(),
@ -512,6 +514,7 @@ impl GraphicElementRendered for ImageFrame<Color> {
}, },
rendering_mode: usvg::ImageRendering::OptimizeSpeed, rendering_mode: usvg::ImageRendering::OptimizeSpeed,
kind: usvg::ImageKind::PNG(png.into()), kind: usvg::ImageKind::PNG(png.into()),
bounding_box: None,
})) }))
} }
} }
@ -594,12 +597,10 @@ impl<T: Primitive> GraphicElementRendered for T {
fn to_usvg_node(&self) -> usvg::Node { fn to_usvg_node(&self) -> usvg::Node {
let text = self; let text = self;
usvg::Node::new(usvg::NodeKind::Text(usvg::Text { usvg::Node::Text(Box::new(usvg::Text {
id: String::new(), id: String::new(),
transform: usvg::Transform::identity(), abs_transform: usvg::Transform::identity(),
rendering_mode: usvg::TextRendering::OptimizeSpeed, rendering_mode: usvg::TextRendering::OptimizeSpeed,
positions: Vec::new(),
rotate: Vec::new(),
writing_mode: usvg::WritingMode::LeftToRight, writing_mode: usvg::WritingMode::LeftToRight,
chunks: vec![usvg::TextChunk { chunks: vec![usvg::TextChunk {
text: text.to_string(), text: text.to_string(),
@ -609,6 +610,14 @@ impl<T: Primitive> GraphicElementRendered for T {
spans: vec![], spans: vec![],
text_flow: usvg::TextFlow::Linear, text_flow: usvg::TextFlow::Linear,
}], }],
dx: Vec::new(),
dy: Vec::new(),
rotate: Vec::new(),
bounding_box: None,
abs_bounding_box: None,
stroke_bounding_box: None,
abs_stroke_bounding_box: None,
flattened: None,
})) }))
} }
} }

View file

@ -44,7 +44,7 @@ pub trait GpuExecutor {
type BufferHandle: Send + Sync; type BufferHandle: Send + Sync;
type TextureHandle: Send + Sync; type TextureHandle: Send + Sync;
type TextureView: Send + Sync; type TextureView: Send + Sync;
type Surface: Send + Sync; type Surface<'window>: Send + Sync;
type Window; type Window;
type CommandBuffer; type CommandBuffer;
@ -55,10 +55,10 @@ pub trait GpuExecutor {
fn create_texture_view(&self, texture: ShaderInput<Self>) -> Result<ShaderInput<Self>>; fn create_texture_view(&self, texture: ShaderInput<Self>) -> Result<ShaderInput<Self>>;
fn create_output_buffer(&self, len: usize, ty: Type, cpu_readable: bool) -> Result<ShaderInput<Self>>; fn create_output_buffer(&self, len: usize, ty: Type, cpu_readable: bool) -> Result<ShaderInput<Self>>;
fn create_compute_pass(&self, layout: &PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self>>>, instances: ComputePassDimensions) -> Result<Self::CommandBuffer>; fn create_compute_pass(&self, layout: &PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self>>>, instances: ComputePassDimensions) -> Result<Self::CommandBuffer>;
fn create_render_pass(&self, texture: Arc<ShaderInput<Self>>, canvas: Arc<SurfaceHandle<Self::Surface>>) -> Result<()>; fn create_render_pass(&self, texture: Arc<ShaderInput<Self>>, canvas: Arc<SurfaceHandle<Self::Surface<'_>>>) -> Result<()>;
fn execute_compute_pipeline(&self, encoder: Self::CommandBuffer) -> Result<()>; fn execute_compute_pipeline(&self, encoder: Self::CommandBuffer) -> Result<()>;
fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self>>) -> ReadBackFuture; fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self>>) -> ReadBackFuture;
fn create_surface(&self, window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<Self::Surface>>; fn create_surface(&self, window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<Self::Surface<'_>>>;
} }
pub trait SpirVCompiler { pub trait SpirVCompiler {
@ -110,7 +110,7 @@ impl GpuExecutor for DummyExecutor {
type BufferHandle = (); type BufferHandle = ();
type TextureHandle = (); type TextureHandle = ();
type TextureView = (); type TextureView = ();
type Surface = (); type Surface<'window> = ();
type Window = (); type Window = ();
type CommandBuffer = (); type CommandBuffer = ();
@ -142,7 +142,7 @@ impl GpuExecutor for DummyExecutor {
todo!() todo!()
} }
fn create_render_pass(&self, _texture: Arc<ShaderInput<Self>>, _canvas: Arc<SurfaceHandle<Self::Surface>>) -> Result<()> { fn create_render_pass(&self, _texture: Arc<ShaderInput<Self>>, _canvas: Arc<SurfaceHandle<Self::Surface<'_>>>) -> Result<()> {
todo!() todo!()
} }
@ -154,7 +154,7 @@ impl GpuExecutor for DummyExecutor {
todo!() todo!()
} }
fn create_surface(&self, _window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<Self::Surface>> { fn create_surface(&self, _window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<Self::Surface<'_>>> {
todo!() todo!()
} }
} }
@ -496,7 +496,7 @@ async fn read_output_buffer_node<'a: 'input, E: 'a + GpuExecutor>(buffer: Arc<Sh
pub struct CreateGpuSurfaceNode {} pub struct CreateGpuSurfaceNode {}
#[node_macro::node_fn(CreateGpuSurfaceNode)] #[node_macro::node_fn(CreateGpuSurfaceNode)]
async fn create_gpu_surface<'a: 'input, E: 'a + GpuExecutor<Window = Io::Surface>, Io: ApplicationIo<Executor = E>>(editor_api: EditorApi<'a, Io>) -> Arc<SurfaceHandle<E::Surface>> { async fn create_gpu_surface<'a: 'input, E: 'a + GpuExecutor<Window = Io::Surface>, Io: ApplicationIo<Executor = E>>(editor_api: EditorApi<'a, Io>) -> Arc<SurfaceHandle<E::Surface<'a>>> {
let canvas = editor_api.application_io.create_surface(); let canvas = editor_api.application_io.create_surface();
let executor = editor_api.application_io.gpu_executor().unwrap(); let executor = editor_api.application_io.gpu_executor().unwrap();
Arc::new(executor.create_surface(canvas).unwrap()) Arc::new(executor.create_surface(canvas).unwrap())
@ -529,7 +529,7 @@ where
} }
#[node_macro::node_fn(RenderTextureNode)] #[node_macro::node_fn(RenderTextureNode)]
async fn render_texture_node<'a: 'input, E: 'a + GpuExecutor>(image: ShaderInputFrame<E>, surface: Arc<SurfaceHandle<E::Surface>>, executor: &'a E) -> SurfaceFrame { async fn render_texture_node<'a: 'input, E: 'a + GpuExecutor>(image: ShaderInputFrame<E>, surface: Arc<SurfaceHandle<E::Surface<'input>>>, executor: &'a E) -> SurfaceFrame {
let surface_id = surface.surface_id; let surface_id = surface.surface_id;
log::trace!("rendering to surface {surface_id:?}"); log::trace!("rendering to surface {surface_id:?}");

View file

@ -40,6 +40,7 @@ struct InternalImaginateControl {
status: Mutex<ImaginateStatus>, status: Mutex<ImaginateStatus>,
trigger_regenerate: AtomicBool, trigger_regenerate: AtomicBool,
#[serde(skip)] #[serde(skip)]
#[specta(skip)]
termination_sender: Mutex<Option<Box<dyn ImaginateTerminationHandle>>>, termination_sender: Mutex<Option<Box<dyn ImaginateTerminationHandle>>>,
} }

View file

@ -141,9 +141,9 @@ impl ApplicationIo for WasmApplicationIo {
use winit::platform::wayland::EventLoopBuilderExtWayland; use winit::platform::wayland::EventLoopBuilderExtWayland;
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
let event_loop = winit::event_loop::EventLoopBuilder::new().with_any_thread(true).build(); let event_loop = winit::event_loop::EventLoopBuilder::new().with_any_thread(true).build().unwrap();
#[cfg(not(feature = "wayland"))] #[cfg(not(feature = "wayland"))]
let event_loop = winit::event_loop::EventLoop::new(); let event_loop = winit::event_loop::EventLoop::new().unwrap();
let window = winit::window::WindowBuilder::new() let window = winit::window::WindowBuilder::new()
.with_title("Graphite") .with_title("Graphite")
.with_inner_size(winit::dpi::PhysicalSize::new(800, 600)) .with_inner_size(winit::dpi::PhysicalSize::new(800, 600))
@ -336,11 +336,9 @@ fn render_canvas(
if let Some(exec) = editor.application_io.gpu_executor() { if let Some(exec) = editor.application_io.gpu_executor() {
todo!() todo!()
} else { } else {
let rtree = resvg::Tree::from_usvg(&usvg_tree); let pixmap_size = usvg_tree.size.to_int_size();
let pixmap_size = rtree.size.to_int_size();
let mut pixmap = resvg::tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap(); let mut pixmap = resvg::tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap();
rtree.render(resvg::tiny_skia::Transform::default(), &mut pixmap.as_mut()); resvg::render(&usvg_tree, resvg::tiny_skia::Transform::default(), &mut pixmap.as_mut());
let array: Clamped<&[u8]> = Clamped(pixmap.data()); let array: Clamped<&[u8]> = Clamped(pixmap.data());
let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::<CanvasRenderingContext2d>().unwrap(); let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::<CanvasRenderingContext2d>().unwrap();
let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(array, pixmap_size.width(), pixmap_size.height()).expect("Failed to construct ImageData"); let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(array, pixmap_size.width(), pixmap_size.height()).expect("Failed to construct ImageData");

View file

@ -369,9 +369,10 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]
async_node!(gpu_executor::ReadOutputBufferNode<_, _>, input: Arc<ShaderInput<WgpuExecutor>>, output: Vec<u8>, params: [&WgpuExecutor, ()]), async_node!(gpu_executor::ReadOutputBufferNode<_, _>, input: Arc<ShaderInput<WgpuExecutor>>, output: Vec<u8>, params: [&WgpuExecutor, ()]),
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]
async_node!(gpu_executor::CreateGpuSurfaceNode, input: WasmEditorApi, output: Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface>>, params: []), async_node!(gpu_executor::CreateGpuSurfaceNode, input: WasmEditorApi, output: Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface<'_>>>, params: []),
#[cfg(feature = "gpu")] // todo!(gpu) get this to compie without saying that one type is more general than the other
async_node!(gpu_executor::RenderTextureNode<_, _>, input: ShaderInputFrame<WgpuExecutor>, output: SurfaceFrame, params: [Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface>>, &WgpuExecutor]), // #[cfg(feature = "gpu")]
// async_node!(gpu_executor::RenderTextureNode<_, _>, input: ShaderInputFrame<WgpuExecutor>, output: SurfaceFrame, params: [Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface<'_>>>, &WgpuExecutor]),
#[cfg(feature = "gpu")] #[cfg(feature = "gpu")]
async_node!( async_node!(
gpu_executor::UploadTextureNode<_>, gpu_executor::UploadTextureNode<_>,

View file

@ -21,7 +21,7 @@ impl Context {
// `request_adapter` instantiates the general connection to the GPU // `request_adapter` instantiates the general connection to the GPU
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions::default()).await?; let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions::default()).await?;
let limits = adapter.limits(); let required_limits = adapter.limits();
// `request_device` instantiates the feature specific connection to the GPU, defining some parameters, // `request_device` instantiates the feature specific connection to the GPU, defining some parameters,
// `features` being the available features. // `features` being the available features.
let (device, queue) = adapter let (device, queue) = adapter
@ -29,10 +29,10 @@ impl Context {
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
label: None, label: None,
#[cfg(not(feature = "passthrough"))] #[cfg(not(feature = "passthrough"))]
features: wgpu::Features::empty(), required_features: wgpu::Features::empty(),
#[cfg(feature = "passthrough")] #[cfg(feature = "passthrough")]
features: wgpu::Features::SPIRV_SHADER_PASSTHROUGH, required_features: wgpu::Features::SPIRV_SHADER_PASSTHROUGH,
limits, required_limits,
}, },
None, None,
) )

View file

@ -124,7 +124,7 @@ async fn execute_shader<I: Pod + Send + Sync, O: Pod + Send + Sync>(device: Arc<
// It is to WebGPU what a command buffer is to Vulkan. // It is to WebGPU what a command buffer is to Vulkan.
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{ {
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None }); let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None, timestamp_writes: None });
cpass.set_pipeline(&compute_pipeline); cpass.set_pipeline(&compute_pipeline);
cpass.set_bind_group(0, &bind_group, &[]); cpass.set_bind_group(0, &bind_group, &[]);
cpass.insert_debug_marker("compute node network evaluation"); cpass.insert_debug_marker("compute node network evaluation");

View file

@ -43,7 +43,7 @@ impl<'a, T: ApplicationIo<Executor = WgpuExecutor>> From<EditorApi<'a, T>> for &
} }
} }
pub type WgpuSurface = Arc<SurfaceHandle<wgpu::Surface>>; pub type WgpuSurface<'window> = Arc<SurfaceHandle<wgpu::Surface<'window>>>;
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
@ -111,7 +111,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
type TextureHandle = Texture; type TextureHandle = Texture;
type TextureView = TextureView; type TextureView = TextureView;
type CommandBuffer = CommandBufferWrapper; type CommandBuffer = CommandBufferWrapper;
type Surface = wgpu::Surface; type Surface<'window> = wgpu::Surface<'window>;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
type Window = HtmlCanvasElement; type Window = HtmlCanvasElement;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -196,6 +196,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
usage, usage,
view_formats: &[format], view_formats: &[format],
}, },
wgpu::util::TextureDataOrder::LayerMajor,
bytes.as_ref(), bytes.as_ref(),
); );
match options { match options {
@ -256,7 +257,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("compute encoder") }); let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("compute encoder") });
{ {
let dimensions = instances.get(); let dimensions = instances.get();
let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None }); let mut cpass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None, timestamp_writes: None });
cpass.set_pipeline(&compute_pipeline); cpass.set_pipeline(&compute_pipeline);
cpass.set_bind_group(0, &bind_group, &[]); cpass.set_bind_group(0, &bind_group, &[]);
cpass.insert_debug_marker("compute node network evaluation"); cpass.insert_debug_marker("compute node network evaluation");
@ -349,10 +350,12 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Load, load: wgpu::LoadOp::Load,
store: true, store: wgpu::StoreOp::Store,
}, },
})], })],
depth_stencil_attachment: None, depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
}); });
render_pass.set_pipeline(&self.render_configuration.render_pipeline); render_pass.set_pipeline(&self.render_configuration.render_pipeline);
@ -430,7 +433,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
fn create_surface(&self, canvas: graphene_core::WasmSurfaceHandle) -> Result<SurfaceHandle<wgpu::Surface>> { fn create_surface(&self, canvas: graphene_core::WasmSurfaceHandle) -> Result<SurfaceHandle<wgpu::Surface>> {
let surface = self.context.instance.create_surface_from_canvas(canvas.surface)?; let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Canvas(canvas.surface))?;
let surface_caps = surface.get_capabilities(&self.context.adapter); let surface_caps = surface.get_capabilities(&self.context.adapter);
let surface_format = wgpu::TextureFormat::Bgra8Unorm; let surface_format = wgpu::TextureFormat::Bgra8Unorm;
@ -442,6 +445,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: wgpu::CompositeAlphaMode::PreMultiplied, alpha_mode: wgpu::CompositeAlphaMode::PreMultiplied,
view_formats: vec![wgpu::TextureFormat::Bgra8UnormSrgb], view_formats: vec![wgpu::TextureFormat::Bgra8UnormSrgb],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&self.context.device, &config); surface.configure(&self.context.device, &config);
Ok(SurfaceHandle { Ok(SurfaceHandle {
@ -451,9 +455,9 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
fn create_surface(&self, window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<wgpu::Surface>> { fn create_surface(&self, window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<wgpu::Surface>> {
let surface = unsafe { self.context.instance.create_surface(window.surface.as_ref()) }?;
let size = window.surface.inner_size(); let size = window.surface.inner_size();
let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Window(Box::new(window.surface)))?;
let surface_caps = surface.get_capabilities(&self.context.adapter); let surface_caps = surface.get_capabilities(&self.context.adapter);
println!("{surface_caps:?}"); println!("{surface_caps:?}");
let surface_format = wgpu::TextureFormat::Bgra8Unorm; let surface_format = wgpu::TextureFormat::Bgra8Unorm;
@ -465,6 +469,7 @@ impl gpu_executor::GpuExecutor for WgpuExecutor {
present_mode: surface_caps.present_modes[0], present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0], alpha_mode: surface_caps.alpha_modes[0],
view_formats: vec![], view_formats: vec![],
desired_maximum_frame_latency: 2,
}; };
surface.configure(&self.context.device, &config); surface.configure(&self.context.device, &config);
self.surface_config.set(Some(config)); self.surface_config.set(Some(config));