Replaced custom "runtime" with tokio, with optional tokio-console support.

`Wgpu` now arcs the window (maybe reversible eventually once tokio supports scoped tasks).
This commit is contained in:
Filipe Rodrigues 2022-04-05 02:00:34 +01:00
parent 2dff20531c
commit 6e69d72bee
No known key found for this signature in database
GPG Key ID: A0E31C6EE7CB70F0
13 changed files with 813 additions and 333 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[build]
rustflags = ["--cfg", "tokio_unstable"]

657
Cargo.lock generated
View File

@ -50,6 +50,15 @@ dependencies = [
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.53"
@ -94,6 +103,38 @@ dependencies = [
"futures-core",
]
[[package]]
name = "async-stream"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e"
dependencies = [
"async-stream-impl",
"futures-core",
]
[[package]]
name = "async-stream-impl"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "async-trait"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "atomic_refcell"
version = "0.1.8"
@ -132,6 +173,12 @@ dependencies = [
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bit-set"
version = "0.5.2"
@ -201,6 +248,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
[[package]]
name = "cache-padded"
version = "1.2.0"
@ -288,7 +341,7 @@ version = "3.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a1132dc3944b31c20dd8b906b3a9f0a5d0243e092d59171414969657ac6aa85"
dependencies = [
"heck",
"heck 0.4.0",
"proc-macro-error",
"proc-macro2",
"quote",
@ -362,6 +415,43 @@ dependencies = [
"cache-padded",
]
[[package]]
name = "console-api"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc347c19eb5b940f396ac155822caee6662f850d97306890ac3773ed76c90c5a"
dependencies = [
"prost",
"prost-types",
"tonic",
"tonic-build",
"tracing-core",
]
[[package]]
name = "console-subscriber"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "565a7dfea2d10dd0e5c57cc394d5d441b1910960d8c9211ed14135e0e6ec3a20"
dependencies = [
"console-api",
"crossbeam-channel",
"crossbeam-utils",
"futures",
"hdrhistogram",
"humantime",
"prost-types",
"serde",
"serde_json",
"thread_local",
"tokio",
"tokio-stream",
"tonic",
"tracing",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "copyless"
version = "0.1.5"
@ -703,6 +793,15 @@ version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
[[package]]
name = "fastrand"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [
"instant",
]
[[package]]
name = "fern"
version = "0.6.0"
@ -719,6 +818,24 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "fixedbitset"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
[[package]]
name = "flate2"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
dependencies = [
"cfg-if 1.0.0",
"crc32fast",
"libc",
"miniz_oxide 0.4.4",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -916,6 +1033,25 @@ dependencies = [
"bitflags",
]
[[package]]
name = "h2"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util 0.7.1",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
@ -925,6 +1061,28 @@ dependencies = [
"ahash",
]
[[package]]
name = "hdrhistogram"
version = "7.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31672b7011be2c4f7456c4ddbcb40e7e9a4a9fad8efe49a6ebaf5f307d0109c0"
dependencies = [
"base64",
"byteorder",
"flate2",
"nom",
"num-traits",
]
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "heck"
version = "0.4.0"
@ -946,6 +1104,82 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "http"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6"
dependencies = [
"bytes",
"http",
"pin-project-lite",
]
[[package]]
name = "httparse"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4"
[[package]]
name = "httpdate"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
version = "0.14.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper-timeout"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
dependencies = [
"hyper",
"pin-project-lite",
"tokio",
"tokio-io-timeout",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -1000,6 +1234,15 @@ dependencies = [
"web-sys",
]
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.1"
@ -1174,6 +1417,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "multimap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "naga"
version = "0.8.5"
@ -1509,7 +1758,7 @@ dependencies = [
"backtrace",
"cfg-if 1.0.0",
"libc",
"petgraph",
"petgraph 0.5.1",
"redox_syscall",
"smallvec",
"thread-id",
@ -1528,10 +1777,40 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
dependencies = [
"fixedbitset",
"fixedbitset 0.2.0",
"indexmap",
]
[[package]]
name = "petgraph"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f"
dependencies = [
"fixedbitset 0.4.1",
"indexmap",
]
[[package]]
name = "pin-project"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pin-project-lite"
version = "0.2.8"
@ -1623,6 +1902,59 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9145ac0af1d93c638c98c40cf7d25665f427b2a44ad0a99b1dccf3e2f25bb987"
[[package]]
name = "prost"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "444879275cb4fd84958b1a1d5420d15e6fcf7c235fe47f053c9c2a80aceb6001"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-build"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62941722fb675d463659e49c4f3fe1fe792ff24fe5bbaa9c08cd3b98a1c354f5"
dependencies = [
"bytes",
"heck 0.3.3",
"itertools",
"lazy_static",
"log",
"multimap",
"petgraph 0.6.0",
"prost",
"prost-types",
"regex",
"tempfile",
"which",
]
[[package]]
name = "prost-derive"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9cc1a3263e07e0bf68e96268f37665207b49560d98739662cdfaae215c720fe"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "prost-types"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534b7a0e836e3c482d2693070f982e39e7611da9695d4d1f5a4b186b51faef0a"
dependencies = [
"bytes",
"prost",
]
[[package]]
name = "quote"
version = "1.0.15"
@ -1721,6 +2053,32 @@ dependencies = [
"redox_syscall",
]
[[package]]
name = "regex"
version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "renderdoc-sys"
version = "0.7.1"
@ -1794,6 +2152,24 @@ dependencies = [
"serde",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
[[package]]
name = "slab"
version = "0.4.5"
@ -1834,6 +2210,16 @@ dependencies = [
"wayland-protocols",
]
[[package]]
name = "socket2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "spirv"
version = "0.2.0+1.5.4"
@ -1861,6 +2247,20 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if 1.0.0",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.2"
@ -1907,6 +2307,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "thread_local"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
dependencies = [
"once_cell",
]
[[package]]
name = "tiff"
version = "0.6.1"
@ -1929,6 +2338,87 @@ dependencies = [
"winapi",
]
[[package]]
name = "tokio"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee"
dependencies = [
"bytes",
"libc",
"memchr",
"mio",
"num_cpus",
"once_cell",
"parking_lot 0.12.0",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"tracing",
"winapi",
]
[[package]]
name = "tokio-io-timeout"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf"
dependencies = [
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-macros"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tokio-stream"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"log",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-util"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764"
dependencies = [
"bytes",
"futures-core",
"futures-sink",
"pin-project-lite",
"tokio",
"tracing",
]
[[package]]
name = "toml"
version = "0.5.8"
@ -1938,12 +2428,154 @@ dependencies = [
"serde",
]
[[package]]
name = "tonic"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff08f4649d10a70ffa3522ca559031285d8e421d727ac85c60825761818f5d0a"
dependencies = [
"async-stream",
"async-trait",
"base64",
"bytes",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-timeout",
"percent-encoding",
"pin-project",
"prost",
"prost-derive",
"tokio",
"tokio-stream",
"tokio-util 0.6.9",
"tower",
"tower-layer",
"tower-service",
"tracing",
"tracing-futures",
]
[[package]]
name = "tonic-build"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9403f1bafde247186684b230dc6f38b5cd514584e8bec1dd32514be4745fa757"
dependencies = [
"proc-macro2",
"prost-build",
"quote",
"syn",
]
[[package]]
name = "tower"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e"
dependencies = [
"futures-core",
"futures-util",
"indexmap",
"pin-project",
"pin-project-lite",
"rand",
"slab",
"tokio",
"tokio-util 0.7.1",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62"
[[package]]
name = "tower-service"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
[[package]]
name = "tracing"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
dependencies = [
"cfg-if 1.0.0",
"log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90442985ee2f57c9e1b548ee72ae842f4a9a20e3f417cc38dbc5dc684d9bb4ee"
dependencies = [
"lazy_static",
"valuable",
]
[[package]]
name = "tracing-futures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
dependencies = [
"pin-project",
"tracing",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9df98b037d039d03400d9dd06b0f8ce05486b5f25e9a2d7d36196e142ebbc52"
dependencies = [
"sharded-slab",
"thread_local",
"tracing-core",
]
[[package]]
name = "try-lock"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "ttf-parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281"
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-width"
version = "0.1.9"
@ -1956,12 +2588,28 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "want"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
dependencies = [
"log",
"try-lock",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
@ -2382,6 +3030,7 @@ dependencies = [
"cgmath",
"chrono",
"clap",
"console-subscriber",
"crossbeam",
"egui",
"egui_wgpu_backend",
@ -2399,6 +3048,7 @@ dependencies = [
"serde",
"serde_json",
"thiserror",
"tokio",
"wgpu",
"winit",
"zsw-egui",
@ -2509,6 +3159,7 @@ dependencies = [
"futures",
"log",
"pollster",
"tokio",
"winit",
"zsw-egui",
"zsw-img",

View File

@ -24,6 +24,7 @@ egui_wgpu_backend = "0.16.0"
# Async
futures = "0.3.21"
pollster = "0.2.4"
tokio = "1.17.0"
# Error handling
anyhow = "1.0.52"

View File

@ -53,7 +53,7 @@
use {
anyhow::Context,
futures::lock::Mutex,
std::{mem, thread, time::Duration},
std::{mem, time::Duration},
winit::window::Window,
zsw_egui::Egui,
zsw_img::ImageLoader,
@ -91,7 +91,7 @@ impl Renderer {
&self,
window: &Window,
input: &Input,
wgpu: &'wgpu Wgpu<'window>,
wgpu: &'wgpu Wgpu,
panels: &Panels,
egui: &'egui Egui,
image_loader: &ImageLoader,
@ -125,9 +125,8 @@ impl Renderer {
});
// Then sleep until next frame
// TODO: Await while sleeping
if let Some(duration) = sleep_duration.checked_sub(total_duration) {
thread::sleep(duration);
tokio::time::sleep(duration).await;
}
}
}
@ -143,7 +142,7 @@ impl Renderer {
/// # Blocking
/// Locks [`zsw_panels::PanelsLock`] on `panels`
async fn update<'window, 'panels>(
wgpu: &Wgpu<'window>,
wgpu: &Wgpu,
panels: &'panels Panels,
image_loader: &ImageLoader,
) -> Result<(), anyhow::Error> {
@ -166,7 +165,7 @@ impl Renderer {
async fn render<'window, 'wgpu, 'egui, 'panels>(
window: &Window,
input: &Input,
wgpu: &'wgpu Wgpu<'window>,
wgpu: &'wgpu Wgpu,
panels: &'panels Panels,
egui: &'egui Egui,
) -> Result<(), anyhow::Error> {

View File

@ -119,7 +119,7 @@ impl SettingsWindow {
/// Blocks until [`Self::paint_jobs`] on `egui` is called.
pub async fn run<'wgpu, 'egui, 'playlist, 'panels, 'profiles>(
&self,
wgpu: &'wgpu Wgpu<'_>,
wgpu: &'wgpu Wgpu,
egui: &'egui Egui,
window: &Window,
panels: &'panels Panels,

View File

@ -7,7 +7,6 @@ use {
Future,
},
std::{
collections::VecDeque,
mem,
ops::{Deref, DerefMut},
pin::Pin,
@ -24,8 +23,8 @@ struct Inner<T> {
/// If this value has been seen
seen: bool,
/// All wakers
wakers: VecDeque<Waker>,
/// Waker
waker: Option<Waker>,
}
/// Fetch-update lock
@ -43,7 +42,7 @@ impl<T> FetchUpdateLock<T> {
let inner = Inner {
value,
seen: false,
wakers: VecDeque::new(),
waker: None,
};
Self {
inner: Mutex::new(inner),
@ -63,7 +62,7 @@ impl<T> FetchUpdateLock<T> {
// Set that the value was seen and wake up someone to update it
inner.seen = true;
if let Some(waker) = inner.wakers.pop_front() {
if let Some(waker) = inner.waker.take() {
waker.wake();
}
@ -94,7 +93,7 @@ impl<T> FetchUpdateLock<T> {
// DEADLOCK: Caller ensures we can wait.
// We guarantee we unlock while waiting
CondVarFuture::new(move |waker| {
inner.wakers.push_back(waker.clone());
inner.waker = Some(waker.clone());
mem::drop(inner);
})
.await;

View File

@ -1,181 +0,0 @@
//! Future helpers
// Imports
use {
parking_lot::{Condvar, Mutex},
std::{
future::Future,
sync::{
atomic::{self, AtomicBool},
Arc,
},
task,
},
};
/// Future runner
///
/// Adapts a future to run on it's own thread, and be cancellable
/// when polling.
#[derive(Debug)]
pub struct FutureRunner {
/// Signal
signal: Arc<FutureSignal>,
/// If we're running
running: AtomicBool,
}
impl FutureRunner {
/// Creates a new future runner
#[must_use]
pub fn new() -> Self {
// Create the waker
Self {
signal: Arc::new(FutureSignal::new()),
running: AtomicBool::new(false),
}
}
/// Executes the future
///
/// # Panics
/// Panics if called more than once
#[allow(clippy::result_unit_err)] // TODO: Use custom enum to say if we were cancelled
pub fn run<F>(&self, f: F) -> Result<F::Output, ()>
where
F: Future,
{
// 'lock' the running bool
assert!(
!self.running.swap(true, atomic::Ordering::AcqRel),
"Cannot run a future runner more than once"
);
// Pin the future
futures::pin_mut!(f);
// Create the waker
let waker = task::Waker::from(Arc::clone(&self.signal));
let mut ctx = task::Context::from_waker(&waker);
// Then poll it until we should exit
// Note: On the first loop, `wait` instantly returns for us to loop
while let FutureSignalStatus::Poll = self.signal.wait() {
match f.as_mut().poll(&mut ctx) {
task::Poll::Ready(output) => return Ok(output),
task::Poll::Pending => (),
}
}
// Exit the signal if we're still waiting
self.signal.exit();
Err(())
}
/// Stops the future
pub fn stop(&self) {
self.signal.exit();
}
}
impl Default for FutureRunner {
fn default() -> Self {
Self::new()
}
}
impl Drop for FutureRunner {
fn drop(&mut self) {
// Stop the future on-drop
self.stop();
}
}
/// Signal inner
#[derive(Debug)]
struct FutureSignalInner {
/// If we should exit
should_exit: bool,
/// If the future should be polled
should_poll: bool,
}
/// Status on signal waiting
enum FutureSignalStatus {
/// Should poll
Poll,
/// Should exit
Exit,
}
/// Waker signal for [`FuturesRunner`]
#[derive(Debug)]
struct FutureSignal {
/// Inner
inner: Mutex<FutureSignalInner>,
/// Condvar for waiting
cond_var: Condvar,
}
impl FutureSignal {
/// Creates a new signal
fn new() -> Self {
Self {
inner: Mutex::new(FutureSignalInner {
should_exit: false,
should_poll: true,
}),
cond_var: Condvar::new(),
}
}
/// Waits until the future should be polled, or we should quit
fn wait(&self) -> FutureSignalStatus {
// Keep waiting until either `should_poll` or `should_exit` are true
// DEADLOCK: We'll be woken up in the waker eventually
let mut inner = self.inner.lock();
loop {
match (inner.should_exit, inner.should_poll) {
// If we should exit, regardless if we should poll, return
// Note: Doesn't matter if we set `should_poll` to false here
(true, _) => break FutureSignalStatus::Exit,
// Else if we should poll, set it to false and return
(_, true) => {
inner.should_poll = false;
break FutureSignalStatus::Poll;
},
// Else wait
_ => self.cond_var.wait(&mut inner),
}
}
}
/// Sets to exit
pub fn exit(&self) {
// Lock, set `should_exit` to `true` and notify
// DEADLOCK: `Self::wait` only locks it temporarily without blocking
let mut inner = self.inner.lock();
inner.should_exit = true;
let _ = self.cond_var.notify_one();
}
}
impl task::Wake for FutureSignal {
fn wake(self: std::sync::Arc<Self>) {
// Set that we should be polling
// DEADLOCK: `Self::wait` only locks it temporarily without blocking
let mut inner = self.inner.lock();
inner.should_poll = true;
// Then notify the waiter
let _ = self.cond_var.notify_one();
}
}

View File

@ -61,7 +61,6 @@
// Modules
mod display_wrapper;
mod fetch_update_lock;
mod future;
mod lock;
mod rect;
mod scan_dir;
@ -71,7 +70,6 @@ mod thread;
pub use {
display_wrapper::DisplayWrapper,
fetch_update_lock::{FetchUpdateLock, FetchUpdateLockGuard},
future::FutureRunner,
lock::Lock,
rect::Rect,
scan_dir::dir_files_iter,

View File

@ -61,7 +61,7 @@ use {
anyhow::Context,
crossbeam::atomic::AtomicCell,
futures::lock::{Mutex, MutexGuard},
std::marker::PhantomData,
std::sync::Arc,
wgpu::TextureFormat,
winit::{dpi::PhysicalSize, window::Window},
};
@ -92,7 +92,7 @@ pub struct Surface {
// seems to not result in any panics, but it might be worth checking, especially if we
// ever need to "restart" `wgpu` in any scenario without restarting the application.
#[derive(Debug)]
pub struct Wgpu<'window> {
pub struct Wgpu {
/// Device
// TODO: There exists a `Device::poll` method, but I'm not sure if we should
// have to call that? Seems to be used for async, but we don't use any
@ -130,27 +130,27 @@ pub struct Wgpu<'window> {
// without showing the user at least 1 frame of the resized surface.
queued_resize: AtomicCell<Option<PhysicalSize<u32>>>,
/// Window lifetime
// Note: Our surface must outlive the window, so we make sure of it using the `'window` lifetime
window_phantom: PhantomData<&'window Window>,
/// Window
// Note: Our surface must outlive the window, so we make sure of it by arcing it
_window: Arc<Window>,
/// Lock source
lock_source: LockSource,
}
impl<'window> Wgpu<'window> {
impl Wgpu {
/// Creates the `wgpu` wrapper given the window to create it in.
pub async fn new(window: &'window Window) -> Result<Wgpu<'window>, anyhow::Error> {
pub async fn new(window: Arc<Window>) -> Result<Self, anyhow::Error> {
// Create the surface and adapter
// SAFETY: Due to our lifetime, we ensure the window outlives us and thus the surface
let (surface, adapter) = unsafe { self::create_surface_and_adapter(window).await? };
// SAFETY: Due to the window being arced, and we storing it, we ensure the window outlives us and thus the surface
let (surface, adapter) = unsafe { self::create_surface_and_adapter(&window).await? };
// Then create the device and it's queue
let (device, queue) = self::create_device(&adapter).await?;
// Configure the surface and get the preferred texture format and surface size
let (surface_texture_format, surface_size) =
self::configure_window_surface(window, &surface, &adapter, &device)?;
self::configure_window_surface(&window, &surface, &adapter, &device)?;
log::info!("Successfully initialized");
Ok(Self {
@ -162,7 +162,7 @@ impl<'window> Wgpu<'window> {
queue,
surface_texture_format,
queued_resize: AtomicCell::new(None),
window_phantom: PhantomData,
_window: window,
lock_source: LockSource,
})
}

View File

@ -32,8 +32,10 @@ epi = "0.16.0"
# Async
async-channel = "1.6.1"
console-subscriber = {version = "0.1.3", optional = true}
futures = "0.3.21"
pollster = "0.2.4"
tokio = {version = "1.17.0", features = ["full"]}
# Serialization
serde = {version = "1.0.132", features = ["derive"]}
@ -73,3 +75,7 @@ native-dialog = "0.6.3"
crossbeam = "0.8.1"
parking_lot = {version = "0.12.0", features = ["deadlock_detection"]}
rayon = "1.5.1"
[features]
tokio-console = ["console-subscriber", "tokio/tracing"]

View File

@ -13,8 +13,10 @@ use {
crate::Args,
anyhow::Context,
cgmath::{Point2, Vector2},
futures::future::OptionFuture,
pollster::FutureExt,
std::{iter, num::NonZeroUsize, thread},
std::{num::NonZeroUsize, sync::Arc, thread},
tokio::task,
winit::{
dpi::{PhysicalPosition, PhysicalSize},
event_loop::EventLoop,
@ -32,135 +34,145 @@ use {
zsw_profiles::Profiles,
zsw_renderer::Renderer,
zsw_settings_window::SettingsWindow,
zsw_util::{FutureRunner, Rect},
zsw_util::Rect,
zsw_wgpu::Wgpu,
};
/// Runs the application
// TODO: Not arc everything
#[allow(clippy::too_many_lines)] // TODO: Refactor
pub fn run(args: &Args) -> Result<(), anyhow::Error> {
#[allow(clippy::future_not_send)] // We only want this to run in the main thread anyway, we spawn everything else
pub async fn run(args: Arc<Args>) -> Result<(), anyhow::Error> {
// Build the window
let (mut event_loop, window) = self::create_window()?;
let window = Arc::new(window);
// Create the wgpu interface
// TODO: Execute future inn background and continue initializing
let wgpu = Wgpu::new(&window).block_on().context("Unable to create renderer")?;
let wgpu = Wgpu::new(Arc::clone(&window))
.await
.context("Unable to create renderer")?;
let wgpu = Arc::new(wgpu);
// Create the playlist
let playlist = Playlist::new();
let playlist = Arc::new(playlist);
// Create the image loader
let image_loader = ImageLoader::new();
let image_loader = Arc::new(image_loader);
// Create the panels
let panels = Panels::new(wgpu.device(), wgpu.surface_texture_format()).context("Unable to create panels")?;
let panels = Arc::new(panels);
// Create egui
let egui = Egui::new(&window, &wgpu).context("Unable to create egui state")?;
let egui = Arc::new(egui);
// Create the profiles
let profiles = Profiles::new().context("Unable to load profiles")?;
let profiles = Arc::new(profiles);
// Create the event handler
let mut event_handler = EventHandler::new();
// Create the renderer
let renderer = Renderer::new();
let renderer = Arc::new(renderer);
// Create the settings window
let settings_window = SettingsWindow::new();
let settings_window = Arc::new(settings_window);
// Create the input
let input = Input::new();
let input = Arc::new(input);
// All runners
// Note: They must exists outside of the thread scope because
// their `run` can last until the very end of the function
let profile_loader_runner = FutureRunner::new();
let playlist_runner = FutureRunner::new();
let image_loader_threads = thread::available_parallelism().map_or(1, NonZeroUsize::get);
let image_loader_runners = iter::repeat_with(FutureRunner::new)
.take(image_loader_threads)
// TODO: Bundle all of these onto a single struct to pass onto the runners,
// via some generic
// Then add all futures
let profiles_loader_task: OptionFuture<_> = args
.profile
.clone()
.map({
let profiles = Arc::clone(&profiles);
let playlist = Arc::clone(&playlist);
let panels = Arc::clone(&panels);
move |path| {
task::Builder::new()
.name("Profiles loader")
.spawn(async move { profiles.run_loader_applier(&path, &playlist, &panels).await })
}
})
.into();
let playlist_task = task::Builder::new().name("Playlist runner").spawn({
let playlist = Arc::clone(&playlist);
async move { playlist.run().await }
});
let image_loader_tasks = thread::available_parallelism().map_or(1, NonZeroUsize::get);
let image_loader_tasks = (0..image_loader_tasks)
.map(|idx| {
let image_loader = Arc::clone(&image_loader);
let playlist = Arc::clone(&playlist);
task::Builder::new()
.name(&format!("Image loader #{idx}"))
.spawn(async move { image_loader.run(&playlist).await })
})
.collect::<Vec<_>>();
let settings_window_runner = FutureRunner::new();
let renderer_runner = FutureRunner::new();
// Start all threads and then wait in the main thread for events
// DEADLOCK: We ensure all threads lock each lock in the same order,
// and that we don't lock them.
thread::scope(|s| {
// Create the thread spawner
let mut thread_spawner = zsw_util::ThreadSpawner::new(s);
// Spawn the profile loader if we have any
// DEADLOCK: See above
if let Some(path) = &args.profile {
thread_spawner.spawn("Profile loader", || {
// Note: We don't care whether we got cancelled or returned successfully
profile_loader_runner
.run(profiles.run_loader_applier(path, &playlist, &panels))
.into_ok_or_err();
})?;
let settings_window_task = task::Builder::new().name("Settings window runner").spawn({
let settings_window = Arc::clone(&settings_window);
let wgpu = Arc::clone(&wgpu);
let egui = Arc::clone(&egui);
let window = Arc::clone(&window);
let profiles = Arc::clone(&profiles);
let playlist = Arc::clone(&playlist);
let panels = Arc::clone(&panels);
let renderer = Arc::clone(&renderer);
async move {
settings_window
.run(&wgpu, &egui, &window, &panels, &playlist, &profiles, &renderer)
.await;
}
// Spawn the playlist thread
// DEADLOCK: See above
thread_spawner.spawn("Playlist", || {
playlist_runner.run(playlist.run()).into_err();
})?;
// Spawn all image loaders
// DEADLOCK: See above
for (thread_idx, runner) in image_loader_runners.iter().enumerate() {
thread_spawner.spawn(format!("Image Loader${thread_idx}"), || {
runner.run(image_loader.run(&playlist)).into_err();
})?;
});
let renderer_task = task::Builder::new().name("Renderer runner").spawn({
let wgpu = Arc::clone(&wgpu);
let egui = Arc::clone(&egui);
let window = Arc::clone(&window);
let panels = Arc::clone(&panels);
let renderer = Arc::clone(&renderer);
let input = Arc::clone(&input);
async move {
renderer
.run(&window, &input, &wgpu, &panels, &egui, &image_loader)
.await;
}
});
// Spawn the settings window thread
// DEADLOCK: See above
thread_spawner.spawn("Settings window", || {
settings_window_runner
.run(settings_window.run(&wgpu, &egui, &window, &panels, &playlist, &profiles, &renderer))
.into_err();
})?;
// Run the event loop until exit
event_loop.run_return(|event, _, control_flow| {
event_handler
.handle_event(&wgpu, &egui, &settings_window, &input, event, control_flow)
.block_on();
});
// Spawn the renderer thread
// DEADLOCK: See above
thread_spawner.spawn("Renderer", || {
renderer_runner
.run(renderer.run(&window, &input, &wgpu, &panels, &egui, &image_loader))
.into_err();
})?;
// Then join all tasks
let _ = profiles_loader_task
.await
.transpose()
.context("Unable to await for profiles loader runner")?;
playlist_task.await.context("Unable to await for playlist runner")?;
for task in image_loader_tasks {
task.await.context("Unable to wait for image loader runner")?;
}
settings_window_task
.await
.context("Unable to await for settings window runner")?;
renderer_task.await.context("Unable to await for renderer runner")?;
// Run event loop in this thread until we quit
// DEADLOCK: `run_return` exits once the user requests it.
// See above
// Note: Doesn't make sense to use a runner here, since nothing will call `stop`.
event_loop.run_return(|event, _, control_flow| {
event_handler
.handle_event(&wgpu, &egui, &settings_window, &input, event, control_flow)
.block_on();
});
// Note: In release builds, once we get here, we can just exit,
// no need to make the user wait for shutdown code.
#[cfg(not(debug_assertions))]
std::process::exit(0);
// Stop all runners at the end
// Note: Order doesn't matter, as they don't block
playlist_runner.stop();
image_loader_runners.iter().for_each(FutureRunner::stop);
settings_window_runner.stop();
renderer_runner.stop();
// Then join all threads
thread_spawner.join_all().context("Unable to join all threads")?;
Ok(())
})
Ok(())
}
/// Creates the window, as well as the associated event loop

View File

@ -28,7 +28,7 @@ impl EventHandler {
// TODO: Inverse dependencies of `settings_window` and `panels` and let them depend on us
pub async fn handle_event<'window, 'egui>(
&mut self,
wgpu: &Wgpu<'_>,
wgpu: &Wgpu,
egui: &'egui Egui,
settings_window: &SettingsWindow,
input: &Input,

View File

@ -76,7 +76,18 @@ mod logger;
pub use self::args::Args;
// Imports
use {anyhow::Context, clap::StructOpt};
use {
anyhow::Context,
clap::StructOpt,
std::{
num::NonZeroUsize,
sync::{
atomic::{self, AtomicUsize},
Arc,
},
thread,
},
};
fn main() -> Result<(), anyhow::Error> {
// Initialize logger
@ -85,9 +96,9 @@ fn main() -> Result<(), anyhow::Error> {
Err(err) => eprintln!("Unable to initialize logger: {err:?}"),
}
// Initialize the deadlock detection
#[cfg(debug_assertions)]
self::deadlock_init();
// Initialize the tokio console subscriber if given the feature
#[cfg(feature = "tokio-console")]
console_subscriber::init();
// Customize the rayon pool thread
// Note: This is used indirectly in `image` by `jpeg-decoder`
@ -98,7 +109,7 @@ fn main() -> Result<(), anyhow::Error> {
// Get arguments
let args = match Args::try_parse() {
Ok(args) => args,
Ok(args) => Arc::new(args),
Err(err) => {
log::warn!("Unable to retrieve arguments: {err:?}");
err.exit();
@ -106,10 +117,23 @@ fn main() -> Result<(), anyhow::Error> {
};
log::debug!("Arguments: {args:#?}");
// Create the runtime and enter it
let runtime = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2 * thread::available_parallelism().map_or(1, NonZeroUsize::get)) // TODO: Adjust?
.enable_time()
.thread_name_fn(|| {
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
let id = NEXT_ID.fetch_add(1, atomic::Ordering::AcqRel);
format!("tokio-runtime-{}", id)
})
.build()
.context("Unable to create runtime")?;
let _runtime_enter = runtime.enter();
// Run the app and restart if we get an error (up to 5 errors)
let mut errors = 0;
while errors < 5 {
match app::run(&args) {
match runtime.block_on(app::run(Arc::clone(&args))) {
Ok(()) => {
log::info!("Application finished");
break;
@ -124,34 +148,3 @@ fn main() -> Result<(), anyhow::Error> {
Ok(())
}
/// Initializes deadlock detection
#[cfg(debug_assertions)]
fn deadlock_init() {
// Create a background thread which checks for deadlocks every 10s
#[allow(clippy::let_underscore_drop)] // We want to detach the thread
let _ = std::thread::Builder::new()
.name("Deadlock detection".to_owned())
.spawn(move || loop {
// Sleep so we aren't continuously checking
std::thread::sleep(std::time::Duration::from_secs(10));
// Then check if we have any and continue if we don't
log::debug!("Checking for deadlocks");
let deadlocks = parking_lot::deadlock::check_deadlock();
if deadlocks.is_empty() {
log::debug!("Found no deadlocks");
continue;
}
// If we do, log them
log::warn!("Detected {} deadlocks", deadlocks.len());
for (idx, threads) in deadlocks.iter().enumerate() {
log::warn!("Deadlock #{idx}");
for thread in threads {
log::warn!("\tThread Id {:#?}", thread.thread_id());
log::warn!("\tBacktrace: {:#?}", thread.backtrace());
}
}
});
}