mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-24 16:13:44 +00:00
Integrate raw WGPU textures into Vello rendering pipeline (#1897)
* WIP * Introduce `Raster` enum and plumb texture injection to vello * Use correct texture formas for usage in vello * Add missing cache implementations * Update vello image override api * Use git version of vello * Fix type for upload texture node * Improve crash resiliance * Fix warnings * Remove unused node impls
This commit is contained in:
parent
25a82d100f
commit
e46af89708
19 changed files with 341 additions and 215 deletions
106
Cargo.lock
generated
106
Cargo.lock
generated
|
@ -266,11 +266,11 @@ checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ash"
|
name = "ash"
|
||||||
version = "0.37.3+1.3.251"
|
version = "0.38.0+1.3.281"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
|
checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.7.4",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -600,18 +600,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.3"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
|
checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec",
|
"bit-vec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-vec"
|
name = "bit-vec"
|
||||||
version = "0.6.3"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
|
@ -1240,12 +1240,12 @@ checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "d3d12"
|
name = "d3d12"
|
||||||
version = "0.20.0"
|
version = "22.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813"
|
checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"libloading 0.8.5",
|
"libloading",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1378,7 +1378,7 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.8.5",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2178,9 +2178,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glutin_wgl_sys"
|
name = "glutin_wgl_sys"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead"
|
checksum = "0a4e1951bbd9434a81aa496fe59ccc2235af3820d27b85f9314e279609211e2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gl_generator",
|
"gl_generator",
|
||||||
]
|
]
|
||||||
|
@ -2217,9 +2217,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gpu-allocator"
|
name = "gpu-allocator"
|
||||||
version = "0.25.0"
|
version = "0.26.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
|
checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"presser",
|
"presser",
|
||||||
|
@ -2361,6 +2361,7 @@ dependencies = [
|
||||||
"vello",
|
"vello",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2631,7 +2632,7 @@ dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"com",
|
"com",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.5",
|
"libloading",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"widestring",
|
"widestring",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
@ -3222,7 +3223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
|
checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.5",
|
"libloading",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3268,16 +3269,6 @@ version = "0.2.155"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
@ -3485,9 +3476,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metal"
|
name = "metal"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb"
|
checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block",
|
"block",
|
||||||
|
@ -3501,11 +3492,10 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "meval"
|
name = "meval"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/Titaniumtown/meval-rs#6bf579fd402928745cf4f24e5c975bece3285179"
|
||||||
checksum = "f79496a5651c8d57cd033c5add8ca7ee4e3d5f7587a4777484640d9cb60392d9"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"nom 1.2.4",
|
"nom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3543,18 +3533,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "0.20.0"
|
version = "22.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231"
|
checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
|
"cfg_aliases 0.1.1",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
"hexf-parse",
|
"hexf-parse",
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"log",
|
"log",
|
||||||
"num-traits",
|
|
||||||
"petgraph",
|
"petgraph",
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"spirv",
|
"spirv",
|
||||||
|
@ -3734,12 +3724,6 @@ version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nom"
|
|
||||||
version = "1.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "7.1.3"
|
version = "7.1.3"
|
||||||
|
@ -6715,7 +6699,7 @@ dependencies = [
|
||||||
"fnv",
|
"fnv",
|
||||||
"home",
|
"home",
|
||||||
"memchr",
|
"memchr",
|
||||||
"nom 7.1.3",
|
"nom",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"petgraph",
|
"petgraph",
|
||||||
]
|
]
|
||||||
|
@ -6919,9 +6903,8 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vello"
|
name = "vello"
|
||||||
version = "0.2.1"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/linebender/vello#5d56854ff871ee98dc53cdf8a0e3f7ec628cb90f"
|
||||||
checksum = "861c12258ed7e72762765e2c88a07bb528040ec4e5f87514d65b19b29a7cccf0"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
|
@ -6938,9 +6921,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vello_encoding"
|
name = "vello_encoding"
|
||||||
version = "0.2.1"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/linebender/vello#5d56854ff871ee98dc53cdf8a0e3f7ec628cb90f"
|
||||||
checksum = "e5d73777327877fa824a45c7195f850390dd3f91feb15f47d331db1fc01abf6d"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"guillotiere",
|
"guillotiere",
|
||||||
|
@ -6951,9 +6933,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vello_shaders"
|
name = "vello_shaders"
|
||||||
version = "0.2.1"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/linebender/vello#5d56854ff871ee98dc53cdf8a0e3f7ec628cb90f"
|
||||||
checksum = "13ab6bcb2b079c3cf57e964d1ba0b1f08901284be1c7f5cba34d3e0e08154bce"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"naga",
|
"naga",
|
||||||
|
@ -7340,12 +7321,11 @@ checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu"
|
name = "wgpu"
|
||||||
version = "0.20.1"
|
version = "22.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90e37c7b9921b75dfd26dd973fdcbce36f13dfa6e2dc82aece584e0ed48c355c"
|
checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"cfg-if",
|
|
||||||
"cfg_aliases 0.1.1",
|
"cfg_aliases 0.1.1",
|
||||||
"document-features",
|
"document-features",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
@ -7366,16 +7346,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core"
|
name = "wgpu-core"
|
||||||
version = "0.21.1"
|
version = "22.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d50819ab545b867d8a454d1d756b90cd5f15da1f2943334ca314af10583c9d39"
|
checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-vec",
|
"bit-vec",
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"cfg_aliases 0.1.1",
|
"cfg_aliases 0.1.1",
|
||||||
"codespan-reporting",
|
|
||||||
"document-features",
|
"document-features",
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"log",
|
"log",
|
||||||
|
@ -7387,7 +7366,6 @@ dependencies = [
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"web-sys",
|
|
||||||
"wgpu-hal",
|
"wgpu-hal",
|
||||||
"wgpu-types",
|
"wgpu-types",
|
||||||
]
|
]
|
||||||
|
@ -7420,9 +7398,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-hal"
|
name = "wgpu-hal"
|
||||||
version = "0.21.1"
|
version = "22.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "172e490a87295564f3fcc0f165798d87386f6231b04d4548bca458cbbfd63222"
|
checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
|
@ -7442,7 +7420,7 @@ dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"khronos-egl",
|
"khronos-egl",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.5",
|
"libloading",
|
||||||
"log",
|
"log",
|
||||||
"metal",
|
"metal",
|
||||||
"naga",
|
"naga",
|
||||||
|
@ -7465,9 +7443,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-types"
|
name = "wgpu-types"
|
||||||
version = "0.20.0"
|
version = "22.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef"
|
checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
@ -8124,7 +8102,7 @@ dependencies = [
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
"libc",
|
"libc",
|
||||||
"libloading 0.8.5",
|
"libloading",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"x11rb-protocol",
|
"x11rb-protocol",
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -56,8 +56,8 @@ chrono = "0.4"
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
fastnoise-lite = "1.1"
|
fastnoise-lite = "1.1"
|
||||||
spirv-std = { git = "https://github.com/GraphiteEditor/rust-gpu.git" }
|
spirv-std = { git = "https://github.com/GraphiteEditor/rust-gpu.git" }
|
||||||
wgpu-types = "0.20"
|
wgpu-types = "22"
|
||||||
wgpu = { version = "0.20", features = ["strict_asserts", "api_log_info"] }
|
wgpu = { version = "22.1", features = ["strict_asserts"] }
|
||||||
once_cell = "1.13" # Remove when `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) is stabilized in Rust 1.80 and we bump our MSRV
|
once_cell = "1.13" # Remove when `core::cell::LazyCell` (<https://doc.rust-lang.org/core/cell/struct.LazyCell.html>) is stabilized in Rust 1.80 and we bump our MSRV
|
||||||
wasm-bindgen = "=0.2.92" # NOTICE: ensure this stays in sync with the `wasm-bindgen-cli` version in `website/content/volunteer/guide/getting-started/_index.md`. We pin this version because wasm-bindgen upgrades may break various things.
|
wasm-bindgen = "=0.2.92" # NOTICE: ensure this stays in sync with the `wasm-bindgen-cli` version in `website/content/volunteer/guide/getting-started/_index.md`. We pin this version because wasm-bindgen upgrades may break various things.
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
|
@ -66,7 +66,7 @@ web-sys = "=0.3.69"
|
||||||
winit = "0.29"
|
winit = "0.29"
|
||||||
url = "2.5"
|
url = "2.5"
|
||||||
tokio = { version = "1.29", features = ["fs", "io-std"] }
|
tokio = { version = "1.29", features = ["fs", "io-std"] }
|
||||||
vello = "0.2"
|
vello = { git = "https://github.com/linebender/vello" }
|
||||||
resvg = "0.42"
|
resvg = "0.42"
|
||||||
usvg = "0.42"
|
usvg = "0.42"
|
||||||
rand = { version = "0.8", default-features = false }
|
rand = { version = "0.8", default-features = false }
|
||||||
|
@ -92,6 +92,9 @@ syn = { version = "2.0", default-features = false, features = [
|
||||||
] }
|
] }
|
||||||
kurbo = { version = "0.11.0", features = ["serde"] }
|
kurbo = { version = "0.11.0", features = ["serde"] }
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
meval = { git = "https://github.com/Titaniumtown/meval-rs" }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 1
|
opt-level = 1
|
||||||
|
|
||||||
|
@ -110,6 +113,7 @@ syn = { opt-level = 3 }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "thin"
|
lto = "thin"
|
||||||
|
debug = true
|
||||||
|
|
||||||
[profile.profiling]
|
[profile.profiling]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|
|
@ -2099,7 +2099,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
DocumentNode {
|
DocumentNode {
|
||||||
manual_composition: Some(concrete!(())),
|
manual_composition: Some(concrete!(Footprint)),
|
||||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||||
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")),
|
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::memo::ImpureMemoNode<_, _, _>")),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -385,11 +385,12 @@ pub async fn introspect_node(path: &[NodeId]) -> Option<Arc<dyn std::any::Any>>
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_node_graph() {
|
pub async fn run_node_graph() -> bool {
|
||||||
let Some(mut runtime) = NODE_RUNTIME.try_lock() else { return };
|
let Some(mut runtime) = NODE_RUNTIME.try_lock() else { return false };
|
||||||
if let Some(ref mut runtime) = runtime.as_mut() {
|
if let Some(ref mut runtime) = runtime.as_mut() {
|
||||||
runtime.run().await;
|
runtime.run().await;
|
||||||
}
|
}
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn replace_node_runtime(runtime: NodeRuntime) -> Option<NodeRuntime> {
|
pub async fn replace_node_runtime(runtime: NodeRuntime) -> Option<NodeRuntime> {
|
||||||
|
|
|
@ -52,8 +52,6 @@ web-sys = { workspace = true, features = [
|
||||||
# Optional workspace dependencies
|
# Optional workspace dependencies
|
||||||
ron = { workspace = true, optional = true }
|
ron = { workspace = true, optional = true }
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
debug = true
|
|
||||||
|
|
||||||
[package.metadata.wasm-pack.profile.dev]
|
[package.metadata.wasm-pack.profile.dev]
|
||||||
wasm-opt = false
|
wasm-opt = false
|
||||||
|
|
|
@ -948,10 +948,10 @@ fn set_timeout(f: &Closure<dyn FnMut()>, delay: Duration) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Provides access to the `Editor` by calling the given closure with it as an argument.
|
/// Provides access to the `Editor` by calling the given closure with it as an argument.
|
||||||
fn editor<T>(callback: impl FnOnce(&mut editor::application::Editor) -> T) -> T {
|
fn editor<T: Default>(callback: impl FnOnce(&mut editor::application::Editor) -> T) -> T {
|
||||||
EDITOR.with(|editor| {
|
EDITOR.with(|editor| {
|
||||||
let mut guard = editor.lock();
|
let mut guard = editor.try_lock();
|
||||||
let Ok(Some(ref mut editor)) = guard.as_deref_mut() else { panic!("Failed to borrow the editor") };
|
let Ok(Some(ref mut editor)) = guard.as_deref_mut() else { return T::default() };
|
||||||
|
|
||||||
callback(editor)
|
callback(editor)
|
||||||
})
|
})
|
||||||
|
@ -961,7 +961,7 @@ fn editor<T>(callback: impl FnOnce(&mut editor::application::Editor) -> T) -> T
|
||||||
pub(crate) fn editor_and_handle(mut callback: impl FnMut(&mut Editor, &mut EditorHandle)) {
|
pub(crate) fn editor_and_handle(mut callback: impl FnMut(&mut Editor, &mut EditorHandle)) {
|
||||||
EDITOR_HANDLE.with(|editor_handle| {
|
EDITOR_HANDLE.with(|editor_handle| {
|
||||||
editor(|editor| {
|
editor(|editor| {
|
||||||
let mut guard = editor_handle.lock();
|
let mut guard = editor_handle.try_lock();
|
||||||
let Ok(Some(ref mut editor_handle)) = guard.as_deref_mut() else {
|
let Ok(Some(ref mut editor_handle)) = guard.as_deref_mut() else {
|
||||||
log::error!("Failed to borrow editor handle");
|
log::error!("Failed to borrow editor handle");
|
||||||
return;
|
return;
|
||||||
|
@ -979,7 +979,9 @@ async fn poll_node_graph_evaluation() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
editor::node_graph_executor::run_node_graph().await;
|
if !editor::node_graph_executor::run_node_graph().await {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
editor_and_handle(|editor, handle| {
|
editor_and_handle(|editor, handle| {
|
||||||
let mut messages = VecDeque::new();
|
let mut messages = VecDeque::new();
|
||||||
|
|
|
@ -14,7 +14,8 @@ nightly = []
|
||||||
alloc = ["dyn-any", "bezier-rs"]
|
alloc = ["dyn-any", "bezier-rs"]
|
||||||
type_id_logging = []
|
type_id_logging = []
|
||||||
wasm = ["web-sys"]
|
wasm = ["web-sys"]
|
||||||
vello = ["dep:vello", "bezier-rs/kurbo"]
|
wgpu = ["dep:wgpu"]
|
||||||
|
vello = ["dep:vello", "bezier-rs/kurbo", "wgpu"]
|
||||||
std = [
|
std = [
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
"dyn-any/std",
|
"dyn-any/std",
|
||||||
|
@ -59,6 +60,7 @@ bezier-rs = { workspace = true, optional = true }
|
||||||
kurbo = { workspace = true, optional = true }
|
kurbo = { workspace = true, optional = true }
|
||||||
base64 = { workspace = true, optional = true }
|
base64 = { workspace = true, optional = true }
|
||||||
vello = { workspace = true, optional = true }
|
vello = { workspace = true, optional = true }
|
||||||
|
wgpu = { workspace = true, optional = true }
|
||||||
specta = { workspace = true, optional = true }
|
specta = { workspace = true, optional = true }
|
||||||
rustybuzz = { workspace = true, optional = true }
|
rustybuzz = { workspace = true, optional = true }
|
||||||
wasm-bindgen = { workspace = true, optional = true }
|
wasm-bindgen = { workspace = true, optional = true }
|
||||||
|
|
|
@ -63,6 +63,55 @@ impl Size for web_sys::HtmlCanvasElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TextureFrame {
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
pub texture: Arc<wgpu::Texture>,
|
||||||
|
#[cfg(not(feature = "wgpu"))]
|
||||||
|
pub texture: (),
|
||||||
|
pub transform: DAffine2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for TextureFrame {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.transform.to_cols_array().iter().for_each(|x| x.to_bits().hash(state));
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
self.texture.global_id().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for TextureFrame {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
return self.transform.eq(&other.transform) && self.texture.global_id() == other.texture.global_id();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "wgpu"))]
|
||||||
|
self.transform.eq(&other.transform)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transform for TextureFrame {
|
||||||
|
fn transform(&self) -> DAffine2 {
|
||||||
|
self.transform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TransformMut for TextureFrame {
|
||||||
|
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||||
|
&mut self.transform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl StaticType for TextureFrame {
|
||||||
|
type Static = TextureFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
impl Size for TextureFrame {
|
||||||
|
fn size(&self) -> UVec2 {
|
||||||
|
UVec2::new(self.texture.width(), self.texture.height())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: Size> From<SurfaceHandleFrame<S>> for SurfaceFrame {
|
impl<S: Size> From<SurfaceHandleFrame<S>> for SurfaceFrame {
|
||||||
fn from(x: SurfaceHandleFrame<S>) -> Self {
|
fn from(x: SurfaceHandleFrame<S>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
use crate::application_io::SurfaceHandleFrame;
|
use crate::application_io::TextureFrame;
|
||||||
use crate::raster::{BlendMode, ImageFrame};
|
use crate::raster::{BlendMode, ImageFrame};
|
||||||
use crate::transform::Footprint;
|
use crate::transform::{Footprint, Transform, TransformMut};
|
||||||
use crate::vector::VectorData;
|
use crate::vector::VectorData;
|
||||||
use crate::{Color, Node, SurfaceFrame};
|
use crate::{Color, Node};
|
||||||
|
|
||||||
use dyn_any::{DynAny, StaticType};
|
use dyn_any::{DynAny, StaticType};
|
||||||
use node_macro::node_fn;
|
use node_macro::node_fn;
|
||||||
|
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use glam::{DAffine2, IVec2, UVec2};
|
use glam::{DAffine2, IVec2};
|
||||||
use web_sys::HtmlCanvasElement;
|
|
||||||
|
|
||||||
pub mod renderer;
|
pub mod renderer;
|
||||||
|
|
||||||
|
@ -65,10 +64,7 @@ pub enum GraphicElement {
|
||||||
GraphicGroup(GraphicGroup),
|
GraphicGroup(GraphicGroup),
|
||||||
/// A vector shape, equivalent to the SVG <path> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
|
/// A vector shape, equivalent to the SVG <path> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path
|
||||||
VectorData(Box<VectorData>),
|
VectorData(Box<VectorData>),
|
||||||
/// A bitmap image with a finite position and extent, equivalent to the SVG <image> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
|
Raster(Raster),
|
||||||
ImageFrame(ImageFrame<Color>),
|
|
||||||
/// A Canvas element
|
|
||||||
Surface(SurfaceFrame),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Can this be removed? It doesn't necessarily make that much sense to have a default when, instead, the entire GraphicElement just shouldn't exist if there's no specific content to assign it.
|
// TODO: Can this be removed? It doesn't necessarily make that much sense to have a default when, instead, the entire GraphicElement just shouldn't exist if there's no specific content to assign it.
|
||||||
|
@ -78,6 +74,58 @@ impl Default for GraphicElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||||
|
pub enum Raster {
|
||||||
|
/// A bitmap image with a finite position and extent, equivalent to the SVG <image> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
|
||||||
|
ImageFrame(ImageFrame<Color>),
|
||||||
|
Texture(TextureFrame),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for Raster {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let frame = ImageFrame::deserialize(deserializer)?;
|
||||||
|
Ok(Raster::ImageFrame(frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::Serialize for Raster {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Raster::ImageFrame(_) => self.serialize(serializer),
|
||||||
|
Raster::Texture(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Transform for Raster {
|
||||||
|
fn transform(&self) -> DAffine2 {
|
||||||
|
match self {
|
||||||
|
Raster::ImageFrame(frame) => frame.transform(),
|
||||||
|
Raster::Texture(frame) => frame.transform(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn local_pivot(&self, pivot: glam::DVec2) -> glam::DVec2 {
|
||||||
|
match self {
|
||||||
|
Raster::ImageFrame(frame) => frame.local_pivot(pivot),
|
||||||
|
Raster::Texture(frame) => frame.local_pivot(pivot),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TransformMut for Raster {
|
||||||
|
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||||
|
match self {
|
||||||
|
Raster::ImageFrame(frame) => frame.transform_mut(),
|
||||||
|
Raster::Texture(frame) => frame.transform_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Some [`ArtboardData`] with some optional clipping bounds that can be exported.
|
/// Some [`ArtboardData`] with some optional clipping bounds that can be exported.
|
||||||
/// Similar to an Inkscape page: https://media.inkscape.org/media/doc/release_notes/1.2/Inkscape_1.2.html#Page_tool
|
/// Similar to an Inkscape page: https://media.inkscape.org/media/doc/release_notes/1.2/Inkscape_1.2.html#Page_tool
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||||
|
@ -202,7 +250,12 @@ async fn add_artboard<Data: Into<Artboard> + Send>(footprint: Footprint, artboar
|
||||||
|
|
||||||
impl From<ImageFrame<Color>> for GraphicElement {
|
impl From<ImageFrame<Color>> for GraphicElement {
|
||||||
fn from(image_frame: ImageFrame<Color>) -> Self {
|
fn from(image_frame: ImageFrame<Color>) -> Self {
|
||||||
GraphicElement::ImageFrame(image_frame)
|
GraphicElement::Raster(Raster::ImageFrame(image_frame))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<TextureFrame> for GraphicElement {
|
||||||
|
fn from(texture: TextureFrame) -> Self {
|
||||||
|
GraphicElement::Raster(Raster::Texture(texture))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<VectorData> for GraphicElement {
|
impl From<VectorData> for GraphicElement {
|
||||||
|
@ -215,39 +268,6 @@ impl From<GraphicGroup> for GraphicElement {
|
||||||
GraphicElement::GraphicGroup(graphic_group)
|
GraphicElement::GraphicGroup(graphic_group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<SurfaceFrame> for GraphicElement {
|
|
||||||
fn from(surface: SurfaceFrame) -> Self {
|
|
||||||
GraphicElement::Surface(surface)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<alloc::sync::Arc<SurfaceHandleFrame<HtmlCanvasElement>>> for GraphicElement {
|
|
||||||
fn from(surface: alloc::sync::Arc<SurfaceHandleFrame<HtmlCanvasElement>>) -> Self {
|
|
||||||
let surface_id = surface.surface_handle.window_id;
|
|
||||||
let transform = surface.transform;
|
|
||||||
GraphicElement::Surface(SurfaceFrame {
|
|
||||||
surface_id,
|
|
||||||
transform,
|
|
||||||
resolution: UVec2 {
|
|
||||||
x: surface.surface_handle.surface.width(),
|
|
||||||
y: surface.surface_handle.surface.height(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<SurfaceHandleFrame<HtmlCanvasElement>> for GraphicElement {
|
|
||||||
fn from(surface: SurfaceHandleFrame<HtmlCanvasElement>) -> Self {
|
|
||||||
let surface_id = surface.surface_handle.window_id;
|
|
||||||
let transform = surface.transform;
|
|
||||||
GraphicElement::Surface(SurfaceFrame {
|
|
||||||
surface_id,
|
|
||||||
transform,
|
|
||||||
resolution: UVec2 {
|
|
||||||
x: surface.surface_handle.surface.width(),
|
|
||||||
y: surface.surface_handle.surface.height(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for GraphicGroup {
|
impl Deref for GraphicGroup {
|
||||||
type Target = Vec<GraphicElement>;
|
type Target = Vec<GraphicElement>;
|
||||||
|
|
|
@ -3,13 +3,12 @@ mod rect;
|
||||||
pub use quad::Quad;
|
pub use quad::Quad;
|
||||||
pub use rect::Rect;
|
pub use rect::Rect;
|
||||||
|
|
||||||
use crate::raster::bbox::Bbox;
|
|
||||||
use crate::raster::{BlendMode, Image, ImageFrame};
|
use crate::raster::{BlendMode, Image, ImageFrame};
|
||||||
use crate::transform::Transform;
|
use crate::transform::Transform;
|
||||||
use crate::uuid::generate_uuid;
|
use crate::uuid::generate_uuid;
|
||||||
use crate::vector::style::{Fill, Stroke, ViewMode};
|
use crate::vector::style::{Fill, Stroke, ViewMode};
|
||||||
use crate::vector::PointId;
|
use crate::vector::PointId;
|
||||||
use crate::SurfaceFrame;
|
use crate::Raster;
|
||||||
use crate::{vector::VectorData, Artboard, Color, GraphicElement, GraphicGroup};
|
use crate::{vector::VectorData, Artboard, Color, GraphicElement, GraphicGroup};
|
||||||
|
|
||||||
use bezier_rs::Subpath;
|
use bezier_rs::Subpath;
|
||||||
|
@ -219,6 +218,12 @@ pub enum ImageRenderMode {
|
||||||
Base64,
|
Base64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct RenderContext {
|
||||||
|
#[cfg(feature = "wgpu")]
|
||||||
|
pub ressource_overrides: std::collections::HashMap<u64, alloc::sync::Arc<wgpu::Texture>>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Static state used whilst rendering
|
/// Static state used whilst rendering
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RenderParams {
|
pub struct RenderParams {
|
||||||
|
@ -268,13 +273,13 @@ pub trait GraphicElementRendered {
|
||||||
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]>;
|
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]>;
|
||||||
fn add_click_targets(&self, click_targets: &mut Vec<ClickTarget>);
|
fn add_click_targets(&self, click_targets: &mut Vec<ClickTarget>);
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn to_vello_scene(&self, transform: DAffine2) -> Scene {
|
fn to_vello_scene(&self, transform: DAffine2, context: &mut RenderContext) -> Scene {
|
||||||
let mut scene = vello::Scene::new();
|
let mut scene = vello::Scene::new();
|
||||||
self.render_to_vello(&mut scene, transform);
|
self.render_to_vello(&mut scene, transform, context);
|
||||||
scene
|
scene
|
||||||
}
|
}
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, _scene: &mut Scene, _transform: DAffine2) {}
|
fn render_to_vello(&self, _scene: &mut Scene, _transform: DAffine2, _render_condext: &mut RenderContext) {}
|
||||||
|
|
||||||
fn contains_artboard(&self) -> bool {
|
fn contains_artboard(&self) -> bool {
|
||||||
false
|
false
|
||||||
|
@ -323,7 +328,7 @@ impl GraphicElementRendered for GraphicGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
|
||||||
let child_transform = transform * self.transform;
|
let child_transform = transform * self.transform;
|
||||||
|
|
||||||
let Some(bounds) = self.bounding_box(transform) else { return };
|
let Some(bounds) = self.bounding_box(transform) else { return };
|
||||||
|
@ -340,7 +345,7 @@ impl GraphicElementRendered for GraphicGroup {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for element in self.iter() {
|
for element in self.iter() {
|
||||||
element.render_to_vello(scene, child_transform);
|
element.render_to_vello(scene, child_transform, context);
|
||||||
}
|
}
|
||||||
if layer {
|
if layer {
|
||||||
scene.pop_layer();
|
scene.pop_layer();
|
||||||
|
@ -406,7 +411,7 @@ impl GraphicElementRendered for VectorData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _: &mut RenderContext) {
|
||||||
use crate::vector::style::GradientType;
|
use crate::vector::style::GradientType;
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
|
@ -593,7 +598,7 @@ impl GraphicElementRendered for Artboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
// Render background
|
// Render background
|
||||||
|
@ -608,7 +613,7 @@ impl GraphicElementRendered for Artboard {
|
||||||
if self.clip {
|
if self.clip {
|
||||||
scene.push_layer(blend_mode, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
scene.push_layer(blend_mode, 1., kurbo::Affine::new(transform.to_cols_array()), &rect);
|
||||||
}
|
}
|
||||||
self.graphic_group.render_to_vello(scene, transform);
|
self.graphic_group.render_to_vello(scene, transform, context);
|
||||||
if self.clip {
|
if self.clip {
|
||||||
scene.pop_layer();
|
scene.pop_layer();
|
||||||
}
|
}
|
||||||
|
@ -643,9 +648,9 @@ impl GraphicElementRendered for crate::ArtboardGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
|
||||||
for artboard in &self.artboards {
|
for artboard in &self.artboards {
|
||||||
artboard.render_to_vello(scene, transform)
|
artboard.render_to_vello(scene, transform, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,42 +659,6 @@ impl GraphicElementRendered for crate::ArtboardGroup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GraphicElementRendered for SurfaceFrame {
|
|
||||||
fn render_svg(&self, render: &mut SvgRender, _render_params: &RenderParams) {
|
|
||||||
let transform = self.transform;
|
|
||||||
|
|
||||||
let (width, height) = (transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length());
|
|
||||||
|
|
||||||
let matrix = format_transform_matrix(transform * DAffine2::from_scale((width, height).into()).inverse());
|
|
||||||
let transform = if matrix.is_empty() { String::new() } else { format!(r#" transform="{}""#, matrix) };
|
|
||||||
|
|
||||||
let canvas = format!(
|
|
||||||
r#"<foreignObject width="{}" height="{}"{transform}><div data-canvas-placeholder="canvas{}"></div></foreignObject>"#,
|
|
||||||
width.abs(),
|
|
||||||
height.abs(),
|
|
||||||
self.surface_id
|
|
||||||
);
|
|
||||||
render.svg.push(canvas.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
|
||||||
fn render_to_vello(&self, _scene: &mut Scene, _transform: DAffine2) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
|
|
||||||
let bbox = Bbox::from_transform(transform);
|
|
||||||
let aabb = bbox.to_axis_aligned_bbox();
|
|
||||||
Some([aabb.start, aabb.end])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
|
||||||
|
|
||||||
fn contains_artboard(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GraphicElementRendered for ImageFrame<Color> {
|
impl GraphicElementRendered for ImageFrame<Color> {
|
||||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||||
let transform = self.transform * render.transform;
|
let transform = self.transform * render.transform;
|
||||||
|
@ -737,7 +706,7 @@ impl GraphicElementRendered for ImageFrame<Color> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, _: &mut RenderContext) {
|
||||||
use vello::peniko;
|
use vello::peniko;
|
||||||
|
|
||||||
let image = &self.image;
|
let image = &self.image;
|
||||||
|
@ -756,51 +725,135 @@ impl GraphicElementRendered for ImageFrame<Color> {
|
||||||
scene.draw_image(&image, vello::kurbo::Affine::new(transform.to_cols_array()));
|
scene.draw_image(&image, vello::kurbo::Affine::new(transform.to_cols_array()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl GraphicElementRendered for Raster {
|
||||||
|
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||||
|
let transform = self.transform() * render.transform;
|
||||||
|
|
||||||
|
match render_params.image_render_mode {
|
||||||
|
ImageRenderMode::Base64 => {
|
||||||
|
let image = match self {
|
||||||
|
Raster::ImageFrame(ref image) => image,
|
||||||
|
Raster::Texture(_) => return,
|
||||||
|
};
|
||||||
|
let (image, blending) = (&image.image, image.alpha_blending);
|
||||||
|
if image.data.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let base64_string = image.base64_string.clone().unwrap_or_else(|| {
|
||||||
|
let output = image.to_png();
|
||||||
|
let preamble = "data:image/png;base64,";
|
||||||
|
let mut base64_string = String::with_capacity(preamble.len() + output.len() * 4);
|
||||||
|
base64_string.push_str(preamble);
|
||||||
|
base64::engine::general_purpose::STANDARD.encode_string(output, &mut base64_string);
|
||||||
|
base64_string
|
||||||
|
});
|
||||||
|
render.leaf_tag("image", |attributes| {
|
||||||
|
attributes.push("width", 1.to_string());
|
||||||
|
attributes.push("height", 1.to_string());
|
||||||
|
attributes.push("preserveAspectRatio", "none");
|
||||||
|
attributes.push("href", base64_string);
|
||||||
|
let matrix = format_transform_matrix(transform);
|
||||||
|
if !matrix.is_empty() {
|
||||||
|
attributes.push("transform", matrix);
|
||||||
|
}
|
||||||
|
if blending.blend_mode != BlendMode::default() {
|
||||||
|
attributes.push("style", blending.blend_mode.render());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||||
|
let transform = self.transform() * transform;
|
||||||
|
(transform.matrix2 != glam::DMat2::ZERO).then(|| (transform * Quad::from_box([DVec2::ZERO, DVec2::ONE])).bounding_box())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
||||||
|
let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE);
|
||||||
|
click_targets.push(ClickTarget::new(subpath, 0.));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "vello")]
|
||||||
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
|
||||||
|
use vello::peniko;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Raster::ImageFrame(image_frame) => {
|
||||||
|
let image = &image_frame.image;
|
||||||
|
if image.data.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let image = vello::peniko::Image {
|
||||||
|
data: image.to_flat_u8().0.into(),
|
||||||
|
width: image.width,
|
||||||
|
height: image.height,
|
||||||
|
format: peniko::Format::Rgba8,
|
||||||
|
extend: peniko::Extend::Repeat,
|
||||||
|
};
|
||||||
|
let transform = transform * self.transform() * DAffine2::from_scale(1. / DVec2::new(image.width as f64, image.height as f64));
|
||||||
|
|
||||||
|
scene.draw_image(&image, vello::kurbo::Affine::new(transform.to_cols_array()));
|
||||||
|
}
|
||||||
|
Raster::Texture(texture) => {
|
||||||
|
let image = vello::peniko::Image {
|
||||||
|
data: vec![].into(),
|
||||||
|
width: texture.texture.width(),
|
||||||
|
height: texture.texture.height(),
|
||||||
|
format: peniko::Format::Rgba8,
|
||||||
|
extend: peniko::Extend::Repeat,
|
||||||
|
};
|
||||||
|
let id = image.data.id();
|
||||||
|
context.ressource_overrides.insert(id, texture.texture.clone());
|
||||||
|
|
||||||
|
let transform = transform * self.transform() * DAffine2::from_scale(1. / DVec2::new(image.width as f64, image.height as f64));
|
||||||
|
|
||||||
|
scene.draw_image(&image, vello::kurbo::Affine::new(transform.to_cols_array()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GraphicElementRendered for GraphicElement {
|
impl GraphicElementRendered for GraphicElement {
|
||||||
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_data) => vector_data.render_svg(render, render_params),
|
GraphicElement::VectorData(vector_data) => vector_data.render_svg(render, render_params),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.render_svg(render, render_params),
|
GraphicElement::Raster(raster) => raster.render_svg(render, render_params),
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.render_svg(render, render_params),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.render_svg(render, render_params),
|
||||||
GraphicElement::Surface(surface) => surface.render_svg(render, render_params),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
|
fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_data) => GraphicElementRendered::bounding_box(&**vector_data, transform),
|
GraphicElement::VectorData(vector_data) => GraphicElementRendered::bounding_box(&**vector_data, transform),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.bounding_box(transform),
|
GraphicElement::Raster(raster) => raster.bounding_box(transform),
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.bounding_box(transform),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.bounding_box(transform),
|
||||||
GraphicElement::Surface(surface) => surface.bounding_box(transform),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
fn add_click_targets(&self, click_targets: &mut Vec<ClickTarget>) {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_data) => vector_data.add_click_targets(click_targets),
|
GraphicElement::VectorData(vector_data) => vector_data.add_click_targets(click_targets),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.add_click_targets(click_targets),
|
GraphicElement::Raster(raster) => raster.add_click_targets(click_targets),
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.add_click_targets(click_targets),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.add_click_targets(click_targets),
|
||||||
GraphicElement::Surface(surface) => surface.add_click_targets(click_targets),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "vello")]
|
#[cfg(feature = "vello")]
|
||||||
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2) {
|
fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_data) => vector_data.render_to_vello(scene, transform),
|
GraphicElement::VectorData(vector_data) => vector_data.render_to_vello(scene, transform, context),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.render_to_vello(scene, transform),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.render_to_vello(scene, transform, context),
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.render_to_vello(scene, transform),
|
GraphicElement::Raster(raster) => raster.render_to_vello(scene, transform, context),
|
||||||
GraphicElement::Surface(surface) => surface.render_to_vello(scene, transform),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_artboard(&self) -> bool {
|
fn contains_artboard(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_data) => vector_data.contains_artboard(),
|
GraphicElement::VectorData(vector_data) => vector_data.contains_artboard(),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.contains_artboard(),
|
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.contains_artboard(),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.contains_artboard(),
|
||||||
GraphicElement::Surface(surface) => surface.contains_artboard(),
|
GraphicElement::Raster(raster) => raster.contains_artboard(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,17 +65,15 @@ impl Transform for GraphicElement {
|
||||||
fn transform(&self) -> DAffine2 {
|
fn transform(&self) -> DAffine2 {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_shape) => vector_shape.transform(),
|
GraphicElement::VectorData(vector_shape) => vector_shape.transform(),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.transform(),
|
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.transform(),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.transform(),
|
||||||
GraphicElement::Surface(surface) => surface.transform(),
|
GraphicElement::Raster(raster) => raster.transform(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_shape) => vector_shape.local_pivot(pivot),
|
GraphicElement::VectorData(vector_shape) => vector_shape.local_pivot(pivot),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.local_pivot(pivot),
|
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.local_pivot(pivot),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.local_pivot(pivot),
|
||||||
GraphicElement::Surface(surface) => surface.local_pivot(pivot),
|
GraphicElement::Raster(raster) => raster.local_pivot(pivot),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,9 +81,8 @@ impl TransformMut for GraphicElement {
|
||||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||||
match self {
|
match self {
|
||||||
GraphicElement::VectorData(vector_shape) => vector_shape.transform_mut(),
|
GraphicElement::VectorData(vector_shape) => vector_shape.transform_mut(),
|
||||||
GraphicElement::ImageFrame(image_frame) => image_frame.transform_mut(),
|
|
||||||
GraphicElement::GraphicGroup(graphic_group) => graphic_group.transform_mut(),
|
GraphicElement::GraphicGroup(graphic_group) => graphic_group.transform_mut(),
|
||||||
GraphicElement::Surface(surface) => surface.transform_mut(),
|
GraphicElement::Raster(raster) => raster.transform_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,7 @@ pub struct MaskImageNode<P, S, Stencil> {
|
||||||
fn mask_image<
|
fn mask_image<
|
||||||
// _P is the color of the input image. It must have an alpha channel because that is going to
|
// _P is the color of the input image. It must have an alpha channel because that is going to
|
||||||
// be modified by the mask
|
// be modified by the mask
|
||||||
_P: Copy + Alpha,
|
_P: Alpha,
|
||||||
// _S is the color of the stencil. It must have a luminance channel because that is used to
|
// _S is the color of the stencil. It must have a luminance channel because that is used to
|
||||||
// mask the input image
|
// mask the input image
|
||||||
_S: Luminance,
|
_S: Luminance,
|
||||||
|
|
|
@ -74,8 +74,7 @@ fn boolean_operation_node(graphic_group: GraphicGroup, boolean_operation: Boolea
|
||||||
let vector_data = collect_vector_data(graphic_group);
|
let vector_data = collect_vector_data(graphic_group);
|
||||||
boolean_operation_on_vector_data(&vector_data, BooleanOperation::Union)
|
boolean_operation_on_vector_data(&vector_data, BooleanOperation::Union)
|
||||||
}
|
}
|
||||||
GraphicElement::ImageFrame(image) => vector_from_image(image),
|
GraphicElement::Raster(image) => vector_from_image(image),
|
||||||
GraphicElement::Surface(image) => vector_from_image(image),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,12 +120,13 @@ async fn render_canvas(render_config: RenderConfig, data: impl GraphicElementRen
|
||||||
let mut scene = Scene::new();
|
let mut scene = Scene::new();
|
||||||
let mut child = Scene::new();
|
let mut child = Scene::new();
|
||||||
|
|
||||||
data.render_to_vello(&mut child, glam::DAffine2::IDENTITY);
|
let mut context = wgpu_executor::RenderContext::default();
|
||||||
|
data.render_to_vello(&mut child, glam::DAffine2::IDENTITY, &mut context);
|
||||||
|
|
||||||
// TODO: Instead of applying the transform here, pass the transform during the translation to avoid the O(Nr cost
|
// TODO: Instead of applying the transform here, pass the transform during the translation to avoid the O(Nr cost
|
||||||
scene.append(&child, Some(kurbo::Affine::new(footprint.transform.to_cols_array())));
|
scene.append(&child, Some(kurbo::Affine::new(footprint.transform.to_cols_array())));
|
||||||
|
|
||||||
exec.render_vello_scene(&scene, &surface_handle, footprint.resolution.x, footprint.resolution.y)
|
exec.render_vello_scene(&scene, &surface_handle, footprint.resolution.x, footprint.resolution.y, &context)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to render Vello scene");
|
.expect("Failed to render Vello scene");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use graphene_core::{concrete, generic, Artboard, ArtboardGroup, GraphicGroup};
|
||||||
use graphene_core::{Cow, ProtoNodeIdentifier, Type};
|
use graphene_core::{Cow, ProtoNodeIdentifier, Type};
|
||||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
||||||
use graphene_std::application_io::RenderConfig;
|
use graphene_std::application_io::{RenderConfig, TextureFrame};
|
||||||
use graphene_std::raster::*;
|
use graphene_std::raster::*;
|
||||||
use graphene_std::wasm_application_io::*;
|
use graphene_std::wasm_application_io::*;
|
||||||
use graphene_std::GraphicElement;
|
use graphene_std::GraphicElement;
|
||||||
|
@ -389,7 +389,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
async_node!(
|
async_node!(
|
||||||
wgpu_executor::UploadTextureNode<_>,
|
wgpu_executor::UploadTextureNode<_>,
|
||||||
input: ImageFrame<Color>,
|
input: ImageFrame<Color>,
|
||||||
output: ShaderInputFrame,
|
output: TextureFrame,
|
||||||
params: [&WgpuExecutor]
|
params: [&WgpuExecutor]
|
||||||
),
|
),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
|
@ -608,6 +608,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: QuantizationChannels, params: [QuantizationChannels]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: QuantizationChannels, params: [QuantizationChannels]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Vec<DVec2>, params: [Vec<DVec2>]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Vec<DVec2>, params: [Vec<DVec2>]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Arc<WasmSurfaceHandle>, params: [Arc<WasmSurfaceHandle>]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Arc<WasmSurfaceHandle>, params: [Arc<WasmSurfaceHandle>]),
|
||||||
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Arc<TextureFrame>, params: [Arc<WasmSurfaceHandle>]),
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: WindowHandle, params: [WindowHandle]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: WindowHandle, params: [WindowHandle]),
|
||||||
#[cfg(feature = "gpu")]
|
#[cfg(feature = "gpu")]
|
||||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: ShaderInputFrame, params: [ShaderInputFrame]),
|
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: ShaderInputFrame, params: [ShaderInputFrame]),
|
||||||
|
@ -639,6 +640,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: ShaderInputFrame, fn_params: [Footprint => ShaderInputFrame]),
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: ShaderInputFrame, fn_params: [Footprint => ShaderInputFrame]),
|
||||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: WgpuSurface, fn_params: [Footprint => WgpuSurface]),
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: WgpuSurface, fn_params: [Footprint => WgpuSurface]),
|
||||||
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: Option<WgpuSurface>, fn_params: [Footprint => Option<WgpuSurface>]),
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: Option<WgpuSurface>, fn_params: [Footprint => Option<WgpuSurface>]),
|
||||||
|
async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Footprint, output: TextureFrame, fn_params: [Footprint => TextureFrame]),
|
||||||
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
|
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
|
||||||
register_node!(graphene_std::raster::ImageFrameNode<_, _>, input: Image<Color>, params: [DAffine2]),
|
register_node!(graphene_std::raster::ImageFrameNode<_, _>, input: Image<Color>, params: [DAffine2]),
|
||||||
register_node!(graphene_std::raster::NoisePatternNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _>, input: (), params: [UVec2, u32, f64, NoiseType, DomainWarpType, f64, FractalType, u32, f64, f64, f64, f64, CellularDistanceFunction, CellularReturnType, f64]),
|
register_node!(graphene_std::raster::NoisePatternNode<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _>, input: (), params: [UVec2, u32, f64, NoiseType, DomainWarpType, f64, FractalType, u32, f64, f64, f64, f64, CellularDistanceFunction, CellularReturnType, f64]),
|
||||||
|
@ -665,6 +667,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
||||||
// async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: WasmSurfaceHandleFrame, fn_params: [Footprint => WasmSurfaceHandleFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
// async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: WasmSurfaceHandleFrame, fn_params: [Footprint => WasmSurfaceHandleFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
||||||
async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: ImageFrame<Color>, fn_params: [Footprint => ImageFrame<Color>, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: ImageFrame<Color>, fn_params: [Footprint => ImageFrame<Color>, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
||||||
|
async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: TextureFrame, fn_params: [Footprint => TextureFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
||||||
async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => GraphicGroup, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => GraphicGroup, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]),
|
||||||
register_node!(graphene_core::transform::SetTransformNode<_>, input: VectorData, params: [VectorData]),
|
register_node!(graphene_core::transform::SetTransformNode<_>, input: VectorData, params: [VectorData]),
|
||||||
register_node!(graphene_core::transform::SetTransformNode<_>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
register_node!(graphene_core::transform::SetTransformNode<_>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||||
|
@ -771,11 +774,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||||
register_node!(graphene_core::ToGraphicElementNode, input: graphene_core::vector::VectorData, params: []),
|
register_node!(graphene_core::ToGraphicElementNode, input: graphene_core::vector::VectorData, params: []),
|
||||||
register_node!(graphene_core::ToGraphicElementNode, input: ImageFrame<Color>, params: []),
|
register_node!(graphene_core::ToGraphicElementNode, input: ImageFrame<Color>, params: []),
|
||||||
register_node!(graphene_core::ToGraphicElementNode, input: GraphicGroup, params: []),
|
register_node!(graphene_core::ToGraphicElementNode, input: GraphicGroup, params: []),
|
||||||
register_node!(graphene_core::ToGraphicElementNode, input: graphene_std::SurfaceFrame, params: []),
|
register_node!(graphene_core::ToGraphicElementNode, input: TextureFrame, params: []),
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
register_node!(graphene_core::ToGraphicElementNode, input: Arc<graphene_std::application_io::SurfaceHandleFrame<wgpu::web_sys::HtmlCanvasElement>>, params: []),
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
register_node!(graphene_core::ToGraphicElementNode, input: graphene_std::application_io::SurfaceHandleFrame<wgpu::web_sys::HtmlCanvasElement>, params: []),
|
|
||||||
register_node!(graphene_core::ToGraphicGroupNode, input: graphene_core::vector::VectorData, params: []),
|
register_node!(graphene_core::ToGraphicGroupNode, input: graphene_core::vector::VectorData, params: []),
|
||||||
register_node!(graphene_core::ToGraphicGroupNode, input: ImageFrame<Color>, params: []),
|
register_node!(graphene_core::ToGraphicGroupNode, input: ImageFrame<Color>, params: []),
|
||||||
register_node!(graphene_core::ToGraphicGroupNode, input: GraphicGroup, params: []),
|
register_node!(graphene_core::ToGraphicGroupNode, input: GraphicGroup, params: []),
|
||||||
|
|
|
@ -14,7 +14,7 @@ passthrough = []
|
||||||
gpu-executor = { path = "../gpu-executor" }
|
gpu-executor = { path = "../gpu-executor" }
|
||||||
|
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
graphene-core = { workspace = true, features = ["std", "alloc", "gpu"] }
|
graphene-core = { workspace = true, features = ["std", "alloc", "gpu", "wgpu"] }
|
||||||
dyn-any = { workspace = true, features = ["log-bad-types", "rc", "glam"] }
|
dyn-any = { workspace = true, features = ["log-bad-types", "rc", "glam"] }
|
||||||
node-macro = { workspace = true }
|
node-macro = { workspace = true }
|
||||||
num-traits = { workspace = true }
|
num-traits = { workspace = true }
|
||||||
|
@ -26,7 +26,6 @@ anyhow = { workspace = true }
|
||||||
wgpu = { workspace = true, features = [
|
wgpu = { workspace = true, features = [
|
||||||
"spirv",
|
"spirv",
|
||||||
"strict_asserts",
|
"strict_asserts",
|
||||||
"api_log_info",
|
|
||||||
] }
|
] }
|
||||||
spirv = { workspace = true }
|
spirv = { workspace = true }
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
|
|
|
@ -38,6 +38,7 @@ impl Context {
|
||||||
#[cfg(feature = "passthrough")]
|
#[cfg(feature = "passthrough")]
|
||||||
required_features: wgpu::Features::SPIRV_SHADER_PASSTHROUGH,
|
required_features: wgpu::Features::SPIRV_SHADER_PASSTHROUGH,
|
||||||
required_limits,
|
required_limits,
|
||||||
|
memory_hints: Default::default(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|
|
@ -104,6 +104,7 @@ async fn execute_shader<I: Pod + Send + Sync, O: Pod + Send + Sync>(device: Arc<
|
||||||
module: &cs_module,
|
module: &cs_module,
|
||||||
entry_point: entry_point.as_str(),
|
entry_point: entry_point.as_str(),
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Instantiates the bind group, once again specifying the binding of buffers.
|
// Instantiates the bind group, once again specifying the binding of buffers.
|
||||||
|
|
|
@ -6,9 +6,8 @@ pub use executor::GpuExecutor;
|
||||||
|
|
||||||
use dyn_any::{DynAny, StaticType};
|
use dyn_any::{DynAny, StaticType};
|
||||||
use gpu_executor::{ComputePassDimensions, GPUConstant, StorageBufferOptions, TextureBufferOptions, TextureBufferType, ToStorageBuffer, ToUniformBuffer};
|
use gpu_executor::{ComputePassDimensions, GPUConstant, StorageBufferOptions, TextureBufferOptions, TextureBufferType, ToStorageBuffer, ToUniformBuffer};
|
||||||
use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle};
|
use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle, TextureFrame};
|
||||||
use graphene_core::raster::color::RGBA16F;
|
use graphene_core::raster::{Image, ImageFrame, SRGBA8};
|
||||||
use graphene_core::raster::{Image, ImageFrame};
|
|
||||||
use graphene_core::transform::{Footprint, Transform};
|
use graphene_core::transform::{Footprint, Transform};
|
||||||
use graphene_core::Type;
|
use graphene_core::Type;
|
||||||
use graphene_core::{Color, Cow, Node, SurfaceFrame};
|
use graphene_core::{Color, Cow, Node, SurfaceFrame};
|
||||||
|
@ -18,9 +17,9 @@ use futures::Future;
|
||||||
use glam::{DAffine2, UVec2};
|
use glam::{DAffine2, UVec2};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vello::{AaConfig, AaSupport, RenderParams, Renderer, RendererOptions, Scene};
|
use vello::{AaConfig, AaSupport, DebugLayers, RenderParams, Renderer, RendererOptions, Scene};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use wgpu::{Buffer, BufferDescriptor, ShaderModule, SurfaceConfiguration, SurfaceError, Texture, TextureView};
|
use wgpu::{Buffer, BufferDescriptor, Origin3d, ShaderModule, SurfaceConfiguration, SurfaceError, Texture, TextureAspect, TextureView};
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
|
@ -129,12 +128,14 @@ unsafe impl StaticType for Surface {
|
||||||
type Static = Surface;
|
type Static = Surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use graphene_core::renderer::RenderContext;
|
||||||
|
|
||||||
// pub trait SpirVCompiler {
|
// pub trait SpirVCompiler {
|
||||||
// fn compile(&self, network: &[ProtoNetwork], io: &ShaderIO) -> Result<Shader>;
|
// fn compile(&self, network: &[ProtoNetwork], io: &ShaderIO) -> Result<Shader>;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
impl WgpuExecutor {
|
impl WgpuExecutor {
|
||||||
pub async fn render_vello_scene(&self, scene: &Scene, surface: &WgpuSurface, width: u32, height: u32) -> Result<()> {
|
pub async fn render_vello_scene(&self, scene: &Scene, surface: &WgpuSurface, width: u32, height: u32, context: &RenderContext) -> Result<()> {
|
||||||
let surface = &surface.surface.inner;
|
let surface = &surface.surface.inner;
|
||||||
let surface_caps = surface.get_capabilities(&self.context.adapter);
|
let surface_caps = surface.get_capabilities(&self.context.adapter);
|
||||||
surface.configure(
|
surface.configure(
|
||||||
|
@ -159,10 +160,23 @@ impl WgpuExecutor {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
antialiasing_method: AaConfig::Msaa8,
|
antialiasing_method: AaConfig::Msaa8,
|
||||||
|
debug: DebugLayers::all(),
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut renderer = self.vello_renderer.lock().unwrap();
|
let mut renderer = self.vello_renderer.lock().unwrap();
|
||||||
|
for (id, texture) in context.ressource_overrides.iter() {
|
||||||
|
let texture_view = wgpu::ImageCopyTextureBase {
|
||||||
|
texture: texture.clone(),
|
||||||
|
mip_level: 0,
|
||||||
|
origin: Origin3d::ZERO,
|
||||||
|
aspect: TextureAspect::All,
|
||||||
|
};
|
||||||
|
renderer.override_image(
|
||||||
|
&vello::peniko::Image::new(vello::peniko::Blob::from_raw_parts(Arc::new(vec![]), *id), vello::peniko::Format::Rgba8, 0, 0),
|
||||||
|
Some(texture_view),
|
||||||
|
);
|
||||||
|
}
|
||||||
renderer
|
renderer
|
||||||
.render_to_surface_async(&self.context.device, &self.context.queue, scene, &surface_texture, &render_params)
|
.render_to_surface_async(&self.context.device, &self.context.queue, scene, &surface_texture, &render_params)
|
||||||
.await
|
.await
|
||||||
|
@ -229,14 +243,14 @@ impl WgpuExecutor {
|
||||||
let bytes = data.to_bytes();
|
let bytes = data.to_bytes();
|
||||||
let usage = match options {
|
let usage = match options {
|
||||||
TextureBufferOptions::Storage => wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC,
|
TextureBufferOptions::Storage => wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC,
|
||||||
TextureBufferOptions::Texture => wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
TextureBufferOptions::Texture => wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC,
|
||||||
TextureBufferOptions::Surface => wgpu::TextureUsages::RENDER_ATTACHMENT,
|
TextureBufferOptions::Surface => wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
let format = match T::format() {
|
let format = match T::format() {
|
||||||
TextureBufferType::Rgba32Float => wgpu::TextureFormat::Rgba32Float,
|
TextureBufferType::Rgba32Float => wgpu::TextureFormat::Rgba32Float,
|
||||||
TextureBufferType::Rgba16Float => wgpu::TextureFormat::Rgba16Float,
|
TextureBufferType::Rgba16Float => wgpu::TextureFormat::Rgba16Float,
|
||||||
TextureBufferType::Rgba8Srgb => wgpu::TextureFormat::Bgra8UnormSrgb,
|
TextureBufferType::Rgba8Srgb => wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
};
|
};
|
||||||
|
|
||||||
let buffer = self.context.device.create_texture_with_data(
|
let buffer = self.context.device.create_texture_with_data(
|
||||||
|
@ -288,6 +302,7 @@ impl WgpuExecutor {
|
||||||
module: &layout.shader.0,
|
module: &layout.shader.0,
|
||||||
entry_point: layout.entry_point.as_str(),
|
entry_point: layout.entry_point.as_str(),
|
||||||
compilation_options: Default::default(),
|
compilation_options: Default::default(),
|
||||||
|
cache: None,
|
||||||
});
|
});
|
||||||
let bind_group_layout = compute_pipeline.get_bind_group_layout(0);
|
let bind_group_layout = compute_pipeline.get_bind_group_layout(0);
|
||||||
|
|
||||||
|
@ -625,6 +640,7 @@ impl WgpuExecutor {
|
||||||
// If the pipeline will be used with a multiview render pass, this
|
// If the pipeline will be used with a multiview render pass, this
|
||||||
// indicates how many array layers the attachments will have.
|
// indicates how many array layers the attachments will have.
|
||||||
multiview: None,
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let vertex_buffer = context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let vertex_buffer = context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
@ -949,8 +965,9 @@ pub struct UploadTextureNode<Executor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node_fn(UploadTextureNode)]
|
#[node_macro::node_fn(UploadTextureNode)]
|
||||||
async fn upload_texture<'a: 'input>(input: ImageFrame<Color>, executor: &'a WgpuExecutor) -> ShaderInputFrame {
|
async fn upload_texture<'a: 'input>(input: ImageFrame<Color>, executor: &'a WgpuExecutor) -> TextureFrame {
|
||||||
let new_data: Vec<RGBA16F> = input.image.data.into_iter().map(|c| c.into()).collect();
|
// let new_data: Vec<RGBA16F> = input.image.data.into_iter().map(|c| c.into()).collect();
|
||||||
|
let new_data = input.image.data.into_iter().map(|c| SRGBA8::from(c)).collect();
|
||||||
let new_image = Image {
|
let new_image = Image {
|
||||||
width: input.image.width,
|
width: input.image.width,
|
||||||
height: input.image.height,
|
height: input.image.height,
|
||||||
|
@ -959,9 +976,14 @@ async fn upload_texture<'a: 'input>(input: ImageFrame<Color>, executor: &'a Wgpu
|
||||||
};
|
};
|
||||||
|
|
||||||
let shader_input = executor.create_texture_buffer(new_image, TextureBufferOptions::Texture).unwrap();
|
let shader_input = executor.create_texture_buffer(new_image, TextureBufferOptions::Texture).unwrap();
|
||||||
|
let texture = match shader_input {
|
||||||
|
ShaderInput::TextureBuffer(buffer, _) => buffer,
|
||||||
|
ShaderInput::StorageTextureBuffer(buffer, _) => buffer,
|
||||||
|
_ => unreachable!("Unsupported ShaderInput type"),
|
||||||
|
};
|
||||||
|
|
||||||
ShaderInputFrame {
|
TextureFrame {
|
||||||
shader_input: Arc::new(shader_input),
|
texture: texture.into(),
|
||||||
transform: input.transform,
|
transform: input.transform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue