mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-03 04:52:16 +00:00
Lay groundwork for directly rendering to the canvas without a cpu roundrip (#1291)
* Add Texture handle type * Add Texture View to shader inputs * Implement basic rendering pipeline * Render first texture using render pipeline * Fix output color space * Precompute the rendering pipeline * Move gpu context creation to editor api * Port gpu-executor nodes to node registry * Fix canvas nodes and make code compile for non wasm targets * Pin wasm-bindgen version * Disable miri temoporarily for better ci times * Fix formatting * Remove unsafe block * Bump wasm-pack version * Bump wasm-bindgen version * Add gpu feature guard for push node * Make Into node async
This commit is contained in:
parent
0c93a62d55
commit
45b04f4eb9
33 changed files with 1574 additions and 339 deletions
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
|
@ -107,15 +107,15 @@ jobs:
|
|||
run: |
|
||||
mold -run cargo nextest run
|
||||
|
||||
miri:
|
||||
runs-on: self-hosted
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: 🧪 Run Rust miri
|
||||
run: |
|
||||
mold -run cargo +nightly miri nextest run -j32
|
||||
#miri:
|
||||
# runs-on: self-hosted
|
||||
#
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
#
|
||||
# - name: 🧪 Run Rust miri
|
||||
# run: |
|
||||
# mold -run cargo +nightly miri nextest run -j32
|
||||
|
||||
cargo-deny:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
476
Cargo.lock
generated
476
Cargo.lock
generated
|
@ -8,6 +8,22 @@ version = "0.11.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5110f1c78cf582855d895ecd0746b653db010cec6d9f5575293f27934d980a39"
|
||||
dependencies = [
|
||||
"ab_glyph_rasterizer",
|
||||
"owned_ttf_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ab_glyph_rasterizer"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.19.0"
|
||||
|
@ -79,6 +95,30 @@ dependencies = [
|
|||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c77a0045eda8b888c76ea473c2b0515ba6f471d318f8927c5c72240937035a6"
|
||||
dependencies = [
|
||||
"android-properties",
|
||||
"bitflags 1.3.2",
|
||||
"cc",
|
||||
"jni-sys",
|
||||
"libc",
|
||||
"log",
|
||||
"ndk 0.7.0",
|
||||
"ndk-context",
|
||||
"ndk-sys 0.4.1+23.1.7779620",
|
||||
"num_enum 0.5.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-properties"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
|
@ -142,6 +182,12 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
|
@ -390,6 +436,25 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-sys"
|
||||
version = "0.1.0-beta.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146"
|
||||
dependencies = [
|
||||
"objc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.2.0-alpha.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42"
|
||||
dependencies = [
|
||||
"block-sys",
|
||||
"objc2-encode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.3.4"
|
||||
|
@ -483,6 +548,19 @@ dependencies = [
|
|||
"system-deps 6.0.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix 0.25.1",
|
||||
"slotmap",
|
||||
"thiserror",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_toml"
|
||||
version = "0.13.3"
|
||||
|
@ -498,6 +576,9 @@ name = "cc"
|
|||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
|
@ -540,6 +621,12 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.24"
|
||||
|
@ -979,6 +1066,15 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
||||
|
||||
[[package]]
|
||||
name = "dlib"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
|
||||
dependencies = [
|
||||
"libloading 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "document-features"
|
||||
version = "0.2.7"
|
||||
|
@ -988,6 +1084,12 @@ dependencies = [
|
|||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.8"
|
||||
|
@ -1117,7 +1219,7 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"memoffset 0.8.0",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
|
@ -1640,6 +1742,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"serde",
|
||||
"spirv",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1705,6 +1808,7 @@ dependencies = [
|
|||
"graph-craft",
|
||||
"graphene-core",
|
||||
"image",
|
||||
"js-sys",
|
||||
"kurbo",
|
||||
"log",
|
||||
"node-macro",
|
||||
|
@ -1713,7 +1817,11 @@ dependencies = [
|
|||
"serde_json",
|
||||
"tempfile",
|
||||
"vulkan-executor",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"wgpu",
|
||||
"wgpu-executor",
|
||||
"wgpu-types",
|
||||
"xxhash-rust",
|
||||
]
|
||||
|
||||
|
@ -2190,6 +2298,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2200,6 +2311,7 @@ dependencies = [
|
|||
"dyn-clone",
|
||||
"futures",
|
||||
"glam",
|
||||
"gpu-executor",
|
||||
"graph-craft",
|
||||
"graphene-core",
|
||||
"graphene-std",
|
||||
|
@ -2208,6 +2320,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"serde",
|
||||
"typed-arena",
|
||||
"wgpu-executor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2282,6 +2395,15 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
|
@ -2535,6 +2657,24 @@ version = "2.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.8.0"
|
||||
|
@ -2564,6 +2704,12 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
|
@ -2686,11 +2832,25 @@ checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
|
|||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"jni-sys",
|
||||
"ndk-sys",
|
||||
"ndk-sys 0.3.0",
|
||||
"num_enum 0.5.11",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"jni-sys",
|
||||
"ndk-sys 0.4.1+23.1.7779620",
|
||||
"num_enum 0.5.11",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-context"
|
||||
version = "0.1.1"
|
||||
|
@ -2706,12 +2866,46 @@ dependencies = [
|
|||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.4.1+23.1.7779620"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "node-macro"
|
||||
version = "0.0.0"
|
||||
|
@ -2727,6 +2921,16 @@ version = "0.1.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify-rust"
|
||||
version = "4.8.0"
|
||||
|
@ -2920,6 +3124,32 @@ dependencies = [
|
|||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.2.0-beta.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.3.0-beta.3.patch-leaks.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"objc-sys",
|
||||
"objc2-encode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-encode"
|
||||
version = "2.0.0-pre.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"
|
||||
dependencies = [
|
||||
"objc-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_exception"
|
||||
version = "0.1.2"
|
||||
|
@ -3007,6 +3237,15 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "221d488cd70617f1bd599ed8ceb659df2147d9393717954d82a0f5e8032a6ab1"
|
||||
dependencies = [
|
||||
"redox_syscall 0.3.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_info"
|
||||
version = "3.7.0"
|
||||
|
@ -3034,6 +3273,15 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owned_ttf_parser"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4"
|
||||
dependencies = [
|
||||
"ttf-parser 0.19.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.15.10"
|
||||
|
@ -3719,7 +3967,7 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"bytemuck",
|
||||
"smallvec",
|
||||
"ttf-parser",
|
||||
"ttf-parser 0.17.1",
|
||||
"unicode-bidi-mirroring",
|
||||
"unicode-ccc",
|
||||
"unicode-general-category",
|
||||
|
@ -3793,6 +4041,19 @@ dependencies = [
|
|||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sctk-adwaita"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda4e97be1fd174ccc2aae81c8b694e803fa99b34e8fd0f057a9d70698e3ed09"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"log",
|
||||
"memmap2",
|
||||
"smithay-client-toolkit",
|
||||
"tiny-skia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.8.2"
|
||||
|
@ -4113,6 +4374,25 @@ version = "1.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"calloop",
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"memmap2",
|
||||
"nix 0.24.3",
|
||||
"pkg-config",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
|
@ -4254,6 +4534,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strict-num"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.7"
|
||||
|
@ -4395,9 +4681,9 @@ dependencies = [
|
|||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"ndk",
|
||||
"ndk 0.6.0",
|
||||
"ndk-context",
|
||||
"ndk-sys",
|
||||
"ndk-sys 0.3.0",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
|
@ -4760,6 +5046,31 @@ dependencies = [
|
|||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
"png",
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia-path"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adbfb5d3f3dd57a0e11d12f4f13d4ebbbc1b5c15b7ab0a156d030b21da5f677c"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"bytemuck",
|
||||
"strict-num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
|
@ -5012,6 +5323,12 @@ version = "0.17.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44dcf002ae3b32cd25400d6df128c5babec3927cd1eb7ce813cfff20eb6c3746"
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "2.0.2"
|
||||
|
@ -5150,6 +5467,12 @@ version = "0.2.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.0.11"
|
||||
|
@ -5260,9 +5583,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -5270,16 +5593,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.15",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -5297,9 +5620,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -5307,22 +5630,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.15",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.84"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
|
@ -5361,6 +5684,79 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"downcast-rs",
|
||||
"libc",
|
||||
"nix 0.24.3",
|
||||
"scoped-tls",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-commons"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
|
||||
dependencies = [
|
||||
"nix 0.24.3",
|
||||
"once_cell",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-cursor"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
|
||||
dependencies = [
|
||||
"nix 0.24.3",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"wayland-client",
|
||||
"wayland-commons",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-sys"
|
||||
version = "0.29.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"lazy_static",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
|
@ -5541,7 +5937,9 @@ dependencies = [
|
|||
"num-traits",
|
||||
"serde",
|
||||
"spirv",
|
||||
"web-sys",
|
||||
"wgpu",
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -5928,6 +6326,41 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.28.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "866db3f712fffba75d31bf0cdecf357c8aeafd158c5b7ab51dba2a2b2d47f196"
|
||||
dependencies = [
|
||||
"android-activity",
|
||||
"bitflags 1.3.2",
|
||||
"cfg_aliases",
|
||||
"core-foundation",
|
||||
"core-graphics",
|
||||
"dispatch",
|
||||
"instant",
|
||||
"libc",
|
||||
"log",
|
||||
"mio",
|
||||
"ndk 0.7.0",
|
||||
"objc2",
|
||||
"once_cell",
|
||||
"orbclient",
|
||||
"percent-encoding",
|
||||
"raw-window-handle",
|
||||
"redox_syscall 0.3.5",
|
||||
"sctk-adwaita",
|
||||
"smithay-client-toolkit",
|
||||
"wasm-bindgen",
|
||||
"wayland-client",
|
||||
"wayland-commons",
|
||||
"wayland-protocols",
|
||||
"wayland-scanner",
|
||||
"web-sys",
|
||||
"windows-sys 0.45.0",
|
||||
"x11-dl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.1"
|
||||
|
@ -6023,6 +6456,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xcursor"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.4"
|
||||
|
|
|
@ -12,7 +12,10 @@ license = "Apache-2.0"
|
|||
|
||||
[features]
|
||||
gpu = ["interpreted-executor/gpu", "graphene-std/gpu", "graphene-core/gpu"]
|
||||
quantization = ["graphene-std/quantization", "interpreted-executor/quantization"]
|
||||
quantization = [
|
||||
"graphene-std/quantization",
|
||||
"interpreted-executor/quantization",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
|
@ -40,7 +43,7 @@ graph-craft = { path = "../node-graph/graph-craft" }
|
|||
interpreted-executor = { path = "../node-graph/interpreted-executor" }
|
||||
dyn-any = { path = "../libraries/dyn-any" }
|
||||
graphene-core = { path = "../node-graph/gcore" }
|
||||
graphene-std = { path = "../node-graph/gstd" }
|
||||
graphene-std = { path = "../node-graph/gstd", features = ["wasm"] }
|
||||
num_enum = "0.6.1"
|
||||
|
||||
[dependencies.document-legacy]
|
||||
|
|
|
@ -14,6 +14,7 @@ use graphene_core::text::Font;
|
|||
use graphene_core::vector::VectorData;
|
||||
use graphene_core::*;
|
||||
|
||||
use graphene_std::wasm_application_io::WasmEditorApi;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
|
@ -239,7 +240,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
inputs: vec![DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::Network(concrete!(EditorApi)),
|
||||
default: NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
}],
|
||||
outputs: vec![DocumentOutputType {
|
||||
name: "Image Frame",
|
||||
|
@ -256,8 +257,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
nodes: [
|
||||
DocumentNode {
|
||||
name: "Create Canvas".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(EditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::wasm_application_io::CreateSurfaceNode")),
|
||||
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
|
@ -276,7 +277,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
inputs: vec![DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::Network(concrete!(EditorApi)),
|
||||
default: NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
}],
|
||||
outputs: vec![DocumentOutputType {
|
||||
name: "Canvas",
|
||||
|
@ -299,8 +300,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
},
|
||||
DocumentNode {
|
||||
name: "Create Canvas".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(EditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::wasm_application_io::CreateSurfaceNode")),
|
||||
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
|
@ -312,7 +313,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentNode {
|
||||
name: "Draw Canvas".to_string(),
|
||||
inputs: vec![NodeInput::node(0, 0), NodeInput::node(2, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::wasm_application_io::DrawImageFrameNode<_>")),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::DrawImageFrameNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
|
@ -331,7 +332,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::Network(concrete!(EditorApi)),
|
||||
default: NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
},
|
||||
],
|
||||
outputs: vec![DocumentOutputType {
|
||||
|
@ -349,7 +350,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
nodes: [
|
||||
DocumentNode {
|
||||
name: "SetNode".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(EditorApi))],
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(WasmEditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::SomeNode")),
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -376,7 +377,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
inputs: vec![DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
default: NodeInput::Network(concrete!(EditorApi)),
|
||||
default: NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
}],
|
||||
outputs: vec![
|
||||
DocumentOutputType {
|
||||
|
@ -727,6 +728,57 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
properties: node_properties::no_properties,
|
||||
},
|
||||
#[cfg(feature = "gpu")]
|
||||
DocumentNodeType {
|
||||
name: "Uniform",
|
||||
category: "Gpu",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![1, 0],
|
||||
outputs: vec![NodeOutput::new(2, 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
name: "Extract Executor".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IntoNode<_, &WgpuExecutor>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Create Uniform".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(f32))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("gpu-executor::UniformNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (id as NodeId, node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::value(TaggedValue::F32(0.), true),
|
||||
},
|
||||
DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
},
|
||||
],
|
||||
outputs: vec![DocumentOutputType {
|
||||
name: "Uniform",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
}],
|
||||
properties: node_properties::input_properties,
|
||||
},
|
||||
#[cfg(feature = "gpu")]
|
||||
DocumentNodeType {
|
||||
name: "GpuImage",
|
||||
category: "Image Adjustments",
|
||||
|
@ -738,6 +790,11 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
|||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true),
|
||||
},
|
||||
DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
},
|
||||
],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
properties: node_properties::no_properties,
|
||||
|
@ -1374,7 +1431,7 @@ pub fn new_text_network(text: String, font: Font, size: f64) -> NodeNetwork {
|
|||
network.push_node(
|
||||
text_generator.to_document_node(
|
||||
[
|
||||
NodeInput::Network(concrete!(graphene_core::EditorApi)),
|
||||
NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
NodeInput::value(TaggedValue::String(text), false),
|
||||
NodeInput::value(TaggedValue::Font(font), false),
|
||||
NodeInput::value(TaggedValue::F64(size), false),
|
||||
|
|
|
@ -17,8 +17,9 @@ use graphene_core::renderer::{SvgSegment, SvgSegmentList};
|
|||
use graphene_core::text::FontCache;
|
||||
use graphene_core::vector::style::ViewMode;
|
||||
|
||||
use graphene_core::wasm_application_io::WasmApplicationIo;
|
||||
use graphene_core::{Color, EditorApi, SurfaceFrame, SurfaceId};
|
||||
use graphene_core::{Color, SurfaceFrame, SurfaceId};
|
||||
use graphene_std::wasm_application_io::WasmApplicationIo;
|
||||
use graphene_std::wasm_application_io::WasmEditorApi;
|
||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
@ -33,7 +34,7 @@ pub struct NodeRuntime {
|
|||
font_cache: FontCache,
|
||||
receiver: Receiver<NodeRuntimeMessage>,
|
||||
sender: Sender<GenerationResponse>,
|
||||
wasm_io: WasmApplicationIo,
|
||||
wasm_io: Option<WasmApplicationIo>,
|
||||
pub(crate) thumbnails: HashMap<LayerId, HashMap<NodeId, SvgSegmentList>>,
|
||||
canvas_cache: HashMap<Vec<LayerId>, SurfaceId>,
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ impl NodeRuntime {
|
|||
sender,
|
||||
font_cache: FontCache::default(),
|
||||
thumbnails: Default::default(),
|
||||
wasm_io: WasmApplicationIo::default(),
|
||||
wasm_io: None,
|
||||
canvas_cache: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -125,10 +126,14 @@ impl NodeRuntime {
|
|||
}
|
||||
|
||||
async fn execute_network<'a>(&'a mut self, path: &[LayerId], scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> {
|
||||
let editor_api = EditorApi {
|
||||
if self.wasm_io.is_none() {
|
||||
self.wasm_io = Some(WasmApplicationIo::new().await);
|
||||
}
|
||||
|
||||
let editor_api = WasmEditorApi {
|
||||
font_cache: &self.font_cache,
|
||||
image_frame,
|
||||
application_io: &self.wasm_io,
|
||||
application_io: &self.wasm_io.as_ref().unwrap(),
|
||||
};
|
||||
|
||||
// We assume only one output
|
||||
|
@ -145,7 +150,7 @@ impl NodeRuntime {
|
|||
use graph_craft::graphene_compiler::Executor;
|
||||
|
||||
let result = match self.executor.input_type() {
|
||||
Some(t) if t == concrete!(EditorApi) => (&self.executor).execute(editor_api).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(WasmEditorApi) => (&self.executor).execute(editor_api).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => (&self.executor).execute(()).await.map_err(|e| e.to_string()),
|
||||
_ => Err("Invalid input type".to_string()),
|
||||
}?;
|
||||
|
@ -154,7 +159,7 @@ impl NodeRuntime {
|
|||
let old_id = self.canvas_cache.insert(path.to_vec(), surface_id);
|
||||
if let Some(old_id) = old_id {
|
||||
if old_id != surface_id {
|
||||
self.wasm_io.destroy_surface(old_id);
|
||||
self.wasm_io.as_ref().map(|io| io.destroy_surface(old_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,49 +298,6 @@ impl NodeGraphExecutor {
|
|||
self.last_output_type.get(path).cloned().flatten()
|
||||
}
|
||||
|
||||
/// Computes an input for a node in the graph
|
||||
pub fn compute_input<T: dyn_any::StaticType>(&mut self, _old_network: &NodeNetwork, _node_path: &[NodeId], _input_index: usize, _editor_api: Cow<EditorApi<'_>>) -> Result<u64, String> {
|
||||
todo!()
|
||||
/*
|
||||
let mut network = old_network.clone();
|
||||
// Adjust the output of the graph so we find the relevant output
|
||||
'outer: for end in (0..node_path.len()).rev() {
|
||||
let mut inner_network = &mut network;
|
||||
for &node_id in &node_path[..end] {
|
||||
inner_network.outputs[0] = NodeOutput::new(node_id, 0);
|
||||
|
||||
let Some(new_inner) = inner_network.nodes.get_mut(&node_id).and_then(|node| node.implementation.get_network_mut()) else {
|
||||
return Err("Failed to find network".to_string());
|
||||
};
|
||||
inner_network = new_inner;
|
||||
}
|
||||
match &inner_network.nodes.get(&node_path[end]).unwrap().inputs[input_index] {
|
||||
// If the input is from a parent network then adjust the input index and continue iteration
|
||||
NodeInput::Network(_) => {
|
||||
input_index = inner_network
|
||||
.inputs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_index, &id)| id == node_path[end])
|
||||
.nth(input_index)
|
||||
.ok_or_else(|| "Invalid network input".to_string())?
|
||||
.0;
|
||||
}
|
||||
// If the input is just a value, return that value
|
||||
NodeInput::Value { tagged_value, .. } => return Some(dyn_any::downcast::<T>(tagged_value.clone().to_any()).map(|v| *v)),
|
||||
// If the input is from a node, set the node to be the output (so that is what is evaluated)
|
||||
NodeInput::Node { node_id, output_index, .. } => {
|
||||
inner_network.outputs[0] = NodeOutput::new(*node_id, *output_index);
|
||||
break 'outer;
|
||||
}
|
||||
NodeInput::ShortCircut(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
self.queue_execution(network, editor_api.into_owned())?
|
||||
*/
|
||||
}
|
||||
|
||||
/// Encodes an image into a format using the image crate
|
||||
fn encode_img(image: Image<Color>, resize: Option<DVec2>, format: image::ImageOutputFormat) -> Result<(Vec<u8>, (u32, u32)), String> {
|
||||
use image::{ImageBuffer, Rgba};
|
||||
|
|
82
frontend/package-lock.json
generated
82
frontend/package-lock.json
generated
|
@ -35,7 +35,7 @@
|
|||
"webpack-cli": "^5.0.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wasm-pack": "0.10.3"
|
||||
"wasm-pack": "0.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
|
@ -2139,12 +2139,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
|
@ -2192,14 +2192,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/binary-install": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-0.1.1.tgz",
|
||||
"integrity": "sha512-DqED0D/6LrS+BHDkKn34vhRqOGjy5gTMgvYZsGK2TpNbdPuz4h+MRlNgGv5QBRd7pWq/jylM4eKNCizgAq3kNQ==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-1.1.0.tgz",
|
||||
"integrity": "sha512-rkwNGW+3aQVSZoD0/o3mfPN6Yxh3Id0R/xzTVBVVpGNlVz8EGwusksxRlbk/A5iKTZt9zkMn3qIqmAt3vpfbzg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"axios": "^0.26.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tar": "^6.1.0"
|
||||
"tar": "^6.1.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
|
@ -3946,9 +3946,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
|
||||
"integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
|
@ -5006,14 +5006,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "6.1.13",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz",
|
||||
"integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==",
|
||||
"version": "6.1.15",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz",
|
||||
"integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^4.0.0",
|
||||
"minipass": "^5.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
|
@ -5266,13 +5266,13 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/wasm-pack": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.10.3.tgz",
|
||||
"integrity": "sha512-dg1PPyp+QwWrhfHsgG12K/y5xzwfaAoK1yuVC/DUAuQsDy5JywWDuA7Y/ionGwQz+JBZVw8jknaKBnaxaJfwTA==",
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.11.1.tgz",
|
||||
"integrity": "sha512-0BKEioKJY/SMqahDEoaUUR8jrRkHO0cdYhRqqHKQMY3Bac6Eep3ZRsTlpFSSwS4LYPxd+Tb5KFFNhUikCkq8Yg==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"binary-install": "^0.1.0"
|
||||
"binary-install": "^1.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"wasm-pack": "run.js"
|
||||
|
@ -7027,12 +7027,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
|
@ -7063,14 +7063,14 @@
|
|||
"dev": true
|
||||
},
|
||||
"binary-install": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-0.1.1.tgz",
|
||||
"integrity": "sha512-DqED0D/6LrS+BHDkKn34vhRqOGjy5gTMgvYZsGK2TpNbdPuz4h+MRlNgGv5QBRd7pWq/jylM4eKNCizgAq3kNQ==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-install/-/binary-install-1.1.0.tgz",
|
||||
"integrity": "sha512-rkwNGW+3aQVSZoD0/o3mfPN6Yxh3Id0R/xzTVBVVpGNlVz8EGwusksxRlbk/A5iKTZt9zkMn3qIqmAt3vpfbzg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"axios": "^0.21.1",
|
||||
"axios": "^0.26.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tar": "^6.1.0"
|
||||
"tar": "^6.1.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"rimraf": {
|
||||
|
@ -8259,9 +8259,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
|
||||
"integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
|
||||
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
|
||||
"optional": true
|
||||
},
|
||||
"minizlib": {
|
||||
|
@ -9005,14 +9005,14 @@
|
|||
"dev": true
|
||||
},
|
||||
"tar": {
|
||||
"version": "6.1.13",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz",
|
||||
"integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==",
|
||||
"version": "6.1.15",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz",
|
||||
"integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^4.0.0",
|
||||
"minipass": "^5.0.0",
|
||||
"minizlib": "^2.1.1",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
|
@ -9163,12 +9163,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"wasm-pack": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.10.3.tgz",
|
||||
"integrity": "sha512-dg1PPyp+QwWrhfHsgG12K/y5xzwfaAoK1yuVC/DUAuQsDy5JywWDuA7Y/ionGwQz+JBZVw8jknaKBnaxaJfwTA==",
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.11.1.tgz",
|
||||
"integrity": "sha512-0BKEioKJY/SMqahDEoaUUR8jrRkHO0cdYhRqqHKQMY3Bac6Eep3ZRsTlpFSSwS4LYPxd+Tb5KFFNhUikCkq8Yg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"binary-install": "^0.1.0"
|
||||
"binary-install": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"watchpack": {
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"webpack": "^5.81.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"wasm-pack": "0.10.3"
|
||||
"wasm-pack": "0.11.1"
|
||||
},
|
||||
"//": "Notes about dependency issues and incompatibilities should be added here when needed.",
|
||||
"homepage": "https://graphite.rs",
|
||||
|
|
|
@ -132,8 +132,8 @@
|
|||
placeholders.forEach((placeholder) => {
|
||||
const canvasName = placeholder.getAttribute("data-canvas-placeholder");
|
||||
// Get the canvas element from the global storage
|
||||
const context = (window as any).imageCanvases[canvasName];
|
||||
placeholder.replaceWith(context.canvas);
|
||||
const canvas = (window as any).imageCanvases[canvasName];
|
||||
placeholder.replaceWith(canvas);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ graphene-core = { path = "../../node-graph/gcore", features = [
|
|||
"alloc",
|
||||
] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
wasm-bindgen = { version = "0.2.84" }
|
||||
wasm-bindgen = { version = "=0.2.86" }
|
||||
serde-wasm-bindgen = "0.4.1"
|
||||
js-sys = "0.3.55"
|
||||
wasm-bindgen-futures = "0.4.33"
|
||||
|
|
|
@ -32,7 +32,7 @@ async = ["async-trait", "alloc"]
|
|||
nightly = []
|
||||
alloc = ["dyn-any", "bezier-rs", "once_cell"]
|
||||
type_id_logging = []
|
||||
wasm = ["wasm-bindgen", "web-sys", "js-sys", "std"]
|
||||
wasm = ["web-sys"]
|
||||
|
||||
[dependencies]
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = [
|
||||
|
@ -77,10 +77,4 @@ js-sys = { version = "0.3.55", optional = true }
|
|||
[dependencies.web-sys]
|
||||
version = "0.3.4"
|
||||
optional = true
|
||||
features = [
|
||||
"Window",
|
||||
"CanvasRenderingContext2d",
|
||||
"ImageData",
|
||||
"Document",
|
||||
"HtmlCanvasElement",
|
||||
]
|
||||
features = ["HtmlCanvasElement"]
|
||||
|
|
|
@ -45,7 +45,7 @@ impl<S> From<SurfaceHandleFrame<S>> for SurfaceFrame {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SurfaceHandle<Surface> {
|
||||
pub surface_id: SurfaceId,
|
||||
pub surface: Surface,
|
||||
|
@ -55,7 +55,7 @@ unsafe impl<T: 'static> StaticType for SurfaceHandle<T> {
|
|||
type Static = SurfaceHandle<T>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SurfaceHandleFrame<Surface> {
|
||||
pub surface_handle: Arc<SurfaceHandle<Surface>>,
|
||||
pub transform: DAffine2,
|
||||
|
@ -87,12 +87,18 @@ impl<'a, Surface> Drop for SurfaceHandle<'a, Surface> {
|
|||
|
||||
pub trait ApplicationIo {
|
||||
type Surface;
|
||||
type Executor;
|
||||
fn create_surface(&self) -> SurfaceHandle<Self::Surface>;
|
||||
fn destroy_surface(&self, surface_id: SurfaceId);
|
||||
fn gpu_executor(&self) -> Option<&Self::Executor> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ApplicationIo> ApplicationIo for &T {
|
||||
type Surface = T::Surface;
|
||||
type Executor = T::Executor;
|
||||
|
||||
fn create_surface(&self) -> SurfaceHandle<T::Surface> {
|
||||
(**self).create_surface()
|
||||
}
|
||||
|
@ -100,6 +106,10 @@ impl<T: ApplicationIo> ApplicationIo for &T {
|
|||
fn destroy_surface(&self, surface_id: SurfaceId) {
|
||||
(**self).destroy_surface(surface_id)
|
||||
}
|
||||
|
||||
fn gpu_executor(&self) -> Option<&T::Executor> {
|
||||
(**self).gpu_executor()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EditorApi<'a, Io> {
|
||||
|
@ -162,6 +172,3 @@ impl ExtractImageFrame {
|
|||
Self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
pub mod wasm_application_io;
|
||||
|
|
|
@ -20,6 +20,7 @@ pub mod value;
|
|||
#[cfg(feature = "gpu")]
|
||||
pub mod gpu;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod memo;
|
||||
pub mod storage;
|
||||
|
||||
|
@ -34,6 +35,7 @@ pub use graphic_element::*;
|
|||
#[cfg(feature = "alloc")]
|
||||
pub mod vector;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod application_io;
|
||||
|
||||
pub mod quantization;
|
||||
|
@ -146,6 +148,9 @@ impl<'i, I: 'i, O: 'i> Node<'i, I> for Pin<&'i (dyn NodeIO<'i, I, Output = O> +
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use crate::application_io::{ExtractImageFrame, SurfaceFrame, SurfaceId};
|
||||
#[cfg(feature = "wasm")]
|
||||
pub use application_io::{wasm_application_io, wasm_application_io::WasmEditorApi as EditorApi};
|
||||
pub type WasmSurfaceHandle = application_io::SurfaceHandle<web_sys::HtmlCanvasElement>;
|
||||
#[cfg(feature = "wasm")]
|
||||
pub type WasmSurfaceHandleFrame = application_io::SurfaceHandleFrame<web_sys::HtmlCanvasElement>;
|
||||
|
|
|
@ -4,8 +4,8 @@ use core::future::Future;
|
|||
#[cfg(feature = "alloc")]
|
||||
use alloc::sync::Arc;
|
||||
use core::cell::Cell;
|
||||
use core::marker::PhantomData;
|
||||
use core::pin::Pin;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Caches the output of a given Node and acts as a proxy
|
||||
#[derive(Default)]
|
||||
|
@ -103,8 +103,6 @@ impl<'i, T: 'i + Clone> Node<'i, Option<T>> for LetNode<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> std::marker::Unpin for LetNode<T> {}
|
||||
|
||||
impl<T> LetNode<T> {
|
||||
pub fn new() -> LetNode<T> {
|
||||
LetNode { cache: Default::default() }
|
||||
|
|
|
@ -211,7 +211,7 @@ pub struct IntoNode<I, O> {
|
|||
_o: PhantomData<O>,
|
||||
}
|
||||
#[node_macro::node_fn(IntoNode<_I, _O>)]
|
||||
fn into<_I, _O>(input: _I) -> _O
|
||||
async fn into<_I, _O>(input: _I) -> _O
|
||||
where
|
||||
_I: Into<_O>,
|
||||
{
|
||||
|
|
|
@ -88,7 +88,7 @@ impl BrushCacheImpl {
|
|||
|
||||
impl Hash for BrushCacheImpl {
|
||||
// Zero hash.
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {}
|
||||
fn hash<H: core::hash::Hasher>(&self, _state: &mut H) {}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod font_cache;
|
||||
mod to_path;
|
||||
|
||||
use crate::EditorApi;
|
||||
use crate::application_io::EditorApi;
|
||||
pub use font_cache::*;
|
||||
use node_macro::node_fn;
|
||||
pub use to_path::*;
|
||||
|
@ -15,7 +15,7 @@ pub struct TextGenerator<Text, FontName, Size> {
|
|||
}
|
||||
|
||||
#[node_fn(TextGenerator)]
|
||||
fn generate_text<'a: 'input>(editor: EditorApi<'a>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
||||
fn generate_text<'a: 'input, T>(editor: EditorApi<'a, T>, text: String, font_name: Font, font_size: f64) -> crate::vector::VectorData {
|
||||
let buzz_face = editor.font_cache.get(&font_name).map(|data| load_face(data));
|
||||
crate::vector::VectorData::from_subpaths(to_path(&text, buzz_face, font_size, None))
|
||||
}
|
||||
|
|
|
@ -108,6 +108,10 @@ pub enum Type {
|
|||
Future(Box<Type>),
|
||||
}
|
||||
|
||||
unsafe impl StaticType for Type {
|
||||
type Static = Self;
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn is_generic(&self) -> bool {
|
||||
matches!(self, Type::Generic(_))
|
||||
|
|
89
node-graph/gpu-compiler/Cargo.lock
generated
89
node-graph/gpu-compiler/Cargo.lock
generated
|
@ -63,7 +63,7 @@ checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -134,7 +134,7 @@ checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -260,7 +260,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -277,7 +277,7 @@ checksum = "3e7e2adeb6a0d4a282e581096b06e1791532b7d576dcde5ccd9382acf55db8e6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -320,7 +320,7 @@ version = "0.3.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -427,7 +427,7 @@ checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -565,6 +565,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"serde",
|
||||
"spirv",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -596,6 +597,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"dyn-any",
|
||||
"glam",
|
||||
"js-sys",
|
||||
"kurbo",
|
||||
"log",
|
||||
"node-macro",
|
||||
|
@ -608,6 +610,8 @@ dependencies = [
|
|||
"specta",
|
||||
"spin",
|
||||
"spirv-std",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -724,9 +728,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.60"
|
||||
version = "0.3.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
|
||||
checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -810,7 +814,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -821,7 +825,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -933,7 +937,7 @@ dependencies = [
|
|||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1006,18 +1010,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.49"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
|
||||
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -1141,7 +1145,7 @@ dependencies = [
|
|||
"smallvec",
|
||||
"spirt",
|
||||
"spirv-tools",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1224,7 +1228,7 @@ checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1304,7 +1308,7 @@ dependencies = [
|
|||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
|
@ -1383,7 +1387,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"spirv-std-types",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1429,6 +1433,17 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
|
@ -1491,7 +1506,7 @@ checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.107",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1641,9 +1656,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.83"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
|
||||
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
|
@ -1651,24 +1666,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.83"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
|
||||
checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.18",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.83"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
|
||||
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -1676,22 +1691,32 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.83"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
|
||||
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.18",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.83"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
|
||||
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
|
|
|
@ -67,7 +67,7 @@ fn constant_attribute(constant: &GPUConstant) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn construct_argument(input: &ShaderInput<()>, position: u32, binding_offset: u32) -> String {
|
||||
pub fn construct_argument<T: gpu_executor::GpuExecutor>(input: &ShaderInput<T>, position: u32, binding_offset: u32) -> String {
|
||||
let line = match input {
|
||||
ShaderInput::Constant(constant) => format!("#[spirv({})] i{}: {}", constant_attribute(constant), position, constant.ty()),
|
||||
ShaderInput::UniformBuffer(_, ty) => {
|
||||
|
@ -76,6 +76,19 @@ pub fn construct_argument(input: &ShaderInput<()>, position: u32, binding_offset
|
|||
ShaderInput::StorageBuffer(_, ty) | ShaderInput::ReadBackBuffer(_, ty) => {
|
||||
format!("#[spirv(storage_buffer, descriptor_set = 0, binding = {})] i{}: &[{}]", position + binding_offset, position, ty,)
|
||||
}
|
||||
ShaderInput::StorageTextureBuffer(_, ty) => {
|
||||
format!("#[spirv(storage_buffer, descriptor_set = 0, binding = {})] i{}: &mut [{}]]", position + binding_offset, position, ty,)
|
||||
}
|
||||
ShaderInput::TextureView(_, _) => {
|
||||
format!(
|
||||
"#[spirv(texture, descriptor_set = 0, binding = {})] i{}: spirv_std::image::Image2d",
|
||||
position + binding_offset,
|
||||
position,
|
||||
)
|
||||
}
|
||||
ShaderInput::TextureBuffer(_, _) => {
|
||||
panic!("Texture Buffers cannot be used as inputs use TextureView instead")
|
||||
}
|
||||
ShaderInput::OutputBuffer(_, ty) => {
|
||||
format!("#[spirv(storage_buffer, descriptor_set = 0, binding = {})] o{}: &mut[{}]", position + binding_offset, position, ty,)
|
||||
}
|
||||
|
|
|
@ -34,3 +34,7 @@ anyhow = "1.0.66"
|
|||
spirv = "0.2.0"
|
||||
futures-intrusive = "0.5.0"
|
||||
futures = "0.3.25"
|
||||
web-sys = { version = "0.3.4", features = [
|
||||
"HtmlCanvasElement",
|
||||
"ImageBitmapRenderingContext",
|
||||
] }
|
||||
|
|
|
@ -5,7 +5,9 @@ use graphene_core::*;
|
|||
use anyhow::Result;
|
||||
use dyn_any::{StaticType, StaticTypeSized};
|
||||
use futures::Future;
|
||||
use glam::UVec3;
|
||||
use glam::{DAffine2, UVec3};
|
||||
use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle};
|
||||
use graphene_core::raster::{Image, ImageFrame, Pixel, SRGBA8};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::borrow::Cow;
|
||||
use std::pin::Pin;
|
||||
|
@ -13,6 +15,7 @@ use std::sync::Arc;
|
|||
|
||||
type ReadBackFuture = Pin<Box<dyn Future<Output = Result<Vec<u8>>>>>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, dyn_any::DynAny)]
|
||||
pub enum ComputePassDimensions {
|
||||
X(u32),
|
||||
XY(u32, u32),
|
||||
|
@ -29,18 +32,33 @@ impl ComputePassDimensions {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Texture {
|
||||
fn width(&self) -> u32;
|
||||
fn height(&self) -> u32;
|
||||
fn format(&self) -> TextureBufferType;
|
||||
fn view<TextureView>(&self) -> TextureView;
|
||||
}
|
||||
|
||||
pub trait GpuExecutor {
|
||||
type ShaderHandle;
|
||||
type BufferHandle;
|
||||
type TextureHandle;
|
||||
type TextureView;
|
||||
type Surface;
|
||||
type Window;
|
||||
type CommandBuffer;
|
||||
|
||||
fn load_shader(&self, shader: Shader) -> Result<Self::ShaderHandle>;
|
||||
fn create_uniform_buffer<T: ToUniformBuffer>(&self, data: T) -> Result<ShaderInput<Self::BufferHandle>>;
|
||||
fn create_storage_buffer<T: ToStorageBuffer>(&self, data: T, options: StorageBufferOptions) -> Result<ShaderInput<Self::BufferHandle>>;
|
||||
fn create_output_buffer(&self, len: usize, ty: Type, cpu_readable: bool) -> Result<ShaderInput<Self::BufferHandle>>;
|
||||
fn create_compute_pass(&self, layout: &PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self::BufferHandle>>>, instances: ComputePassDimensions) -> Result<Self::CommandBuffer>;
|
||||
fn create_uniform_buffer<T: ToUniformBuffer>(&self, data: T) -> Result<ShaderInput<Self>>;
|
||||
fn create_storage_buffer<T: ToStorageBuffer>(&self, data: T, options: StorageBufferOptions) -> Result<ShaderInput<Self>>;
|
||||
fn create_texture_buffer<T: ToTextureBuffer>(&self, data: T, options: TextureBufferOptions) -> 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_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 execute_compute_pipeline(&self, encoder: Self::CommandBuffer) -> Result<()>;
|
||||
fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self::BufferHandle>>) -> ReadBackFuture;
|
||||
fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self>>) -> ReadBackFuture;
|
||||
fn create_surface(&self, window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<Self::Surface>>;
|
||||
}
|
||||
|
||||
pub trait SpirVCompiler {
|
||||
|
@ -84,37 +102,143 @@ impl GPUConstant {
|
|||
}
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct DummyExecutor;
|
||||
|
||||
impl GpuExecutor for DummyExecutor {
|
||||
type ShaderHandle = ();
|
||||
type BufferHandle = ();
|
||||
type TextureHandle = ();
|
||||
type TextureView = ();
|
||||
type Surface = ();
|
||||
type Window = ();
|
||||
type CommandBuffer = ();
|
||||
|
||||
fn load_shader(&self, _shader: Shader) -> Result<Self::ShaderHandle> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_uniform_buffer<T: ToUniformBuffer>(&self, _data: T) -> Result<ShaderInput<Self>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_storage_buffer<T: ToStorageBuffer>(&self, _data: T, _options: StorageBufferOptions) -> Result<ShaderInput<Self>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_texture_buffer<T: ToTextureBuffer>(&self, _data: T, _options: TextureBufferOptions) -> Result<ShaderInput<Self>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_output_buffer(&self, _len: usize, _ty: Type, _cpu_readable: bool) -> Result<ShaderInput<Self>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_compute_pass(&self, _layout: &PipelineLayout<Self>, _read_back: Option<Arc<ShaderInput<Self>>>, _instances: ComputePassDimensions) -> Result<Self::CommandBuffer> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn execute_compute_pipeline(&self, _encoder: Self::CommandBuffer) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_render_pass(&self, _texture: Arc<ShaderInput<Self>>, _canvas: Arc<SurfaceHandle<Self::Surface>>) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn read_output_buffer(&self, _buffer: Arc<ShaderInput<Self>>) -> ReadBackFuture {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_texture_view(&self, _texture: ShaderInput<Self>) -> Result<ShaderInput<Self>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_surface(&self, _window: SurfaceHandle<Self::Window>) -> Result<SurfaceHandle<Self::Surface>> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
type AbstractShaderInput = ShaderInput<DummyExecutor>;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
/// All the possible inputs to a shader.
|
||||
pub enum ShaderInput<BufferHandle> {
|
||||
UniformBuffer(BufferHandle, Type),
|
||||
StorageBuffer(BufferHandle, Type),
|
||||
pub enum ShaderInput<E: GpuExecutor + ?Sized> {
|
||||
UniformBuffer(E::BufferHandle, Type),
|
||||
StorageBuffer(E::BufferHandle, Type),
|
||||
TextureBuffer(E::TextureHandle, Type),
|
||||
StorageTextureBuffer(E::TextureHandle, Type),
|
||||
TextureView(E::TextureView, Type),
|
||||
/// A struct representing a work group memory buffer. This cannot be accessed by the CPU.
|
||||
WorkGroupMemory(usize, Type),
|
||||
Constant(GPUConstant),
|
||||
OutputBuffer(BufferHandle, Type),
|
||||
ReadBackBuffer(BufferHandle, Type),
|
||||
OutputBuffer(E::BufferHandle, Type),
|
||||
ReadBackBuffer(E::BufferHandle, Type),
|
||||
}
|
||||
|
||||
unsafe impl<E: 'static> StaticType for ShaderInput<E>
|
||||
where
|
||||
E: GpuExecutor,
|
||||
{
|
||||
type Static = Self;
|
||||
}
|
||||
|
||||
pub enum BindingType<'a, E: GpuExecutor> {
|
||||
UniformBuffer(&'a E::BufferHandle),
|
||||
StorageBuffer(&'a E::BufferHandle),
|
||||
TextureView(&'a E::TextureView),
|
||||
}
|
||||
|
||||
/// Extract the buffer handle from a shader input.
|
||||
impl<BufferHandle> ShaderInput<BufferHandle> {
|
||||
pub fn buffer(&self) -> Option<&BufferHandle> {
|
||||
impl<E: GpuExecutor> ShaderInput<E> {
|
||||
pub fn binding(&self) -> Option<BindingType<E>> {
|
||||
match self {
|
||||
ShaderInput::UniformBuffer(buffer, _) => Some(BindingType::UniformBuffer(buffer)),
|
||||
ShaderInput::StorageBuffer(buffer, _) => Some(BindingType::StorageBuffer(buffer)),
|
||||
ShaderInput::WorkGroupMemory(_, _) => None,
|
||||
ShaderInput::Constant(_) => None,
|
||||
ShaderInput::TextureBuffer(_, _) => None,
|
||||
ShaderInput::StorageTextureBuffer(_, _) => None,
|
||||
ShaderInput::TextureView(tex, _) => Some(BindingType::TextureView(tex)),
|
||||
ShaderInput::OutputBuffer(buffer, _) => Some(BindingType::StorageBuffer(buffer)),
|
||||
ShaderInput::ReadBackBuffer(buffer, _) => Some(BindingType::StorageBuffer(buffer)),
|
||||
}
|
||||
}
|
||||
pub fn buffer(&self) -> Option<&E::BufferHandle> {
|
||||
match self {
|
||||
ShaderInput::UniformBuffer(buffer, _) => Some(buffer),
|
||||
ShaderInput::StorageBuffer(buffer, _) => Some(buffer),
|
||||
ShaderInput::WorkGroupMemory(_, _) => None,
|
||||
ShaderInput::Constant(_) => None,
|
||||
ShaderInput::TextureBuffer(_, _) => None,
|
||||
ShaderInput::StorageTextureBuffer(_, _) => None,
|
||||
ShaderInput::TextureView(_tex, _) => None,
|
||||
ShaderInput::OutputBuffer(buffer, _) => Some(buffer),
|
||||
ShaderInput::ReadBackBuffer(buffer, _) => Some(buffer),
|
||||
}
|
||||
}
|
||||
pub fn texture(&self) -> Option<&E::TextureHandle> {
|
||||
match self {
|
||||
ShaderInput::UniformBuffer(_, _) => None,
|
||||
ShaderInput::StorageBuffer(_, _) => None,
|
||||
ShaderInput::WorkGroupMemory(_, _) => None,
|
||||
ShaderInput::Constant(_) => None,
|
||||
ShaderInput::TextureBuffer(tex, _) => Some(tex),
|
||||
ShaderInput::StorageTextureBuffer(tex, _) => Some(tex),
|
||||
ShaderInput::TextureView(_, _) => None,
|
||||
ShaderInput::OutputBuffer(_, _) => None,
|
||||
ShaderInput::ReadBackBuffer(_, _) => None,
|
||||
}
|
||||
}
|
||||
pub fn ty(&self) -> Type {
|
||||
match self {
|
||||
ShaderInput::UniformBuffer(_, ty) => ty.clone(),
|
||||
ShaderInput::StorageBuffer(_, ty) => ty.clone(),
|
||||
ShaderInput::WorkGroupMemory(_, ty) => ty.clone(),
|
||||
ShaderInput::Constant(c) => c.ty(),
|
||||
ShaderInput::TextureBuffer(_, ty) => ty.clone(),
|
||||
ShaderInput::StorageTextureBuffer(_, ty) => ty.clone(),
|
||||
ShaderInput::TextureView(_, ty) => ty.clone(),
|
||||
ShaderInput::OutputBuffer(_, ty) => ty.clone(),
|
||||
ShaderInput::ReadBackBuffer(_, ty) => ty.clone(),
|
||||
}
|
||||
|
@ -133,8 +257,8 @@ pub struct Shader<'a> {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct ShaderIO {
|
||||
pub inputs: Vec<ShaderInput<()>>,
|
||||
pub output: ShaderInput<()>,
|
||||
pub inputs: Vec<AbstractShaderInput>,
|
||||
pub output: AbstractShaderInput,
|
||||
}
|
||||
|
||||
pub struct StorageBufferOptions {
|
||||
|
@ -144,6 +268,12 @@ pub struct StorageBufferOptions {
|
|||
pub storage: bool,
|
||||
}
|
||||
|
||||
pub enum TextureBufferOptions {
|
||||
Storage,
|
||||
Texture,
|
||||
Surface,
|
||||
}
|
||||
|
||||
pub trait ToUniformBuffer: StaticType {
|
||||
fn to_bytes(&self) -> Cow<[u8]>;
|
||||
}
|
||||
|
@ -168,9 +298,61 @@ impl<T: Pod + Zeroable + StaticTypeSized> ToStorageBuffer for Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait TextureFormat {
|
||||
fn format() -> TextureBufferType;
|
||||
}
|
||||
|
||||
impl TextureFormat for Color {
|
||||
fn format() -> TextureBufferType {
|
||||
TextureBufferType::Rgba32Float
|
||||
}
|
||||
}
|
||||
impl TextureFormat for SRGBA8 {
|
||||
fn format() -> TextureBufferType {
|
||||
TextureBufferType::Rgba8Srgb
|
||||
}
|
||||
}
|
||||
|
||||
pub enum TextureBufferType {
|
||||
Rgba32Float,
|
||||
Rgba8Srgb,
|
||||
}
|
||||
|
||||
pub trait ToTextureBuffer: StaticType {
|
||||
fn to_bytes(&self) -> Cow<[u8]>;
|
||||
fn ty() -> Type;
|
||||
fn format() -> TextureBufferType;
|
||||
fn size(&self) -> (u32, u32);
|
||||
}
|
||||
|
||||
impl<T: Pod + Zeroable + StaticTypeSized + Pixel + TextureFormat> ToTextureBuffer for Image<T>
|
||||
where
|
||||
T::Static: Pixel,
|
||||
{
|
||||
fn to_bytes(&self) -> Cow<[u8]> {
|
||||
Cow::Borrowed(bytemuck::cast_slice(self.data.as_slice()))
|
||||
}
|
||||
fn ty() -> Type {
|
||||
concrete!(T)
|
||||
}
|
||||
fn format() -> TextureBufferType {
|
||||
T::format()
|
||||
}
|
||||
fn size(&self) -> (u32, u32) {
|
||||
(self.width, self.height)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collection of all arguments that are passed to the shader.
|
||||
pub struct Bindgroup<E: GpuExecutor + ?Sized> {
|
||||
pub buffers: Vec<Arc<ShaderInput<E::BufferHandle>>>,
|
||||
pub buffers: Vec<Arc<ShaderInput<E>>>,
|
||||
}
|
||||
|
||||
unsafe impl<E: GpuExecutor + ?Sized + StaticType> StaticType for Bindgroup<E>
|
||||
where
|
||||
E::Static: GpuExecutor,
|
||||
{
|
||||
type Static = Bindgroup<E::Static>;
|
||||
}
|
||||
|
||||
/// A struct representing a compute pipeline.
|
||||
|
@ -178,7 +360,14 @@ pub struct PipelineLayout<E: GpuExecutor + ?Sized> {
|
|||
pub shader: E::ShaderHandle,
|
||||
pub entry_point: String,
|
||||
pub bind_group: Bindgroup<E>,
|
||||
pub output_buffer: Arc<ShaderInput<E::BufferHandle>>,
|
||||
pub output_buffer: Arc<ShaderInput<E>>,
|
||||
}
|
||||
|
||||
unsafe impl<E: GpuExecutor + ?Sized + StaticType> StaticType for PipelineLayout<E>
|
||||
where
|
||||
E::Static: GpuExecutor,
|
||||
{
|
||||
type Static = PipelineLayout<E::Static>;
|
||||
}
|
||||
|
||||
/// Extracts arguments from the function arguments and wraps them in a node.
|
||||
|
@ -205,7 +394,7 @@ pub struct UniformNode<Executor> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(UniformNode)]
|
||||
fn uniform_node<T: ToUniformBuffer, E: GpuExecutor>(data: T, executor: &'input E) -> ShaderInput<E::BufferHandle> {
|
||||
async fn uniform_node<'a: 'input, T: ToUniformBuffer, E: GpuExecutor + 'a>(data: T, executor: &'a E) -> ShaderInput<E> {
|
||||
executor.create_uniform_buffer(data).unwrap()
|
||||
}
|
||||
|
||||
|
@ -214,7 +403,7 @@ pub struct StorageNode<Executor> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(StorageNode)]
|
||||
fn storage_node<T: ToStorageBuffer, E: GpuExecutor>(data: T, executor: &'input E) -> ShaderInput<E::BufferHandle> {
|
||||
async fn storage_node<'a: 'input, T: ToStorageBuffer, E: GpuExecutor + 'a>(data: T, executor: &'a E) -> ShaderInput<E> {
|
||||
executor
|
||||
.create_storage_buffer(
|
||||
data,
|
||||
|
@ -233,7 +422,7 @@ pub struct PushNode<Value> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(PushNode)]
|
||||
fn push_node<T>(mut vec: Vec<T>, value: T) {
|
||||
async fn push_node<T>(mut vec: Vec<T>, value: T) {
|
||||
vec.push(value);
|
||||
}
|
||||
|
||||
|
@ -243,8 +432,8 @@ pub struct CreateOutputBufferNode<Executor, Ty> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(CreateOutputBufferNode)]
|
||||
fn create_output_buffer_node<E: GpuExecutor>(size: usize, executor: &'input E, ty: Type) -> ShaderInput<E::BufferHandle> {
|
||||
executor.create_output_buffer(size, ty, true).unwrap()
|
||||
async fn create_output_buffer_node<'a: 'input, E: GpuExecutor + 'a>(size: usize, executor: &'a E, ty: Type) -> Arc<ShaderInput<E>> {
|
||||
Arc::new(executor.create_output_buffer(size, ty, true).unwrap())
|
||||
}
|
||||
|
||||
pub struct CreateComputePassNode<Executor, Output, Instances> {
|
||||
|
@ -254,12 +443,7 @@ pub struct CreateComputePassNode<Executor, Output, Instances> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(CreateComputePassNode)]
|
||||
fn create_compute_pass_node<'any_input, E: 'any_input + GpuExecutor>(
|
||||
layout: PipelineLayout<E>,
|
||||
executor: &'any_input E,
|
||||
output: ShaderInput<E::BufferHandle>,
|
||||
instances: ComputePassDimensions,
|
||||
) -> E::CommandBuffer {
|
||||
async fn create_compute_pass_node<'a: 'input, E: 'a + GpuExecutor>(layout: PipelineLayout<E>, executor: &'a E, output: ShaderInput<E>, instances: ComputePassDimensions) -> E::CommandBuffer {
|
||||
executor.create_compute_pass(&layout, Some(output.into()), instances).unwrap()
|
||||
}
|
||||
|
||||
|
@ -271,7 +455,7 @@ pub struct CreatePipelineLayoutNode<_E, EntryPoint, Bindgroup, OutputBuffer> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(CreatePipelineLayoutNode<_E>)]
|
||||
fn create_pipeline_layout_node<_E: GpuExecutor>(shader: _E::ShaderHandle, entry_point: String, bind_group: Bindgroup<_E>, output_buffer: Arc<ShaderInput<_E::BufferHandle>>) -> PipelineLayout<_E> {
|
||||
async fn create_pipeline_layout_node<_E: GpuExecutor>(shader: _E::ShaderHandle, entry_point: String, bind_group: Bindgroup<_E>, output_buffer: Arc<ShaderInput<_E>>) -> PipelineLayout<_E> {
|
||||
PipelineLayout {
|
||||
shader,
|
||||
entry_point,
|
||||
|
@ -285,15 +469,68 @@ pub struct ExecuteComputePipelineNode<Executor> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(ExecuteComputePipelineNode)]
|
||||
fn execute_compute_pipeline_node<E: GpuExecutor>(encoder: E::CommandBuffer, executor: &'input mut E) {
|
||||
async fn execute_compute_pipeline_node<'a: 'input, E: 'a + GpuExecutor>(encoder: E::CommandBuffer, executor: &'a E) {
|
||||
executor.execute_compute_pipeline(encoder).unwrap();
|
||||
}
|
||||
|
||||
// TODO
|
||||
// pub struct ReadOutputBufferNode<Executor> {
|
||||
// executor: Executor,
|
||||
// }
|
||||
// #[node_macro::node_fn(ReadOutputBufferNode)]
|
||||
// fn read_output_buffer_node<E: GpuExecutor>(buffer: E::BufferHandle, executor: &'input mut E) -> Vec<u8> {
|
||||
// executor.read_output_buffer(buffer).await.unwrap()
|
||||
// }
|
||||
pub struct ReadOutputBufferNode<Executor, ComputePass> {
|
||||
executor: Executor,
|
||||
_compute_pass: ComputePass,
|
||||
}
|
||||
#[node_macro::node_fn(ReadOutputBufferNode)]
|
||||
async fn read_output_buffer_node<'a: 'input, E: 'a + GpuExecutor>(buffer: Arc<ShaderInput<E>>, executor: &'a E, _compute_pass: ()) -> Vec<u8> {
|
||||
executor.read_output_buffer(buffer).await.unwrap()
|
||||
}
|
||||
|
||||
pub struct 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>) -> SurfaceHandle<E::Surface> {
|
||||
let canvas = editor_api.application_io.create_surface();
|
||||
let executor = editor_api.application_io.gpu_executor().unwrap();
|
||||
executor.create_surface(canvas).unwrap()
|
||||
}
|
||||
|
||||
pub struct RenderTextureNode<Surface, EditorApi> {
|
||||
surface: Surface,
|
||||
executor: EditorApi,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ShaderInputFrame<E: GpuExecutor + ?Sized> {
|
||||
shader_input: Arc<ShaderInput<E>>,
|
||||
transform: DAffine2,
|
||||
}
|
||||
|
||||
unsafe impl<E: GpuExecutor + ?Sized + StaticType> StaticType for ShaderInputFrame<E>
|
||||
where
|
||||
E::Static: GpuExecutor,
|
||||
{
|
||||
type Static = ShaderInputFrame<E::Static>;
|
||||
}
|
||||
|
||||
#[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 {
|
||||
let surface_id = surface.surface_id;
|
||||
|
||||
executor.create_render_pass(image.shader_input, surface).unwrap();
|
||||
|
||||
SurfaceFrame {
|
||||
surface_id,
|
||||
transform: image.transform,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UploadTextureNode<E> {
|
||||
executor: E,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(UploadTextureNode)]
|
||||
async fn upload_texture<'a: 'input, E: 'a + GpuExecutor>(input: ImageFrame<Color>, executor: &'a E) -> ShaderInputFrame<E> {
|
||||
let shader_input = executor.create_texture_buffer(input.image, TextureBufferOptions::Texture).unwrap();
|
||||
|
||||
ShaderInputFrame {
|
||||
shader_input: Arc::new(shader_input),
|
||||
transform: input.transform,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,9 +394,9 @@ impl NodeNetwork {
|
|||
(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "CacheNode".to_string(),
|
||||
name: "MemoNode".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::Network(ty)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode")),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode")),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
|
|
|
@ -299,8 +299,8 @@ impl<'a> TaggedValue {
|
|||
x if x == TypeId::of::<graphene_core::Artboard>() => Ok(TaggedValue::Artboard(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<glam::IVec2>() => Ok(TaggedValue::IVec2(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::SurfaceFrame>() => Ok(TaggedValue::SurfaceFrame(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::wasm_application_io::WasmSurfaceHandleFrame>() => {
|
||||
let frame = *downcast::<graphene_core::wasm_application_io::WasmSurfaceHandleFrame>(input).unwrap();
|
||||
x if x == TypeId::of::<graphene_core::WasmSurfaceHandleFrame>() => {
|
||||
let frame = *downcast::<graphene_core::WasmSurfaceHandleFrame>(input).unwrap();
|
||||
Ok(TaggedValue::SurfaceFrame(frame.into()))
|
||||
}
|
||||
_ => Err(format!("Cannot convert {:?} to TaggedValue", DynAny::type_name(input.as_ref()))),
|
||||
|
|
|
@ -9,16 +9,12 @@ license = "MIT OR Apache-2.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = ["wgpu"]
|
||||
gpu = [
|
||||
"graphene-core/gpu",
|
||||
"gpu-compiler-bin-wrapper",
|
||||
"compilation-client",
|
||||
"gpu-executor",
|
||||
]
|
||||
default = ["wasm"]
|
||||
gpu = ["graphene-core/gpu", "gpu-compiler-bin-wrapper", "compilation-client", "gpu-executor"]
|
||||
vulkan = ["gpu", "vulkan-executor"]
|
||||
wgpu = ["gpu", "wgpu-executor"]
|
||||
quantization = ["autoquant"]
|
||||
wasm = ["wasm-bindgen", "web-sys", "js-sys"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
|
@ -29,6 +25,7 @@ graphene-core = { path = "../gcore", features = [
|
|||
"async",
|
||||
"std",
|
||||
"serde",
|
||||
"alloc",
|
||||
], default-features = false }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = ["derive"] }
|
||||
graph-craft = { path = "../graph-craft" }
|
||||
|
@ -53,8 +50,25 @@ xxhash-rust = { workspace = true }
|
|||
serde_json = "1.0.96"
|
||||
reqwest = { version = "0.11.17", features = ["rustls", "rustls-tls"] }
|
||||
futures = "0.3.28"
|
||||
wasm-bindgen = { version = "0.2.84", optional = true }
|
||||
js-sys = { version = "0.3.55", optional = true }
|
||||
wgpu-types = "0.16.0"
|
||||
wgpu = "0.16.1"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
features = ["derive"]
|
||||
|
||||
|
||||
[dependencies.web-sys]
|
||||
version = "0.3.4"
|
||||
optional = true
|
||||
features = [
|
||||
"Window",
|
||||
"CanvasRenderingContext2d",
|
||||
"ImageData",
|
||||
"Document",
|
||||
"HtmlCanvasElement",
|
||||
"ImageBitmapRenderingContext",
|
||||
]
|
||||
|
|
|
@ -6,10 +6,12 @@ use graph_craft::document::*;
|
|||
use graph_craft::proto::*;
|
||||
use graphene_core::raster::*;
|
||||
use graphene_core::*;
|
||||
use wgpu_executor::NewExecutor;
|
||||
use wgpu_executor::WgpuExecutor;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::wasm_application_io::WasmApplicationIo;
|
||||
|
||||
pub struct GpuCompiler<TypingContext, ShaderIO> {
|
||||
typing_context: TypingContext,
|
||||
io: ShaderIO,
|
||||
|
@ -37,12 +39,13 @@ async fn compile_gpu(node: &'input DocumentNode, mut typing_context: TypingConte
|
|||
compilation_client::compile(proto_networks, input_types, output_types, io).await.unwrap()
|
||||
}
|
||||
|
||||
pub struct MapGpuNode<Node> {
|
||||
pub struct MapGpuNode<Node, EditorApi> {
|
||||
node: Node,
|
||||
editor_api: EditorApi,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(MapGpuNode)]
|
||||
async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Color> {
|
||||
async fn map_gpu<'a: 'input>(image: ImageFrame<Color>, node: DocumentNode, editor_api: graphene_core::application_io::EditorApi<'a, WasmApplicationIo>) -> ImageFrame<Color> {
|
||||
log::debug!("Executing gpu node");
|
||||
let compiler = graph_craft::graphene_compiler::Compiler {};
|
||||
let inner_network = NodeNetwork::value_network(node);
|
||||
|
@ -121,7 +124,24 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
|||
//return ImageFrame::empty();
|
||||
let len: usize = image.image.data.len();
|
||||
|
||||
let executor = NewExecutor::new().await.unwrap();
|
||||
let executor = &editor_api.application_io.gpu_executor.as_ref().unwrap();
|
||||
|
||||
/*
|
||||
let canvas = editor_api.application_io.create_surface();
|
||||
|
||||
let surface = unsafe { executor.create_surface(canvas) }.unwrap();
|
||||
//log::debug!("id: {:?}", surface);
|
||||
let surface_id = surface.surface_id;
|
||||
|
||||
let texture = executor.create_texture_buffer(image.image.clone(), TextureBufferOptions::Texture).unwrap();
|
||||
|
||||
//executor.create_render_pass(texture, surface).unwrap();
|
||||
|
||||
let frame = SurfaceFrame {
|
||||
surface_id,
|
||||
transform: image.transform,
|
||||
};
|
||||
return frame;*/
|
||||
log::debug!("creating buffer");
|
||||
let width_uniform = executor.create_uniform_buffer(image.image.width).unwrap();
|
||||
let storage_buffer = executor
|
||||
|
@ -152,7 +172,6 @@ async fn map_gpu(image: ImageFrame<Color>, node: DocumentNode) -> ImageFrame<Col
|
|||
io: shader.io,
|
||||
};
|
||||
log::debug!("loading shader");
|
||||
log::debug!("shader: {:?}", shader.source);
|
||||
let shader = executor.load_shader(shader).unwrap();
|
||||
log::debug!("loaded shader");
|
||||
let pipeline = PipelineLayout {
|
||||
|
@ -333,7 +352,7 @@ async fn blend_gpu_image(foreground: ImageFrame<Color>, background: ImageFrame<C
|
|||
.unwrap();
|
||||
let len = background.image.data.len();
|
||||
|
||||
let executor = NewExecutor::new()
|
||||
let executor = WgpuExecutor::new()
|
||||
.await
|
||||
.expect("Failed to create wgpu executor. Please make sure that webgpu is enabled for your browser.");
|
||||
log::debug!("creating buffer");
|
|
@ -12,7 +12,7 @@ pub mod http;
|
|||
pub mod any;
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
pub mod executor;
|
||||
pub mod gpu_nodes;
|
||||
|
||||
#[cfg(feature = "quantization")]
|
||||
pub mod quantization;
|
||||
|
@ -22,3 +22,6 @@ pub use graphene_core::*;
|
|||
pub mod image_segmentation;
|
||||
|
||||
pub mod brush;
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
pub mod wasm_application_io;
|
||||
|
|
|
@ -1,27 +1,34 @@
|
|||
use std::{cell::RefCell, collections::HashMap};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::{ApplicationIo, SurfaceHandle, SurfaceHandleFrame, SurfaceId};
|
||||
use crate::{
|
||||
use dyn_any::StaticType;
|
||||
use graphene_core::application_io::{ApplicationIo, SurfaceHandle, SurfaceHandleFrame, SurfaceId};
|
||||
use graphene_core::{
|
||||
raster::{color::SRGBA8, ImageFrame},
|
||||
Node,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
use dyn_any::StaticType;
|
||||
use js_sys::{Object, Reflect};
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::{Clamped, JsCast, JsValue};
|
||||
use web_sys::{window, CanvasRenderingContext2d, HtmlCanvasElement};
|
||||
#[cfg(feature = "wgpu")]
|
||||
use wgpu_executor::WgpuExecutor;
|
||||
|
||||
pub struct Canvas(CanvasRenderingContext2d);
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct WasmApplicationIo {
|
||||
ids: RefCell<u64>,
|
||||
canvases: RefCell<HashMap<SurfaceId, CanvasRenderingContext2d>>,
|
||||
#[cfg(feature = "wgpu")]
|
||||
pub(crate) gpu_executor: Option<WgpuExecutor>,
|
||||
}
|
||||
|
||||
impl WasmApplicationIo {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
pub async fn new() -> Self {
|
||||
Self {
|
||||
ids: RefCell::new(0),
|
||||
#[cfg(feature = "wgpu")]
|
||||
gpu_executor: WgpuExecutor::new().await,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,24 +36,36 @@ unsafe impl StaticType for WasmApplicationIo {
|
|||
type Static = WasmApplicationIo;
|
||||
}
|
||||
|
||||
pub type WasmEditorApi<'a> = super::EditorApi<'a, WasmApplicationIo>;
|
||||
impl<'a> From<WasmEditorApi<'a>> for &'a WasmApplicationIo {
|
||||
fn from(editor_api: WasmEditorApi<'a>) -> Self {
|
||||
editor_api.application_io
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
impl<'a> From<&'a WasmApplicationIo> for &'a WgpuExecutor {
|
||||
fn from(app_io: &'a WasmApplicationIo) -> Self {
|
||||
app_io.gpu_executor.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub type WasmEditorApi<'a> = graphene_core::application_io::EditorApi<'a, WasmApplicationIo>;
|
||||
|
||||
impl ApplicationIo for WasmApplicationIo {
|
||||
type Surface = CanvasRenderingContext2d;
|
||||
type Surface = HtmlCanvasElement;
|
||||
#[cfg(feature = "wgpu")]
|
||||
type Executor = WgpuExecutor;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
type Executor = ();
|
||||
|
||||
fn create_surface(&self) -> SurfaceHandle<Self::Surface> {
|
||||
let wrapper = || {
|
||||
let document = window().expect("should have a window in this context").document().expect("window should have a document");
|
||||
|
||||
let canvas: HtmlCanvasElement = document.create_element("canvas")?.dyn_into::<HtmlCanvasElement>()?;
|
||||
// TODO: replace "2d" with "bitmaprenderer" once we switch to ImageBitmap (lives on gpu) from ImageData (lives on cpu)
|
||||
let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::<CanvasRenderingContext2d>().unwrap();
|
||||
let mut guard = self.ids.borrow_mut();
|
||||
let id = SurfaceId(*guard);
|
||||
*guard += 1;
|
||||
self.canvases.borrow_mut().insert(id, context.clone());
|
||||
// store the canvas in the global scope so it doesn't get garbage collected
|
||||
|
||||
let window = window().expect("should have a window in this context");
|
||||
let window = Object::from(window);
|
||||
|
||||
|
@ -60,21 +79,19 @@ impl ApplicationIo for WasmApplicationIo {
|
|||
|
||||
// Convert key and value to JsValue
|
||||
let js_key = JsValue::from_str(format!("canvas{}", id.0).as_str());
|
||||
let js_value = JsValue::from(context.clone());
|
||||
let js_value = JsValue::from(canvas.clone());
|
||||
|
||||
let canvases = Object::from(canvases.unwrap());
|
||||
|
||||
// Use Reflect API to set property
|
||||
Reflect::set(&canvases, &js_key, &js_value)?;
|
||||
Ok::<_, JsValue>(SurfaceHandle { surface_id: id, surface: context })
|
||||
Ok::<_, JsValue>(SurfaceHandle { surface_id: id, surface: canvas })
|
||||
};
|
||||
|
||||
wrapper().expect("should be able to set canvas in global scope")
|
||||
}
|
||||
|
||||
fn destroy_surface(&self, surface_id: SurfaceId) {
|
||||
self.canvases.borrow_mut().remove(&surface_id);
|
||||
|
||||
let window = window().expect("should have a window in this context");
|
||||
let window = Object::from(window);
|
||||
|
||||
|
@ -93,15 +110,20 @@ impl ApplicationIo for WasmApplicationIo {
|
|||
|
||||
wrapper().expect("should be able to set canvas in global scope")
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
fn gpu_executor(&self) -> Option<&Self::Executor> {
|
||||
self.gpu_executor.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
pub type WasmSurfaceHandle = SurfaceHandle<CanvasRenderingContext2d>;
|
||||
pub type WasmSurfaceHandleFrame = SurfaceHandleFrame<CanvasRenderingContext2d>;
|
||||
pub type WasmSurfaceHandle = SurfaceHandle<HtmlCanvasElement>;
|
||||
pub type WasmSurfaceHandleFrame = SurfaceHandleFrame<HtmlCanvasElement>;
|
||||
|
||||
pub struct CreateSurfaceNode {}
|
||||
|
||||
#[node_macro::node_fn(CreateSurfaceNode)]
|
||||
fn create_surface_node<'a: 'input>(editor: WasmEditorApi<'a>) -> Arc<SurfaceHandle<CanvasRenderingContext2d>> {
|
||||
async fn create_surface_node<'a: 'input>(editor: WasmEditorApi<'a>) -> Arc<SurfaceHandle<HtmlCanvasElement>> {
|
||||
editor.application_io.create_surface().into()
|
||||
}
|
||||
|
||||
|
@ -110,15 +132,17 @@ pub struct DrawImageFrameNode<Surface> {
|
|||
}
|
||||
|
||||
#[node_macro::node_fn(DrawImageFrameNode)]
|
||||
async fn draw_image_frame_node<'a: 'input>(image: ImageFrame<SRGBA8>, surface_handle: Arc<SurfaceHandle<CanvasRenderingContext2d>>) -> SurfaceHandleFrame<CanvasRenderingContext2d> {
|
||||
async fn draw_image_frame_node<'a: 'input>(image: ImageFrame<SRGBA8>, surface_handle: Arc<SurfaceHandle<HtmlCanvasElement>>) -> SurfaceHandleFrame<HtmlCanvasElement> {
|
||||
let image_data = image.image.data;
|
||||
let array: Clamped<&[u8]> = Clamped(bytemuck::cast_slice(image_data.as_slice()));
|
||||
if image.image.width > 0 && image.image.height > 0 {
|
||||
let canvas = surface_handle.surface.canvas().expect("Failed to get canvas");
|
||||
let canvas = &surface_handle.surface;
|
||||
canvas.set_width(image.image.width);
|
||||
canvas.set_height(image.image.height);
|
||||
let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(array, image.image.width, image.image.height).expect("Failed to construct ImageData");
|
||||
surface_handle.surface.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
||||
// TODO: replace "2d" with "bitmaprenderer" once we switch to ImageBitmap (lives on gpu) from ImageData (lives on cpu)
|
||||
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, image.image.width as u32, image.image.height as u32).expect("Failed to construct ImageData");
|
||||
context.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
||||
}
|
||||
SurfaceHandleFrame {
|
||||
surface_handle,
|
|
@ -16,6 +16,8 @@ quantization = ["graphene-std/quantization"]
|
|||
graphene-core = { path = "../gcore", features = ["async", "std"] }
|
||||
graphene-std = { path = "../gstd" }
|
||||
graph-craft = { path = "../graph-craft" }
|
||||
gpu-executor = { path = "../gpu-executor" }
|
||||
wgpu-executor = { path = "../wgpu-executor" }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = [
|
||||
"log-bad-types",
|
||||
"glam",
|
||||
|
|
|
@ -8,15 +8,19 @@ use graphene_core::structural::Then;
|
|||
use graphene_core::value::{ClonedNode, CopiedNode, ValueNode};
|
||||
use graphene_core::vector::brush_stroke::BrushStroke;
|
||||
use graphene_core::vector::VectorData;
|
||||
use graphene_core::wasm_application_io::WasmSurfaceHandle;
|
||||
use graphene_core::wasm_application_io::*;
|
||||
use graphene_core::{application_io::SurfaceHandle, SurfaceFrame, WasmSurfaceHandleFrame};
|
||||
use graphene_core::{concrete, generic};
|
||||
use graphene_core::{fn_type, raster::*};
|
||||
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
|
||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
||||
use graphene_std::wasm_application_io::*;
|
||||
|
||||
#[cfg(feature = "gpu")]
|
||||
use gpu_executor::{GpuExecutor, ShaderInput, ShaderInputFrame};
|
||||
use graphene_std::raster::*;
|
||||
use graphene_std::wasm_application_io::WasmEditorApi;
|
||||
use wgpu_executor::WgpuExecutor;
|
||||
|
||||
use dyn_any::StaticType;
|
||||
use glam::{DAffine2, DVec2};
|
||||
|
@ -79,7 +83,7 @@ macro_rules! async_node {
|
|||
args.reverse();
|
||||
let node = <$path>::new($(graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"))),*);
|
||||
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
any.into_type_erased()
|
||||
Box::new(any) as TypeErasedBox
|
||||
})
|
||||
},
|
||||
{
|
||||
|
@ -181,7 +185,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
register_node!(graphene_core::ops::AddNode, input: (u32, u32), params: []),
|
||||
register_node!(graphene_core::ops::AddNode, input: (u32, &u32), params: []),
|
||||
register_node!(graphene_core::ops::CloneNode<_>, input: &ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_core::ops::CloneNode<_>, input: &graphene_core::EditorApi, params: []),
|
||||
register_node!(graphene_core::ops::CloneNode<_>, input: &WasmEditorApi, params: []),
|
||||
register_node!(graphene_core::ops::AddParameterNode<_>, input: u32, params: [u32]),
|
||||
register_node!(graphene_core::ops::AddParameterNode<_>, input: &u32, params: [u32]),
|
||||
register_node!(graphene_core::ops::AddParameterNode<_>, input: u32, params: [&u32]),
|
||||
|
@ -190,9 +194,11 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [f64]),
|
||||
register_node!(graphene_core::ops::AddParameterNode<_>, input: f64, params: [&f64]),
|
||||
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]),
|
||||
register_node!(graphene_core::ops::SomeNode, input: graphene_core::EditorApi, params: []),
|
||||
register_node!(graphene_core::ops::IntoNode<_, ImageFrame<SRGBA8>>, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_core::ops::IntoNode<_, ImageFrame<Color>>, input: ImageFrame<SRGBA8>, params: []),
|
||||
register_node!(graphene_core::ops::SomeNode, input: WasmEditorApi, params: []),
|
||||
async_node!(graphene_core::ops::IntoNode<_, ImageFrame<SRGBA8>>, input: ImageFrame<Color>, output: ImageFrame<SRGBA8>, params: []),
|
||||
async_node!(graphene_core::ops::IntoNode<_, ImageFrame<Color>>, input: ImageFrame<SRGBA8>, output: ImageFrame<Color>, params: []),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::ops::IntoNode<_, &WgpuExecutor>, input: WasmEditorApi, output: &WgpuExecutor, params: []),
|
||||
register_node!(graphene_std::raster::DownresNode<_>, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_std::raster::MaskImageNode<_, _, _>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
register_node!(graphene_std::raster::MaskImageNode<_, _, _>, input: ImageFrame<Color>, params: [ImageFrame<Luma>]),
|
||||
|
@ -244,26 +250,68 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
register_node!(graphene_std::raster::EmptyImageNode<_, _>, input: DAffine2, params: [Color]),
|
||||
register_node!(graphene_core::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_core::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
|
||||
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: graphene_core::EditorApi, params: []),
|
||||
async_node!(graphene_std::wasm_application_io::CreateSurfaceNode, input: WasmEditorApi, output: Arc<SurfaceHandle<<graphene_std::wasm_application_io::WasmApplicationIo as graphene_core::application_io::ApplicationIo>::Surface>>, params: []),
|
||||
async_node!(
|
||||
graphene_core::wasm_application_io::DrawImageFrameNode<_>,
|
||||
graphene_std::wasm_application_io::DrawImageFrameNode<_>,
|
||||
input: ImageFrame<SRGBA8>,
|
||||
output: WasmSurfaceHandleFrame,
|
||||
params: [Arc<WasmSurfaceHandle>]
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(gpu_executor::UniformNode<_>, input: f32, output: ShaderInput<WgpuExecutor>, params: [&WgpuExecutor]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(gpu_executor::StorageNode<_>, input: Vec<u8>, output: ShaderInput<WgpuExecutor>, params: [&WgpuExecutor]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(
|
||||
gpu_executor::PushNode<_>,
|
||||
input: Vec<ShaderInput<WgpuExecutor>>,
|
||||
output: Vec<ShaderInput<WgpuExecutor>>,
|
||||
params: [ShaderInput<WgpuExecutor>]
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(gpu_executor::CreateOutputBufferNode<_, _>, input: usize, output: gpu_executor::ShaderInput<WgpuExecutor>, params: [&WgpuExecutor, Type]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(gpu_executor::CreateComputePassNode<_, _, _>, input: gpu_executor::PipelineLayout<WgpuExecutor>, output: <WgpuExecutor as GpuExecutor>::CommandBuffer, params: [&WgpuExecutor, ShaderInput<WgpuExecutor>, gpu_executor::ComputePassDimensions]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(gpu_executor::CreatePipelineLayoutNode<_, _, _, _>, input: <WgpuExecutor as GpuExecutor>::ShaderHandle, output: gpu_executor::PipelineLayout<WgpuExecutor>, params: [String, gpu_executor::Bindgroup<WgpuExecutor>, Arc<ShaderInput<WgpuExecutor>>]),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(
|
||||
gpu_executor::ExecuteComputePipelineNode<_>,
|
||||
input: <WgpuExecutor as GpuExecutor>::CommandBuffer,
|
||||
output: (),
|
||||
params: [&WgpuExecutor]
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(gpu_executor::ReadOutputBufferNode<_, _>, input: Arc<ShaderInput<WgpuExecutor>>, output: Vec<u8>, params: [&WgpuExecutor, ()]),
|
||||
#[cfg(all(feature = "gpu", target_arch = "wasm32"))]
|
||||
async_node!(gpu_executor::CreateGpuSurfaceNode, input: WasmEditorApi, output: Arc<SurfaceHandle<<WgpuExecutor as GpuExecutor>::Surface>>, params: []),
|
||||
#[cfg(feature = "gpu")]
|
||||
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::UploadTextureNode<_>,
|
||||
input: ImageFrame<Color>,
|
||||
output: ShaderInputFrame<WgpuExecutor>,
|
||||
params: [&WgpuExecutor]
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let document_node: DowncastBothNode<(), graph_craft::document::DocumentNode> = DowncastBothNode::new(args[0].clone());
|
||||
let editor_api: DowncastBothNode<(), WasmEditorApi> = DowncastBothNode::new(args[1].clone());
|
||||
//let document_node = ClonedNode::new(document_node.eval(()));
|
||||
let node = graphene_std::executor::MapGpuNode::new(document_node);
|
||||
let node = graphene_std::gpu_nodes::MapGpuNode::new(document_node, editor_api);
|
||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(graph_craft::document::DocumentNode)]),
|
||||
NodeIOTypes::new(
|
||||
concrete!(ImageFrame<Color>),
|
||||
concrete!(SurfaceFrame),
|
||||
vec![fn_type!(graph_craft::document::DocumentNode), fn_type!(WasmEditorApi)],
|
||||
),
|
||||
)],
|
||||
#[cfg(feature = "gpu")]
|
||||
vec![(
|
||||
|
@ -273,7 +321,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
let background: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0].clone());
|
||||
let blend_mode: DowncastBothNode<(), BlendMode> = DowncastBothNode::new(args[1].clone());
|
||||
let opacity: DowncastBothNode<(), f32> = DowncastBothNode::new(args[2].clone());
|
||||
let node = graphene_std::executor::BlendGpuImageNode::new(background, blend_mode, opacity);
|
||||
let node = graphene_std::gpu_nodes::BlendGpuImageNode::new(background, blend_mode, opacity);
|
||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
|
||||
any.into_type_erased()
|
||||
|
@ -374,47 +422,39 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f64]),
|
||||
raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f64, f64, f64]),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<ImageFrame<Color>>, params: []),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<graphene_core::EditorApi>, params: []),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<WasmEditorApi>, params: []),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: VectorData, params: [VectorData]),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: ImageFrame<Color>,
|
||||
params: [ImageFrame<Color>]
|
||||
),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: graphene_core::EditorApi, output: VectorData, params: [VectorData]),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
input: WasmEditorApi,
|
||||
output: graphene_core::GraphicGroup,
|
||||
params: [graphene_core::GraphicGroup]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
input: WasmEditorApi,
|
||||
output: graphene_core::Artboard,
|
||||
params: [graphene_core::Artboard]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
input: WasmEditorApi,
|
||||
output: WasmSurfaceHandleFrame,
|
||||
params: [WasmSurfaceHandleFrame]
|
||||
),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: SurfaceFrame, params: [SurfaceFrame]),
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_core::memo::RefNode<_, _>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let node: DowncastBothNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = graphene_std::any::DowncastBothNode::new(args[0].clone());
|
||||
let node: DowncastBothNode<Option<WasmEditorApi>, WasmEditorApi> = graphene_std::any::DowncastBothNode::new(args[0].clone());
|
||||
let node = <graphene_core::memo::RefNode<_, _>>::new(node);
|
||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(graphene_core::EditorApi),
|
||||
vec![fn_type!(Option<graphene_core::EditorApi>, graphene_core::EditorApi)],
|
||||
),
|
||||
NodeIOTypes::new(concrete!(()), concrete!(WasmEditorApi), vec![fn_type!(Option<WasmEditorApi>, WasmEditorApi)]),
|
||||
)],
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Image<Color>, params: [Image<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
|
@ -443,9 +483,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
|
||||
params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
|
||||
),
|
||||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: WasmEditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
|
||||
register_node!(graphene_core::ExtractImageFrame, input: graphene_core::EditorApi, params: []),
|
||||
register_node!(graphene_core::ExtractImageFrame, input: WasmEditorApi, params: []),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
|
|
|
@ -10,10 +10,19 @@ default = []
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
graphene-core = { path = "../gcore", features = ["async", "std", "alloc", "gpu"] }
|
||||
graphene-core = { path = "../gcore", features = [
|
||||
"async",
|
||||
"std",
|
||||
"alloc",
|
||||
"gpu",
|
||||
] }
|
||||
graph-craft = { path = "../graph-craft" }
|
||||
gpu-executor = { path = "../gpu-executor" }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "rc", "glam"] }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = [
|
||||
"log-bad-types",
|
||||
"rc",
|
||||
"glam",
|
||||
] }
|
||||
future-executor = { path = "../future-executor" }
|
||||
num-traits = "0.2"
|
||||
log = "0.4"
|
||||
|
@ -27,3 +36,5 @@ wgpu = { version = "0.16", features = ["spirv"] }
|
|||
spirv = "0.2.0"
|
||||
futures-intrusive = "0.5.0"
|
||||
futures = "0.3.25"
|
||||
web-sys = { version = "0.3.4", features = ["HtmlCanvasElement"] }
|
||||
winit = "0.28.6"
|
||||
|
|
|
@ -6,6 +6,7 @@ pub struct Context {
|
|||
pub device: Arc<Device>,
|
||||
pub queue: Arc<Queue>,
|
||||
pub instance: Arc<Instance>,
|
||||
pub adapter: Arc<wgpu::Adapter>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
|
@ -16,9 +17,9 @@ impl Context {
|
|||
// `request_adapter` instantiates the general connection to the GPU
|
||||
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions::default()).await?;
|
||||
|
||||
let limits = adapter.limits();
|
||||
//let limits = adapter.limits();
|
||||
|
||||
log::trace!("Adapter limits: {:?}", limits);
|
||||
//log::trace!("Adapter limits: {:?}", limits);
|
||||
|
||||
// `request_device` instantiates the feature specific connection to the GPU, defining some parameters,
|
||||
// `features` being the available features.
|
||||
|
@ -27,7 +28,7 @@ impl Context {
|
|||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
features: wgpu::Features::empty(),
|
||||
limits,
|
||||
limits: Default::default(),
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
@ -42,6 +43,7 @@ impl Context {
|
|||
Some(Self {
|
||||
device: Arc::new(device),
|
||||
queue: Arc::new(queue),
|
||||
adapter: Arc::new(adapter),
|
||||
instance: Arc::new(instance),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,36 +2,117 @@ mod context;
|
|||
mod executor;
|
||||
|
||||
pub use context::Context;
|
||||
use dyn_any::{DynAny, StaticType};
|
||||
pub use executor::GpuExecutor;
|
||||
use gpu_executor::{ComputePassDimensions, Shader, ShaderInput, StorageBufferOptions, ToStorageBuffer, ToUniformBuffer};
|
||||
use gpu_executor::{ComputePassDimensions, Shader, ShaderInput, StorageBufferOptions, TextureBufferOptions, TextureBufferType, ToStorageBuffer, ToUniformBuffer};
|
||||
use graph_craft::Type;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use futures::Future;
|
||||
use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle};
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu::{Buffer, BufferDescriptor, CommandBuffer, ShaderModule};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NewExecutor {
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu::{Buffer, BufferDescriptor, CommandBuffer, ShaderModule, Texture, TextureView};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use web_sys::HtmlCanvasElement;
|
||||
|
||||
#[derive(Debug, dyn_any::DynAny)]
|
||||
pub struct WgpuExecutor {
|
||||
context: Context,
|
||||
render_configuration: RenderConfiguration,
|
||||
}
|
||||
|
||||
impl gpu_executor::GpuExecutor for NewExecutor {
|
||||
type ShaderHandle = ShaderModule;
|
||||
impl<'a, T: ApplicationIo<Executor = WgpuExecutor>> From<EditorApi<'a, T>> for &'a WgpuExecutor {
|
||||
fn from(editor_api: EditorApi<'a, T>) -> Self {
|
||||
editor_api.application_io.gpu_executor().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
struct Vertex {
|
||||
position: [f32; 3],
|
||||
tex_coords: [f32; 2],
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
fn desc() -> wgpu::VertexBufferLayout<'static> {
|
||||
use std::mem;
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
||||
step_mode: wgpu::VertexStepMode::Vertex,
|
||||
attributes: &[
|
||||
wgpu::VertexAttribute {
|
||||
offset: 0,
|
||||
shader_location: 0,
|
||||
format: wgpu::VertexFormat::Float32x3,
|
||||
},
|
||||
wgpu::VertexAttribute {
|
||||
offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress,
|
||||
shader_location: 1,
|
||||
format: wgpu::VertexFormat::Float32x2,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const VERTICES: &[Vertex] = &[
|
||||
Vertex {
|
||||
position: [-1., 1., 0.0],
|
||||
tex_coords: [0., 0.],
|
||||
}, // A
|
||||
Vertex {
|
||||
position: [-1., -1., 0.0],
|
||||
tex_coords: [0., 1.],
|
||||
}, // B
|
||||
Vertex {
|
||||
position: [1., 1., 0.0],
|
||||
tex_coords: [1., 0.],
|
||||
}, // C
|
||||
Vertex {
|
||||
position: [1., -1., 0.0],
|
||||
tex_coords: [1., 1.],
|
||||
}, // D
|
||||
];
|
||||
|
||||
const INDICES: &[u16] = &[0, 1, 2, 2, 1, 3];
|
||||
|
||||
type WgpuShaderInput = ShaderInput<WgpuExecutor>;
|
||||
|
||||
#[derive(Debug, DynAny)]
|
||||
#[repr(transparent)]
|
||||
pub struct CommandBufferWrapper(CommandBuffer);
|
||||
|
||||
#[derive(Debug, DynAny)]
|
||||
#[repr(transparent)]
|
||||
pub struct ShaderModuleWrapper(ShaderModule);
|
||||
|
||||
impl gpu_executor::GpuExecutor for WgpuExecutor {
|
||||
type ShaderHandle = ShaderModuleWrapper;
|
||||
type BufferHandle = Buffer;
|
||||
type CommandBuffer = CommandBuffer;
|
||||
type TextureHandle = Texture;
|
||||
type TextureView = TextureView;
|
||||
type CommandBuffer = CommandBufferWrapper;
|
||||
type Surface = wgpu::Surface;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
type Window = HtmlCanvasElement;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
type Window = winit::window::Window;
|
||||
|
||||
fn load_shader(&self, shader: Shader) -> Result<Self::ShaderHandle> {
|
||||
let shader_module = self.context.device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some(shader.name),
|
||||
source: wgpu::ShaderSource::SpirV(shader.source),
|
||||
});
|
||||
Ok(shader_module)
|
||||
Ok(ShaderModuleWrapper(shader_module))
|
||||
}
|
||||
|
||||
fn create_uniform_buffer<T: ToUniformBuffer>(&self, data: T) -> Result<ShaderInput<Self::BufferHandle>> {
|
||||
fn create_uniform_buffer<T: ToUniformBuffer>(&self, data: T) -> Result<WgpuShaderInput> {
|
||||
let bytes = data.to_bytes();
|
||||
let buffer = self.context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: None,
|
||||
|
@ -41,7 +122,7 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
|||
Ok(ShaderInput::UniformBuffer(buffer, Type::new::<T>()))
|
||||
}
|
||||
|
||||
fn create_storage_buffer<T: ToStorageBuffer>(&self, data: T, options: StorageBufferOptions) -> Result<ShaderInput<Self::BufferHandle>> {
|
||||
fn create_storage_buffer<T: ToStorageBuffer>(&self, data: T, options: StorageBufferOptions) -> Result<WgpuShaderInput> {
|
||||
let bytes = data.to_bytes();
|
||||
let mut usage = wgpu::BufferUsages::empty();
|
||||
|
||||
|
@ -66,8 +147,44 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
|||
});
|
||||
Ok(ShaderInput::StorageBuffer(buffer, data.ty()))
|
||||
}
|
||||
fn create_texture_buffer<T: gpu_executor::ToTextureBuffer>(&self, data: T, options: TextureBufferOptions) -> Result<WgpuShaderInput> {
|
||||
let bytes = data.to_bytes();
|
||||
let usage = match options {
|
||||
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::Surface => wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
};
|
||||
let format = match T::format() {
|
||||
TextureBufferType::Rgba32Float => wgpu::TextureFormat::Rgba32Float,
|
||||
TextureBufferType::Rgba8Srgb => wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
};
|
||||
|
||||
fn create_output_buffer(&self, len: usize, ty: Type, cpu_readable: bool) -> Result<ShaderInput<Self::BufferHandle>> {
|
||||
let buffer = self.context.device.create_texture_with_data(
|
||||
self.context.queue.as_ref(),
|
||||
&wgpu::TextureDescriptor {
|
||||
label: None,
|
||||
size: wgpu::Extent3d {
|
||||
width: data.size().0,
|
||||
height: data.size().1,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format,
|
||||
usage,
|
||||
view_formats: &[format],
|
||||
},
|
||||
bytes.as_ref(),
|
||||
);
|
||||
match options {
|
||||
TextureBufferOptions::Storage => Ok(ShaderInput::StorageTextureBuffer(buffer, T::ty())),
|
||||
TextureBufferOptions::Texture => Ok(ShaderInput::TextureBuffer(buffer, T::ty())),
|
||||
TextureBufferOptions::Surface => Ok(ShaderInput::TextureBuffer(buffer, T::ty())),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_output_buffer(&self, len: usize, ty: Type, cpu_readable: bool) -> Result<WgpuShaderInput> {
|
||||
log::debug!("Creating output buffer with len: {}", len);
|
||||
let create_buffer = |usage| {
|
||||
Ok::<_, anyhow::Error>(self.context.device.create_buffer(&BufferDescriptor {
|
||||
|
@ -83,11 +200,11 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
|||
};
|
||||
Ok(buffer)
|
||||
}
|
||||
fn create_compute_pass(&self, layout: &gpu_executor::PipelineLayout<Self>, read_back: Option<Arc<ShaderInput<Self::BufferHandle>>>, instances: ComputePassDimensions) -> Result<CommandBuffer> {
|
||||
fn create_compute_pass(&self, layout: &gpu_executor::PipelineLayout<Self>, read_back: Option<Arc<WgpuShaderInput>>, instances: ComputePassDimensions) -> Result<Self::CommandBuffer> {
|
||||
let compute_pipeline = self.context.device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
|
||||
label: None,
|
||||
layout: None,
|
||||
module: &layout.shader,
|
||||
module: &layout.shader.0,
|
||||
entry_point: layout.entry_point.as_str(),
|
||||
});
|
||||
let bind_group_layout = compute_pipeline.get_bind_group_layout(0);
|
||||
|
@ -97,11 +214,15 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
|||
.buffers
|
||||
.iter()
|
||||
.chain(std::iter::once(&layout.output_buffer))
|
||||
.flat_map(|input| input.buffer())
|
||||
.flat_map(|input| input.binding())
|
||||
.enumerate()
|
||||
.map(|(i, buffer)| wgpu::BindGroupEntry {
|
||||
binding: i as u32,
|
||||
resource: buffer.as_entire_binding(),
|
||||
resource: match buffer {
|
||||
gpu_executor::BindingType::UniformBuffer(buf) => buf.as_entire_binding(),
|
||||
gpu_executor::BindingType::StorageBuffer(buf) => buf.as_entire_binding(),
|
||||
gpu_executor::BindingType::TextureView(buf) => wgpu::BindingResource::TextureView(buf),
|
||||
},
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
@ -123,27 +244,77 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
|||
// Sets adds copy operation to command encoder.
|
||||
// Will copy data from storage buffer on GPU to staging buffer on CPU.
|
||||
if let Some(buffer) = read_back {
|
||||
let ShaderInput::ReadBackBuffer(output, ty) = buffer.as_ref() else {
|
||||
let ShaderInput::ReadBackBuffer(output, _ty) = buffer.as_ref() else {
|
||||
bail!("Tried to read back from a non read back buffer");
|
||||
};
|
||||
let size = output.size();
|
||||
assert_eq!(size, layout.output_buffer.buffer().unwrap().size());
|
||||
let ShaderInput::OutputBuffer(output_buffer, ty) = layout.output_buffer.as_ref() else {
|
||||
bail!("Tried to read back from a non output buffer");
|
||||
};
|
||||
assert_eq!(size, output_buffer.size());
|
||||
assert_eq!(ty, &layout.output_buffer.ty());
|
||||
encoder.copy_buffer_to_buffer(
|
||||
layout.output_buffer.buffer().ok_or_else(|| anyhow::anyhow!("Tried to use an non buffer as the shader output"))?,
|
||||
0,
|
||||
output,
|
||||
0,
|
||||
size,
|
||||
);
|
||||
encoder.copy_buffer_to_buffer(output_buffer, 0, output, 0, size);
|
||||
}
|
||||
|
||||
// Submits command encoder for processing
|
||||
Ok(encoder.finish())
|
||||
Ok(CommandBufferWrapper(encoder.finish()))
|
||||
}
|
||||
|
||||
fn create_render_pass(&self, texture: Arc<ShaderInput<Self>>, canvas: Arc<SurfaceHandle<wgpu::Surface>>) -> Result<()> {
|
||||
let texture = texture.texture().expect("Expected texture input");
|
||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let output = canvas.as_ref().surface.get_current_texture()?;
|
||||
let view = output.texture.create_view(&wgpu::TextureViewDescriptor {
|
||||
format: Some(wgpu::TextureFormat::Rgba8Unorm),
|
||||
..Default::default()
|
||||
});
|
||||
let output_texture_bind_group = self.context.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &self.render_configuration.texture_bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: wgpu::BindingResource::TextureView(&texture_view),
|
||||
},
|
||||
wgpu::BindGroupEntry {
|
||||
binding: 1,
|
||||
resource: wgpu::BindingResource::Sampler(&self.render_configuration.sampler),
|
||||
},
|
||||
],
|
||||
label: Some("output_texture_bind_group"),
|
||||
});
|
||||
|
||||
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder") });
|
||||
|
||||
{
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Render Pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
|
||||
store: true,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(&self.render_configuration.render_pipeline);
|
||||
render_pass.set_bind_group(0, &output_texture_bind_group, &[]);
|
||||
render_pass.set_vertex_buffer(0, self.render_configuration.vertex_buffer.slice(..));
|
||||
render_pass.set_index_buffer(self.render_configuration.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
|
||||
render_pass.draw_indexed(0..self.render_configuration.num_indices, 0, 0..1);
|
||||
}
|
||||
|
||||
let encoder = encoder.finish();
|
||||
self.context.queue.submit(Some(encoder));
|
||||
output.present();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn execute_compute_pipeline(&self, encoder: Self::CommandBuffer) -> Result<()> {
|
||||
self.context.queue.submit(Some(encoder));
|
||||
self.context.queue.submit(Some(encoder.0));
|
||||
|
||||
// Poll the device in a blocking manner so that our future resolves.
|
||||
// In an actual application, `device.poll(...)` should
|
||||
|
@ -152,7 +323,7 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self::BufferHandle>>) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>>>> {
|
||||
fn read_output_buffer(&self, buffer: Arc<ShaderInput<Self>>) -> Pin<Box<dyn Future<Output = Result<Vec<u8>>>>> {
|
||||
Box::pin(async move {
|
||||
if let ShaderInput::ReadBackBuffer(buffer, _) = buffer.as_ref() {
|
||||
let buffer_slice = buffer.slice(..);
|
||||
|
@ -187,13 +358,168 @@ impl gpu_executor::GpuExecutor for NewExecutor {
|
|||
} else {
|
||||
bail!("Tried to read a non readback buffer")
|
||||
}
|
||||
}) as _
|
||||
})
|
||||
}
|
||||
|
||||
fn create_texture_view(&self, texture: ShaderInput<Self>) -> Result<ShaderInput<Self>> {
|
||||
//Ok(ShaderInput::TextureView(texture.create_view(&wgpu::TextureViewDescriptor::default()), ) )
|
||||
let ShaderInput::TextureBuffer(texture, ty) = &texture else {
|
||||
bail!("Tried to create a texture view from a non texture");
|
||||
};
|
||||
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
Ok(ShaderInput::TextureView(view, ty.clone()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
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_caps = surface.get_capabilities(&self.context.adapter);
|
||||
let surface_format = wgpu::TextureFormat::Rgba8Unorm;
|
||||
let config = wgpu::SurfaceConfiguration {
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
format: surface_format,
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
present_mode: surface_caps.present_modes[0],
|
||||
alpha_mode: wgpu::CompositeAlphaMode::PreMultiplied,
|
||||
view_formats: vec![wgpu::TextureFormat::Rgba8UnormSrgb],
|
||||
};
|
||||
surface.configure(&self.context.device, &config);
|
||||
Ok(SurfaceHandle {
|
||||
surface_id: canvas.surface_id,
|
||||
surface,
|
||||
})
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn create_surface(&self, window: SurfaceHandle<winit::window::Window>) -> Result<SurfaceHandle<wgpu::Surface>> {
|
||||
let surface = unsafe { self.context.instance.create_surface(&window.surface) }?;
|
||||
let surface_id = window.surface_id;
|
||||
Ok(SurfaceHandle { surface_id, surface })
|
||||
}
|
||||
}
|
||||
|
||||
impl NewExecutor {
|
||||
impl WgpuExecutor {
|
||||
pub async fn new() -> Option<Self> {
|
||||
let context = Context::new().await?;
|
||||
Some(Self { context })
|
||||
|
||||
let texture_bind_group_layout = context.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Texture {
|
||||
multisampled: false,
|
||||
view_dimension: wgpu::TextureViewDimension::D2,
|
||||
sample_type: wgpu::TextureSampleType::Float { filterable: false },
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
label: Some("texture_bind_group_layout"),
|
||||
});
|
||||
|
||||
let sampler = context.device.create_sampler(&wgpu::SamplerDescriptor {
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
mag_filter: wgpu::FilterMode::Nearest,
|
||||
min_filter: wgpu::FilterMode::Nearest,
|
||||
mipmap_filter: wgpu::FilterMode::Nearest,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let shader = context.device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some("Shader"),
|
||||
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
|
||||
});
|
||||
|
||||
let render_pipeline_layout = context.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Render Pipeline Layout"),
|
||||
bind_group_layouts: &[&texture_bind_group_layout],
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
let render_pipeline = context.device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Render Pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &shader,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[Vertex::desc()],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &shader,
|
||||
entry_point: "fs_main",
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: wgpu::TextureFormat::Rgba8Unorm,
|
||||
blend: Some(wgpu::BlendState {
|
||||
color: wgpu::BlendComponent::REPLACE,
|
||||
alpha: wgpu::BlendComponent::REPLACE,
|
||||
}),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: None,
|
||||
// Setting this to anything other than Fill requires Features::POLYGON_MODE_LINE
|
||||
// or Features::POLYGON_MODE_POINT
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
// Requires Features::DEPTH_CLIP_CONTROL
|
||||
unclipped_depth: false,
|
||||
// Requires Features::CONSERVATIVE_RASTERIZATION
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
// If the pipeline will be used with a multiview render pass, this
|
||||
// indicates how many array layers the attachments will have.
|
||||
multiview: None,
|
||||
});
|
||||
|
||||
let vertex_buffer = context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
contents: bytemuck::cast_slice(VERTICES),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
});
|
||||
let index_buffer = context.device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Index Buffer"),
|
||||
contents: bytemuck::cast_slice(INDICES),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
});
|
||||
let num_indices = INDICES.len() as u32;
|
||||
let render_configuration = RenderConfiguration {
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
num_indices,
|
||||
render_pipeline,
|
||||
texture_bind_group_layout,
|
||||
sampler,
|
||||
};
|
||||
|
||||
Some(Self { context, render_configuration })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RenderConfiguration {
|
||||
vertex_buffer: wgpu::Buffer,
|
||||
index_buffer: wgpu::Buffer,
|
||||
num_indices: u32,
|
||||
render_pipeline: wgpu::RenderPipeline,
|
||||
texture_bind_group_layout: wgpu::BindGroupLayout,
|
||||
sampler: wgpu::Sampler,
|
||||
}
|
||||
|
|
43
node-graph/wgpu-executor/src/shader.wgsl
Normal file
43
node-graph/wgpu-executor/src/shader.wgsl
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Vertex shader
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) tex_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
@location(0) tex_coords: vec2<f32>,
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
model: VertexInput,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.tex_coords = model.tex_coords;
|
||||
out.clip_position = vec4<f32>(model.position, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fragment shader
|
||||
|
||||
@group(0) @binding(0)
|
||||
var t_diffuse: texture_2d<f32>;
|
||||
@group(0)@binding(1)
|
||||
var s_diffuse: sampler;
|
||||
|
||||
fn linearToSRGB(color: vec3<f32>) -> vec3<f32> {
|
||||
let a = 0.055;
|
||||
return select(pow(color, vec3<f32>(1.0 / 2.2)) * (1.0 + a) - a,
|
||||
color / 12.92,
|
||||
color <= vec3<f32>(0.0031308));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
var color = textureSample(t_diffuse, s_diffuse, in.tex_coords);
|
||||
var linearColor = color.rgb;
|
||||
var srgbColor = linearToSRGB(linearColor);
|
||||
return vec4<f32>(srgbColor, color.a);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue