diff --git a/Cargo.lock b/Cargo.lock index 45e3250..6b7f034 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,37 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ab_glyph" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aes" version = "0.8.4" @@ -13,6 +44,17 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "version_check", +] + [[package]] name = "ahash" version = "0.8.12" @@ -20,6 +62,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", + "const-random", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -34,6 +78,49 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + +[[package]] +name = "android-activity" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" +dependencies = [ + "android-properties", + "bitflags 2.11.0", + "cc", + "jni", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 2.0.18", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "1.0.0" @@ -90,18 +177,417 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "arrow" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d441fdda254b65f3e9025910eb2c2066b6295d9c8ed409522b8d2ace1ff8574c" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced5406f8b720cc0bc3aa9cf5758f93e8593cda5490677aa194e4b4b383f9a59" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num-traits", +] + +[[package]] +name = "arrow-array" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772bd34cacdda8baec9418d80d23d0fb4d50ef0735685bd45158b83dfeb6e62d" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.16.1", + "num-complex", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-buffer" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "898f4cf1e9598fdb77f356fdf2134feedfd0ee8d5a4e0a5f573e7d0aec16baa4" +dependencies = [ + "bytes", + "half", + "num-bigint", + "num-traits", +] + +[[package]] +name = "arrow-cast" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0127816c96533d20fc938729f48c52d3e48f99717e7a0b5ade77d742510736d" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "atoi", + "base64", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num-traits", + "ryu", +] + +[[package]] +name = "arrow-data" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d10beeab2b1c3bb0b53a00f7c944a178b622173a5c7bcabc3cb45d90238df4" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num-integer", + "num-traits", +] + +[[package]] +name = "arrow-ord" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a7ba279b20b52dad300e68cfc37c17efa65e68623169076855b3a9e941ca5" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", +] + +[[package]] +name = "arrow-row" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14fe367802f16d7668163ff647830258e6e0aeea9a4d79aaedf273af3bdcd3e" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c30a1365d7a7dc50cc847e54154e6af49e4c4b0fddc9f607b687f29212082743" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "arrow-select" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78694888660a9e8ac949853db393af2a8b8fc82c19ce333132dfa2e72cc1a7fe" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num-traits", +] + +[[package]] +name = "arrow-string" +version = "58.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e04a01f8bb73ce54437514c5fd3ee2aa3e8abe4c777ee5cc55853b1652f79e" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num-traits", + "regex", + "regex-syntax", +] + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases 0.2.1", +] + +[[package]] +name = "borsh-derive" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.11.0", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.60" @@ -109,6 +595,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] @@ -118,6 +606,29 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "windows-link", +] + [[package]] name = "cipher" version = "0.4.4" @@ -159,7 +670,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -168,12 +679,152 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width 0.1.14", +] + [[package]] name = "colorchoice" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "com" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "comfy-table" +version = "7.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a" +dependencies = [ + "crossterm", + "unicode-segmentation", + "unicode-width 0.2.2", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.17", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "cpp_demangle" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0667304c32ea56cb4cd6d2d7c0cfe9a2f8041229db8c033af7f8d69492429def" +dependencies = [ + "cfg-if", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -183,6 +834,67 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crossterm" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +dependencies = [ + "bitflags 2.11.0", + "crossterm_winapi", + "parking_lot", + "rustix 0.38.44", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.7" @@ -193,6 +905,159 @@ dependencies = [ "typenum", ] +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "d3d12" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbd1f579714e3c809ebd822c81ef148b1ceaeb3d535352afc73fd0c4c6a0017" +dependencies = [ + "bitflags 2.11.0", + "libloading", + "winapi", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "duckdb" +version = "1.10502.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdc796383b176dd5a45353fbb5e64583c0ee4da12cb62c9e510b785324b2488" +dependencies = [ + "arrow", + "cast", + "comfy-table", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libduckdb-sys", + "num-integer", + "rust_decimal", + "strum", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -205,12 +1070,155 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "filetime" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" +dependencies = [ + "cfg-if", + "libc", + "libredox", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -222,21 +1230,230 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "gethostname" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "ahash", + "rustix 1.1.4", + "windows-link", ] [[package]] -name = "hashlink" -version = "0.9.1" +name = "getrandom" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ - "hashbrown", + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "gilrs" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa85c2e35dc565c90511917897ea4eae16b77f2773d5223536f7b602536d462" +dependencies = [ + "fnv", + "gilrs-core", + "log", + "uuid", + "vec_map", +] + +[[package]] +name = "gilrs-core" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23f2cc5144060a7f8d9e02d3fce5d06705376568256a509cdbc3c24d47e4f04" +dependencies = [ + "inotify", + "js-sys", + "libc", + "libudev-sys", + "log", + "nix 0.30.1", + "objc2-core-foundation", + "objc2-io-kit", + "uuid", + "vec_map", + "wasm-bindgen", + "web-sys", + "windows 0.62.2", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.11.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd4240fc91d3433d5e5b0fc5b67672d771850dc19bbee03c1381e19322803d7" +dependencies = [ + "log", + "presser", + "thiserror 1.0.69", + "winapi", + "windows 0.52.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.11.0", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "hassle-rs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +dependencies = [ + "bitflags 2.11.0", + "com", + "libc", + "libloading", + "thiserror 1.0.69", + "widestring", + "winapi", ] [[package]] @@ -245,6 +1462,291 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", +] + +[[package]] +name = "inferno" +version = "0.11.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88" +dependencies = [ + "ahash 0.8.12", + "indexmap", + "is-terminal", + "itoa", + "log", + "num-format", + "once_cell", + "quick-xml 0.26.0", + "rgb", + "str_stack", +] + +[[package]] +name = "inotify" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199" +dependencies = [ + "bitflags 2.11.0", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "inout" version = "0.1.4" @@ -254,6 +1756,33 @@ dependencies = [ "generic-array", ] +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -266,12 +1795,166 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys 0.4.1", + "log", + "simd_cesu8", + "thiserror 2.0.18", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.117", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" +dependencies = [ + "cfg-if", + "futures-util", + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + [[package]] name = "libc" version = "0.2.184" @@ -279,14 +1962,91 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] -name = "libsqlite3-sys" -version = "0.28.0" +name = "libduckdb-sys" +version = "1.10502.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" +checksum = "8d7401630ae2abcff642f7156294289e50f2d222e061c026ad797b01bf20c215" dependencies = [ "cc", + "flate2", "pkg-config", + "reqwest", + "serde", + "serde_json", + "tar", "vcpkg", + "zip", +] + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +dependencies = [ + "bitflags 2.11.0", + "libc", + "plain", + "redox_syscall 0.7.4", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", ] [[package]] @@ -295,6 +2055,21 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "matchers" version = "0.2.0" @@ -310,6 +2085,173 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "metal" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" +dependencies = [ + "bitflags 2.11.0", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "metrics" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5312e9ba3771cfa961b585728215e3d972c950a3eed9252aa093d6301277e8" +dependencies = [ + "ahash 0.8.12", + "portable-atomic", +] + +[[package]] +name = "metrics-util" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8496cc523d1f94c1385dd8f0f0c2c480b2b8aeccb5b7e4485ad6365523ae376" +dependencies = [ + "aho-corasick", + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.15.5", + "indexmap", + "metrics", + "ordered-float", + "quanta", + "radix_trie", + "rand 0.9.4", + "rand_xoshiro", + "sketches-ddsketch", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "naga" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.11.0", + "cfg_aliases 0.1.1", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "rustc-hash 1.1.0", + "spirv", + "termcolor", + "thiserror 1.0.69", + "unicode-xid", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.11.0", + "jni-sys 0.3.1", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -319,6 +2261,323 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.11.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.11.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "bitflags 2.11.0", + "libc", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -331,6 +2590,89 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "orbclient" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6" +dependencies = [ + "libc", + "libredox", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -343,6 +2685,101 @@ version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "pprof" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afad4d4df7b31280028245f152d5a575083e2abb822d05736f5e47653e77689f" +dependencies = [ + "aligned-vec", + "backtrace", + "cfg-if", + "findshlibs", + "inferno", + "libc", + "log", + "nix 0.26.4", + "once_cell", + "protobuf", + "protobuf-codegen-pure", + "smallvec", + "spin", + "symbolic-demangle", + "tempfile", + "thiserror 1.0.69", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -352,6 +2789,145 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" + +[[package]] +name = "protobuf" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" + +[[package]] +name = "protobuf-codegen" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033460afb75cf755fcfc16dfaed20b86468082a2ea24e05ac35ab4a099a017d6" +dependencies = [ + "protobuf", +] + +[[package]] +name = "protobuf-codegen-pure" +version = "2.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a29399fc94bcd3eeaa951c715f7bea69409b2445356b00519740bcd6ddd865" +dependencies = [ + "protobuf", + "protobuf-codegen", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases 0.2.1", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.2", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash 2.1.2", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases 0.2.1", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + [[package]] name = "quote" version = "1.0.45" @@ -361,6 +2937,156 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_xoshiro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "range-alloc" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca45419789ae5a7899559e9512e58ca889e41f04f1f2445e9f4b290ceccd1d08" + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + [[package]] name = "regex-automata" version = "0.4.14" @@ -379,19 +3105,275 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] -name = "rusqlite" -version = "0.31.0" +name = "rend" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" dependencies = [ - "bitflags", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", + "bytecheck", ] +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce901f9a19d251159075a4c37af514c3b8ef99c22e02dd8c19161cf397ee94a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.6", + "rkyv", + "serde", + "serde_json", + "wasm-bindgen", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -419,7 +3401,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -435,6 +3417,18 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -450,18 +3444,214 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "simd_cesu8" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "sketches-ddsketch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.11.0", + "calloop", + "calloop-wayland-source", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.44", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str_stack" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "symbolic-common" +version = "12.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f3cdeaae6779ecba2567f20bf7716718b8c4ce6717c9def4ced18786bb11ea" +dependencies = [ + "debugid", + "memmap2", + "stable_deref_trait", + "uuid", +] + +[[package]] +name = "symbolic-demangle" +version = "12.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "672c6ad9cb8fce6a1283cc9df9070073cccad00ae241b80e3686328a64e3523b" +dependencies = [ + "cpp_demangle", + "rustc-demangle", + "symbolic-common", +] + +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.117" @@ -473,13 +3663,92 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -490,7 +3759,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -502,6 +3771,195 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.52.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.11+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.44" @@ -513,6 +3971,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.18", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.31" @@ -521,7 +3992,18 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "tracing-chrome" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0a738ed5d6450a9fb96e86a23ad808de2b727fd1394585da5cdd6788ffe724" +dependencies = [ + "serde_json", + "tracing-core", + "tracing-subscriber", ] [[package]] @@ -534,6 +4016,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-error" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" +dependencies = [ + "tracing", + "tracing-subscriber", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -545,6 +4037,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.23" @@ -555,14 +4057,29 @@ dependencies = [ "nu-ansi-term", "once_cell", "regex-automata", + "serde", + "serde_json", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", + "tracing-serde", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + [[package]] name = "typenum" version = "1.19.0" @@ -575,12 +4092,70 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -593,18 +4168,518 @@ 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_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "serde", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wayland-backend" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.1.4", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" +dependencies = [ + "bitflags 2.11.0", + "rustix 1.1.4", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.11.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d" +dependencies = [ + "rustix 1.1.4", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" +dependencies = [ + "proc-macro2", + "quick-xml 0.39.2", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "wgpu" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d1c4ba43f80542cf63a0a6ed3134629ae73e8ab51e4b765a67f3aa062eb433" +dependencies = [ + "arrayvec", + "cfg_aliases 0.1.1", + "document-features", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348c840d1051b8e86c3bcd31206080c5e71e5933dabd79be1ce732b0b2f089a" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.11.0", + "cfg_aliases 0.1.1", + "document-features", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 1.0.69", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6bbf4b4de8b2a83c0401d9e5ae0080a2792055f25859a02bf9be97952bbed4f" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.11.0", + "block", + "cfg_aliases 0.1.1", + "core-graphics-types", + "d3d12", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 1.0.69", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "22.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9d91f0e2c4b51434dfa6db77846f2793149d8e73f800fa2e41f52b8eac3c5d" +dependencies = [ + "bitflags 2.11.0", + "js-sys", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core 0.52.0", + "windows-targets", +] + +[[package]] +name = "windows" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" +dependencies = [ + "windows-collections", + "windows-core 0.62.2", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ + "windows-core 0.62.2", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core 0.62.2", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core 0.62.2", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.59.0" @@ -639,6 +4714,15 @@ dependencies = [ "windows_x86_64_msvc", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -687,14 +4771,147 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winit" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6755fa58a9f8350bd1e472d4c3fcc25f824ec358933bba33306d0b63df5978d" +dependencies = [ + "ahash 0.8.12", + "android-activity", + "atomic-waker", + "bitflags 2.11.0", + "block2", + "bytemuck", + "calloop", + "cfg_aliases 0.2.1", + "concurrent-queue", + "core-foundation", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix 0.38.44", + "sctk-adwaita", + "smithay-client-toolkit", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix 1.1.4", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix 1.1.4", +] + +[[package]] +name = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + [[package]] name = "xenia-analysis" version = "0.1.0" dependencies = [ "anyhow", - "rusqlite", + "duckdb", + "metrics", "serde", + "serde_json", "tracing", + "xenia-cpu", "xenia-xex", ] @@ -704,10 +4921,17 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "metrics", + "metrics-util", + "pprof", "serde", "serde_json", "tracing", + "tracing-appender", + "tracing-chrome", + "tracing-error", "tracing-subscriber", + "winit", "xenia-analysis", "xenia-apu", "xenia-cpu", @@ -717,6 +4941,7 @@ dependencies = [ "xenia-kernel", "xenia-memory", "xenia-types", + "xenia-ui", "xenia-vfs", "xenia-xex", ] @@ -725,7 +4950,7 @@ dependencies = [ name = "xenia-apu" version = "0.1.0" dependencies = [ - "thiserror", + "thiserror 2.0.18", "tracing", "xenia-types", ] @@ -734,8 +4959,10 @@ dependencies = [ name = "xenia-cpu" version = "0.1.0" dependencies = [ - "bitflags", - "thiserror", + "bitflags 2.11.0", + "serde", + "serde_json", + "thiserror 2.0.18", "tracing", "xenia-memory", "xenia-types", @@ -746,7 +4973,7 @@ name = "xenia-debugger" version = "0.1.0" dependencies = [ "anyhow", - "thiserror", + "thiserror 2.0.18", "tracing", "xenia-cpu", "xenia-memory", @@ -758,8 +4985,12 @@ name = "xenia-gpu" version = "0.1.0" dependencies = [ "anyhow", + "bytemuck", "byteorder", - "thiserror", + "crossbeam-channel", + "metrics", + "naga", + "thiserror 2.0.18", "tracing", "xenia-memory", "xenia-types", @@ -769,8 +5000,9 @@ dependencies = [ name = "xenia-hid" version = "0.1.0" dependencies = [ - "thiserror", + "thiserror 2.0.18", "tracing", + "xenia-memory", "xenia-types", ] @@ -779,20 +5011,24 @@ name = "xenia-kernel" version = "0.1.0" dependencies = [ "anyhow", - "thiserror", + "metrics", + "thiserror 2.0.18", "tracing", "xenia-cpu", + "xenia-gpu", + "xenia-hid", "xenia-memory", "xenia-types", + "xenia-vfs", ] [[package]] name = "xenia-memory" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 2.11.0", "libc", - "thiserror", + "thiserror 2.0.18", "tracing", "windows-sys 0.59.0", "xenia-types", @@ -802,10 +5038,29 @@ dependencies = [ name = "xenia-types" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 2.11.0", "byteorder", "serde", - "thiserror", + "thiserror 2.0.18", +] + +[[package]] +name = "xenia-ui" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytemuck", + "crossbeam-utils", + "gilrs", + "metrics", + "pollster", + "tracing", + "wgpu", + "winit", + "xenia-gpu", + "xenia-hid", + "xenia-kernel", + "xenia-memory", ] [[package]] @@ -814,7 +5069,7 @@ version = "0.1.0" dependencies = [ "anyhow", "byteorder", - "thiserror", + "thiserror 2.0.18", "tracing", "xenia-types", ] @@ -826,14 +5081,63 @@ dependencies = [ "aes", "anyhow", "byteorder", + "metrics", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", "tracing", "xenia-memory", "xenia-types", ] +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.11.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "yoke" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.8.48" @@ -851,11 +5155,103 @@ checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zip" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" +dependencies = [ + "arbitrary", + "crc32fast", + "flate2", + "indexmap", + "memchr", + "zopfli", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml index 3510aa2..d00a940 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "crates/xenia-hid", "crates/xenia-debugger", "crates/xenia-analysis", + "crates/xenia-ui", "crates/xenia-app", ] @@ -33,10 +34,17 @@ xenia-apu = { path = "crates/xenia-apu" } xenia-hid = { path = "crates/xenia-hid" } xenia-debugger = { path = "crates/xenia-debugger" } xenia-analysis = { path = "crates/xenia-analysis" } +xenia-ui = { path = "crates/xenia-ui" } # External dependencies tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "registry"] } +tracing-appender = "0.2" +tracing-chrome = "0.7" +tracing-error = "0.2" +metrics = "0.24" +metrics-util = "0.19" +pprof = { version = "0.14", features = ["flamegraph", "protobuf-codec"] } bitflags = "2" byteorder = "1" thiserror = "2" @@ -44,4 +52,13 @@ anyhow = "1" serde = { version = "1", features = ["derive"] } serde_json = "1" aes = "0.8" -rusqlite = { version = "0.31", features = ["bundled"] } +duckdb = { version = "1", features = ["bundled"] } + +# UI / rendering / input (used by xenia-ui and xenia-app with --ui) +winit = "0.30" +wgpu = "22" +gilrs = "0.11" +pollster = "0.3" +crossbeam-utils = "0.8" +crossbeam-channel = "0.5" +bytemuck = { version = "1", features = ["derive"] } diff --git a/crates/xenia-ui/Cargo.toml b/crates/xenia-ui/Cargo.toml new file mode 100644 index 0000000..b629e74 --- /dev/null +++ b/crates/xenia-ui/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "xenia-ui" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +xenia-hid = { workspace = true } +xenia-kernel = { workspace = true } +xenia-memory = { workspace = true } +anyhow = { workspace = true } +tracing = { workspace = true } +winit = { workspace = true } +wgpu = { workspace = true } +gilrs = { workspace = true } +pollster = { workspace = true } +crossbeam-utils = { workspace = true } +bytemuck = { workspace = true } +metrics = { workspace = true } +xenia-gpu = { workspace = true } diff --git a/crates/xenia-ui/src/app.rs b/crates/xenia-ui/src/app.rs new file mode 100644 index 0000000..e36e13f --- /dev/null +++ b/crates/xenia-ui/src/app.rs @@ -0,0 +1,501 @@ +//! winit `ApplicationHandler` that drives the xenia-rs UI window. +//! +//! Threading model: +//! +//! ```text +//! ┌─ main thread ────────────────────────────────────────────────┐ +//! │ App: ApplicationHandler │ +//! │ on Resumed → create Window (Arc) + RenderState │ +//! │ on UserEvent(SwapEvent) → request redraw │ +//! │ on WindowEvent::RedrawRequested: │ +//! │ 1. poll gilrs → update AtomicCell │ +//! │ 2. pull latest frontbuffer snapshot from shared Mutex │ +//! │ and upload to wgpu texture │ +//! │ 3. rebuild HUD quads │ +//! │ 4. render + present │ +//! │ on WindowEvent::CloseRequested → flip shutdown, exit │ +//! └──────────────────────────────────────────────────────────────┘ +//! +//! ┌─ CPU thread (xenia-app owned) ───────────────────────────────┐ +//! │ interpreter loop; VdSwap posts SwapEvent via EventLoopProxy │ +//! └──────────────────────────────────────────────────────────────┘ +//! ``` + +use std::sync::Arc; +use std::sync::atomic::Ordering; +use std::time::Instant; + +use winit::application::ApplicationHandler; +use winit::event::{StartCause, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop}; +use winit::window::{WindowAttributes, WindowId}; + +use crate::bridge::{FrontbufferSnapshot, SwapEvent, UiHandles}; +use crate::input::HostInput; +use crate::render::{RenderState, HudVertex, push_string}; + +struct App { + handles: Arc, + input: HostInput, + render: Option, + last_revision: u64, + title: String, + start: Instant, + last_poll: Instant, + /// Counter of UserEvents received (== VdSwap count). + swap_events: u64, + last_swap_info: Option, + /// Last `SwapInfo.frame_index` we cleared the frontbuffer for via the + /// Xenos pipeline. Reset-on-advance triggers a fresh clear for the + /// next batch of dispatched draws. + last_xenos_swap_frame: u64, + /// Shader-blob keys we've already run through the static + /// `shader_metrics::emit_for` analyzer. Prevents per-frame + /// double-counting of `gpu.shader.interpret` / `gpu.shader.reject`. + seen_shader_blobs: std::collections::HashSet<(u8, u32)>, +} + +impl App { + fn new(handles: Arc, title: String) -> anyhow::Result { + let input = HostInput::new()?; + let now = Instant::now(); + Ok(Self { + handles, + input, + render: None, + last_revision: 0, + title, + start: now, + last_poll: now, + swap_events: 0, + last_swap_info: None, + last_xenos_swap_frame: 0, + seen_shader_blobs: std::collections::HashSet::new(), + }) + } + + fn poll_input( + input: &mut HostInput, + handles: &UiHandles, + ) { + input.poll(); + let connected = input.is_connected(); + handles.gamepad_connected.store(connected, Ordering::Relaxed); + let snap = input.snapshot(); + handles.gamepad.store(snap); + } + + fn build_hud( + handles: &UiHandles, + title: &str, + start: Instant, + swap_events: u64, + last_swap_info: Option, + rs: &RenderState, + ) -> Vec { + let mut verts: Vec = Vec::with_capacity(512); + let (sw, _sh) = rs.surface_size(); + let scale = ((sw as f32 / 960.0).max(1.0)).min(3.0); + // Glyph cell is 8 px tall at scale=1; `line_h` = row pitch. 14 px + // gives ~6 px of breathing room between lines so adjacent text never + // overlaps (previous bug: line positions `1.9×` and `2.0×` were + // within one glyph of each other and smeared together). + let line_h = 14.0 * scale; + let pad = 6.0 * scale; + let white = [1.0, 1.0, 1.0, 0.95]; + let green = [0.55, 0.95, 0.55, 0.95]; + let amber = [0.95, 0.85, 0.4, 0.95]; + let cyan = [0.55, 0.85, 0.95, 0.95]; + let muted = [0.75, 0.75, 0.85, 0.85]; + + let uptime = start.elapsed().as_secs_f32(); + let pad_snapshot = handles.gamepad.load(); + let connected = handles.gamepad_connected.load(Ordering::Relaxed); + + // Row 0: title + uptime + live instruction rate. + let mut y = pad; + let ins_total = handles + .instructions_counter + .load(Ordering::Relaxed); + let ips = if uptime > 0.05 { + ins_total as f32 / uptime + } else { + 0.0 + }; + push_string( + &mut verts, + &format!( + "xenia-rs UI {} uptime {:>6.1}s ins {:>10} ({:>5.1} kIPS)", + title, + uptime, + ins_total, + ips / 1000.0 + ), + pad, + y, + scale, + green, + ); + + // Row 1: swap info. + y += line_h; + let swap_line = match last_swap_info { + Some(info) => format!( + "Swaps: {:>5} fb {:#010x} {}x{} fmt {} cs {}", + swap_events, info.frontbuffer_addr, info.width, info.height, + info.texture_format, info.color_space + ), + None => format!("Swaps: {:>5} (waiting for first VdSwap)", swap_events), + }; + push_string(&mut verts, &swap_line, pad, y, scale, muted); + + // Row 2: GPU totals. + y += line_h; + let gpu_line = match last_swap_info { + Some(info) => format!( + "GPU: draws={:>6} pkts={:>8} IBs={:>4} waits={:>4} resolves={:>4} (cp={:>4}/sk={:>3}) RTs={:>3} irq={:>4}/{:<4} xlated={:>3}", + info.draws_total, + info.packets_total, + info.indirect_buffer_jumps, + info.wait_reg_mem_blocks, + info.resolves_total, + info.resolves_copied_total, + info.resolves_skipped_total, + info.unique_render_targets, + info.interrupts_delivered, + info.interrupts_dropped, + rs.translated_pipeline_count(), + ), + None => String::from( + "GPU: draws= 0 pkts= 0 IBs= 0 waits= 0 resolves= 0 (cp= 0/sk= 0) RTs= 0 irq= 0/0 xlated= 0", + ), + }; + push_string(&mut verts, &gpu_line, pad, y, scale, muted); + + // Row 2b: First-Pixels M4 — rendering-path observability. Shows + // whether the Xenos pipeline is actually dispatching and whether + // the translator or the interpreter served each draw. A `1x1` + // fb_size is the classic signature of "ensure_frontbuffer_at_least + // never fired" — useful at-a-glance diagnostic when nothing + // visibly renders. + y += line_h; + let (fbw, fbh) = rs.frontbuffer_size(); + let render_line = format!( + "Render: xdispatch: xlated={:>5} interp={:>5} xlated-pipelines={:>3} tex-cache={:>3} fb={}x{}", + rs.xenos_dispatches_translator, + rs.xenos_dispatches_interpreter, + rs.translated_pipeline_count(), + rs.host_texture_count(), + fbw, + fbh, + ); + push_string(&mut verts, &render_line, pad, y, scale, cyan); + + // Row 3: latest draw details. + y += line_h; + let draw_line = match last_swap_info { + Some(info) if info.draws_total > 0 => { + let prim = match info.last_draw_prim { + 0 => "None", + 1 => "PointList", + 2 => "LineList", + 3 => "LineStrip", + 4 => "TriangleList", + 5 => "TriangleFan", + 6 => "TriangleStrip", + 8 => "RectangleList", + 13 => "QuadList", + _ => "Unknown", + }; + format!( + "Draw: last {} verts={} code={:#x}", + prim, info.last_draw_vertex_count, info.last_draw_prim + ) + } + _ => String::from("Draw: (no DRAW_INDX seen yet)"), + }; + push_string(&mut verts, &draw_line, pad, y, scale, cyan); + + // Row 4: gamepad status. + y += line_h; + let pad_line = if connected { + format!( + "Pad[0]: btn {:04X} LT {:02X} RT {:02X} L({:>+6},{:>+6}) R({:>+6},{:>+6})", + pad_snapshot.buttons, + pad_snapshot.left_trigger, + pad_snapshot.right_trigger, + pad_snapshot.left_stick_x, + pad_snapshot.left_stick_y, + pad_snapshot.right_stick_x, + pad_snapshot.right_stick_y, + ) + } else { + String::from("Pad[0]: (no controller)") + }; + push_string( + &mut verts, + &pad_line, + pad, + y, + scale, + if connected { white } else { amber }, + ); + + // Row 5 (blank gap) + help text. + y += line_h * 2.0; + let help = "Close window or press Alt+F4 to stop the CPU thread and exit."; + push_string(&mut verts, help, pad, y, scale, muted); + + verts + } + + fn ingest_frontbuffer( + handles: &UiHandles, + last_revision: &mut u64, + last_swap_info: &mut Option, + rs: &mut RenderState, + ) { + let Ok(snap) = handles.frontbuffer.lock() else { return }; + if snap.revision == *last_revision { + return; + } + *last_revision = snap.revision; + *last_swap_info = snap.info; + let FrontbufferSnapshot { + width, + height, + ref rgba, + .. + } = *snap; + if width == 0 || height == 0 || rgba.is_empty() { + return; + } + rs.upload_frontbuffer(width, height, rgba); + } +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if self.render.is_some() { + return; + } + let attrs = WindowAttributes::default() + .with_title(format!("xenia-rs — {}", self.title)) + .with_inner_size(winit::dpi::LogicalSize::new(1280.0, 720.0)); + let window = match event_loop.create_window(attrs) { + Ok(w) => Arc::new(w), + Err(e) => { + tracing::error!("failed to create window: {e}"); + event_loop.exit(); + return; + } + }; + match RenderState::new(window.clone()) { + Ok(rs) => self.render = Some(rs), + Err(e) => { + tracing::error!("failed to initialize wgpu: {e}"); + event_loop.exit(); + } + } + } + + fn new_events(&mut self, event_loop: &ActiveEventLoop, _cause: StartCause) { + // Check shutdown (e.g. CPU thread crashed and flipped the flag). + if self.handles.shutdown.load(Ordering::Relaxed) { + event_loop.exit(); + return; + } + // Animate the HUD/gamepad readout at ~60 Hz even without swap events. + let now = Instant::now(); + if now.duration_since(self.last_poll).as_millis() >= 16 { + self.last_poll = now; + Self::poll_input(&mut self.input, &self.handles); + if let Some(ref rs) = self.render { + rs.window.request_redraw(); + } + } + event_loop.set_control_flow(ControlFlow::Poll); + } + + fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: SwapEvent) { + self.swap_events = self.swap_events.wrapping_add(1); + self.last_swap_info = Some(event.0); + if let Some(ref rs) = self.render { + rs.window.request_redraw(); + } + } + + #[tracing::instrument(skip_all, name = "ui.window_event")] + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + _window_id: WindowId, + event: WindowEvent, + ) { + if self.render.is_none() { + return; + } + match event { + WindowEvent::CloseRequested => { + self.handles.request_shutdown(); + event_loop.exit(); + } + WindowEvent::Resized(size) => { + if let Some(rs) = self.render.as_mut() { + rs.resize(size.width, size.height); + } + } + WindowEvent::RedrawRequested => { + let _redraw = tracing::debug_span!("ui.redraw").entered(); + Self::poll_input(&mut self.input, &self.handles); + let rs = self.render.as_mut().unwrap(); + + // P3 draw-dispatch: if the GPU has captured more draws than + // we've rendered via the Xenos host pipeline, catch up. + // We prefer the Xenos pipeline over the raw frontbuffer + // scrape once any draw has fired — the scrape is only + // useful while the game is pre-draw (no DRAW_INDX yet). + let draws_total = self + .last_swap_info + .map(|s| s.draws_total) + .unwrap_or(0); + if draws_total > 0 { + rs.ensure_frontbuffer_at_least(1280, 720); + let already = rs.xenos_draws_rendered; + if draws_total > already { + let frame_idx = self + .last_swap_info + .map(|s| s.frame_index) + .unwrap_or(0); + if frame_idx != self.last_xenos_swap_frame { + rs.clear_frontbuffer([0.04, 0.04, 0.06, 1.0]); + self.last_xenos_swap_frame = frame_idx; + } + let delta = (draws_total - already) as u32; + let (verts_hint, prim_kind, vs_key, ps_key) = self + .last_swap_info + .map(|s| { + ( + s.last_draw_vertex_count.max(3), + s.last_draw_prim, + s.vs_blob_key, + s.ps_blob_key, + ) + }) + .unwrap_or((3, 4, 0, 0)); + // Look up blobs + constants from the bridge and + // pack into the WGSL-interpreter layout. Empty + // slices produce zero-clause packed buffers — the + // WGSL walker short-circuits and the placeholder + // export path still renders. + let raw_vs: Vec = self + .handles + .shader_blobs + .lock() + .ok() + .and_then(|g| g.get(&vs_key).cloned()) + .unwrap_or_default(); + let raw_ps: Vec = self + .handles + .shader_blobs + .lock() + .ok() + .and_then(|g| g.get(&ps_key).cloned()) + .unwrap_or_default(); + let parsed_vs = xenia_gpu::ucode::parse_shader(&raw_vs); + let parsed_ps = xenia_gpu::ucode::parse_shader(&raw_ps); + // First time we see a blob key, run the static + // metrics analyzer. Keyed on (stage_tag, blob_key) + // because the guest can reuse a key across stages. + if self.seen_shader_blobs.insert((0u8, vs_key)) { + xenia_gpu::shader_metrics::emit_for(&parsed_vs, "vs"); + } + if self.seen_shader_blobs.insert((1u8, ps_key)) { + xenia_gpu::shader_metrics::emit_for(&parsed_ps, "ps"); + } + let vs_packed = xenia_gpu::ucode::pack_for_wgsl(&parsed_vs); + let ps_packed = xenia_gpu::ucode::pack_for_wgsl(&parsed_ps); + let constants = self + .handles + .xenos_constants + .lock() + .map(|g| *g) + .unwrap_or_default(); + // P5: bind any kernel-decoded primary texture + // before dispatching the draw. `None` reverts the + // pipeline's magenta-stub placeholder. + let tex_payload = self + .handles + .primary_texture + .lock() + .ok() + .and_then(|g| g.clone()); + rs.bind_primary_texture(tex_payload); + rs.dispatch_xenos_draws( + already, + delta, + verts_hint, + prim_kind, + vs_key, + ps_key, + &parsed_vs, + &parsed_ps, + &vs_packed, + &ps_packed, + &constants, + ); + } + } else { + Self::ingest_frontbuffer( + &self.handles, + &mut self.last_revision, + &mut self.last_swap_info, + rs, + ); + } + let verts = Self::build_hud( + &self.handles, + &self.title, + self.start, + self.swap_events, + self.last_swap_info, + rs, + ); + rs.set_hud_vertices(&verts); + match rs.render() { + Ok(()) => {} + Err(wgpu::SurfaceError::Lost | wgpu::SurfaceError::Outdated) => { + let (w, h) = rs.surface_size(); + rs.resize(w, h); + } + Err(wgpu::SurfaceError::OutOfMemory) => { + tracing::error!("wgpu surface OOM — exiting"); + self.handles.request_shutdown(); + event_loop.exit(); + } + Err(e) => { + tracing::warn!("wgpu surface error: {e:?}"); + } + } + } + _ => {} + } + } +} + +/// Run the UI on the calling thread (must be the main thread on macOS/Windows). +/// +/// Takes ownership of the [`EventLoop`] (created by the caller so the caller +/// can mint the `EventLoopProxy` used by the kernel bridge). Returns when the +/// window is closed or the CPU thread flipped the shutdown flag. +pub fn run( + event_loop: EventLoop, + handles: UiHandles, + title: impl Into, +) -> anyhow::Result<()> { + let mut app = App::new(Arc::new(handles), title.into())?; + event_loop.run_app(&mut app)?; + // Make sure the CPU thread sees shutdown even on graceful exit. + app.handles.request_shutdown(); + Ok(()) +} diff --git a/crates/xenia-ui/src/bridge.rs b/crates/xenia-ui/src/bridge.rs new file mode 100644 index 0000000..6bf3d1e --- /dev/null +++ b/crates/xenia-ui/src/bridge.rs @@ -0,0 +1,167 @@ +//! UI/kernel bridge construction. +//! +//! The UI side owns: +//! - a gamepad snapshot cell (writer) + connected flag (writer), +//! - a shared staging buffer that the CPU thread fills with the guest's +//! frontbuffer bytes on each `VdSwap`, +//! - an `EventLoopProxy` to wake winit with a redraw request, +//! - a shutdown atomic the UI flips on window close. +//! +//! The kernel side gets a [`xenia_kernel::UiBridge`] made from closures over +//! the same shared state, so it can read gamepad + post swaps from the CPU +//! thread without knowing about winit. + +use std::collections::HashMap; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; +use std::sync::Mutex; + +use crossbeam_utils::atomic::AtomicCell; +use winit::event_loop::EventLoopProxy; +use xenia_gpu::texture_cache::TextureKey; +use xenia_gpu::xenos_constants::XenosConstantsBlock; +use xenia_hid::GamepadState; +use xenia_kernel::{SwapInfo, UiBridge}; +use xenia_memory::MemoryAccess; + +/// Snapshot of the guest frontbuffer, copied out of guest memory on each +/// `VdSwap` so the UI thread can upload it without touching the CPU thread's +/// [`xenia_memory::GuestMemory`]. +#[derive(Default)] +pub struct FrontbufferSnapshot { + /// Width of the most-recently-swapped frontbuffer, in pixels. + pub width: u32, + /// Height in pixels. + pub height: u32, + /// Tightly-packed RGBA8 bytes (`width * height * 4`). Decoded from the + /// raw guest bytes by the kernel-side closure (see [`build`]). + pub rgba: Vec, + /// Monotonic counter so the UI can tell new frames apart from stale + /// re-reads. + pub revision: u64, + /// The most recent swap metadata. Kept alongside the bytes for HUD use. + pub info: Option, +} + +/// The UI-side half of the bridge. Installed into the [`App`](crate::app) +/// that runs on the main thread. +pub struct UiHandles { + pub gamepad: Arc>, + pub gamepad_connected: Arc, + pub shutdown: Arc, + pub frontbuffer: Arc>, + /// Live-updated summed CPU instruction counter. The `xenia-app` run + /// loop stores `cycle_count` into this every ~10k instructions so the + /// HUD keeps animating even before the first `VdSwap` fires. Authoritative + /// counter comes from scheduler HW-thread contexts; this atomic is just + /// a cross-thread cache. + pub instructions_counter: Arc, + /// P3b assets: cloned by `vd_swap` via `UiBridge::publish_assets`. + /// The UI redraw path reads them (mutex-guarded) alongside the + /// corresponding `SwapInfo` and passes them to the Xenos pipeline. + pub shader_blobs: Arc>>>, + pub xenos_constants: Arc>, + /// P5 primary texture — `None` means "no texture this frame, use + /// the magenta stub"; `Some((key, bytes))` means the kernel decoded + /// fetch-constant slot 0 into linear bytes that the UI should + /// upload into the host cache and bind at `@group(1) @binding(0)`. + pub primary_texture: Arc)>>>, +} + +/// Swap event posted by the CPU-side `VdSwap` handler via +/// [`EventLoopProxy::send_event`] after the frontbuffer bytes have been +/// copied into [`UiHandles::frontbuffer`]. +#[derive(Clone, Copy, Debug)] +pub struct SwapEvent(pub SwapInfo); + +/// Build a paired ([`UiHandles`], [`UiBridge`]). +/// +/// The proxy is the winit user-event injector for a freshly-constructed +/// `EventLoop`; `xenia-app` owns the event loop and keeps the +/// `UiHandles` alongside it. +pub fn build(proxy: EventLoopProxy) -> (UiHandles, UiBridge) { + let gamepad = Arc::new(AtomicCell::new(GamepadState::default())); + let gamepad_connected = Arc::new(AtomicBool::new(false)); + let shutdown = Arc::new(AtomicBool::new(false)); + let frontbuffer = Arc::new(Mutex::new(FrontbufferSnapshot::default())); + let instructions_counter = Arc::new(AtomicU64::new(0)); + let shader_blobs = Arc::new(Mutex::new(HashMap::>::new())); + let xenos_constants = Arc::new(Mutex::new(XenosConstantsBlock::default())); + let primary_texture: Arc)>>> = + Arc::new(Mutex::new(None)); + + let kernel_bridge = UiBridge { + gamepad: { + let gp = Arc::clone(&gamepad); + Arc::new(move || gp.load()) + }, + // `post_swap` now only bumps the SwapInfo + revision; the RGBA + // bytes arrive via `publish_frontbuffer` earlier in the same + // `VdSwap` (P4 replaced the raw-scrape path with a CPU-side + // detile). Posting the swap event after the bytes land guarantees + // the UI's redraw path sees the latest pixels. + post_swap: { + let proxy = proxy.clone(); + let fb = Arc::clone(&frontbuffer); + Arc::new(move |info: SwapInfo, _mem: &dyn MemoryAccess| { + if let Ok(mut lock) = fb.lock() { + lock.info = Some(info); + lock.revision = lock.revision.wrapping_add(1); + } + let _ = proxy.send_event(SwapEvent(info)); + }) + }, + shutdown: Arc::clone(&shutdown), + gamepad_connected: Arc::clone(&gamepad_connected), + instructions_counter: Arc::clone(&instructions_counter), + publish_xenos_assets: { + let blobs = Arc::clone(&shader_blobs); + let consts = Arc::clone(&xenos_constants); + Arc::new(move |new_blobs, new_consts| { + if let Ok(mut g) = blobs.lock() { + *g = new_blobs; + } + if let Ok(mut g) = consts.lock() { + *g = new_consts; + } + }) + }, + publish_frontbuffer: { + let fb = Arc::clone(&frontbuffer); + Arc::new(move |w, h, bytes| { + if let Ok(mut lock) = fb.lock() { + lock.width = w; + lock.height = h; + lock.rgba = bytes; + } + }) + }, + publish_texture: { + let tex = Arc::clone(&primary_texture); + Arc::new(move |payload| { + if let Ok(mut lock) = tex.lock() { + *lock = payload; + } + }) + }, + }; + + let handles = UiHandles { + gamepad, + gamepad_connected, + shutdown, + frontbuffer, + instructions_counter, + shader_blobs, + xenos_constants, + primary_texture, + }; + (handles, kernel_bridge) +} + + +impl UiHandles { + pub fn request_shutdown(&self) { + self.shutdown.store(true, Ordering::Relaxed); + } +} diff --git a/crates/xenia-ui/src/font.rs b/crates/xenia-ui/src/font.rs new file mode 100644 index 0000000..919e4d5 --- /dev/null +++ b/crates/xenia-ui/src/font.rs @@ -0,0 +1,231 @@ +//! Minimal 8×8 bitmap font for the HUD. +//! +//! Only printable ASCII (0x20..0x7E) is populated. Each glyph is 8 bytes, one +//! byte per row, MSB = leftmost pixel. This is a bespoke hand-drawn font just +//! wide enough for status-line text ("Swap: 0x1234 Pad: 0x0040 …"); no +//! international glyphs, no kerning, no anti-aliasing. +//! +//! The font is rendered by uploading the 8×(8·N) atlas as an R8 texture and +//! sampling one cell per character quad from the HUD shader. + +pub const CELL_W: u32 = 8; +pub const CELL_H: u32 = 8; +pub const FIRST: u8 = 0x20; +pub const LAST: u8 = 0x7E; +pub const GLYPH_COUNT: u32 = (LAST as u32) - (FIRST as u32) + 1; + +/// Build the atlas as a linear R8 buffer, `CELL_W × (CELL_H * GLYPH_COUNT)`, +/// one glyph per 8-row strip stacked top-to-bottom. +pub fn build_atlas() -> Vec { + let mut out = vec![0u8; (CELL_W * CELL_H * GLYPH_COUNT) as usize]; + for ch in FIRST..=LAST { + let rows = GLYPHS[(ch - FIRST) as usize]; + for (row, byte) in rows.iter().enumerate() { + for col in 0..8 { + let bit = (byte >> (7 - col)) & 1; + if bit != 0 { + let idx = ((ch - FIRST) as u32 * CELL_H + row as u32) * CELL_W + col as u32; + out[idx as usize] = 0xFF; + } + } + } + } + out +} + +/// 95 glyphs (0x20..0x7E). Each entry is 8 bytes of rows. +/// Hand-crafted for the HUD lines we actually emit. Most punctuation is +/// covered; unsupported chars fall through to the space glyph. +#[rustfmt::skip] +pub const GLYPHS: [[u8; 8]; 95] = [ + // 0x20 ' ' + [0,0,0,0,0,0,0,0], + // '!' + [0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x00], + // '"' + [0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00], + // '#' + [0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x00], + // '$' + [0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00], + // '%' + [0x00,0xC6,0xCC,0x18,0x30,0x66,0xC6,0x00], + // '&' + [0x38,0x6C,0x38,0x76,0xDC,0xCC,0x76,0x00], + // '\'' + [0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00], + // '(' + [0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00], + // ')' + [0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00], + // '*' + [0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00], + // '+' + [0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00], + // ',' + [0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30], + // '-' + [0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00], + // '.' + [0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00], + // '/' + [0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00], + // '0' + [0x7C,0xC6,0xCE,0xD6,0xE6,0xC6,0x7C,0x00], + // '1' + [0x18,0x38,0x18,0x18,0x18,0x18,0x7E,0x00], + // '2' + [0x7C,0xC6,0x06,0x1C,0x30,0x66,0xFE,0x00], + // '3' + [0x7C,0xC6,0x06,0x3C,0x06,0xC6,0x7C,0x00], + // '4' + [0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x1E,0x00], + // '5' + [0xFE,0xC0,0xC0,0xFC,0x06,0xC6,0x7C,0x00], + // '6' + [0x38,0x60,0xC0,0xFC,0xC6,0xC6,0x7C,0x00], + // '7' + [0xFE,0xC6,0x0C,0x18,0x30,0x30,0x30,0x00], + // '8' + [0x7C,0xC6,0xC6,0x7C,0xC6,0xC6,0x7C,0x00], + // '9' + [0x7C,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00], + // ':' + [0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00], + // ';' + [0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30], + // '<' + [0x06,0x0C,0x18,0x30,0x18,0x0C,0x06,0x00], + // '=' + [0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00], + // '>' + [0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00], + // '?' + [0x7C,0xC6,0x0C,0x18,0x18,0x00,0x18,0x00], + // '@' + [0x7C,0xC6,0xDE,0xDE,0xDE,0xC0,0x78,0x00], + // 'A' + [0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x00], + // 'B' + [0xFC,0x66,0x66,0x7C,0x66,0x66,0xFC,0x00], + // 'C' + [0x3C,0x66,0xC0,0xC0,0xC0,0x66,0x3C,0x00], + // 'D' + [0xF8,0x6C,0x66,0x66,0x66,0x6C,0xF8,0x00], + // 'E' + [0xFE,0x62,0x68,0x78,0x68,0x62,0xFE,0x00], + // 'F' + [0xFE,0x62,0x68,0x78,0x68,0x60,0xF0,0x00], + // 'G' + [0x3C,0x66,0xC0,0xC0,0xCE,0x66,0x3E,0x00], + // 'H' + [0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00], + // 'I' + [0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00], + // 'J' + [0x1E,0x0C,0x0C,0x0C,0xCC,0xCC,0x78,0x00], + // 'K' + [0xE6,0x66,0x6C,0x78,0x6C,0x66,0xE6,0x00], + // 'L' + [0xF0,0x60,0x60,0x60,0x62,0x66,0xFE,0x00], + // 'M' + [0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0x00], + // 'N' + [0xC6,0xE6,0xF6,0xDE,0xCE,0xC6,0xC6,0x00], + // 'O' + [0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x38,0x00], + // 'P' + [0xFC,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00], + // 'Q' + [0x7C,0xC6,0xC6,0xC6,0xCE,0x7C,0x0E,0x00], + // 'R' + [0xFC,0x66,0x66,0x7C,0x6C,0x66,0xE6,0x00], + // 'S' + [0x7C,0xC6,0xE0,0x78,0x0E,0xC6,0x7C,0x00], + // 'T' + [0x7E,0x7E,0x5A,0x18,0x18,0x18,0x3C,0x00], + // 'U' + [0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00], + // 'V' + [0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x00], + // 'W' + [0xC6,0xC6,0xC6,0xD6,0xFE,0xEE,0xC6,0x00], + // 'X' + [0xC6,0xC6,0x6C,0x38,0x6C,0xC6,0xC6,0x00], + // 'Y' + [0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00], + // 'Z' + [0xFE,0xC6,0x8C,0x18,0x32,0x66,0xFE,0x00], + // '[' + [0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00], + // '\\' + [0xC0,0x60,0x30,0x18,0x0C,0x06,0x02,0x00], + // ']' + [0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00], + // '^' + [0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00], + // '_' + [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF], + // '`' + [0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00], + // 'a' + [0x00,0x00,0x78,0x0C,0x7C,0xCC,0x76,0x00], + // 'b' + [0xE0,0x60,0x7C,0x66,0x66,0x66,0xDC,0x00], + // 'c' + [0x00,0x00,0x7C,0xC6,0xC0,0xC6,0x7C,0x00], + // 'd' + [0x1C,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00], + // 'e' + [0x00,0x00,0x7C,0xC6,0xFE,0xC0,0x7C,0x00], + // 'f' + [0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00], + // 'g' + [0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0xF8], + // 'h' + [0xE0,0x60,0x6C,0x76,0x66,0x66,0xE6,0x00], + // 'i' + [0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00], + // 'j' + [0x06,0x00,0x0E,0x06,0x06,0x66,0x66,0x3C], + // 'k' + [0xE0,0x60,0x66,0x6C,0x78,0x6C,0xE6,0x00], + // 'l' + [0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00], + // 'm' + [0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0x00], + // 'n' + [0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x00], + // 'o' + [0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0x00], + // 'p' + [0x00,0x00,0xDC,0x66,0x66,0x7C,0x60,0xF0], + // 'q' + [0x00,0x00,0x76,0xCC,0xCC,0x7C,0x0C,0x1E], + // 'r' + [0x00,0x00,0xDC,0x76,0x60,0x60,0xF0,0x00], + // 's' + [0x00,0x00,0x7E,0xC0,0x7C,0x06,0xFC,0x00], + // 't' + [0x30,0x30,0x7C,0x30,0x30,0x36,0x1C,0x00], + // 'u' + [0x00,0x00,0xCC,0xCC,0xCC,0xCC,0x76,0x00], + // 'v' + [0x00,0x00,0xC6,0xC6,0xC6,0x6C,0x38,0x00], + // 'w' + [0x00,0x00,0xC6,0xD6,0xD6,0xFE,0x6C,0x00], + // 'x' + [0x00,0x00,0xC6,0x6C,0x38,0x6C,0xC6,0x00], + // 'y' + [0x00,0x00,0xC6,0xC6,0xC6,0x7E,0x06,0xFC], + // 'z' + [0x00,0x00,0xFE,0x4C,0x18,0x32,0xFE,0x00], + // '{' + [0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00], + // '|' + [0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00], + // '}' + [0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00], + // '~' + [0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00], +]; diff --git a/crates/xenia-ui/src/input.rs b/crates/xenia-ui/src/input.rs new file mode 100644 index 0000000..ce40266 --- /dev/null +++ b/crates/xenia-ui/src/input.rs @@ -0,0 +1,159 @@ +//! gilrs → [`xenia_hid::GamepadState`] adapter. + +use gilrs::{Axis, Button, EventType, Gilrs, GilrsBuilder}; +use xenia_hid::{GamepadState, buttons}; + +/// Simulated-pad policy: if no physical controller is attached, advertise +/// a connected pad (with all-zero state) so games don't early-exit on +/// `XamInputGetState → ERROR_DEVICE_NOT_CONNECTED`. Set +/// `XENIA_FAKE_PAD=0` to disable and report the true no-controller status. +fn fake_pad_policy() -> bool { + match std::env::var("XENIA_FAKE_PAD").as_deref() { + Ok("0") | Ok("false") | Ok("off") => false, + _ => true, + } +} + +pub struct HostInput { + ctx: Gilrs, + /// Currently-active gilrs pad id. `None` until the first Connected event. + active: Option, + /// `true` if the pad is really physical; `false` for the zeroed simulated + /// pad we advertise when no hardware is attached (see `fake_pad_policy`). + pub physical_attached: bool, + fake_allowed: bool, +} + +impl HostInput { + pub fn new() -> anyhow::Result { + let ctx = GilrsBuilder::new() + .add_included_mappings(true) + .build() + .map_err(|e| anyhow::anyhow!("gilrs init failed: {e}"))?; + let active = ctx.gamepads().next().map(|(id, _)| id); + let physical_attached = active.is_some(); + let fake_allowed = fake_pad_policy(); + tracing::info!( + physical = physical_attached, + fake_allowed, + "input: init (pad simulation: {})", + if fake_allowed && !physical_attached { + "simulated (no physical pad)" + } else if physical_attached { + "physical" + } else { + "disabled" + } + ); + Ok(Self { + ctx, + active, + physical_attached, + fake_allowed, + }) + } + + /// True iff a gamepad is "available" for user index 0 — either the + /// actual host pad, or a simulated one when `XENIA_FAKE_PAD != 0`. + pub fn is_connected(&self) -> bool { + if self.physical_attached + && self + .active + .and_then(|id| self.ctx.connected_gamepad(id)) + .is_some() + { + return true; + } + self.fake_allowed + } + + /// Pump gilrs events until empty. Updates the internal "active pad" + /// registration; pad state is sampled by [`snapshot`]. + pub fn poll(&mut self) { + while let Some(event) = self.ctx.next_event() { + match event.event { + EventType::Connected => { + if self.active.is_none() { + self.active = Some(event.id); + self.physical_attached = true; + tracing::info!("gilrs: pad connected (id={:?})", event.id); + } + } + EventType::Disconnected => { + if self.active == Some(event.id) { + self.active = None; + tracing::info!("gilrs: pad disconnected (id={:?})", event.id); + self.active = self.ctx.gamepads().next().map(|(id, _)| id); + self.physical_attached = self.active.is_some(); + } + } + _ => {} + } + } + } + + /// Build an Xbox-360-layout `GamepadState` from the active gilrs pad. + /// Returns `GamepadState::default()` (all-zero) when no pad is present. + pub fn snapshot(&self) -> GamepadState { + let Some(id) = self.active else { + return GamepadState::default(); + }; + let Some(pad) = self.ctx.connected_gamepad(id) else { + return GamepadState::default(); + }; + let mut state = GamepadState::default(); + + let pressed = |btn: Button| pad.is_pressed(btn); + let set = |state: &mut GamepadState, btn: Button, mask: u16| { + if pressed(btn) { + state.buttons |= mask; + } + }; + set(&mut state, Button::DPadUp, buttons::DPAD_UP); + set(&mut state, Button::DPadDown, buttons::DPAD_DOWN); + set(&mut state, Button::DPadLeft, buttons::DPAD_LEFT); + set(&mut state, Button::DPadRight, buttons::DPAD_RIGHT); + set(&mut state, Button::Start, buttons::START); + set(&mut state, Button::Select, buttons::BACK); + set(&mut state, Button::LeftThumb, buttons::LEFT_THUMB); + set(&mut state, Button::RightThumb, buttons::RIGHT_THUMB); + set(&mut state, Button::LeftTrigger, buttons::LEFT_SHOULDER); + set(&mut state, Button::RightTrigger, buttons::RIGHT_SHOULDER); + set(&mut state, Button::Mode, buttons::GUIDE); + set(&mut state, Button::South, buttons::A); + set(&mut state, Button::East, buttons::B); + set(&mut state, Button::West, buttons::X); + set(&mut state, Button::North, buttons::Y); + + // Triggers: gilrs reports LeftTrigger2 / RightTrigger2 as axes in + // range [0.0, 1.0]. Map to u8 0..=255. + let trig = |axis: Axis| -> u8 { + pad.axis_data(axis) + .map(|d| (d.value().clamp(0.0, 1.0) * 255.0) as u8) + .unwrap_or(0) + }; + state.left_trigger = pad + .button_data(Button::LeftTrigger2) + .map(|d| (d.value().clamp(0.0, 1.0) * 255.0) as u8) + .unwrap_or_else(|| trig(Axis::LeftZ)); + state.right_trigger = pad + .button_data(Button::RightTrigger2) + .map(|d| (d.value().clamp(0.0, 1.0) * 255.0) as u8) + .unwrap_or_else(|| trig(Axis::RightZ)); + + // Sticks: gilrs reports [-1.0, 1.0]. Xbox uses i16 [-32768, 32767]. + let stick = |axis: Axis| -> i16 { + let v = pad + .axis_data(axis) + .map(|d| d.value().clamp(-1.0, 1.0)) + .unwrap_or(0.0); + (v * 32767.0) as i16 + }; + state.left_stick_x = stick(Axis::LeftStickX); + state.left_stick_y = stick(Axis::LeftStickY); + state.right_stick_x = stick(Axis::RightStickX); + state.right_stick_y = stick(Axis::RightStickY); + + state + } +} diff --git a/crates/xenia-ui/src/lib.rs b/crates/xenia-ui/src/lib.rs new file mode 100644 index 0000000..b89cf08 --- /dev/null +++ b/crates/xenia-ui/src/lib.rs @@ -0,0 +1,21 @@ +//! Host UI for `xenia-rs exec --ui`. +//! +//! Opens a winit window, drives a wgpu swapchain, polls gilrs for gamepad +//! input, and presents the guest frontbuffer whenever `VdSwap` fires on the +//! CPU thread. See the crate-level diagram in `app.rs`. +//! +//! Entry point is [`run`], which is called on the main thread by `xenia-app`. +//! The caller gets a matching [`UiHandles`] to install on the kernel state +//! before spawning the CPU worker thread — see [`build`]. + +mod app; +pub mod bridge; +mod font; +mod input; +mod render; +mod texture_cache_host; +mod xenos_pipeline; + +pub use app::run; +pub use bridge::{SwapEvent, UiHandles, build}; +pub use xenos_pipeline::{DrawRequest, XenosPipeline}; diff --git a/crates/xenia-ui/src/render.rs b/crates/xenia-ui/src/render.rs new file mode 100644 index 0000000..ea19a49 --- /dev/null +++ b/crates/xenia-ui/src/render.rs @@ -0,0 +1,1004 @@ +//! wgpu rendering state for the UI window. +//! +//! One [`RenderState`] is built on `ApplicationHandler::resumed` and reused +//! for the lifetime of the window. It owns the wgpu device/queue/surface, +//! the frontbuffer texture (resized on demand when the guest reports a new +//! `SwapInfo`), and the two pipelines (`blit`, `hud`). + +use std::sync::Arc; + +use bytemuck::{Pod, Zeroable}; +use wgpu::util::DeviceExt; +use winit::window::Window; + +use crate::font; +use crate::xenos_pipeline::{DrawRequest, XenosPipeline}; + +/// HUD vertex layout — six of these per character quad. +#[repr(C)] +#[derive(Clone, Copy, Pod, Zeroable)] +pub struct HudVertex { + pub pos_px: [f32; 2], + pub uv: [f32; 2], + pub rgba: [f32; 4], +} + +#[repr(C)] +#[derive(Clone, Copy, Pod, Zeroable)] +struct BlitUniforms { + aspect_correction: [f32; 2], + _pad0: [f32; 2], + fallback_rgb: [f32; 3], + _pad1: f32, +} + +#[repr(C)] +#[derive(Clone, Copy, Pod, Zeroable)] +struct HudUniforms { + inv_surface: [f32; 2], + _pad: [f32; 2], +} + +pub struct RenderState { + pub window: Arc, + surface: wgpu::Surface<'static>, + device: wgpu::Device, + queue: wgpu::Queue, + config: wgpu::SurfaceConfiguration, + sampler: wgpu::Sampler, + + // Blit pipeline (frontbuffer → screen). + blit_pipeline: wgpu::RenderPipeline, + blit_bind_group_layout: wgpu::BindGroupLayout, + blit_uniforms: wgpu::Buffer, + blit_bind_group: wgpu::BindGroup, + frontbuffer_tex: wgpu::Texture, + frontbuffer_view: wgpu::TextureView, + frontbuffer_size: (u32, u32), + frontbuffer_aspect: f32, + + // HUD pipeline (bitmap font → screen). + hud_pipeline: wgpu::RenderPipeline, + hud_uniforms: wgpu::Buffer, + hud_bind_group: wgpu::BindGroup, + hud_vertex_buffer: wgpu::Buffer, + hud_vertex_capacity: u64, + hud_vertex_count: u32, + + /// Background color used when no frontbuffer has been uploaded yet. + pub fallback_rgb: [f32; 3], + + /// Xenos host pipeline. Renders captured `DRAW_INDX*` events into the + /// frontbuffer texture with the placeholder `xenos_interp.wgsl`. + xenos_pipeline: XenosPipeline, + /// Draws rendered so far via `xenos_pipeline`. Tracked to know how + /// many fresh procedural draws to dispatch between `draws_total` + /// reports in `SwapInfo`. + pub xenos_draws_rendered: u64, + /// First-Pixels M4 — per-path dispatch counters. `draws_total` in + /// `SwapInfo` reflects the *guest-side* captured-draw count; these + /// split it into "served by a compiled translator pipeline" vs "fell + /// back to the uber-shader interpreter". HUD surfaces both so when + /// the game actually reaches DRAW_INDX we can tell at a glance + /// whether (a) we dispatched at all, (b) the translator accepted + /// the shader, or (c) we're running the slow interpreter path. + pub xenos_dispatches_translator: u64, + pub xenos_dispatches_interpreter: u64, + /// One-shot latch so we emit a tracing::info! on the **first** real + /// draw dispatch rather than spamming every frame. Pairs with the + /// "first translator compile" latch below. + first_dispatch_logged: bool, + first_translator_compile_logged: bool, + /// P5 host-side wgpu texture cache — keyed on `TextureKey`, uploads + /// kernel-decoded linear bytes into `wgpu::Texture` + `TextureView` + /// and hands the view to the xenos pipeline's `@group(1) @binding(0)` + /// slot. + host_texture_cache: crate::texture_cache_host::TextureCacheHost, +} + +impl RenderState { + /// Create a new render state bound to `window`. + pub fn new(window: Arc) -> anyhow::Result { + let size = window.inner_size(); + let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default()); + let surface = instance + .create_surface(window.clone()) + .map_err(|e| anyhow::anyhow!("create_surface failed: {e}"))?; + let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::LowPower, + force_fallback_adapter: false, + compatible_surface: Some(&surface), + })) + .ok_or_else(|| anyhow::anyhow!("no wgpu adapter available"))?; + + // Request the adapter's *actual* limits (not the extra-conservative + // `downlevel_defaults` ceiling of 2048²). Otherwise resizing the + // window past 2048×anything panics in `Surface::configure` with + // "Surface width and height must be within the maximum supported + // texture size". + let adapter_limits = adapter.limits(); + let (device, queue) = pollster::block_on(adapter.request_device( + &wgpu::DeviceDescriptor { + label: Some("xenia-ui device"), + required_features: wgpu::Features::empty(), + required_limits: adapter_limits.clone(), + memory_hints: wgpu::MemoryHints::Performance, + }, + None, + ))?; + + let surface_caps = surface.get_capabilities(&adapter); + let format = surface_caps + .formats + .iter() + .copied() + .find(|f| f.is_srgb()) + .unwrap_or(surface_caps.formats[0]); + let present_mode = if surface_caps.present_modes.contains(&wgpu::PresentMode::Mailbox) { + wgpu::PresentMode::Mailbox + } else { + wgpu::PresentMode::Fifo + }; + let max_dim = adapter_limits.max_texture_dimension_2d.max(1); + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format, + width: size.width.clamp(1, max_dim), + height: size.height.clamp(1, max_dim), + present_mode, + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + desired_maximum_frame_latency: 2, + }; + surface.configure(&device, &config); + + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("xenia-ui sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + + // ── Blit pipeline ── + let blit_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("blit.wgsl"), + source: wgpu::ShaderSource::Wgsl(include_str!("shaders/blit.wgsl").into()), + }); + let blit_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("blit bind group layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + }); + let blit_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("blit pipeline layout"), + bind_group_layouts: &[&blit_bgl], + push_constant_ranges: &[], + }); + let blit_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("blit pipeline"), + layout: Some(&blit_pipeline_layout), + vertex: wgpu::VertexState { + module: &blit_shader, + entry_point: "vs_main", + compilation_options: Default::default(), + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &blit_shader, + entry_point: "fs_main", + compilation_options: Default::default(), + targets: &[Some(wgpu::ColorTargetState { + format: config.format, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + cache: None, + }); + + // Placeholder 1×1 frontbuffer so a bind group can exist before the + // guest posts its first swap. + let (frontbuffer_tex, frontbuffer_view) = make_frontbuffer(&device, 1, 1); + let initial_uniforms = BlitUniforms { + aspect_correction: [1.0, 1.0], + _pad0: [0.0; 2], + fallback_rgb: [0.06, 0.06, 0.09], + _pad1: 0.0, + }; + let blit_uniforms = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("blit uniforms"), + contents: bytemuck::bytes_of(&initial_uniforms), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + let blit_bind_group = make_blit_bg( + &device, + &blit_bgl, + &blit_uniforms, + &frontbuffer_view, + &sampler, + ); + + // ── HUD pipeline ── + let hud_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("hud.wgsl"), + source: wgpu::ShaderSource::Wgsl(include_str!("shaders/hud.wgsl").into()), + }); + let atlas_bytes = font::build_atlas(); + let atlas_size = wgpu::Extent3d { + width: font::CELL_W, + height: font::CELL_H * font::GLYPH_COUNT, + depth_or_array_layers: 1, + }; + let atlas = device.create_texture(&wgpu::TextureDescriptor { + label: Some("hud font atlas"), + size: atlas_size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::R8Unorm, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }); + queue.write_texture( + wgpu::ImageCopyTexture { + texture: &atlas, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &atlas_bytes, + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(font::CELL_W), + rows_per_image: Some(font::CELL_H * font::GLYPH_COUNT), + }, + atlas_size, + ); + let atlas_view = atlas.create_view(&wgpu::TextureViewDescriptor::default()); + + let hud_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("hud bind group layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + }); + let hud_pipeline_layout = + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("hud pipeline layout"), + bind_group_layouts: &[&hud_bgl], + push_constant_ranges: &[], + }); + let hud_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("hud pipeline"), + layout: Some(&hud_pipeline_layout), + vertex: wgpu::VertexState { + module: &hud_shader, + entry_point: "vs_main", + compilation_options: Default::default(), + buffers: &[wgpu::VertexBufferLayout { + array_stride: std::mem::size_of::() as u64, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &wgpu::vertex_attr_array![ + 0 => Float32x2, + 1 => Float32x2, + 2 => Float32x4, + ], + }], + }, + fragment: Some(wgpu::FragmentState { + module: &hud_shader, + entry_point: "fs_main", + compilation_options: Default::default(), + targets: &[Some(wgpu::ColorTargetState { + format: config.format, + blend: Some(wgpu::BlendState { + // Premultiplied alpha blend. + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::One, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent::OVER, + }), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + ..Default::default() + }, + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + cache: None, + }); + + let initial_hud_uniforms = HudUniforms { + inv_surface: [1.0 / config.width as f32, 1.0 / config.height as f32], + _pad: [0.0; 2], + }; + let hud_uniforms = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("hud uniforms"), + contents: bytemuck::bytes_of(&initial_hud_uniforms), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + let hud_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("hud bind group"), + layout: &hud_bgl, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: hud_uniforms.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(&atlas_view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + ], + }); + // Initial 4KB vertex buffer — grown on demand. + let hud_vertex_capacity = 4096; + let hud_vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("hud vertex buffer"), + size: hud_vertex_capacity, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + // The Xenos host pipeline renders against the frontbuffer's sRGB + // format. When the frontbuffer is recreated (resize), the pipeline + // itself doesn't need rebuilding because the format stays constant + // (`XENOS_FRONTBUFFER_FORMAT`). + let xenos_pipeline = XenosPipeline::new(&device, &queue, XENOS_FRONTBUFFER_FORMAT); + + Ok(Self { + window, + surface, + device, + queue, + config, + sampler, + blit_pipeline, + blit_bind_group_layout: blit_bgl, + blit_uniforms, + blit_bind_group, + frontbuffer_tex, + frontbuffer_view, + frontbuffer_size: (1, 1), + frontbuffer_aspect: 16.0 / 9.0, + hud_pipeline, + hud_uniforms, + hud_bind_group, + hud_vertex_buffer, + hud_vertex_capacity, + hud_vertex_count: 0, + fallback_rgb: [0.06, 0.06, 0.09], + xenos_pipeline, + xenos_draws_rendered: 0, + xenos_dispatches_translator: 0, + xenos_dispatches_interpreter: 0, + first_dispatch_logged: false, + first_translator_compile_logged: false, + host_texture_cache: crate::texture_cache_host::TextureCacheHost::new(), + }) + } + + /// First-Pixels M4 — (width, height) of the frontbuffer texture the + /// Xenos pipeline currently paints into. Surfaced on the HUD so a + /// "1×1" value immediately reveals the pipeline never `ensured` + /// itself to the swap-reported 1280×720 (a common misconfiguration + /// signature). + pub fn frontbuffer_size(&self) -> (u32, u32) { + self.frontbuffer_size + } + + /// Live count of wgpu-uploaded guest textures in the host cache. + /// Mirrors `xenia_gpu::texture_cache::TextureCache::len` but only + /// counts entries that actually have GPU-side storage (i.e. had a + /// supported format on decode). Expected to stay at 0 until the + /// game first binds a texture; see the `xdispatch` split on the + /// HUD render row for when that happens. + pub fn host_texture_count(&self) -> usize { + self.host_texture_cache.len() + } + + /// Upload a kernel-decoded texture into the host wgpu cache and bind + /// it into the xenos pipeline. `None` reverts to the built-in dummy. + /// Called from `app.rs` right before `dispatch_xenos_draws`. + pub fn bind_primary_texture( + &mut self, + payload: Option<(xenia_gpu::texture_cache::TextureKey, Vec)>, + ) { + use xenia_gpu::texture_cache::CachedTexture; + // Destructure to split borrows — `host_texture_cache`, `device`, + // `queue`, and `xenos_pipeline` are disjoint fields on `self`. + let Self { + device, + queue, + xenos_pipeline, + host_texture_cache, + .. + } = self; + match payload { + None => xenos_pipeline.set_texture_view(device, None), + Some((key, bytes)) => { + let cached = CachedTexture { + key, + version_when_uploaded: 0, + bytes, + }; + host_texture_cache.upload(device, queue, &cached); + metrics::counter!( + "gpu.texture.upload", + "fmt" => format!("{:?}", key.format), + ) + .increment(1); + let view_ref = host_texture_cache + .view_for(&key) + .expect("upload just ran; view must exist"); + xenos_pipeline.set_texture_view(device, Some(view_ref)); + } + } + } + + pub fn surface_size(&self) -> (u32, u32) { + (self.config.width, self.config.height) + } + + pub fn resize(&mut self, width: u32, height: u32) { + if width == 0 || height == 0 { + return; + } + // Clamp to the adapter's `max_texture_dimension_2d`. If the user + // drags the window larger than the GPU can back (e.g., a GLES + // fallback adapter with 2048² max), `surface.configure()` panics + // unless we cap first. + let max_dim = self.device.limits().max_texture_dimension_2d.max(1); + let clamped_w = width.min(max_dim); + let clamped_h = height.min(max_dim); + if (clamped_w, clamped_h) != (width, height) { + tracing::debug!( + from = format_args!("{width}x{height}"), + to = format_args!("{clamped_w}x{clamped_h}"), + max_dim, + "ui.resize: clamped to adapter texture limit" + ); + } + self.config.width = clamped_w; + self.config.height = clamped_h; + self.surface.configure(&self.device, &self.config); + let u = HudUniforms { + inv_surface: [1.0 / clamped_w as f32, 1.0 / clamped_h as f32], + _pad: [0.0; 2], + }; + self.queue + .write_buffer(&self.hud_uniforms, 0, bytemuck::bytes_of(&u)); + } + + /// Ensure the frontbuffer host render target is at least `w×h`. Used + /// by the Xenos pipeline so procedural draws go to a full-size target + /// even when the guest hasn't published a VdSwap-derived size yet. + pub fn ensure_frontbuffer_at_least(&mut self, w: u32, h: u32) { + let (cw, ch) = self.frontbuffer_size; + let max_dim = self.device.limits().max_texture_dimension_2d.max(1); + let nw = w.max(cw).min(max_dim); + let nh = h.max(ch).min(max_dim); + if (nw, nh) != (cw, ch) { + let (tex, view) = make_frontbuffer(&self.device, nw, nh); + self.frontbuffer_tex = tex; + self.frontbuffer_view = view; + self.frontbuffer_size = (nw, nh); + self.frontbuffer_aspect = nw as f32 / nh as f32; + self.blit_bind_group = make_blit_bg( + &self.device, + &self.blit_bind_group_layout, + &self.blit_uniforms, + &self.frontbuffer_view, + &self.sampler, + ); + } + } + + /// Render `count` captured draws into the frontbuffer texture via the + /// Xenos host pipeline. `base_draw_index` is the monotonic index of the + /// first draw in the batch; the shader uses `base_draw_index + i` as + /// its per-draw identifier for procedural colouring. + /// + /// Caller should first `ensure_frontbuffer_at_least` to a non-1×1 size + /// and (typically) call `clear_frontbuffer_black` if this is the first + /// batch since the last swap. + pub fn dispatch_xenos_draws( + &mut self, + base_draw_index: u64, + count: u32, + vertex_count_hint: u32, + prim_kind: u32, + vs_key: u32, + ps_key: u32, + parsed_vs: &xenia_gpu::ucode::ParsedShader, + parsed_ps: &xenia_gpu::ucode::ParsedShader, + vs_ucode: &[u32], + ps_ucode: &[u32], + constants: &xenia_gpu::xenos_constants::XenosConstantsBlock, + ) { + if count == 0 { + return; + } + let _span = tracing::debug_span!( + "ui.xenos.dispatch", + count, + base_draw_index, + vs_len = vs_ucode.len(), + ps_len = ps_ucode.len() + ) + .entered(); + metrics::counter!("gpu.xenos.draw_dispatch").increment(count as u64); + metrics::histogram!("ui.xenos.upload_ucode_kb") + .record(((vs_ucode.len() + ps_ucode.len()) as f64) * 4.0 / 1024.0); + // Upload shader + constants once per batch; all draws in this batch + // share the same program + per-frame constants. + self.xenos_pipeline + .upload_shader_and_constants(&self.queue, vs_ucode, ps_ucode, constants); + + // P7 — try to translate this (vs, ps) pair to a dedicated WGSL + // module + compiled pipeline. If either stage refuses (see + // `xenia_gpu::translator::reject` reasons), fall back to the + // runtime interpreter so we still render *something*. The + // translate+compile is memoised per `(vs_key, ps_key)` so the + // overhead only hits first-use of a shader pair. + let pre_translator_count = self.xenos_pipeline.translated_pipeline_count(); + let use_translated = vs_key != 0 + && ps_key != 0 + && ensure_translated_pipeline( + &mut self.xenos_pipeline, + &self.device, + vs_key, + ps_key, + parsed_vs, + parsed_ps, + ); + // First-Pixels M4 — one-shot log when the translator compiles its + // very first pipeline. Good terminal signal that P7 is actually + // doing work on this workload; also identifies which (vs, ps) key + // pair succeeded so follow-up inspection can target it. + if !self.first_translator_compile_logged + && self.xenos_pipeline.translated_pipeline_count() > pre_translator_count + { + self.first_translator_compile_logged = true; + tracing::info!( + vs_key = format_args!("{:#010x}", vs_key), + ps_key = format_args!("{:#010x}", ps_key), + "first translator pipeline compiled" + ); + } + + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("xenos dispatch"), + }); + let mut served_translator: u64 = 0; + let mut served_interpreter: u64 = 0; + for i in 0..count { + let idx = base_draw_index.wrapping_add(i as u64) as u32; + let req = DrawRequest { + draw_index: idx, + vertex_count: vertex_count_hint.max(3), + prim_kind, + }; + if use_translated + && let Some(p) = self.xenos_pipeline.translated_pipeline(vs_key, ps_key) { + self.xenos_pipeline.render_one_with_pipeline( + &self.queue, + &mut encoder, + &self.frontbuffer_view, + req, + p, + ); + metrics::counter!("gpu.shader.use", "path" => "translator") + .increment(1); + served_translator += 1; + continue; + } + self.xenos_pipeline.render_one( + &self.queue, + &mut encoder, + &self.frontbuffer_view, + req, + ); + metrics::counter!("gpu.shader.use", "path" => "interpreter").increment(1); + served_interpreter += 1; + } + self.queue.submit(std::iter::once(encoder.finish())); + self.xenos_draws_rendered = self.xenos_draws_rendered.saturating_add(count as u64); + self.xenos_dispatches_translator = + self.xenos_dispatches_translator.saturating_add(served_translator); + self.xenos_dispatches_interpreter = + self.xenos_dispatches_interpreter.saturating_add(served_interpreter); + // First-Pixels M4 — one-shot "we actually rendered something" log. + // Fires the moment the pipeline dispatches its first real guest + // draw; subsequent draws stay silent so the log doesn't flood. + if !self.first_dispatch_logged && count > 0 { + self.first_dispatch_logged = true; + let (fbw, fbh) = self.frontbuffer_size; + tracing::info!( + base_draw_index, + count, + vs_key = format_args!("{:#010x}", vs_key), + ps_key = format_args!("{:#010x}", ps_key), + served_translator, + served_interpreter, + fb_w = fbw, + fb_h = fbh, + "first Xenos draw dispatched" + ); + } + } + + /// Count of distinct translator pipelines compiled so far. Surfaced + /// on the HUD as `xlated=N` to make "is P7 working?" observable. + pub fn translated_pipeline_count(&self) -> usize { + self.xenos_pipeline.translated_pipeline_count() + } + + /// Clear the frontbuffer to `[r,g,b,a]` in linear space. Matches the + /// fallback clear the outer swapchain render does so the two stages + /// agree on "no draws yet = dark navy". + pub fn clear_frontbuffer(&mut self, color: [f64; 4]) { + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("xenos frontbuffer clear"), + }); + self.xenos_pipeline + .clear(&mut encoder, &self.frontbuffer_view, color); + self.queue.submit(std::iter::once(encoder.finish())); + } + + /// Upload a new frontbuffer. `rgba` is assumed to be tightly packed + /// `width*height*4` bytes in RGBA8. Resizes the texture if dimensions + /// change. + pub fn upload_frontbuffer(&mut self, width: u32, height: u32, rgba: &[u8]) { + if width == 0 || height == 0 { + return; + } + if (width, height) != self.frontbuffer_size { + let (tex, view) = make_frontbuffer(&self.device, width, height); + self.frontbuffer_tex = tex; + self.frontbuffer_view = view; + self.frontbuffer_size = (width, height); + self.frontbuffer_aspect = width as f32 / height as f32; + self.blit_bind_group = make_blit_bg( + &self.device, + &self.blit_bind_group_layout, + &self.blit_uniforms, + &self.frontbuffer_view, + &self.sampler, + ); + } + let expected = (width as usize) * (height as usize) * 4; + if rgba.len() < expected { + tracing::warn!( + "upload_frontbuffer: short buffer ({} < {}); skipping", + rgba.len(), + expected + ); + return; + } + self.queue.write_texture( + wgpu::ImageCopyTexture { + texture: &self.frontbuffer_tex, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &rgba[..expected], + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(width * 4), + rows_per_image: Some(height), + }, + wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }, + ); + } + + /// Upload fresh HUD quads. Replaces the previous HUD for this frame. + pub fn set_hud_vertices(&mut self, verts: &[HudVertex]) { + self.hud_vertex_count = verts.len() as u32; + if verts.is_empty() { + return; + } + let needed = std::mem::size_of_val(verts) as u64; + if needed > self.hud_vertex_capacity { + self.hud_vertex_capacity = needed.next_power_of_two(); + self.hud_vertex_buffer = self.device.create_buffer(&wgpu::BufferDescriptor { + label: Some("hud vertex buffer (grown)"), + size: self.hud_vertex_capacity, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + } + self.queue + .write_buffer(&self.hud_vertex_buffer, 0, bytemuck::cast_slice(verts)); + } + + /// Present one frame. + #[tracing::instrument(skip_all, name = "ui.render")] + pub fn render(&mut self) -> Result<(), wgpu::SurfaceError> { + // Update blit uniforms (letterbox aspect). + let aspect_surface = self.config.width as f32 / self.config.height as f32; + let (sx, sy) = if aspect_surface > self.frontbuffer_aspect { + // Surface is wider than the frontbuffer → bars on sides. + (self.frontbuffer_aspect / aspect_surface, 1.0) + } else { + (1.0, aspect_surface / self.frontbuffer_aspect) + }; + let blit_u = BlitUniforms { + aspect_correction: [sx, sy], + _pad0: [0.0; 2], + fallback_rgb: self.fallback_rgb, + _pad1: 0.0, + }; + self.queue + .write_buffer(&self.blit_uniforms, 0, bytemuck::bytes_of(&blit_u)); + + let frame = self.surface.get_current_texture()?; + let view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("xenia-ui frame"), + }); + { + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("blit + hud"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: self.fallback_rgb[0] as f64, + g: self.fallback_rgb[1] as f64, + b: self.fallback_rgb[2] as f64, + a: 1.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + pass.set_pipeline(&self.blit_pipeline); + pass.set_bind_group(0, &self.blit_bind_group, &[]); + pass.draw(0..3, 0..1); + + if self.hud_vertex_count > 0 { + pass.set_pipeline(&self.hud_pipeline); + pass.set_bind_group(0, &self.hud_bind_group, &[]); + pass.set_vertex_buffer(0, self.hud_vertex_buffer.slice(..)); + pass.draw(0..self.hud_vertex_count, 0..1); + } + } + self.queue.submit(std::iter::once(encoder.finish())); + frame.present(); + Ok(()) + } +} + +pub(crate) const XENOS_FRONTBUFFER_FORMAT: wgpu::TextureFormat = + wgpu::TextureFormat::Rgba8UnormSrgb; + +/// P7 — translate a (vs, ps) parsed shader pair to WGSL and insert it into +/// the pipeline cache keyed on `(vs_key, ps_key)`. Returns `true` on +/// success or if the pair was already cached. On translator rejection +/// bumps `gpu.shader.translate_reject{reason,stage}` and returns `false`, +/// signalling the caller to fall back to the interpreter. +fn ensure_translated_pipeline( + xenos_pipeline: &mut XenosPipeline, + device: &wgpu::Device, + vs_key: u32, + ps_key: u32, + parsed_vs: &xenia_gpu::ucode::ParsedShader, + parsed_ps: &xenia_gpu::ucode::ParsedShader, +) -> bool { + use xenia_gpu::translator::{combine_stages, translate, Stage, Translation}; + if xenos_pipeline.has_translated(vs_key, ps_key) { + return true; + } + let vs_body = match translate(parsed_vs, Stage::Vertex) { + Translation::Ok(body) => body, + Translation::Reject(reason) => { + metrics::counter!( + "gpu.shader.translate_reject", + "stage" => "vs", + "reason" => reason, + ) + .increment(1); + return false; + } + }; + let ps_body = match translate(parsed_ps, Stage::Pixel) { + Translation::Ok(body) => body, + Translation::Reject(reason) => { + metrics::counter!( + "gpu.shader.translate_reject", + "stage" => "ps", + "reason" => reason, + ) + .increment(1); + return false; + } + }; + let wgsl = combine_stages(&vs_body, &ps_body); + xenos_pipeline.insert_translated(device, vs_key, ps_key, &wgsl) +} + +fn make_frontbuffer(device: &wgpu::Device, w: u32, h: u32) -> (wgpu::Texture, wgpu::TextureView) { + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: Some("frontbuffer"), + size: wgpu::Extent3d { + width: w, + height: h, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: XENOS_FRONTBUFFER_FORMAT, + // `RENDER_ATTACHMENT` added so the Xenos host pipeline (P3, see + // `xenos_pipeline.rs`) can render procedural draws directly into + // this texture instead of only consuming CPU-side raw scrapes. + usage: wgpu::TextureUsages::TEXTURE_BINDING + | wgpu::TextureUsages::COPY_DST + | wgpu::TextureUsages::RENDER_ATTACHMENT, + view_formats: &[], + }); + let view = tex.create_view(&wgpu::TextureViewDescriptor::default()); + (tex, view) +} + +fn make_blit_bg( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + uniforms: &wgpu::Buffer, + fb_view: &wgpu::TextureView, + sampler: &wgpu::Sampler, +) -> wgpu::BindGroup { + device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("blit bind group"), + layout, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: uniforms.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::TextureView(fb_view), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: wgpu::BindingResource::Sampler(sampler), + }, + ], + }) +} + +/// Layout helpers for the HUD text compositor. +pub mod hud { + use super::HudVertex; + use crate::font; + + /// Emit six vertices (two triangles) for a single character at + /// `(px, py)` in pixel space, color `rgba`, scale factor `scale`. + pub fn push_char(out: &mut Vec, ch: char, px: f32, py: f32, scale: f32, rgba: [f32; 4]) { + let b = ch as u32; + if b < font::FIRST as u32 || b > font::LAST as u32 { + return; + } + let idx = b - font::FIRST as u32; + let w = font::CELL_W as f32 * scale; + let h = font::CELL_H as f32 * scale; + // UV: each glyph occupies y = idx * CELL_H .. (idx+1) * CELL_H in the + // atlas; atlas width = CELL_W. + let atlas_h = (font::CELL_H * font::GLYPH_COUNT) as f32; + let v0 = (idx * font::CELL_H) as f32 / atlas_h; + let v1 = ((idx + 1) * font::CELL_H) as f32 / atlas_h; + + let tl = HudVertex { pos_px: [px, py], uv: [0.0, v0], rgba }; + let tr = HudVertex { pos_px: [px + w, py], uv: [1.0, v0], rgba }; + let bl = HudVertex { pos_px: [px, py + h], uv: [0.0, v1], rgba }; + let br = HudVertex { pos_px: [px + w, py + h], uv: [1.0, v1], rgba }; + out.extend_from_slice(&[tl, tr, bl, bl, tr, br]); + } + + pub fn push_string(out: &mut Vec, s: &str, px: f32, py: f32, scale: f32, rgba: [f32; 4]) { + let mut cx = px; + let step = font::CELL_W as f32 * scale; + for ch in s.chars() { + push_char(out, ch, cx, py, scale, rgba); + cx += step; + } + } +} + +pub use hud::push_string; diff --git a/crates/xenia-ui/src/shaders/blit.wgsl b/crates/xenia-ui/src/shaders/blit.wgsl new file mode 100644 index 0000000..5f7139f --- /dev/null +++ b/crates/xenia-ui/src/shaders/blit.wgsl @@ -0,0 +1,59 @@ +// Full-screen blit of the guest frontbuffer texture, with aspect-ratio +// letterboxing. A three-vertex fullscreen triangle covers the viewport; the +// fragment shader samples the frontbuffer and emits sRGB colors directly, +// letting the swapchain handle the final gamma step. + +struct Uniforms { + // aspect_correction.xy = scaling factors applied to the clip-space + // position to letterbox the frontbuffer into the swapchain window. + aspect_correction: vec2, + // tint for when the frontbuffer is missing / unknown format. When the + // guest has not yet swapped a frame, CPU side uploads a 1x1 texture and + // we just want the background color. + fallback_rgb: vec3, + _pad: f32, +}; + +@group(0) @binding(0) var u: Uniforms; +@group(0) @binding(1) var frontbuffer: texture_2d; +@group(0) @binding(2) var samp: sampler; + +struct VsOut { + @builtin(position) clip: vec4, + @location(0) uv: vec2, + @location(1) in_bounds: f32, +}; + +@vertex +fn vs_main(@builtin(vertex_index) vid: u32) -> VsOut { + // Fullscreen triangle: (-1,-1), (3,-1), (-1,3). + var pos = array, 3>( + vec2(-1.0, -1.0), + vec2( 3.0, -1.0), + vec2(-1.0, 3.0), + ); + let p = pos[vid]; + // Scale by the aspect-correction factor so the frontbuffer stays at its + // native aspect inside the window. + let corrected = p * u.aspect_correction; + var out: VsOut; + out.clip = vec4(corrected, 0.0, 1.0); + // UV runs [0,1] across the unscaled fullscreen triangle's extent + // [(-1,-1), (3,-1), (-1,3)] → UV = (p+1)*0.5 mapped with Y flipped. + let uv_raw = (p + vec2(1.0, 1.0)) * 0.5; + out.uv = vec2(uv_raw.x, 1.0 - uv_raw.y); + // Also pass a flag telling the FS whether the original position (before + // aspect correction) was inside [-1,1]; outside = letterbox region. + let in_bounds = f32(all(abs(corrected) <= vec2(1.0, 1.0))); + out.in_bounds = in_bounds; + return out; +} + +@fragment +fn fs_main(in: VsOut) -> @location(0) vec4 { + if (in.uv.x < 0.0 || in.uv.x > 1.0 || in.uv.y < 0.0 || in.uv.y > 1.0) { + return vec4(u.fallback_rgb, 1.0); + } + let sample = textureSample(frontbuffer, samp, in.uv); + return vec4(sample.rgb, 1.0); +} diff --git a/crates/xenia-ui/src/shaders/hud.wgsl b/crates/xenia-ui/src/shaders/hud.wgsl new file mode 100644 index 0000000..5fa7c5a --- /dev/null +++ b/crates/xenia-ui/src/shaders/hud.wgsl @@ -0,0 +1,47 @@ +// Textured-quad pipeline for the HUD overlay. Each character is a 6-vertex +// (two-triangle) quad with a UV into the font atlas. The CPU-side HUD code +// pushes a vertex buffer every frame describing the text to draw. + +struct VsIn { + @location(0) pos_px: vec2, // pixel-space position in the window + @location(1) uv: vec2, // atlas UV + @location(2) rgba: vec4, +}; + +struct HudUniforms { + // Inverse of the surface dimensions so the VS can map pixel coordinates + // into clip space: clip.xy = (pos_px / surface_size) * 2.0 - 1.0 with Y + // flipped. + inv_surface: vec2, + _pad: vec2, +}; + +@group(0) @binding(0) var u: HudUniforms; +@group(0) @binding(1) var atlas: texture_2d; +@group(0) @binding(2) var samp: sampler; + +struct VsOut { + @builtin(position) clip: vec4, + @location(0) uv: vec2, + @location(1) rgba: vec4, +}; + +@vertex +fn vs_main(in: VsIn) -> VsOut { + var out: VsOut; + let clip_xy = in.pos_px * u.inv_surface * 2.0 - vec2(1.0, 1.0); + // Invert Y so pos_px=(0,0) is top-left. + out.clip = vec4(clip_xy.x, -clip_xy.y, 0.0, 1.0); + out.uv = in.uv; + out.rgba = in.rgba; + return out; +} + +@fragment +fn fs_main(in: VsOut) -> @location(0) vec4 { + let coverage = textureSample(atlas, samp, in.uv).r; + // Atlas is R8 where 0xFF = glyph pixel. We premultiply by the input alpha + // so the pipeline's alpha-blend pass composits correctly. + let a = coverage * in.rgba.a; + return vec4(in.rgba.rgb * a, a); +} diff --git a/crates/xenia-ui/src/texture_cache_host.rs b/crates/xenia-ui/src/texture_cache_host.rs new file mode 100644 index 0000000..2cb9b87 --- /dev/null +++ b/crates/xenia-ui/src/texture_cache_host.rs @@ -0,0 +1,227 @@ +//! Host-side wgpu texture cache — pairs with `xenia_gpu::texture_cache` (the +//! CPU-side decoded-bytes layer) by mapping the same [`TextureKey`] onto an +//! uploaded `wgpu::Texture` + `TextureView`. +//! +//! The xenos pipeline only binds one texture at a time (group 1 single slot); +//! this cache lets the draw-dispatch loop uphold that layout without +//! re-uploading the same texture across frames. Entries carry the +//! `version_when_uploaded` stamp that originated from +//! [`xenia_memory::GuestMemory::page_version`]; on a stale hit the caller +//! re-decodes (via the CPU cache) and [`TextureCacheHost::upload`] replaces +//! the wgpu texture in place. + +use std::collections::HashMap; + +use xenia_gpu::texture_cache::{CachedTexture, TextureFormat, TextureKey}; + +pub struct HostTextureEntry { + /// Retained so the `wgpu::Texture` outlives its `TextureView` for + /// the lifetime of the cache entry. wgpu views internally reference + /// their backing texture through an `Arc`, so dropping this field + /// would technically still leave the view valid — but keeping it + /// makes the ownership intent explicit and avoids relying on wgpu + /// internals. Read only at construction; the `#[allow]` silences + /// `dead_code` since Rust can't tell the field is load-bearing for + /// drop ordering. + #[allow(dead_code)] + pub texture: wgpu::Texture, + pub view: wgpu::TextureView, + pub version_when_uploaded: u64, +} + +pub struct TextureCacheHost { + entries: HashMap, + /// HUD-surfaced counters — mirror the CPU-side cache so a session + /// can tell whether uploads are dominated by fresh work or stale + /// invalidations. + pub uploads_total: u64, + pub reuploads_total: u64, +} + +impl Default for TextureCacheHost { + fn default() -> Self { + Self::new() + } +} + +impl TextureCacheHost { + pub fn new() -> Self { + Self { + entries: HashMap::new(), + uploads_total: 0, + reuploads_total: 0, + } + } + + pub fn len(&self) -> usize { + self.entries.len() + } + + /// Kept for API symmetry with `len` (clippy recommends both together). + /// Unused in code today — callers check `len() == 0` via the HUD. + #[allow(dead_code)] + pub fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + /// Upload (or refresh) a cached texture. Returns a `&TextureView` the + /// pipeline can bind. Idempotent when `cached.version_when_uploaded` + /// matches an existing entry — in that case we just hand back the + /// existing view without touching GPU bandwidth. + pub fn upload( + &mut self, + device: &wgpu::Device, + queue: &wgpu::Queue, + cached: &CachedTexture, + ) -> &HostTextureEntry { + let key = cached.key; + let needs_refresh = match self.entries.get(&key) { + None => true, + Some(existing) => existing.version_when_uploaded < cached.version_when_uploaded, + }; + if !needs_refresh { + return self.entries.get(&key).unwrap(); + } + // Evict + re-upload. For P5 we always recreate the texture (no + // in-place writeback); re-uploading a 1280×720 texture is <3 MB + // and happens only when the guest actually touches the bytes. + let Some(descriptor) = descriptor_for(&key) else { + // Unsupported — keep a record-keeping entry pointing at a + // dummy and let the pipeline fall back to its own magenta + // placeholder. We still create a minimal 1×1 magenta view + // so `get` returns something bindable. + let (tex, view) = create_magenta_stub(device, queue); + let entry = HostTextureEntry { + texture: tex, + view, + version_when_uploaded: cached.version_when_uploaded, + }; + self.entries.insert(key, entry); + self.uploads_total += 1; + return self.entries.get(&key).unwrap(); + }; + let texture = device.create_texture(&descriptor); + // Write pixel data. BCn formats require block-aligned extents; + // uncompressed formats use byte-aligned rows. First-Pixels M5: + // BC1 = 8 bytes/block, BC2/BC3 = 16 bytes/block. + let bytes_per_row = match key.format { + TextureFormat::Dxt1 => Some((key.width as u32).div_ceil(4) * 8), + TextureFormat::Dxt2_3 | TextureFormat::Dxt4_5 => { + Some((key.width as u32).div_ceil(4) * 16) + } + // K8888 and K565 (CPU-expanded to Rgba8Unorm) both produce + // 4 bytes per texel in the wgpu-uploadable buffer. + _ => Some(key.width as u32 * 4), + }; + queue.write_texture( + wgpu::ImageCopyTexture { + texture: &texture, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &cached.bytes, + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row, + rows_per_image: None, + }, + wgpu::Extent3d { + width: key.width as u32, + height: key.height as u32, + depth_or_array_layers: 1, + }, + ); + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let entry = HostTextureEntry { + texture, + view, + version_when_uploaded: cached.version_when_uploaded, + }; + let had_prior = self.entries.contains_key(&key); + self.entries.insert(key, entry); + if had_prior { + self.reuploads_total += 1; + } else { + self.uploads_total += 1; + } + self.entries.get(&key).unwrap() + } + + pub fn view_for(&self, key: &TextureKey) -> Option<&wgpu::TextureView> { + self.entries.get(key).map(|e| &e.view) + } +} + +/// wgpu `TextureDescriptor` matching a Xenos [`TextureKey`]. Returns `None` +/// for unsupported formats — caller uses a magenta stub. +/// +/// First-Pixels M5 adds `K565` (CPU-expanded to `Rgba8Unorm` in the +/// decoder), `Dxt2_3` → `Bc2RgbaUnorm`, and `Dxt4_5` → `Bc3RgbaUnorm`. +/// BC2/BC3 have a 16-byte block footprint (BC1 is 8), so `upload`'s +/// `bytes_per_row` computation branches on the block size too. +fn descriptor_for(key: &TextureKey) -> Option> { + let format = match key.format { + TextureFormat::K8888 => wgpu::TextureFormat::Rgba8Unorm, + TextureFormat::K565 => wgpu::TextureFormat::Rgba8Unorm, // CPU-expanded + TextureFormat::Dxt1 => wgpu::TextureFormat::Bc1RgbaUnorm, + TextureFormat::Dxt2_3 => wgpu::TextureFormat::Bc2RgbaUnorm, + TextureFormat::Dxt4_5 => wgpu::TextureFormat::Bc3RgbaUnorm, + _ => return None, + }; + Some(wgpu::TextureDescriptor { + label: Some("xenos cached texture"), + size: wgpu::Extent3d { + width: key.width as u32, + height: key.height as u32, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }) +} + +fn create_magenta_stub( + device: &wgpu::Device, + queue: &wgpu::Queue, +) -> (wgpu::Texture, wgpu::TextureView) { + let tex = device.create_texture(&wgpu::TextureDescriptor { + label: Some("xenos cached stub"), + size: wgpu::Extent3d { + width: 1, + height: 1, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }); + queue.write_texture( + wgpu::ImageCopyTexture { + texture: &tex, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &[0xFFu8, 0x00, 0xFF, 0xFF], + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(4), + rows_per_image: Some(1), + }, + wgpu::Extent3d { + width: 1, + height: 1, + depth_or_array_layers: 1, + }, + ); + let view = tex.create_view(&wgpu::TextureViewDescriptor::default()); + (tex, view) +} diff --git a/crates/xenia-ui/src/xenos_pipeline.rs b/crates/xenia-ui/src/xenos_pipeline.rs new file mode 100644 index 0000000..b9fb647 --- /dev/null +++ b/crates/xenia-ui/src/xenos_pipeline.rs @@ -0,0 +1,643 @@ +//! Host pipeline that consumes PM4 `DRAW_INDX*` captures. +//! +//! Drives [`xenia_gpu::shaders::XENOS_INTERP_WGSL`]. This file owns the +//! wgpu bind-group + pipeline + buffer surface the Xenos WGSL interpreter +//! binds to. The WGSL module is expected to declare: +//! +//! ```text +//! @group(0) @binding(0) var xenos_draw : XenosDrawConstants; // 16 B +//! @group(0) @binding(1) var xenos_consts : XenosConstants; // ~9.2 KB +//! @group(0) @binding(2) var vs_ucode : array; +//! @group(0) @binding(3) var ps_ucode : array; +//! @group(0) @binding(4) var vertex_buffer : array; +//! ``` +//! +//! Texture bindings (M6) are a single-slot stub for P3b: +//! +//! ```text +//! @group(1) @binding(0) var xenos_tex : texture_2d; +//! @group(1) @binding(1) var xenos_samp : sampler; +//! ``` +//! +//! The bound texture is a 1×1 magenta placeholder. Real per-slot guest +//! texture uploads + format decode land with the texture cache (P5). + +use bytemuck::{Pod, Zeroable}; +use wgpu::util::DeviceExt; + +use xenia_gpu::shaders::XENOS_INTERP_WGSL; +use xenia_gpu::xenos_constants::XenosConstantsBlock; + +/// Per-draw constants mirroring the WGSL `XenosDrawConstants` uniform +/// block. Ordering / padding matches `xenos_interp.wgsl` exactly. +#[repr(C)] +#[derive(Clone, Copy, Pod, Zeroable)] +struct DrawConstants { + draw_index: u32, + vertex_count: u32, + prim_kind: u32, + _pad: u32, +} + +/// Submitted to [`XenosPipeline::render_one`] to render one captured draw. +#[derive(Clone, Copy, Debug)] +pub struct DrawRequest { + /// Monotonic draw counter; shader uses it for per-draw colour rotation. + pub draw_index: u32, + /// Host-normalised vertex count (after primitive-processor rewrite). + pub vertex_count: u32, + /// Xenos primitive-type code; shader may branch on it in P3b+. + pub prim_kind: u32, +} + +/// Reasonable upper bound on a single shader blob (dwords). Most Xbox 360 +/// shaders are ≪ 4 KB; 64 KB is orders-of-magnitude slack. +const UCODE_BUFFER_MAX_DWORDS: u64 = 16 * 1024; // 64 KB each for VS & PS +/// 16 MB of vertex data — enough for any realistic Xenos draw. +const VERTEX_BUFFER_MAX_BYTES: u64 = 16 * 1024 * 1024; + +pub struct XenosPipeline { + pipeline: wgpu::RenderPipeline, + draw_ctx_buffer: wgpu::Buffer, + constants_buffer: wgpu::Buffer, + vs_ucode_buffer: wgpu::Buffer, + ps_ucode_buffer: wgpu::Buffer, + vertex_buffer: wgpu::Buffer, + bind_group: wgpu::BindGroup, + /// P5: swapped per-draw when a new cached texture becomes active. + tex_bind_group: wgpu::BindGroup, + /// Layout + sampler retained so `set_texture_view` can rebuild + /// `tex_bind_group` on the fly without re-reading the pipeline. + tex_bgl: wgpu::BindGroupLayout, + sampler: wgpu::Sampler, + /// Fallback 1×1 magenta texture — used when no guest texture has been + /// uploaded yet or when a draw references an unsupported format. + dummy_view: wgpu::TextureView, + /// P7 — retained pipeline layout + compiled-pipeline cache for + /// Xenos→WGSL translator output. Keyed on `(vs_blob_key, ps_blob_key)` + /// so every (vs, ps) pair gets compiled once and re-used for every + /// subsequent draw. Interpreter pipeline remains the fallback. + pipeline_layout: wgpu::PipelineLayout, + translated_cache: std::collections::HashMap<(u32, u32), wgpu::RenderPipeline>, + pub target_format: wgpu::TextureFormat, +} + +impl XenosPipeline { + pub fn new( + device: &wgpu::Device, + queue: &wgpu::Queue, + target_format: wgpu::TextureFormat, + ) -> Self { + let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("xenos_interp.wgsl"), + source: wgpu::ShaderSource::Wgsl(XENOS_INTERP_WGSL.into()), + }); + + let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("xenos bind group layout"), + entries: &[ + // b0: draw_ctx (16 B uniform) + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: std::num::NonZeroU64::new( + std::mem::size_of::() as u64, + ), + }, + count: None, + }, + // b1: XenosConstants read-only storage (~9.2 KB). Not uniform + // because the block contains packed `array` fields and + // WGSL's uniform address space would require 16-byte stride. + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: std::num::NonZeroU64::new( + XenosConstantsBlock::SIZE as u64, + ), + }, + count: None, + }, + // b2: vs_ucode (read-only storage) + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + // b3: ps_ucode (read-only storage) + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + // b4: vertex_buffer (read-only storage) + wgpu::BindGroupLayoutEntry { + binding: 4, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: true }, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }, + ], + }); + let tex_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: Some("xenos tex bind group layout"), + entries: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Texture { + sample_type: wgpu::TextureSampleType::Float { filterable: true }, + view_dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: None, + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), + count: None, + }, + ], + }); + + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("xenos pipeline layout"), + bind_group_layouts: &[&bgl, &tex_bgl], + push_constant_ranges: &[], + }); + + // Buffer allocation. `queue.write_buffer` uses COPY_DST; all + // interpreter-facing buffers need it. + let initial_draw = DrawConstants { + draw_index: 0, + vertex_count: 3, + prim_kind: 4, + _pad: 0, + }; + let draw_ctx_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("xenos draw ctx"), + contents: bytemuck::bytes_of(&initial_draw), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + let constants_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("xenos constants"), + size: XenosConstantsBlock::SIZE as u64, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let vs_ucode_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("xenos vs ucode"), + size: UCODE_BUFFER_MAX_DWORDS * 4, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let ps_ucode_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("xenos ps ucode"), + size: UCODE_BUFFER_MAX_DWORDS * 4, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("xenos vertex buffer"), + size: VERTEX_BUFFER_MAX_BYTES, + usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + // Dummy 1×1 magenta texture — placeholder until P5's texture cache + // lands. Every `interpret_texture_fetch` samples this for now so the + // interpreter can exercise textureSample paths without a real cache. + let dummy_tex = device.create_texture(&wgpu::TextureDescriptor { + label: Some("xenos dummy texture"), + size: wgpu::Extent3d { + width: 1, + height: 1, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }); + // Magenta (255, 0, 255, 255) so a missing-texture read visibly stands + // out on-screen when the interpreter does sample it. + queue.write_texture( + wgpu::ImageCopyTexture { + texture: &dummy_tex, + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + aspect: wgpu::TextureAspect::All, + }, + &[0xFFu8, 0x00, 0xFF, 0xFF], + wgpu::ImageDataLayout { + offset: 0, + bytes_per_row: Some(4), + rows_per_image: Some(1), + }, + wgpu::Extent3d { + width: 1, + height: 1, + depth_or_array_layers: 1, + }, + ); + let dummy_view = dummy_tex.create_view(&wgpu::TextureViewDescriptor::default()); + let dummy_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("xenos dummy sampler"), + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + ..Default::default() + }); + let tex_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("xenos tex bind group"), + layout: &tex_bgl, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(&dummy_view), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&dummy_sampler), + }, + ], + }); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("xenos bind group"), + layout: &bgl, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: draw_ctx_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: constants_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 2, + resource: vs_ucode_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 3, + resource: ps_ucode_buffer.as_entire_binding(), + }, + wgpu::BindGroupEntry { + binding: 4, + resource: vertex_buffer.as_entire_binding(), + }, + ], + }); + + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("xenos_interp pipeline"), + layout: Some(&layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + compilation_options: Default::default(), + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + compilation_options: Default::default(), + targets: &[Some(wgpu::ColorTargetState { + format: target_format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent::OVER, + }), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + cache: None, + }); + + Self { + pipeline, + draw_ctx_buffer, + constants_buffer, + vs_ucode_buffer, + ps_ucode_buffer, + vertex_buffer, + bind_group, + tex_bind_group, + tex_bgl, + sampler: dummy_sampler, + dummy_view, + pipeline_layout: layout, + translated_cache: std::collections::HashMap::new(), + target_format, + } + } + + /// P7 — does the translator cache already have a pipeline for this + /// (vs, ps) pair? + pub fn has_translated(&self, vs_blob_key: u32, ps_blob_key: u32) -> bool { + self.translated_cache + .contains_key(&(vs_blob_key, ps_blob_key)) + } + + /// P7 — fetch a cached translator pipeline. `None` if not yet built. + pub fn translated_pipeline( + &self, + vs_blob_key: u32, + ps_blob_key: u32, + ) -> Option<&wgpu::RenderPipeline> { + self.translated_cache + .get(&(vs_blob_key, ps_blob_key)) + } + + /// P7 — compile a translator-produced WGSL module into a + /// `wgpu::RenderPipeline` and insert it into the cache keyed on + /// `(vs_blob_key, ps_blob_key)`. Returns `true` on success. Duplicate + /// inserts are no-ops. Emits `gpu.shader.compile_ok` on success. + pub fn insert_translated( + &mut self, + device: &wgpu::Device, + vs_blob_key: u32, + ps_blob_key: u32, + wgsl: &str, + ) -> bool { + let key = (vs_blob_key, ps_blob_key); + if self.translated_cache.contains_key(&key) { + return true; + } + let shader = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("xenos translated module"), + source: wgpu::ShaderSource::Wgsl(wgsl.to_string().into()), + }) + })) { + Ok(m) => m, + Err(_) => { + metrics::counter!("gpu.shader.compile_err", "stage" => "module") + .increment(1); + return false; + } + }; + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("xenos translated pipeline"), + layout: Some(&self.pipeline_layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "vs_main", + compilation_options: Default::default(), + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "fs_main", + compilation_options: Default::default(), + targets: &[Some(wgpu::ColorTargetState { + format: self.target_format, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha, + operation: wgpu::BlendOperation::Add, + }, + alpha: wgpu::BlendComponent::OVER, + }), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + multiview: None, + cache: None, + }); + self.translated_cache.insert(key, pipeline); + metrics::counter!("gpu.shader.compile_ok").increment(1); + true + } + + /// Render one draw with the translator-produced pipeline instead of + /// the interpreter. Mirrors [`render_one`] except the bound pipeline + /// is swapped for `pipeline`. + pub fn render_one_with_pipeline( + &self, + queue: &wgpu::Queue, + encoder: &mut wgpu::CommandEncoder, + target_view: &wgpu::TextureView, + req: DrawRequest, + pipeline: &wgpu::RenderPipeline, + ) { + let cb = DrawConstants { + draw_index: req.draw_index, + vertex_count: req.vertex_count.max(3), + prim_kind: req.prim_kind, + _pad: 0, + }; + queue.write_buffer(&self.draw_ctx_buffer, 0, bytemuck::bytes_of(&cb)); + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("xenos translated draw"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: target_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + pass.set_pipeline(pipeline); + pass.set_bind_group(0, &self.bind_group, &[]); + pass.set_bind_group(1, &self.tex_bind_group, &[]); + let rounded = req.vertex_count.div_ceil(3) * 3; + pass.draw(0..rounded.max(3), 0..1); + } + + /// Number of distinct translator pipelines cached. Surfaced to the HUD. + pub fn translated_pipeline_count(&self) -> usize { + self.translated_cache.len() + } + + /// P5 — swap the active texture bound at `@group(1) @binding(0)`. + /// `view` is typically a wgpu texture view obtained from the + /// [`TextureCacheHost`]. Pass `None` to revert to the built-in dummy + /// magenta stub. + pub fn set_texture_view(&mut self, device: &wgpu::Device, view: Option<&wgpu::TextureView>) { + let bound = view.unwrap_or(&self.dummy_view); + self.tex_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + label: Some("xenos tex bind group (rebind)"), + layout: &self.tex_bgl, + entries: &[ + wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::TextureView(bound), + }, + wgpu::BindGroupEntry { + binding: 1, + resource: wgpu::BindingResource::Sampler(&self.sampler), + }, + ], + }); + } + + /// Clear `target_view` to `color`, store. + pub fn clear( + &self, + encoder: &mut wgpu::CommandEncoder, + target_view: &wgpu::TextureView, + color: [f64; 4], + ) { + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("xenos frontbuffer clear"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: target_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: color[0], + g: color[1], + b: color[2], + a: color[3], + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + let _ = &mut pass; + } + + /// Upload shader microcode + constants once (before the batch of draws + /// that share them). Skips zero-length blobs. + pub fn upload_shader_and_constants( + &self, + queue: &wgpu::Queue, + vs_ucode: &[u32], + ps_ucode: &[u32], + constants: &XenosConstantsBlock, + ) { + queue.write_buffer(&self.constants_buffer, 0, bytemuck::bytes_of(constants)); + if !vs_ucode.is_empty() { + let bytes: &[u8] = bytemuck::cast_slice(vs_ucode); + let max = (UCODE_BUFFER_MAX_DWORDS * 4) as usize; + queue.write_buffer(&self.vs_ucode_buffer, 0, &bytes[..bytes.len().min(max)]); + } + if !ps_ucode.is_empty() { + let bytes: &[u8] = bytemuck::cast_slice(ps_ucode); + let max = (UCODE_BUFFER_MAX_DWORDS * 4) as usize; + queue.write_buffer(&self.ps_ucode_buffer, 0, &bytes[..bytes.len().min(max)]); + } + } + + /// Upload vertex data (as raw big-endian dwords — the WGSL side will + /// bswap as needed during format unpacking). + pub fn upload_vertex_data(&self, queue: &wgpu::Queue, data: &[u32]) { + if data.is_empty() { + return; + } + let bytes: &[u8] = bytemuck::cast_slice(data); + let max = VERTEX_BUFFER_MAX_BYTES as usize; + queue.write_buffer(&self.vertex_buffer, 0, &bytes[..bytes.len().min(max)]); + } + + /// Render one captured draw. + pub fn render_one( + &self, + queue: &wgpu::Queue, + encoder: &mut wgpu::CommandEncoder, + target_view: &wgpu::TextureView, + req: DrawRequest, + ) { + let cb = DrawConstants { + draw_index: req.draw_index, + vertex_count: req.vertex_count.max(3), + prim_kind: req.prim_kind, + _pad: 0, + }; + queue.write_buffer(&self.draw_ctx_buffer, 0, bytemuck::bytes_of(&cb)); + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("xenos draw"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: target_view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Load, + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + pass.set_pipeline(&self.pipeline); + pass.set_bind_group(0, &self.bind_group, &[]); + pass.set_bind_group(1, &self.tex_bind_group, &[]); + let rounded = req.vertex_count.div_ceil(3) * 3; + pass.draw(0..rounded.max(3), 0..1); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn draw_constants_layout_matches_wgsl_uniform() { + assert_eq!(std::mem::size_of::(), 16); + } +}